Embeddings
Embeddings
把文本转成向量,用于语义搜索、检索(RAG)、推荐、聚类和去重。提供 OpenAI 的 text-embedding-3 系列模型,价格只有 OpenAI 的一半。模型 ID、请求和响应、返回的向量全都一样:为 OpenAI 写的代码,改一下 base URL 和 key 就能跑。
/v1/embeddings只为发送的文本付费,向量不额外收费。两个模型每次输入最多读取 8,192 个 token。Text Embedding 3 Small 适合起步:便宜、快,足够应付大多数搜索和 RAG 场景。Text Embedding 3 Large 更大、更准,适合检索质量比存储和成本更重要的场景。
快速开始
import osfrom openai import OpenAIclient = OpenAI( base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"],)response = client.embeddings.create( model="text-embedding-3-small", input="The food was delicious and the waiter was friendly.",)vector = response.data[0].embedding # a list of 1,536 floatsprint(len(vector), response.usage.prompt_tokens) # 1536 10任何 OpenAI SDK 都能用:把地址指向 https://api.zurelay.com/v1,换成你的 Zurelay key,调用它的 embeddings 方法即可。返回的是 OpenAI 的格式:
{ "object": "list", "data": [ { "object": "embedding", "index": 0, "embedding": [-0.0022748, -0.0093183, 0.0158532, ..., -0.0028842] } ], "model": "text-embedding-3-small", "usage": { "prompt_tokens": 10, "total_tokens": 10 }}data 按你发送的顺序为每个输入返回一个 embedding,各自带 index。usage.prompt_tokens 是这次请求的计费依据。响应头里也有同样的信息:x-zurelay-model 标明模型,x-zurelay-input-tokens 标明 token 数,用 x-request-id 可以在请求日志里定位这次请求。
参数
modelstring必填text-embedding-3-small或text-embedding-3-large。input字符串或数组必填- 可嵌入的内容:一个字符串、一个最多 2,048 个字符串的数组、一个 token ID 数组(来自 OpenAI
cl100k_base分词器的整数),或一个最多 2,048 个这种数组的数组。每个输入最多 8,192 个 token,且不能是空字符串。 encoding_formatstringfloat(默认):每个 embedding 是一个数字数组。base64:每个是 little-endian float32 数字的 base64 字符串,体积更小,下载更快。参见 Base64。dimensionsinteger- 缩短向量:在
text-embedding-3-small上可设为 1 到 1,536,在text-embedding-3-large上为 1 到 3,072。不填则使用完整长度。参见 更短的向量。 userstring- 可选:本次请求所针对的最终用户 ID,与 OpenAI 的 API 一致。会被接受,但不会对向量产生任何影响。
批量请求
一次请求发送多段文本:input 接受最多 2,048 个元素的数组,返回结果顺序与输入一致。一次请求带上千段文本,比发一千次请求快得多,费用却相同:按 token 计费,而不是按请求计费。每个请求的总量请控制在 300,000 token 以内。
# pip install tiktokenimport tiktoken# The tokenizer text-embedding-3 counts with, to keep each request under the limitsenc = tiktoken.get_encoding("cl100k_base")def batches(texts, max_inputs=2048, max_tokens=300_000): batch, tokens = [], 0 for text in texts: count = len(enc.encode(text)) if batch and (len(batch) == max_inputs or tokens + count > max_tokens): yield batch batch, tokens = [], 0 batch.append(text) tokens += count if batch: yield batchvectors = []for batch in batches(texts): response = client.embeddings.create(model="text-embedding-3-small", input=batch) vectors += [item.embedding for item in response.data] # in the order sent超过 8,192 token 的文档,先切分成块再嵌入。做搜索和 RAG 时,几百 token、一两个段落的块,通常比整篇文档匹配得更准。
用 dimensions 缩短向量
text-embedding-3 系列模型训练时就考虑了这一点,缩短后的向量依然可用:指定 dimensions,返回的是完整向量的前半段,并重新归一化到长度 1。更短的向量占用更少存储和内存,检索也更快,代价是精度略降。Text Embedding 3 Large 在 1,024 维时,占用空间只有完整 3,072 维的三分之一。
response = client.embeddings.create( model="text-embedding-3-large", input="The food was delicious and the waiter was friendly.", dimensions=1024,)print(len(response.data[0].embedding)) # 1024Base64
设置 "encoding_format": "base64" 后,每个 embedding 会以 little-endian float32 数字的 base64 字符串返回,而不是 JSON 数组:体积更小,下载和解析也更快。如果不传 encoding_format,OpenAI 的 Python SDK 会自行请求 base64 并替你解码,所以无论哪种方式,拿到的都是普通浮点数。如果你自己请求 base64,返回的就是字符串,可以这样解码:
import base64import numpy as npresponse = client.embeddings.create( model="text-embedding-3-small", input=["First text", "Second text"], encoding_format="base64",)# Each embedding is a base64 string of little-endian float32 numbersvectors = [np.frombuffer(base64.b64decode(item.embedding), dtype="<f4") for item in response.data]语义搜索
把文档嵌入一次,把向量存好。搜索时用同一个模型嵌入查询,再按文档向量与查询的余弦相似度排序:越接近 1,语义越接近,即使两者没有任何共同词语。text-embedding-3 的向量长度为 1,所以用点积排序结果一样。
# pip install openai numpyimport osimport numpy as npfrom openai import OpenAIclient = OpenAI(base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"])MODEL = "text-embedding-3-small"docs = [ "To change your password, open Settings, choose Security and click Change password.", "Invoices are emailed on the first day of each month and can be downloaded under Billing.", "Invite teammates from the Team page; each person signs in with their own email.", "API keys can be limited to a monthly budget, a rate limit and a list of models.",]def embed(texts): response = client.embeddings.create(model=MODEL, input=texts) return np.array([item.embedding for item in response.data])doc_vectors = embed(docs) # embed once, and store the vectors beside the textdef search(query, k=2): query_vector = embed([query])[0] # The vectors have length 1, so the dot product is the cosine similarity scores = doc_vectors @ query_vector best = np.argsort(-scores)[:k] return [(docs[i], float(scores[i])) for i in best]for text, score in search("How can I change my password?"): print(f"{score:.3f} {text}") # the password article comes first文档超过几千个时,把向量放进向量数据库或向量索引(pgvector、Qdrant、Pinecone、Weaviate、Chroma 等),排序交给它来做。
检索(RAG)
检索增强生成用你自己的文档来回答问题:先找出与问题最接近的段落,再连同问题一起交给对话模型。这两件事用同一个 Zurelay key 就够了。
# After the search example above: retrieve, then answer from what was foundquestion = "How do I stop a key from spending too much?"notes = "\n".join(text for text, _ in search(question))answer = client.chat.completions.create( model="gpt-6-luna", messages=[ { "role": "system", "content": "Answer from these notes only. If they don't say, say so.\n\n" + notes, }, {"role": "user", "content": question}, ],)print(answer.choices[0].message.content)LangChain、LlamaIndex 和 AI SDK
带有 OpenAI embeddings 类的框架,配上 Zurelay 的 base URL 和 key 就能用,模型 ID 仍是 OpenAI 的那套。
LangChain
# pip install langchain-openaiimport osfrom langchain_openai import OpenAIEmbeddingsembeddings = OpenAIEmbeddings( model="text-embedding-3-small", base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"],)query_vector = embeddings.embed_query("How can I change my password?")doc_vectors = embeddings.embed_documents(["First document", "Second document"])LangChain 的 Python OpenAIEmbeddings 默认会自己分词,然后发送 token ID。Zurelay 接受 token 数组,所以默认设置直接可用。
LlamaIndex
# pip install llama-index-embeddings-openaiimport osfrom llama_index.core import Settingsfrom llama_index.embeddings.openai import OpenAIEmbeddingSettings.embed_model = OpenAIEmbedding( model="text-embedding-3-small", api_base="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"],)vector = Settings.embed_model.get_text_embedding("How can I change my password?")设置好 Settings.embed_model 后,你构建的每个索引和检索器都通过 Zurelay 做嵌入。对话模型请参见 LlamaIndex 指南。
Vercel AI SDK
// npm install ai @ai-sdk/openaiimport { createOpenAI } from "@ai-sdk/openai";import { cosineSimilarity, embed, embedMany } from "ai";const zurelay = createOpenAI({ baseURL: "https://api.zurelay.com/v1", apiKey: process.env.ZURELAY_API_KEY,});const model = zurelay.embedding("text-embedding-3-small");const { embeddings } = await embedMany({ model, values: ["First document", "Second document"] });const { embedding } = await embed({ model, value: "How can I change my password?" });console.log(cosineSimilarity(embedding, embeddings[0]));应用与向量存储
凡是可以用自定义 base URL 调用 OpenAI embeddings 的应用,用法都一样:把 base URL 设为 https://api.zurelay.com/v1,用你的 Zurelay key 和上面某个模型 ID 即可。包括 Open WebUI 用于文档的 OpenAI embedding 引擎、LibreChat 的 RAG API、n8n 的 Embeddings OpenAI 节点,以及 Dify 的 OpenAI 兼容模型供应商。
与 OpenAI 相同的向量
发往 text-embedding-3-small 和 text-embedding-3-large 的请求都跑在 OpenAI 自己的模型上。我们把每条线路都与 OpenAI 的 API 做了比对:同样的文本、同样的模型,向量与 OpenAI 一致,余弦相似度在 0.9999 以上。所以用 OpenAI API 建的索引,通过 Zurelay 嵌入查询照样能用;用 Zurelay 建的索引,接上 OpenAI 也没问题。两边切换不需要重新嵌入。
换模型就得重新嵌入
不同模型的向量无法相互比较
text-embedding-3-small 的向量和 text-embedding-3-large 的向量放在一起毫无意义,和其他任何模型的向量也一样:每个模型都把文本放在自己的空间里。所以要换模型,就用新模型把已存的内容全部重新嵌入,之后也用这个模型做查询。同理,embeddings 请求永远由你指定的模型来回答。不管你的设置如何,智能路由都不会把它交给别的模型:模型不可用时你会收到 503 model_unavailable,可以重试,而不是拿到与索引对不上的向量。
限制
- 每个请求最多 2,048 个输入。
- 每个输入最多 8,192 token,整个请求最多 300,000 token。
- 不接受空字符串。
dimensions可设为 1 到该模型的完整长度:text-embedding-3-small上是 1,536,text-embedding-3-large上是 3,072。- 超出限制的请求会被拒绝,返回的
400会指明是哪项限制,且不产生费用。 - 限制了可用模型的 key,需要把 embedding 模型加进它的列表。参见 Key 限制与规则。
embeddings 的费用
Embeddings 只按输入 tokens 计费,计数方式与 OpenAI 相同,向量本身免费。 Text Embedding 3 Small 每 1M tokens 收费 $0.01 以及 Text Embedding 3 Large $0.065,只有 OpenAI 价格的一半。100 万条各 100 tokens 的文本,合计 100M tokens,用 Text Embedding 3 Small 生成向量花 $1.00 以及配合 Text Embedding 3 Large 时的 $6.50,在 OpenAI 则要 $2.00 以及 $13.00。
单次请求没有最低消费:10 tokens 的请求就按 10 tokens 计费。更短的输入dimensions和 base64 编码价格一样。每次响应的 usage 和 x-zurelay-input-tokens 请求头会说明按什么计费,每次请求都记在请求日志里,失败的请求不收费。
错误
错误的格式与 OpenAI 一致,所以 OpenAI 的 SDK 会像处理 OpenAI 的错误那样把它们抛出来。
密钥、额度、预算和速率限制的报错与其他所有端点相同,详见错误。OpenAI 的 SDK 会自动重试值得重试的错误。
先试一试
有疑问,或发现内容缺失?联系我们的支持团队,我们会通过邮件回复,通常只需一分钟。