Rerank 接口没有像 Chat Completions 那样统一的标准,同一段代码换个供应商就可能 404 或 422。排查时先按 HTTP 状态码分层,再处理“返回 200 但结果不对”的软错误。本文按鉴权、候选集、限流、超时和空结果五类展开,最后给一份可复用的重试代码和日志清单。模型与价格以站内模型价格为准。
说明:Cohere、Jina、Voyage 等名称均为其权利人的商标,本文仅作技术讨论;接口路径、限额与错误码可能随版本变化,请以对应厂商文档为准。
一、五类问题先分清
| 现象 | 常见状态码 | 典型原因 | 处理顺序 |
|---|---|---|---|
| 鉴权失败 | 401、403 | Key 错误、请求头缺失、模型未开通 | 先修凭证与权限 |
| 请求被拒 | 400、422 | 候选集过大、字段不匹配、文档为空 | 查请求体与限额 |
| 路径错误 | 404 | 端点写错、模型名旧、Base URL 拼接错误 | 对照官方文档 |
| 限流或配额 | 429 | 并发突增、共享 Key、重试风暴 | 退避、降并发 |
| 超时或上游错误 | 504、5xx | 候选过多、文档过长、上游过载 | 缩小请求、有限重试 |
| 返回为空 | 200 | top_n 非法、字段读错、文档被过滤 | 加断言与告警 |
日志至少记录时间、端点、模型、文档条数、总字符数、top_n、状态码、耗时、重试次数和请求 ID。不要记录完整 Key,也不要把用户文档原文整段打印。
二、401 与 403:先查鉴权,再查权限
401 表示身份没有通过验证,和模型能力、余额通常无关。按下面顺序排查:
- 请求头是否使用 Authorization: Bearer 加 Key,有些网关则要求 x-api-key。
- Key 前后是否有空格、换行或多余引号。从聊天窗口复制最容易带进来。
- 环境变量是否被本地配置或部署平台覆盖,线上和本地是否用了不同的 Key。
- Key 是否对重排接口开通。有的账户只有对话权限,没有 Rerank 权限。
- 端点是否写错。/v1/rerank 与 /v2/rerank 的格式可能不同,把对话接口的 Base URL 直接拼上 /rerank,很容易得到 404 或 401。
403 是身份有效但权限不够,重点看模型是否开通、IP 是否在白名单、项目权限和欠费状态。401 不要重试,重试只会放大失败日志,还可能触发风控。先用最小 curl 跑通,再回到业务代码。
三、400 与 422:候选集过大、字段不匹配
候选集过大是最常见的 400 来源。托管接口通常对单次文档数、单文档 token 和请求体大小都有上限。以 Cohere 为例,官方建议单次不要超过一千条文档,单文档默认截断到 4096 token;其他厂商的数值不同,且会随模型版本调整,接入前要查对应文档。超限时的正确做法不是盲目重试,而是:
- 把候选集分片,每片单独重排,再按分数合并;
- 在召回阶段就把候选控制在合理范围,例如五十到两百条;
- 对超长文档先切块或截断,不要把整篇 PDF 直接塞进 documents;
- 去掉空字符串、null、纯空白和重复文档。
字段不匹配也会报 400 或 422:top_n 写成 top_k,或反过来;Jina、Cohere 多用 top_n,Voyage 用 top_k。documents 传了对象数组而不是字符串数组,或把 id 和 text 放错层级。top_n 大于文档数量时,有的接口报错,有的自动截断。return_documents、truncation、max_tokens_per_doc 等参数也可能不被当前供应商支持。JSON 里的 NaN、Infinity、未转义换行同样会触发解析失败。
排查方法:保留脱敏后的原始请求体,用最小示例逐项加回参数,一次只改一个变量。
四、429:限流、配额与重试风暴
429 表示请求被限流或配额用尽,常见原因有:每秒请求数或并发超过套餐、按 token 计的配额在高峰期耗尽、多个服务共用一把 Key、客户端重试没有退避。先看响应头里的 Retry-After 和配额字段,再决定等待还是降并发。
处理顺序:
- 确认是单 Key 限流还是账户级配额。
- 把重试改为指数退避加随机抖动,尊重 Retry-After。
- 限制并发,用队列削峰,而不是无限重试。
- 把批量任务放到低峰期,离线评测与线上流量分开。
- 为关键业务准备降级:跳过重排,保留召回顺序。
不要用固定一秒重试打满。多个实例同时重试会形成重试风暴,把小限流放大成持续故障。
五、超时、504 与 5xx
超时要分连接超时和读取超时。连接超时通常是网络、DNS、代理或 TLS 问题;读取超时更多是候选集太大、文档太长、上游排队或模型冷启动。504 一般表示网关等不到上游响应,和客户端自己的超时是两件事。
排查顺序:
- 用最小请求测试,一条 query、五条短文档,确认不是网络完全不通。
- 逐步增加文档数量,找到耗时拐点。
- 检查单文档长度和总 token,必要时截断。
- 检查客户端超时是否短于服务端处理时间。
- 对 5xx 和超时做有限次重试,超过阈值就降级。
- 记录请求 ID 和上游返回的 trace id,方便和供应商对账。
重排通常不是流式接口,不能靠流式输出掩盖长耗时。对延迟敏感的业务,应把重排放在异步链路,或只对前几十条候选重排。
六、返回 200 但结果为空或不对
这类软错误更隐蔽:documents 为空数组,接口返回空结果;top_n 设为 0 或负数;所有文档都被业务过滤条件排除;读错响应字段,有的返回 results,有的返回 data;index 是原文档数组的下标,但分片后忘了加偏移量;分数语义不同,有的归一化到零到一,有的输出 logits,排序方向也可能不同;返回的是文档正文而不是 index,去重时把相同文本合并了。
建议在客户端加断言:结果数量不超过 top_n,每个 index 在合法范围内,分数按供应商语义单调。发现异常时记录原始响应摘要,不要静默返回空列表。
七、一份可复用的重试代码
下面示例把错误分成三类:鉴权和参数错误不重试,429 和 5xx 退避重试,超时有限重试;重试耗尽后降级为原召回顺序。
import random
import time
import requests
def rerank(query, documents, top_n=10, model="<rerank-model>",
url="<base-url>/v1/rerank", api_key="<key>"):
payload = {"model": model, "query": query,
"documents": documents, "top_n": top_n}
headers = {"Authorization": f"Bearer {api_key}"}
last_error = None
for attempt in range(5):
try:
resp = requests.post(url, json=payload, headers=headers,
timeout=(3.05, 30))
except requests.Timeout as exc:
last_error = exc
time.sleep(min(2 ** attempt + random.random(), 20))
continue
if resp.status_code in (400, 401, 403, 404, 422):
raise RuntimeError(f"不可重试 {resp.status_code}: {resp.text[:300]}")
if resp.status_code == 429 or resp.status_code >= 500:
retry_after = resp.headers.get("Retry-After")
wait = float(retry_after) if retry_after else min(
2 ** attempt + random.random(), 20)
time.sleep(wait)
last_error = RuntimeError(f"可重试 {resp.status_code}")
continue
data = resp.json()
results = data.get("results") or data.get("data") or []
if not results:
return list(range(min(top_n, len(documents))))
return [item["index"] for item in results[:top_n]]
raise RuntimeError(f"重试耗尽: {last_error}")
# 调用方仍需按供应商字段做适配,例如 Voyage 使用 data 与 top_k。
如果文档分片重排,合并时要把分片内 index 加上偏移量,再统一排序。
八、日志与监控清单
每次调用至少记录:时间、端点、模型、文档条数、总字符数或估算 token、top_n、状态码、错误类型、耗时、重试次数、请求 ID。不要记录完整 Key,也不要把用户文档原文整段写入日志;需要排查时记录哈希、长度和脱敏后的前若干字符。
监控看四个指标:429 比例、超时与 5xx 比例、空结果比例、p95 延迟。再按业务线拆分,避免一个高频低价值任务把配额吃光,掩盖了核心业务的异常。
常见问题
401 和 403 有什么区别?
401 是身份没通过验证,通常是 Key 缺失、格式错误或失效;403 是身份有效但权限不够,可能是模型未开通、IP 不在白名单、项目或余额受限。先修鉴权,再查权限。
候选集超过接口上限怎么办?
在客户端分片,每片单独重排后按分数合并,并给 index 加偏移量。更根本的做法是在召回阶段控制数量,通常几十到几百条足够,不要把上千条全部送进重排。
429 重试几次合适?
没有统一答案。建议有限次重试,例如三到五次,指数退避加随机抖动,并尊重 Retry-After;同时限制并发。重试耗尽后降级,不要让请求无限堆积。
Rerank 接口超时,能像对话一样用流式吗?
一般不能。重排需要看完整个候选集才能给出稳定排序,多数接口是同步返回。延迟敏感时,应减少候选数、截断文档长度,或把重排放到异步任务。
返回 200 但没有结果,是什么原因?
先查 documents 是否为空、top_n 是否合法、业务过滤是否把文档全部排除;再查响应字段是否读错,以及分片合并时 index 是否越界。加断言和空结果告警,比事后排查更有效。
下一步
排查完成后,建议固定一组最小复现和一组回归用例,再在中商起航 AI 网关创建测试 Key 验证调用链路;计费与限额以模型价格页为准。
相关阅读:
