OpenAI Embeddings 怎样按批量输入组织请求
来源:17golang原创
时间:2026-10-26 02:35:58 124浏览 收藏
当待向量化的文本从几十条增长到几千条时,最稳妥的做法不是把它们拼成一段超长字符串,而是把多条字符串作为同一个 Embeddings 请求的 input 数组,并在本地控制每批的数量和 token 预算。这样每个向量仍然对应一条原始记录,某一批失败时也只需要处理这一批。
官方地址:https://developers.openai.com/api/docs/guides/embeddings
- 批量输入使用字符串数组;批次大小是工程策略,不等于服务端固定值。
- 每条输入要控制在模型上限内,单次请求还要关注所有输入合计 token。
- 用返回项的
index绑定原始记录,向量维度固定后再写入下游存储。
多条文本应该怎样进入同一个 Embeddings 请求
OpenAI Embeddings 的 input 可以是一个字符串,也可以是字符串数组。数组中的每个元素代表一条独立文本,返回结果会在 data 中给出对应的 embedding 项。这个模型更适合“多条记录分别向量化”,而不是把标题、正文和其他记录拼在一起后失去记录边界。
官方 API reference 给出了两个需要同时考虑的输入边界:所有 embedding 模型单条输入最多 8192 tokens;单次请求中所有输入合计最多 300000 tokens。下面的 64 条只是一个便于控制失败范围的起始批次,不是硬性规定。短文本可以适当增大,长文本或限流敏感的任务则应该减小。

先按可控数量切出批次
先把空字符串过滤掉,再用固定的 max_items 切片。这里不在示例中假装用字符数精确代替 token 数;如果文本长度差异很大,应在切批前接入与模型匹配的 tokenizer,或者降低单批数量,给合计 token 留出余量。
from openai import OpenAI
client = OpenAI()
def split_batches(texts: list[str], max_items: int = 64):
"""把非空文本切成小批次,控制一次失败影响的记录范围。"""
# 过滤空白输入,避免把无意义文本发送到接口。
cleaned = [text.strip() for text in texts if text and text.strip()]
for start in range(0, len(cleaned), max_items):
# max_items 是本地工程策略,不代表接口的固定批量上限。
yield cleaned[start:start + max_items]
def embed_texts(texts: list[str]) -> list[list[float]]:
"""按批次提交文本,并按返回 index 放回连续结果列表。"""
results: list[list[float] | None] = [None] * len(
[text for text in texts if text and text.strip()]
)
offset = 0
for batch in split_batches(texts):
try:
response = client.embeddings.create(
model="text-embedding-3-small",
input=batch,
encoding_format="float",
)
# 返回 index 是批次内位置,必须加上本批在全量结果中的偏移量。
for item in response.data:
results[offset + item.index] = item.embedding
offset += len(batch)
except Exception:
# 真实任务中记录 batch 起点并重试当前批次,不要悄悄跳过。
raise
# 让调用方尽早发现批次回填不完整,而不是把 None 写入向量库。
if any(vector is None for vector in results):
raise RuntimeError("embedding result is incomplete")
return [vector for vector in results if vector is not None]
这段代码有两个容易忽略的点。第一,空文本过滤后,结果数组的长度必须以清洗后的文本为准。第二,item.index 是当前批次内的索引,所以要加上 offset 才能定位到全量结果中的位置。生产环境可以把当前批次的起点、请求参数和异常类型写入任务日志,重试时只重试该批次。
为什么要用返回的 index 还原记录顺序
向量不是脱离业务记录独立存在的。写入数据库或向量存储时,通常还需要保留文章 ID、商品 ID或文档版本。最简单的安全做法是为每条输入保留一个业务主键,并用批次内位置建立临时映射;收到响应后,以 data.index 找回原记录,而不是直接假定返回数组永远按照你的输入顺序排列。

| 字段 | 用途 | 处理建议 |
|---|---|---|
| record_id | 业务记录身份 | 始终和向量一起保存 |
| batch index | 当前批次内位置 | 只作为临时回填键 |
| data.index | 响应中的位置 | 映射回本批输入 |
| dimensions | 向量长度 | 写入下游前固定并记录 |
失败批次和 dimensions 怎么处理
批量请求的好处是减少请求次数,代价是单次失败会影响一组记录。因此建议把每批当成独立任务:保存批次起止位置,成功后再提交下游;失败时只重试当前批次,并设置有限次数与退避。不要在异常分支里继续把未知长度的结果写入向量存储。
text-embedding-3-small 默认返回 1536 维,text-embedding-3-large 默认返回 3072 维;官方指南说明,dimensions 可以用于 text-embedding-3 及更新模型,以换取更小的存储与计算开销。这个参数一旦用于生产索引,就应该和向量库的 schema、相似度计算及后续查询保持一致,不能只在写入时临时改变。
def build_request(batch: list[str], dimensions: int | None = None) -> dict:
"""构造一个可记录、可重试的请求参数。"""
# 请求前再次检查空批次,避免把无效任务交给远端接口。
if not batch:
raise ValueError("batch must not be empty")
payload = {
"model": "text-embedding-3-small",
"input": batch,
"encoding_format": "float",
}
if dimensions is not None:
# dimensions 只应在选定模型和下游 schema 都支持时设置。
payload["dimensions"] = dimensions
return payload
常见问题
把多条文本拼成一个字符串和传入字符串数组有什么区别?
拼成一个字符串只会得到一个输入对应的向量;传入字符串数组则让每个元素保持独立记录边界,并在响应中得到多个 embedding 项。
批次越大越省请求吗?
通常会减少请求次数,但会增加单次失败影响范围,也更容易触碰总 token、限流或超时边界。应按文本长度和重试成本选择,而不是只追求更大的数组。
能不能只按字符串长度判断 token?
不能把字符数当成精确 token 数。文本差异明显时应使用匹配模型的 tokenizer,或降低批次并为合计 token 预留余量。
dimensions 设小后还能和旧向量混用吗?
不要默认可以。向量长度和模型配置应作为索引契约的一部分;切换维度前先规划重建、分区或版本化策略。
批量 Embeddings 的核心不是把数组做大,而是保持三条边界:输入记录不混淆、每批额度可控、返回索引能回到业务主键。沿着这三条边界组织代码,后续无论接入检索、聚类还是推荐,都更容易定位失败和迁移模型。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
412 收藏
-
114 收藏
-
277 收藏
-
101 收藏
-
123 收藏
-
231 收藏
-
417 收藏
-
352 收藏
-
348 收藏
-
439 收藏
-
241 收藏
-
208 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习