Embedding API 中转常被当成“换个地址、便宜一点”的选择。但向量化是批量任务,一次迁移可能涉及几十万条文本;中转一旦限流、截断或悄悄换了模型,损失不是一次请求,而是整个索引的可信度。

本文讲四个问题:中转有哪些形态、批量请求怎么设计、计费怎么核对、迁移和验真怎么做。具体模型与价格以站内模型价格为准。

说明:OpenAI 及其他模型、服务名称是其各自权利人的商标,本文与相关厂商无隶属关系。中转市场形态变化较快,本文不构成对任何服务方的背书。

一、中转、代理、网关不是一回事

  • 网络代理:只解决网络可达性,转发 HTTP 或 HTTPS 请求,Key 仍由自己管理。
  • 商业中转:由服务方转发到上游,可能附带计费、限额、日志和发票;市场上也有共享或转售 Key 的形态,稳定性取决于运营方。
  • 统一 AI 网关:提供 OpenAI 兼容入口,聚合多个模型,发放独立 Key,带控制台和用量统计。
  • 自建代理:自己部署反向代理或网关,控制力最强,但运维和上游账号都要自己承担。

签约前先确认对方提供哪一层服务、Key 归谁、数据经过哪里。概念不清,后面所有对比都会失焦。

维度 官方直连 自建代理 商业中转 统一 AI 网关
计费口径 厂商账单,规则清楚 上游账单加自担成本 取决于运营方,需对账 站内统一账单
批量吞吐 受账号限额约束 可排队,仍受上游限制 可能共享池,需确认 看网关限额与调度
Key 归属 自己持有 自己持有 可能共享或转售 通常独立 Key
数据边界 自行评估 自行负责 需审查条款与留存 需审查条款与资质
发票与合同 视主体而定 无第三方合同 看服务方能力 通常可开票
运维成本 中 高 低到中 低

二、批量请求:先压测,再谈价格

Embedding 的吞吐由三个变量决定:单请求条数、单条文本长度、并发数。不同服务方对单请求条数、总 Token 和请求体大小都有上限,超出时可能返回参数错误,也可能被中间层直接截断。

压测要用生产数据。取一批真实文档块,分别按小批、中批、大批组装请求,观察单批耗时、P95 延迟、429 比例和错误类型。批量不是越大越好:批次过大时,一次失败重跑的成本高,超时也更难控制。

建议的分批流程:

  1. 先统计文本长度分布,按 Token 估算而不是按条数硬切。
  2. 设定单批上限,同时留出余量应对长文本。
  3. 并发从低开始,每轮增加,记录吞吐与错误率。
  4. 达到目标吞吐后停止加并发,避免把余量吃满。
  5. 把每批的输入哈希、Token 用量和结果落盘,便于对账和续跑。

三、重试与部分失败

Embedding 请求是只读操作,重试不会产生重复写入,但会把失败放大成账单。429 和瞬时 5xx 适合指数退避加随机抖动;401、403、404 和参数错误应立即停止,先修 Key、地址或请求体。

部分失败要单独处理。如果一批 200 条中有 3 条因超长被拒,不要整批无限重试;应拆出问题文本,修正或截断后单独提交,其余结果正常入库。入库用内容哈希做 upsert,确保重跑不会产生重复记录。

import hashlib
import os
import time
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["RELAY_API_KEY"],
    base_url=os.environ["RELAY_BASE_URL"],
    timeout=60.0,
    max_retries=0,
)
MODEL = os.environ["EMBEDDING_MODEL"]

def key_of(text):
    return hashlib.sha256(text.encode("utf-8")).hexdigest()

def embed_with_retry(batch, attempts=4):
    for i in range(attempts):
        try:
            resp = client.embeddings.create(model=MODEL, input=batch)
            store = {
                key_of(batch[d.index]): d.embedding
                for d in resp.data
            }
            return store, resp.usage
        except Exception as exc:
            if i == attempts - 1:
                raise
            time.sleep(min(2 ** i, 30))

texts = ["文档块一", "文档块二", "文档块三"]
store, usage = embed_with_retry(texts)
print(len(store), len(next(iter(store.values()))), usage)

四、计费透明度

Embedding 通常按输入 Token 计费,没有输出 Token,这一点和聊天模型不同。对账时要问清:

  • Token 如何计算,是否与厂商 tokenizer 一致。
  • 失败请求、重试请求是否计费。
  • 是否有批量折扣、缓存或阶梯价。
  • 用量能否按项目、Key、模型导出。
  • 预付款是否有有效期,余额能否退款。
  • 发票内容、币种和汇率如何确定。

“倍率低”不等于总成本低。若中转把失败重试也计费,或用量统计与响应 usage 对不上,低价会被隐性损耗抵消。具体价格与规则以模型价格和对方账单为准,不要采信口头承诺。

五、Key 风险与数据边界

中转最容易被忽略的是 Key 归属。共享 Key、转售额度或来源不明的余额,可能带来四个问题:上游封禁时业务一起中断;多租户共用导致限流互相影响;请求内容经过第三方,日志和留存不透明;服务条款不允许转售时,纠纷缺少依据。

选服务方时至少确认公司主体、服务条款、隐私政策、数据保留位置、发票能力和故障联系方式。含个人信息、合同原文或密钥的文本,不要发给无法说明数据去向的中转。强监管场景优先评估直连、私有部署或可签数据处理协议的服务。

六、迁移清单

从直连迁到中转或网关,建议按顺序做:

  1. 盘点现有模型、维度、批量参数和索引结构,记录基线成功率和 P95 延迟。
  2. 用固定样本在直连上跑一遍,保存向量、usage 和耗时。
  3. 新建测试 Key,设置预算和告警,不要直接复用生产 Key。
  4. 只改 base_url 和 api_key,在预发环境跑通最小请求。
  5. 用同一批样本调用中转,比较维度、条数、usage 和余弦相似度。
  6. 灰度 5%–10% 的批量任务,观察 3–7 天,保留直连作为回退。
  7. 全量迁移后对账一周,确认账单、入库条数和失败重跑记录一致。
  8. 旧索引至少保留一个版本,确认检索效果稳定后再清理。

如果中转换的是不同模型,旧向量不能直接混用。应建立并行索引,全量重算后对比检索效果,再决定是否切换。

七、怎么验证一个中转是否靠谱

  • 向量一致性:同一输入分别走直连和中转,比较维度与余弦相似度;明显偏离时先排查是否换模型或截断。
  • 用量一致性:响应 usage 与后台账单逐批核对,重点看失败和重试是否重复计费。
  • 延迟与错误率:用真实批量在晚高峰测试,记录 P50/P95、429 和 5xx 比例。
  • 批量上限:确认单请求条数、总 Token 和请求体大小限制,避免生产批次被截断。
  • Key 隔离:确认是否独立 Key、能否轮换、额度和限流是否与其他客户共享。
  • 合同与支持:查主体、条款、发票和工单响应;只有个人联系方式、拒绝提供用量明细,都是红旗。

响应里的 model 字段不能单独作为证据,它可以被改写。组合验证比单点检查可靠。

八、什么时候不该用中转

数据敏感且无法审查留存策略、需要厂商直接支持、调用量很小、团队没有对账人力时,中转未必划算。中转也不能绕开上游限流和服务条款。若只是偶尔做小规模向量化,直连加简单脚本可能更省心。

需要统一入口和多模型对比,可以在中商起航 AI 网关创建测试 Key,先用固定样本验证向量一致性,再迁移批量任务;可选模型与计费方式见模型价格。

相关阅读:

常见问题

Embedding API 中转和聊天中转有什么不同?

聊天中转关注流式输出和首 Token 延迟;Embedding 中转关注批量吞吐、单请求上限、失败续跑和向量一致性。对账时还要注意 Embedding 通常只计输入 Token。

中转返回的向量和直连能混用吗?

只有在同一模型、同一版本的前提下才建议混用。不同模型的向量空间不同,即使维度相同也不能混入同一索引。迁移前用固定样本做余弦相似度对比。

批量请求失败一半怎么办?

先判断失败类型:限流和瞬时 5xx 可退避重试;超长或参数错误要拆出问题文本单独处理。用内容哈希做幂等键,重跑时只补缺失部分,避免重复入库。

中转计费按什么算?

多数按输入 Token 计费,但 Token 口径、失败与重试是否计费、是否有批量折扣,各家不同。以账单和用量明细为准,签约前把这些写进对比表。

迁移到中转需要重新向量化吗?

同一模型、同一版本通常不需要;换模型则必须重建索引。即使不需要重算,也建议保留旧索引和回退路线,并对固定样本做一致性验证。