正在寻找 Open AI embeddings API?OpenAI 的嵌入端点会将文本转换为数值向量,使应用程序能够检索相关段落。请求只是第一步:实用的搜索功能还需要稳定的文档 ID、一致的向量空间,以及能告诉您检索是否得到改进的测试。
本指南构建一个小型 Python 搜索示例,说明应与每个向量一同存储哪些内容,并提供一份将实验投入产品的核对清单。它直接使用 OpenAI。必须针对每个提供商分别验证网关兼容性和模型可用性。
Open AI embeddings API:您需要的请求
使用嵌入模型和 API 密钥将文本发送到 POST https://api.openai.com/v1/embeddings。当您的应用程序需要数值数组时,请选择 encoding_format="float"。对于批处理,请使用每个响应项的 index 将向量重新关联到其输入。响应还包含令牌使用量。dimensions 选项受第三代嵌入模型支持。OpenAI API 参考。
嵌入不是生成的答案。在检索增强型应用程序中,搜索会先选出源段落;随后可通过单独的生成调用,使用这些段落来回答问题。将这些阶段分开,您就可以诊断糟糕的结果:是搜索检索到了错误的证据,还是回答模型错误使用了良好的证据?
选择模型并保持其配置固定
文档说明的默认向量长度为:text-embedding-3-small 是 1,536,text-embedding-3-large 是 3,072。这些模型可通过 dimensions 支持较短的输出向量。较短的向量会改变存储和检索之间的权衡;这并不是跳过评估的理由。OpenAI 嵌入指南。
从一种配置和一小组具有代表性的查询开始。将模型、请求的维度数量和文本处理版本与索引一同记录。两个长度相同的向量并不能证明它们来自兼容的模型。更改模型或处理规则时,请构建单独的索引并进行比较,然后再切换生产流量。
一个极简 Python 语义搜索示例
在您的 Python 环境中安装 openai,并通过常规的密钥管理器或环境配置提供 OPENAI_API_KEY。不要将密钥放入源代码控制或浏览器代码中。官方 Python SDK 会在构造 OpenAI() 时读取该变量。
将以下内容保存为 search_demo.py。它使用三个虚构的支持文档,为语料库和查询创建嵌入,并使用余弦相似度对文档进行排序。运行它会产生计费 API 请求。输出取决于服务响应;该示例不保证特定的分数或排名。
import math
from openai import OpenAI
client = OpenAI(timeout=30.0, max_retries=2)
model = "text-embedding-3-small"
dimensions = 1536
documents = [
{"id": "key-rotation", "text": "Replace an exposed API key and revoke the old credential."},
{"id": "invoice-export", "text": "Download a monthly invoice from the billing workspace."},
{"id": "request-timeout", "text": "Record the request ID and retry temporary upstream timeouts."},
]
query = "What should I do after accidentally sharing a secret key?"
def embed(texts):
response = client.embeddings.create(
model=model, input=texts,
dimensions=dimensions, encoding_format="float",
)
ordered = sorted(response.data, key=lambda item: item.index)
if [item.index for item in ordered] != list(range(len(texts))):
raise ValueError("Unexpected embedding response indices")
vectors = [item.embedding for item in ordered]
if any(len(vector) != dimensions for vector in vectors):
raise ValueError("Unexpected vector dimensions")
print("Input tokens:", response.usage.prompt_tokens)
return vectors
def cosine(a, b):
if len(a) != len(b):
raise ValueError("Vector dimensions do not match")
denominator = math.sqrt(sum(x*x for x in a) * sum(y*y for y in b))
if not denominator:
raise ValueError("Cannot compare a zero vector")
return sum(x*y for x, y in zip(a, b)) / denominator
vectors = embed([document["text"] for document in documents])
query_vector = embed([query])[0]
ranked = sorted(
((cosine(query_vector, vector), document["id"])
for document, vector in zip(documents, vectors)),
reverse=True,
)
for score, document_id in ranked:
print(document_id, round(score, 4))
运行 python search_demo.py。确认三个 ID 都各出现一次,并且每个嵌入均具有配置的长度。然后将查询改为询问发票。这是对数据流的冒烟测试,并不能证明系统已准备好承载真实的支持流量。为便于说明,该示例会在每次执行时再次嵌入语料库;已部署的服务通常应持久化文档向量,并且只嵌入新增或变更的内容。
将演示转化为可靠的文档索引
以下记录布局是一个实用的起点。这是应用程序设计示例,并非 OpenAI 要求的字段架构。
| 随每个分块存储的内容 | 重要原因 |
|---|---|
document_id 和 chunk_id | 无需依赖数组顺序即可更新或删除正确的内容。 |
| 源 URL、章节标题和源修订版本 | 显示有用的引用并追踪过时的答案。 |
| 内容哈希和处理版本 | 识别哪些分块实际需要重新生成嵌入。 |
| 模型和维度数量 | 防止意外混用不兼容的向量配置。 |
| 租户和访问控制元数据 | 将检索结果筛选为请求用户可访问的文档。 |
| 文本和嵌入 | 选定其向量后返回源段落。 |
在有意义的边界处分割文档,然后检查令牌长度。包含问题答案的章节在被单独检索时应仍然易于理解。应审慎评估重叠部分:过度重叠可能会使结果集充满同一段落的重复版本。
对于首次实验,上述内存循环已经足够。随着语料库增长,请使用支持所需筛选、删除和检索行为的索引或向量存储。在依赖相似度分数之前,先测试这些操作。来自错误客户的高度相似段落绝不能仅仅因为排名第一就被返回。
分别检查输入和批处理限制
OpenAI 当前的端点参考文档规定,每个输入最多 8,192 个令牌,单个请求中所有输入合计最多 300,000 个令牌;文档还规定批处理输入最多为 2,048 个。空文本无效。请计算令牌数而非字符数,并在构建批次时在限制值以下留出余量。端点限制。
如果您使用 Azure OpenAI,端点配置、身份验证和部署命名都有各自的设置。请遵循该服务的 Azure 嵌入说明,而不要假设可以原样复制直接调用 OpenAI 的请求。使用网关时也应采取同样的区分方式:首先检查其端点、模型访问权限、支持的参数和计费账户。
估算成本时不要忽略索引重建
嵌入成本取决于输入令牌,因此请分别计算文档摄取、变更的分块和查询嵌入。请使用相关模型页面上的当前价格,例如 text-embedding-3-small,并确认所报费率是否适用于您的请求模式。
作为规划示例,设 P 为您核实后的每百万输入令牌价格:
初次导入:50,000 个分块 × 400 个令牌 = 2,000 万个令牌
每月变更: 5,000 个分块 × 400 个令牌 = 200 万个令牌
每月查询:200,000 次查询 × 20 个令牌 = 400 万个令牌
首次嵌入成本 = 20 × P
后续嵌入成本 = (2 + 4) × P = 6 × P
这些是示例性的工作负载假设,并非 Flatkey 或 OpenAI 的价格。请另行加入向量存储、搜索基础设施以及任何答案生成调用的成本。如果更换嵌入模型,请在迁移预算中包含一次完整的重新嵌入。对未变更文档重新生成嵌入的管道,成本可能高于使用更大但正确缓存的模型处理相同工作负载。
添加重试前先诊断错误
| 症状 | 首要有效检查 |
|---|---|
| 身份验证错误 | 确认该密钥对您调用的端点和账户有效。 |
| 无效请求 | 检查错误正文、空字符串、令牌数量和支持的参数。 |
| 速率限制或配额错误 | 区分请求速率压力和账户配额耗尽。 |
| 临时服务器错误或超时 | 保留请求标识符,并采用有界重试行为。 |
| 向量存储维度错误 | 将集合配置与实际返回的向量长度进行比较。 |
| 看似合理但无关的结果 | 在归咎于网络之前,检查分块文本、模型一致性和查询示例。 |
前四项检查遵循 OpenAI 错误指南。后两项与您的应用程序和索引有关。在添加另一个重试循环之前,请遵循服务器的重试指导,并考虑 SDK 重试。记录运行元数据时,不要记录凭据或不必要的私有文档文本。
选择回答模型前评估检索
根据真实用户问题创建一个小型标注集,其中包括释义、精确产品名称、含糊的问题以及您的语料库无法回答的问题。在调整系统之前,先为每个可回答的查询写下预期的源文档。
对于每种候选配置,记录可接受的来源是否出现在前几个结果中、返回了多少重复材料、检索延迟以及每次查询的成本。逐一审查失败案例。如果查询要求精确的错误代码,关键字匹配可以补充语义相似度。如果缺少来源,改变嵌入维度无法凭空创造它。
保留一部分未参与调参的问题用于最终比较。不要根据三个文档的演示选择一个相似度阈值,并将其视为通用置信度分数。有效的验收测试应反映错误检索在您自身应用中的后果。
Flatkey 在应用程序中的定位
Flatkey 提供与 OpenAI 兼容的模型路由器以及当前模型目录。使用 Flatkey 集成文档来评估应用程序中的模型生成部分。上述示例直接调用 OpenAI;它们并不能证明嵌入模型或所有嵌入参数都可通过 Flatkey 使用。
对于多提供商应用程序,应将检索配置与回答模型配置保持独立。这样,您便可在无需为每次实验重建文档索引的情况下比较回答模型。规划路由、账户控制和运营检查时,请参阅 Flatkey 的 API 架构指南。
常见问题
嵌入 API 本身能回答问题吗?
它返回向量。您的应用程序使用这些向量来选择相关内容;如果您需要书面回答,则回答模型是一个独立组件。
我可以比较不同嵌入模型的向量吗?
即使它们的维度相同,也不要假定它们共享有意义的坐标空间。请保留特定于模型的索引,并使用相同的问题和源文档评估迁移。
我应该立即选择最大的嵌入模型吗?
应从可衡量的配置开始。在接受更大的索引或不同的模型之前,请根据您自己的查询比较检索质量、延迟、存储和成本。
我应该先构建什么?
使用 Open AI embeddings API 为一个小型且权限安全的语料库生成嵌入,验证文档到向量的映射,并使用带标签的问题测试检索。在该循环产生可靠证据后,再扩展语料库。



