文本向量化
POST /v1/embeddings —— 把文本转成向量,用于检索、聚类与相似度。
向量化是做什么的#
向量化把一段文本变成一串数字(一个向量),使得意思相近的文本得到方向相近的向量。有了它,"检索"就从"字面包含关键词"变成了"意思接近"——用户搜"退钱",能命中写着"退款"的那篇文档。
典型用法:把你的文档逐段向量化后存进向量数据库;用户提问时把问题也向量化,在库里找最接近的几段,再把这几段连同问题一起交给对话模型作答。这套做法叫检索增强生成(RAG)。
同一批数据必须用同一个模型
不同模型产出的向量互不兼容,维度不同,即使维度碰巧相同也不在同一个语义空间里。换模型意味着整库重算,所以选型要在灌数据之前定下来。
发起请求#
与 OpenAI 的 Embeddings 接口同形,改掉 base_url 与 api_key 就能用现成 SDK。向量模型只走这条端点:把向量模型名发到 /v1/chat/completions 不会得到有意义的结果,反过来把对话模型发到这里会被判成用错端点。
modelstring必填- 向量模型名,可在 模型广场 按 embedding 模态筛选。
inputstring | string[] | int[] | int[][]必填- 待向量化的内容。四种形态都接受:单条文本、文本数组、单条 token id 数组、token id 数组的数组。数组形态单次最多 2048 条,超了直接报
invalid_request而不是发给上游——超限的请求在上游只会换来一个 400,而我们已经为它做了路由与预扣。 encoding_formatstringfloat(默认)或base64。选base64时向量原样回传,不做一次解码再编码的往返——那趟往返除了浪费 CPU,还会因为 float32 的十进制往返丢精度。dimensionsinteger- 降维后的输出维数,取决于模型是否支持。这里只校验它大于 0:具体上限随模型而异,硬编码一个上限会在模型更新时误拦合法请求。
userstring- 调用方自定义的终端用户标识,透传给上游。
bash
curl https://ai.oceango.hk/v1/embeddings \ -H "Authorization: Bearer $AIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "text-embedding-3-small", "input": ["今天天气不错", "The weather is nice today"] }'响应#
data 按 index 与请求里 input 的顺序一一对应。即使只发了一条文本,data 也是数组。
json
{ "object": "list", "model": "text-embedding-3-small", "data": [ { "object": "embedding", "index": 0, "embedding": [0.0023, -0.0091, "..."] }, { "object": "embedding", "index": 1, "embedding": [0.0117, 0.0042, "..."] } ], "usage": { "prompt_tokens": 14, "total_tokens": 14 }}没有流式
向量化的结果是定长向量,一次返回完,
stream 在这里没有意义,也不接受。Python:一次编码多段文本
python
import osfrom openai import OpenAI
client = OpenAI(api_key=os.environ["AIROUTER_API_KEY"], base_url="https://ai.oceango.hk/v1")
response = client.embeddings.create( model="openai/text-embedding-3-small", input=[ "订单在支付后 7 天内可以申请全额退款。", "我们的办公地址位于香港中环。", ],)
for item in response.data: print(item.index, len(item.embedding), item.embedding[:3])Node.js:批量编码后写进你的向量库
javascript
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.AIROUTER_API_KEY, baseURL: 'https://ai.oceango.hk/v1',});
const chunks = ['订单在支付后 7 天内可以申请全额退款。', '我们的办公地址位于香港中环。'];
const { data } = await client.embeddings.create({ model: 'openai/text-embedding-3-small', input: chunks,});
// data 与 input 顺序一致,用 index 对回原文for (const item of data) { await vectorStore.upsert({ text: chunks[item.index], vector: item.embedding });}计费#
只按输入 token 计价,没有输出那一项。向量化不生成 token,成本完全由输入长度决定,所以预扣里不含输出那一项——沿用对话的估算会凭空加上几百个输出 token,对单价高的向量模型来说是把预扣放大好几倍,用户会在余额充足的情况下被判成余额不足。
- 响应里的
usage.prompt_tokens与usage.total_tokens相等,这不是 bug。 - 预扣按估算值打上放大系数,实结按上游报回来的真实 token 数;差额当场退回。
- 计费口径与对话一致,详见 计费。
常见错误#
错误信封、请求 ID 与重试建议与其它端点完全一致,见 错误处理。