文章

LLM Reranker 生产评估实战:用黄金查询集、nDCG 与延迟预算守住 RAG 召回质量

本文深入讲解RAG系统中LLM Reranker的生产评估方法论,覆盖黄金查询集构建、nDCG与MRR排序指标、候选集预算优化、延迟成本治理、灰度上线门禁与回滚策略,帮助团队建立独立的重排序评估体系,避免只看最终答案质量而忽视召回排序退化。

背景问题:RAG 质量退化,很多时候不是生成模型的问题

RAG 系统上线后,团队最容易盯住两个现象:模型回答错了,或者回答没有引用到正确资料。直觉上,这像是大模型不够强、提示词不够好,或者向量索引没有召回相关文档。但在生产链路里,还有一个经常被低估的环节:reranker 是否把真正有用的候选片段排到了前面

典型 RAG 链路可以拆成四步:

  1. 第一阶段检索从大 corpus 中取出 candidate_k 个候选片段
  2. Reranker 对候选片段重新打分排序
  3. 系统把前 top_n 个片段拼入上下文
  4. 最后由 LLM 生成答案

如果 reranker 把强相关片段排到第 8 位,而系统只取前 5 个片段,最终答案看起来就是”模型没读到资料”。

Cohere 的 Rerank API 文档把 rerank 描述为:输入 query 和一组文本,输出带 relevance score 的有序结果;接口还提供 top_nmax_tokens_per_docpriority 等参数。这说明 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_003doc_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 Layerrecall_at_20recall_at_50missing_reference_context_rate判断候选集是否包含正确答案
Rerank Layerndcg_at_5ndcg_at_10mrrcontext_precision_at_5判断重排是否把关键片段提前
Generation Layeranswer_groundednesscitation_hit_raterefusal_or_fallback_rate判断最终答案质量

这样做的价值是:当线上质量下降时,可以快速判断问题发生在召回、重排还是生成,而不是把所有问题都归因给大模型。

工程落地:先建黄金查询集,再谈模型替换

黄金查询集要覆盖真实业务分布

Reranker 评估的第一步不是调模型,而是建立 golden query set。这套数据至少包含四类问题:

  1. 高频标准问题:例如”如何重置密码""如何申请退款”
  2. 低频但高风险问题:例如权限、合同、赔付、合规条款
  3. 容易混淆的问题:例如两个产品版本、两个相似流程、同名字段
  4. 线上失败样本:例如用户点踩、人工客服接管、无引用回答

每条样本至少保存以下字段:

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 本身。

推荐的离线评估流程如下:

  1. 固定 corpus_snapshot_id
  2. 固定 index_version
  3. 固定 first_stage_retriever_config
  4. 对 golden query set 生成 candidate set
  5. 保存 query_id -> candidate_context_ids
  6. 对多个 reranker 版本复用同一批 candidate set
  7. 计算排序指标与延迟成本

候选集可以作为评估制品保存:

{
  "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_ktop_n
小候选集205
中候选集505
大候选集1008

评估时同时记录延迟与成本指标:

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_idchunking_versionindex_versionretriever_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 看看答案好不好”,而是一套包含黄金查询集、排序指标、候选集预算、延迟治理和灰度门禁的系统工程。只有建立起独立的重排序评估体系,团队才能在模型迭代时快速定位问题发生在召回、重排还是生成环节,用数据驱动决策而非主观感受。

参考资料

常见问题

Reranker 上线前只看人工主观回答质量够吗?
不够。回答质量会同时受检索、重排、提示词和生成模型影响。Reranker 评估需要独立观察 top-k 排序质量、相关上下文位置、延迟和成本,避免把召回问题误判成生成问题。
nDCG、MRR、Recall@K 应该优先看哪个?
RAG 场景通常先保证 Recall@K 不丢关键证据,再用 nDCG@K 和 MRR 评估相关证据是否排在前面。若答案只依赖一个关键片段,MRR 更敏感;若需要多个证据,nDCG 与 Context Precision 更有价值。
候选集越大,reranker 效果一定越好吗?
不一定。候选集变大通常会增加延迟和成本,也可能引入更多噪声。生产系统应在固定延迟预算下测试不同 candidate_k 和 top_n,选择质量、成本和稳定性综合最优的区间。
没有人标注数据时能不能上线 reranker?
可以先用线上失败样本、FAQ、文档标题和人工抽样构建小规模评估集,但不建议完全没有评估集就上线。即便只有 100 条高价值查询,也比只靠主观体验可靠。