一、先把架构摆对:两段式检索
重排序不是独立的检索方案,它是检索管线的第二级。1
召回(Recall)
用向量检索或 BM25 从全量文档里捞出候选集。这一步要快、要宁滥勿缺,
目标是”正确答案在这批里”,而不是”正确答案排第一”。
2
精排(Rerank)
把候选集连同 query 一起送进
bge-reranker-v2-m3,逐条打分重排。
这一步要准,目标是把正确答案顶到最前面。3
截断并送进大模型
取重排后的 Top-3 到 Top-5 拼进 prompt。
这一步决定了最终答案质量——送进去的越准,大模型幻觉越少、上下文成本越低。
为什么不能跳过召回直接精排:重排序是交叉编码器,必须拿到 query 才能算分,无法离线预计算。
百万篇文档逐条打分,成本和延迟都不可接受。召回负责把规模从百万降到百,精排负责把百排准。
完整可运行示例
下面这段代码就是一个最小但完整的两段式检索,向量召回用text-embedding-3-small,
精排用 bge-reranker-v2-m3,两个模型同一个 API易 令牌:
二、召回多少条送进精排?
实测延迟(短文档,每档 5 次取 P50):
关键在于存在约 2 秒的固定开销:只送 1 篇也要 2 秒。所以候选从 1 加到 100,延迟只多 1.8 秒,
而检索质量的提升远大于这 1.8 秒的代价。
真正决定延迟的是 token 总量,不是文档条数。 同样 50 条候选:
条数相同、延迟差 4.7 倍。这也是下一节「切块」不会拖慢检索的原因——
切块只增加条数,不增加总 token 量。
如果确实要排大量文档(比如离线批处理),拆成多个 ≤100 条的请求,并发控制在 4 以内。
注意拆分不会降低 token 总量,TPM 20,000 依然是总闸门——离线批处理要按分钟节流。
该配额正在扩容中,有大批量需求可先联系 API易客服确认可用额度。
三、长文档必须切块
这是收益最大的一步预处理。实测数据说明了两件事: 其一,无关内容会稀释相关性。 同一句命中内容,后面接不同长度的无关填充:
其二,长文档会抬高噪声得分。 同一篇不相关文档,短版得分 0.029,接上 450 字无关内容后
涨到 0.121——翻了 4 倍。长噪声文档更容易挤进 Top-N。
两者叠加的后果:一篇把答案写在文末的长文档,会输给一篇通篇跑题的长文档。
四、阈值怎么定(别拍脑袋设 0.5)
relevance_score 经 sigmoid 映射到 0–1 区间,看起来很像一个置信度。它不是。
实测跨全部质量用例的得分分布:
一个 0.5 的固定阈值会:滤掉全部跨语言正确结果、滤掉多数非中文场景的第二名,
同时放行那篇关键词高度重合的干扰文档
(查询”苹果公司 2024 财年营业收入”,一篇讲苹果种植收购价的文档拿到了 0.945,排第三)。
注意最后一行:不相关文档的最高分(0.945)高于相关文档的最低分(0.289)。
两个分布是重叠的——这从根本上决定了不存在一个”安全”的绝对阈值。
五、否定语义要额外兜底
这是模型的明确弱项。查询”哪些景点适合冬天去?“,两篇明确说不适合冬天的文档排到了第 2、第 3, 把真正相关的挤到第 4、第 5,nDCG@3 只有 0.47。 模型匹配的是”冬天 + 景点 + 旅游”这个话题,没有理解那个”不”字。 兜底做法:重排序后加一道轻量大模型判断。用便宜的小模型即可,成本可控:六、多语言与跨语言
实测中 / 英 / 日 / 韩 / 俄 / 法 / 阿拉伯语,以及中↔英跨语言检索,排序全部正确。 单一模型就能覆盖多语言知识库,不需要按语言分别部署。 但要注意分数量级差异:
跨语言场景下正确答案的绝对分低 1–2 个数量级,但排序依然正确。
七、并发、缓存与幂等
先算配额预算,再谈并发
上游(华为云 MaaS)给本模型的配额是 TPM 20,000 / RPM 120。 这是接入这个模型时最容易低估的约束——同平台 BGE-M3 向量化模型是 1,200,000 TPM,差 60 倍。 实测(每组前静默 70 秒让配额窗口归零)分离出两个互相独立的机制:
结论一:并发槽位约 4–5 个在途请求。 R1/R2 的 token 消耗只占 3–4% TPM 却大面积失败,
且并发从 10 提到 20 后成功数仍停在 4–5;而 R5 串行 20 次全过。超出槽位的请求直接 429、不排队。
结论二:TPM 20,000 独立生效,与并发无关。 R4 完全串行,第 8 个请求在累计 16,093 tokens 时
开始 429,连挂 9 个后窗口滑动恢复:
每分钟能跑多少次检索
按实测≈26.9 tokens/文档 折算:
候选数的选择同时是质量决策和容量决策:候选翻倍,检索质量提升有限,但吞吐直接减半。
这也解释了为什么单请求候选集不能太大——1000 条候选 = 26,867 tokens,
一个请求就吃掉整分钟预算的 134%,必然 429;2000 条是 269%。
配额正在扩容中:上述 TPM 20,000 是上游给到的初始配额,API易 已在向平台申请扩容。
如果你的业务量超出上表的测算,请直接联系 API易客服评估提升上游配额,
不必按当前数字自行降级方案。
缓存
实测同一请求重复 10 次,得分逐位一致(漂移 0)。 只有打乱候选顺序重发时才出现 3.7e-4 量级的漂移(bf16 批处理抖动),排序不受影响。 所以结果可以放心缓存:- 缓存 key 用
query 归一化 + 候选文档内容哈希(有序) - 不要把
relevance_score本身当幂等标识或去重 key——换个候选顺序它就会变最后几位 - 高频重复查询(FAQ、热门搜索)缓存命中率通常很高,能同时省掉延迟和上游压力
八、接入现成框架
参数名与 Cohere Rerank v1 一致(query / documents / top_n / return_documents),
但 documents 只接受字符串数组,传 [{"text": "..."}] 会返回 400,响应体也没有 Cohere 的
id / meta 字段。
九、上线前的检查清单
正确性
正确性
- 用
results[].index回填原始文档对象,而不是按文本反查 - 长文档已切块(200–500 字),并按文档聚合取最高分
- 单个「query + 文档」对不超过 8192 tokens,否则会 400
- 含否定/排除语义的查询有大模型兜底
稳定性
稳定性
- 候选集控制在 100 条以内
- 并发上限设到 4 以内(实测上游槽位约 4–5 个在途请求,超出直接 429 不排队)
- 按 TPM 20,000 核算过峰值吞吐(100 篇候选约 15 次/分钟),确认够业务用
- 实现了 429 退避重试(上游拥塞是瞬时状态)
- 超时设置 ≥ 60 秒(100 条短文档 P95 约 4.3 秒,但长文档或大候选集会到几十秒)
- 请求路径确认是
/v1/rerank——路径写错返回的是 200 + HTML,不是 404 - 模型名拼写正确且全小写——写错返回的是 503,容易误判为渠道故障
效果
效果
- 阈值策略用的是 Top-N 或相对阈值,不是拍脑袋的固定值
- 多语言/跨语言场景验证过分数量级,没有被低分误伤
- 标注了一小批真实 query 做过 A/B(开/关重排序),确认指标真的涨了
成本与缓存
成本与缓存
- 知道
usage.input_tokens/output_tokens恒为 0,用量看prompt_tokens/total_tokens - 知道
top_n和return_documents都不影响用量,所有候选都会过一遍模型 - 成本核算以控制台账单为准(
prompt_tokens与total_tokens在 100 篇候选时相差约 45%, 本轮测试未能确认实际扣的是哪个) - 高频查询接了结果缓存