背景问题:RAG 质量退化,很多时候不是生成模型的问题
RAG 系统上线后,团队最容易盯住两个现象:模型回答错了,或者回答没有引用到正确资料。直觉上,这像是大模型不够强、提示词不够好,或者向量索引没有召回相关文档。但在生产链路里,还有一个经常被低估的环节:reranker 是否把真正有用的候选片段排到了前面。
典型 RAG 链路可以拆成四步:
- 第一阶段检索从大 corpus 中取出
candidate_k个候选片段 - Reranker 对候选片段重新打分排序
- 系统把前
top_n个片段拼入上下文 - 最后由 LLM 生成答案
如果 reranker 把强相关片段排到第 8 位,而系统只取前 5 个片段,最终答案看起来就是”模型没读到资料”。
Cohere 的 Rerank API 文档把 rerank 描述为:输入 query 和一组文本,输出带 relevance score 的有序结果;接口还提供 top_n、max_tokens_per_doc、priority 等参数。这说明 reranker 不是一个抽象的”质量增强器”,而是一个有输入规模、截断、排序、成本和优先级约束的生产组件。
因此,reranker 上线不能只做几条人工问答测试。它需要一套独立评估机制:黄金查询集、相关片段标注、排序指标、延迟预算、灰度门禁和回滚策略。
核心原理:Reranker 解决的是”候选排序”,不是”全库召回”
第一阶段检索决定上限
Reranker 通常只处理第一阶段检索已经返回的候选片段。如果正确片段没有进入 candidate_k,reranker 再强也无法把它排到前面。这一点决定了评估时不能只看 reranker 后的 top_n,还要同时记录 first-stage retriever 的 Recall@K。
例如:
query: 如何申请企业管理员权限?
first_stage_candidate_k: 50
rerank_top_n: 8
reference_context_ids: [doc_acl_003, doc_acl_004]
如果 doc_acl_003 和 doc_acl_004 根本没进入前 50 个候选,那么问题在检索召回。如果它们进入前 50,但 reranker 后排在第 20 和第 31,问题才更可能出在重排。如果它们排在前 8,但生成答案仍然错误,问题才应该继续排查上下文拼接、提示词和生成模型。
Reranker 改善的是排序密度
RAG 里真正重要的不是”相关文档是否存在于候选集里”,而是”相关文档是否出现在模型可见的前几个上下文槽位”。这就是为什么 nDCG@K、MRR、Precision@K、Context Precision 比单纯人工看一条答案更有诊断价值。
LlamaIndex 的 Retrieval Evaluation 示例把 hit-rate、MRR、Precision、Recall、AP、nDCG 作为 retriever 评估指标,并用 ground-truth context 对检索结果做比较。Ragas 的 Context Precision 文档则强调,它评估的是检索上下文中相关 chunk 是否排在更靠前的位置,并基于 Precision@K 进行计算。
对于生产 RAG,建议把指标拆成三层:
| 层级 | 指标 | 用途 |
|---|---|---|
| Retrieval Layer | recall_at_20、recall_at_50、missing_reference_context_rate | 判断候选集是否包含正确答案 |
| Rerank Layer | ndcg_at_5、ndcg_at_10、mrr、context_precision_at_5 | 判断重排是否把关键片段提前 |
| Generation Layer | answer_groundedness、citation_hit_rate、refusal_or_fallback_rate | 判断最终答案质量 |
这样做的价值是:当线上质量下降时,可以快速判断问题发生在召回、重排还是生成,而不是把所有问题都归因给大模型。
工程落地:先建黄金查询集,再谈模型替换
黄金查询集要覆盖真实业务分布
Reranker 评估的第一步不是调模型,而是建立 golden query set。这套数据至少包含四类问题:
- 高频标准问题:例如”如何重置密码""如何申请退款”
- 低频但高风险问题:例如权限、合同、赔付、合规条款
- 容易混淆的问题:例如两个产品版本、两个相似流程、同名字段
- 线上失败样本:例如用户点踩、人工客服接管、无引用回答
每条样本至少保存以下字段:
query_id: q_20260706_001
query: "企业管理员如何批量导入员工?"
query_type: "permission_and_operations"
expected_answer_intent: "说明入口、模板、字段校验和失败处理"
reference_context_ids:
- "admin_guide_12"
- "employee_import_faq_03"
negative_context_ids:
- "personal_user_import_01"
- "legacy_import_doc_07"
priority: "high"
这里的 negative_context_ids 很重要。Reranker 最常见的问题不是完全找不到相关资料,而是把”看起来很像但答案边界错误”的片段排到前面。没有 hard negative,评估集很容易过于乐观。
固定候选集,才能比较 reranker
比较两个 reranker 时,必须尽量固定第一阶段检索候选集。否则 A 模型跑在一批候选上,B 模型跑在另一批候选上,指标差异可能来自 retriever、索引版本、切块策略或数据更新,而不是 reranker 本身。
推荐的离线评估流程如下:
- 固定
corpus_snapshot_id - 固定
index_version - 固定
first_stage_retriever_config - 对 golden query set 生成 candidate set
- 保存
query_id -> candidate_context_ids - 对多个 reranker 版本复用同一批 candidate set
- 计算排序指标与延迟成本
候选集可以作为评估制品保存:
{
"eval_run_id": "rerank-eval-20260706-001",
"corpus_snapshot_id": "kb-20260705-1800",
"index_version": "vector-index-v42",
"candidate_k": 50,
"queries": [
{
"query_id": "q_001",
"candidate_context_ids": ["doc_7", "doc_2", "doc_91"],
"reference_context_ids": ["doc_2"]
}
]
}
不要只看平均分
平均 nDCG 提升可能掩盖高风险问题。更稳妥的方式是同时看整体指标和分桶指标:
metric_report:
overall:
ndcg_at_5: 0.74
mrr: 0.68
recall_at_50: 0.91
by_query_type:
permission_and_acl:
ndcg_at_5: 0.61
regression_cases: 12
billing:
ndcg_at_5: 0.79
regression_cases: 3
product_howto:
ndcg_at_5: 0.82
regression_cases: 1
生产系统真正关心的是:新 reranker 是否让关键场景退化。一个模型整体提升 3%,但在权限、计费、医疗、金融或合同条款类问题上退化,就不应该直接全量发布。
候选集预算:candidate_k 不是越大越好
很多团队会默认把 candidate_k 从 20 拉到 100,再交给 reranker 处理,期望”多给一些候选,总会更好”。这在成本和效果上都不稳定。
BEIR 论文的结论提醒我们,BM25 是强健的基线,reranking 和 late-interaction 架构通常有较好的 zero-shot 表现,但也带来更高计算成本。另有研究专门讨论了 reranker 推理规模扩大后的后果:当 reranker 对越来越多文档打分时,收益可能递减,甚至在某些情况下质量会下降。因此,生产系统需要把 candidate_k 当作一个受预算约束的参数,而不是固定越大越好。
建议每次 reranker 评估至少跑三组候选集:
| 配置 | candidate_k | top_n |
|---|---|---|
| 小候选集 | 20 | 5 |
| 中候选集 | 50 | 5 |
| 大候选集 | 100 | 8 |
评估时同时记录延迟与成本指标:
cost_latency_metrics:
- p50_rerank_latency_ms
- p95_rerank_latency_ms
- timeout_rate
- avg_docs_reranked_per_query
- avg_tokens_per_doc_after_truncation
- cost_per_1k_queries
最终选择的不是最高 nDCG,而是在 SLO 内最稳定的组合。比如 candidate_k=100 的 nDCG@5 比 candidate_k=50 高 1%,但 p95 延迟增加 300ms,且超时率上升,那么它未必适合默认线上流量。
延迟治理:Reranker 要有降级路径
Reranker 位于检索和生成之间,一旦超时,会直接拉长用户可感知延迟。生产链路至少需要三种降级策略。
Budget-Aware Cutoff
当候选文档过长时,先按片段长度、来源优先级、初检分数裁剪,避免长文档挤爆 reranker 的 token 上限。Cohere 文档中提到 long documents 会按 max_tokens_per_doc 截断,这类行为必须纳入评估,否则线下看到的是完整文档,线上实际打分的是截断文档。
Timeout Fallback
如果 reranker 超时,可以退回第一阶段检索排序,但要在日志中标记 rerank_fallback=true,避免后续质量分析混乱。
Query-Class Routing
不是所有查询都值得使用昂贵 reranker。例如导航型问题、精确 ID 查询、固定 FAQ 命中,可以直接走轻量策略;多跳、长尾、相似条款混淆问题才进入强 reranker。
rerank_policy:
default:
enabled: true
candidate_k: 50
top_n: 6
timeout_ms: 350
exact_id_query:
enabled: false
reason: "metadata filter is enough"
high_risk_policy_query:
enabled: true
candidate_k: 100
top_n: 8
timeout_ms: 600
fallback:
on_timeout: "use_first_stage_order"
log_event: true
灰度上线:用门禁阻止”看起来更聪明”的退化
Reranker 更换经常伴随模型版本、prompt、切块策略、索引字段和过滤条件变化。上线门禁应当分成离线、影子、灰度三层。
离线门禁
离线门禁要求新版本在固定评估集上超过基线:
offline_gate:
baseline: "reranker-v1"
candidate: "reranker-v2"
pass_rules:
ndcg_at_5_delta: ">= 0.02"
mrr_delta: ">= 0"
high_priority_regression_count: "<= 3"
p95_latency_ms: "<= 450"
影子流量
影子阶段不影响真实回答,只把线上 query 同时送到新旧 reranker,比较前 top_n 的差异。重点观察:
shadow_metrics:
- top_5_overlap_rate
- reference_doc_drop_rate
- rerank_score_distribution_shift
- timeout_rate
- long_doc_truncation_rate
如果 top_5 overlap 很低,不代表一定差,但说明排序行为发生显著变化,需要人工抽样复核。
小流量灰度
灰度阶段必须绑定用户体验指标,例如引用命中率、二次追问率、人工接管率、点踩率。这里不建议只看回答满意度,因为它受生成模型波动影响较大。更稳定的做法是同时记录检索诊断字段:
{
"query_id": "online_q_abc",
"reranker_version": "v2",
"candidate_k": 50,
"top_context_ids": ["doc_11", "doc_08", "doc_19"],
"rerank_latency_ms": 286,
"fallback": false,
"citation_hit": true,
"user_feedback": "thumb_up"
}
这样,线上问题可以回放到同一套评估框架,而不是停留在”用户觉得回答不好”。
常见误区
误区一:Reranker 分数可以跨 query 比较
很多 reranker 输出 relevance_score,但不同 query、不同候选集、不同模型版本下,分数未必有稳定的全局含义。更安全的用法是把分数当作同一 query 内的排序依据,而不是用固定阈值做全局拦截。
误区二:只评估最终答案,不评估上下文排序
最终答案质量会混合多个变量。要诊断 reranker,就必须保存候选集、排序结果、参考 context、top_n 拼接结果和最终答案。否则问题出现时只能猜。
误区三:线上切块变化后继续复用旧评估结果
切块策略、metadata、索引版本一变,reranker 面对的候选文本就变了。评估报告必须记录 corpus_snapshot_id、chunking_version、index_version 和 retriever_config。
误区四:忽视长文档截断
如果 reranker 对长文档自动截断,相关证据可能被截掉。评估时要统计 truncation_rate,并抽查被截断后仍被判高分的文档。
上线检查清单
上线前至少确认以下事项:
数据集
- 黄金查询集覆盖高风险场景
- Hard negative contexts 已标注
- 线上失败样本已回填
可复现性
corpus_snapshot_id已记录- Candidate set 已保存
- Reranker 版本已固定
- Prompt 或 instruction 版本已固定
指标
recall_at_k已报告ndcg_at_k已报告mrr已报告- 延迟与超时指标已报告
生产就绪
- Timeout fallback 机制已就绪
- Fallback 事件已记录日志
- 影子对比已启用
- 回滚开关已就绪
总结
LLM Reranker 的生产评估不是”跑几个 case 看看答案好不好”,而是一套包含黄金查询集、排序指标、候选集预算、延迟治理和灰度门禁的系统工程。只有建立起独立的重排序评估体系,团队才能在模型迭代时快速定位问题发生在召回、重排还是生成环节,用数据驱动决策而非主观感受。