RAG 到底该怎么测

先把评测对象分开

RAG 评测不能只在流程末尾给最终答案打一个分。先分开看三件事。

  1. 系统有没有找到当前用户可访问、能够支撑答案的正确证据。
  2. 进入模型的上下文是否完整、干净,模型有没有正确使用这些证据。
  3. 整个运行是否安全、可复现,失败后能不能定位到文档、检索、生成、引用、权限或评测器。

例如,用户问 “标准版账号能否导出审计日志”,检索只找到允许导出的旧版规则,模型却靠自身记忆碰巧回答 “不能导出”。答案文字碰巧正确,检索、证据来源和端到端 RAG 仍然失败。系统换一个模型,或者遇到模型没有见过的新规则,正确答案就无法稳定复现。

一次完整的 RAG 评测流程

评测开始前,先写清这次实验要支持什么决策。是在比较某个组件,还是判断候选版本能否上线。这个问题不明确,后面的样本和分数就没有统一的解释。

阶段 要做什么 必须留下的证据
1. 定义决策 写清候选版本、基线版本、预期改善和不可退化项。 实验假设、风险切片、发布门槛。
2. 冻结评测对象 固定 corpus、文档版本、chunking、索引、Embedding、retriever、reranker、Prompt、生成模型和代码版本。 可复现的运行版本清单,也就是 run manifest,不能只记模型名称。
3. 构造评测集 准备真实 query,并按任务需要标注 qrels、gold evidence、gold answer、expected behavior、用户角色和 query time。 数据集版本、审核记录、无答案与权限样本。
4. 执行并记录 trace 用同一批样本运行基线与候选版本,保存 query rewrite、候选文档、排序分、最终 context、答案和引用。 每条样本的 run/trace ID 与阶段输出。
5. 分层评分 先跑 ID、qrels、ACL、schema 等确定性检查,再跑相关性、忠实度、正确性和引用支持等语义评测。 每个指标的实现、输入、版本、分数和错误状态。
6. 人工复核与归因 复核高风险、低分、临界分和 Judge 分歧样本,区分系统失败、样本错误和评测器错误。 人工标签、仲裁理由、主失败层和次失败层。
7. 配对比较与准出 按同一 query 比较基线与候选,检查平均变化、关键切片、退化样本、成本和延迟。 逐样本 delta、置信范围、阻断项和发布决定。
8. 线上回流 对生产 trace 做规则检查和抽样评测,把投诉、人工修正、低置信回答和事故补回评测集。 线上信号、样本来源、修复后回归结果。

这条流程包含两个相连的循环,离线侧负责 “可比较、可复现、可准出”,线上侧负责 “发现真实失败并补回数据集”。如果只有离线 benchmark,评测集会逐渐脱离真实用户;如果只有线上点赞点踩,又很难知道退化来自哪一层。

qrels 记录哪些检索结果算相关

qrelsquery relevance judgments 的缩写,记录某个问题与哪些检索对象相关,以及相关到什么程度。它不保存答案,也不是分数。Recall@k、MRR、nDCG 等检索指标会使用这份参考数据。

下面用一个虚构样本说明。用户问,

标准版账号可以导出审计日志吗?

假设语料中有三个检索对象,

evidence_id 内容 人工判断
plan-v3#audit-export 当前版本说明,仅企业版支持导出。 强相关,直接支持答案。
plan-v3#audit-view 标准版可以查看近期日志摘要。 辅助相关,用于补充替代能力。
plan-v2#audit-faq 旧版本 FAQ,曾写标准版可以导出。 已判断不应作为当前答案依据。

为方便计算,记 A 为当前导出规则,B 为标准版可查看日志摘要,O 为过期规则,U 为另一租户的越权资料,X 为普通无关文档。

这份 qrels 把相关性分成 2/1/0。这只是当前评测集的等级约定,具体含义要写进 dataset card,其他 benchmark 可能采用不同分级。

query_id        evidence_id             relevance  judgment_status
rag-policy-001  plan-v3#audit-export    2          judged
rag-policy-001  plan-v3#audit-view      1          judged
rag-policy-001  plan-v2#audit-faq       0          judged

qrels 需要先定义 evidence_id 指向什么,可以是整篇 document、一个 passage、一个 chunk 或稳定的 source span。不同实验不能一会儿按文档、一会儿按 chunk,却把分数直接比较。比较不同 chunking 时,chunk ID 会变化,最好另外保存跨版本稳定的 doc_id + section/source_span,再为各个 chunking 版本建立映射。

还要区分 “相关性为 0” 和 “没有出现在 qrels 中”,

如果一个问题必须同时找到两份证据,例如 E1 说明适用范围、E2 说明金额上限,扁平 qrels 还不够。评测集应把它们组成一个完整 evidence set,并检查两份证据是否都进入 top-k;只命中其中一份不能算完整召回。

评测集怎样建起来

评测集决定了分数能说明什么。题目很多,证据和预期行为却含糊,最后只会得到一堆无法解释的平均分。

第一批 query 可以从四类地方收集。

长期维护时,可以按用途把评测集分成四组。

分区 用途 使用限制
开发集(Dev 或 tuning) 调 Prompt、Retriever、Reranker 和阈值 研发可以反复查看和调试
固定回归集(Frozen regression) 每次发布都要复跑的稳定回归集 修改样本必须留下原因和版本
保留集(Holdout 或 canary) 检查是否过拟合已知评测集 日常调参不能查看答案
评分器校准集(Judge calibration) 校准自动评分器 与被测系统的开发集分开管理

如果团队一边查看所有错误样本,一边针对这些样本调 Prompt,随后又在同一批数据上宣布版本提升,评测集已经变成训练材料。Holdout 首先要保持独立,规模再按风险和统计需要确定。

Gold evidence 可以由搜索结果、文档链接或模型生成候选,正式进入回归集前仍需人工确认。审核人至少要回答几件事。

模型很适合帮人找候选和发现漏项,但它不能独自决定 gold。生成模型、被测模型和 Judge 若共享同一种错误,自动生成的标准答案会把错误一起固化。

最小样本可以这样记录。

sample_id: rag-policy-001
raw_query: 标准版账号能否导出审计日志
query_type: single_hop_policy
principal:
  tenant: T1
  role: standard_admin
query_time: 2026-08-19
answerability: answerable
acceptable_evidence_sets:
  - [A, B]
required_claims:
  - 标准版不支持导出审计日志
  - 标准版可以查看近期日志摘要
forbidden_evidence: [O, U]
expected_behavior: answer_with_citation
review_status: human_verified
dataset_partition: frozen_regression

这个样本不要求模型逐字复述某个 gold answer。开放式回答更适合保存 required claims、可接受变体、禁止 claim 和引用要求。只有答案确实有唯一值时,exact match 才是合适的评分方式。

一次 RAG 运行到底要保存什么

同一个问题运行后,需要留下六类数据。

Query rewrite

原始 query 是用户真正输入的文字,

标准版能导审计日志吗?

Query rewrite 是系统为了检索而生成的查询表达,可能同时产生检索文本和结构化过滤条件,

rewritten_query: 标准版 审计日志 导出权限
filters:
  plan: standard
  feature: audit_log_export
  policy_time: 2026-08-18
strategy: structured-rewrite-v2

要保存原始 query、改写结果、过滤条件、改写策略、Prompt/模型版本。评测重点是 “是否保留原意”,不能只看改写后召回是否提高。例如把 “标准版” 删掉后,系统可能轻易召回企业版文档,Recall 会升高,可是问题已经被改写错。

候选文档

候选文档是初始检索返回、尚未重排和裁剪的结果,可以是整篇 document、passage 或 chunk。使用 hybrid retrieval 时,还要分开记录各条召回通道的结果。

- evidence_id: plan-v2#audit-faq
  source: dense
  rank: 1
  score: 0.91
  version: v2
- evidence_id: plan-v3#audit-export
  source: bm25
  rank: 1
  score: 13.4
  version: v3

需要记录 ID、文档版本、召回通道、通道内排名、原始分数和权限判断。BM25 分数与向量相似度不在同一量纲,不能直接拿 13.40.91 比大小。

排序

排序记录的是 fusion 或 reranker 之后的顺序。至少要保存每个阶段的 rank 和 score,而不是只保留最后 top-k,

plan-v3#audit-export: candidate_rank=2 -> rerank_rank=1
plan-v2#audit-faq:    candidate_rank=1 -> rerank_rank=4

这样 gold evidence 已进入候选但最终没进入 context 时,才能判断是 reranker、融合权重还是 context selection 出了问题。只保留最终结果,会把排序失败误判成召回失败。

最终 context

最终 context 是真正放进生成模型 Prompt 的内容。它经过 ACL 和版本过滤、去重、重排、裁剪或压缩,通常只是候选集的一部分。

需要保存 context 中每段内容的 evidence ID、顺序、原文位置、版本、权限结果、token 数,以及是否经过摘要或压缩。评测时要问,正确证据是否完整、旧文档是否混入、重复内容是否挤占 token、多个证据是否互相冲突。

答案

答案记录要同时保存展示文本和生成条件。

answer: 标准版不支持导出审计日志,但可以查看近期日志摘要。
model: example-model-v2
prompt_version: rag-answer-v5
temperature: 0.2
latency_ms: 820

只有保存模型、Prompt、生成参数、耗时、token 和原始输出,才能解释为什么同一 context 在两个版本中得到不同结果。清洗后的展示文本不能替代原始生成记录。

引用

引用需要建立 “答案中的 claim 到具体证据位置” 的映射,不能只在答案结尾放一个 URL。

- claim: 标准版不支持导出审计日志
  evidence_id: plan-v3#audit-export
  anchor: section:审计日志与导出权限
- claim: 标准版可以查看近期日志摘要
  evidence_id: plan-v3#audit-view
  anchor: section:标准版日志能力

引用评测至少看两件事,需要证据的关键 claim 是否都被覆盖,以及每个引用是否真正支持它对应的 claim。还要检查来源版本、权限和原文定位;引用了一份真实但过期或无权访问的文档,仍然不能通过。

要不要逐环节测试

要。每个环节无需维护一套互相重复的端到端题库,评测分为两层。

只有端到端评测时,失败后很难定位责任;只有组件评测时,各段都通过,组合后仍可能因为版本、权限、接口和数据分布发生问题。生产 RAG 通常需要二者同时存在。

环节 评测输入 预期结果 主要检查
Query rewrite 原始 query、对话上下文、用户/时间条件 规范化意图、检索 query、filters、是否需要澄清 意图保持、关键实体/时间/角色保留、schema、下游召回变化
初始检索 固定 corpus/index、改写后的 query 带 relevance 的 gold evidence 或 evidence set Recall@k、Hit@k、完整证据集召回、ACL
Reranker 固定候选池、候选文本、query 候选的 graded relevance 和禁止证据 nDCG、MRR、Precision@k、gold rank delta、延迟
Context builder rerank 结果、ACL、token budget 必须进入和禁止进入的证据、完整 evidence set Context Precision/Recall、去重、冲突、版本、权限、token
最终回复 query、最终 context、expected behavior gold claims、可接受变体、禁止 claim、引用要求 schema、正确性、faithfulness、完整性、引用、拒答
端到端 同一批样本运行基线和候选版本 业务任务与风险门禁 分层指标、逐样本 delta、失败归因、成本和延迟

1. Query rewrite 怎么测

rewrite Prompt 和 rewritten query 是两件事。

评测集保存 rewrite_prompt_version,再为每个问题标注预期的结构化结果,无需为每条样本重复保存 Prompt。检查字段和语义是否正确,比要求模型逐字输出某一句话更稳定。

semantic_intent_id: audit-export-standard-plan
raw_queries:
  - 标准版能导日志吗?
  - 基础套餐可以下载审计记录吗?
  - 我们用的是标准版,审计日志能不能导出?
expected_rewrite:
  feature: audit_log_export
  plan: standard
  action: check_permission
required_terms: [审计日志, 导出]
forbidden_drift: [企业版客户数据]

同一语义问题的不同问法,确实可能映射到同一个 canonical intent 或同一组结构化 filters。这种成组样本叫 paraphrase family,适合测试表达变化时意图是否保持稳定。

但不应强求改写后的自然语言字符串完全相同。以下情况合理结果可能不同,

Query rewrite 可以分三层测试。结构化字段先做 exact/schema check,语义是否保持交给人工或 Judge 抽检,最后比较改写前后的下游检索表现。

2. 初始检索怎么测

Retriever 是 “召回器” 或 “检索器”。它接收原始或改写后的 query,到搜索索引中快速找出一批可能相关的 document、passage 或 chunk,形成后续 Reranker 使用的候选池。

常见 Retriever 包括,

Retriever 和 Reranker 的职责可以这样区分。

Retriever:从几十万条资料中快速找出候选 Top-N,重点是别漏。
Reranker:在 Top-N 候选内部精细排序,选出最终 Top-K,重点是排准。

例如 Retriever 先从知识库召回 50 条候选,Reranker 再从这 50 条中选出最适合进入 context 的 5 条。Retriever 漏掉的证据,Reranker 看不到,也不可能补回来。

初始检索的首要任务是 “把可能正确的证据找进候选池”,此时覆盖比精细排序更重要。

评测集应为 query 标注 qrels 或完整 evidence set,但通常不要求 top-k 必须是一份完全固定的 ID 顺序。原因是可能存在多份等价证据,索引更新后也可能出现新的有效 passage。更稳的验收方式是,

这一层常看 Recall@k、Hit@k 和完整证据集召回。MRR、nDCG 也能观察初始排序,但如果后面有独立 reranker,retriever 的首要准出指标通常仍是候选池召回率。

Recall@k 看找回了多少证据

设 qrels 中与问题相关的全部证据为集合 G,系统返回的前 k 条为 TopK

Recall@k = |TopK ∩ G| / |G|

仍以 A、B 两条相关证据为例。

G = {A, B}

系统 Top-2 返回,

Top2 = {A, X}

系统找回了 A,漏掉 B。

Recall@2 = 1/2 = 0.5

Recall 只看 “找回多少”,不看顺序。{A,X}{X,A} 的 Recall@2 相同。它的解释依赖 qrels 是否完整;如果还有一条实际相关的证据没有被标注,系统取回它时可能反而被误当作错误结果。

Hit@k 看是否至少命中一条

Hit@k 对单条 query 是二元结果,

Hit@k = 1,TopK 中至少有一条相关证据
Hit@k = 0,TopK 中一条相关证据都没有

Top2={A,X} 至少命中 A,因此,

Hit@2 = 1

在整个评测集上,Hit Rate@k 是命中 query 的比例。例如 100 个问题里有 82 个至少命中一条相关证据,Hit Rate@5=0.82。

Hit@k 很适合 “找到任意一条可回答证据就够了” 的单事实任务,但对多证据问题过于宽松。一个问题需要 A、B 两条证据,系统只找到 A,Hit 仍然是 1。

完整证据集召回看证据是否凑齐

有些问题必须同时找到一组互相配合的证据,相关证据数量多也不代表已经满足回答条件。在这个例子里,完整回答要同时用到当前导出规则 A 和替代能力 B。

A:当前版审计日志导出规则
B:标准版可以查看日志摘要

把必需组合记作,

S1 = {A, B}

完整证据集召回可以定义为,

CompleteEvidence@k = 1,存在至少一套 S 完整包含在 TopK 中
CompleteEvidence@k = 0,没有任何一套完整证据被找齐

Top3={A,X,B} 同时包含 A 和 B,因此 CompleteEvidence@3=1。如果 Top-2 是 {A,X},即使 Hit@2=1、Recall@2 也不为 0,由于缺少 B,完整证据集仍然失败。

同一个问题可以存在多套可接受证据,

S1 = {A, B}
S2 = {D, E}

只要 TopK 完整包含 S1 或 S2 中任意一套即可通过。这个指标尤其适合多跳问答、跨文档比较和需要 “规则 + 例外条件” 的问题。

什么是多跳问题

多跳问题是指,没有任何一条证据能够单独回答,必须先从一条证据得到中间事实,再把它和另一条或多条证据组合,才能形成最终结论。这里的 “跳” 就是从一个事实走到下一个事实的连接步骤。

单跳问题例如,

标准版是否支持导出审计日志?

如果一条当前版本的产品权限表已经明确写出答案,找到并读取这一条证据就够了。

多跳问题例如,

Acme 工作区的管理员能否导出审计日志?如果不能,他还能使用什么替代能力?

假设答案分散在三处,

M1:账户资料说明 Acme 当前使用 Standard Plan。
M2:权限规则说明只有 Enterprise Plan 的管理员可以导出审计日志。
M3:功能说明 Standard Plan 可以查看最近 30 天的日志摘要。

回答需要完成三步连接,

第 1 跳:由 M1 确认 Acme 是 Standard Plan。
第 2 跳:把 Standard Plan 代入 M2,得出不能导出。
第 3 跳:读取 M3,给出可查看近期摘要的替代能力。

只找到 M2,系统只知道 “企业版可以导出”,却不知道 Acme 是什么版本;只找到 M1+M2,可以判断不能导出,却无法回答替代能力。M1、M2、M3 都进入 Context,才具备完整回答条件。

问题很长不一定是多跳。例如 “请详细解释标准版导出权限” 可能仍然只依赖一份文档。一次问了两个互不依赖的问题也不一定是多跳;真正的多跳要求证据之间存在依赖或组合关系。

常见多跳类型包括,

多跳评测集不应只保存一个扁平的相关文档列表,而应表达完整证据组合和最终必须覆盖的 claim,

query_id: rag-multihop-001
subquestions:
  - Acme 当前使用什么 Plan?
  - 该 Plan 是否允许管理员导出审计日志?
  - 不允许时有哪些替代能力?
acceptable_evidence_sets:
  - [M1, M2, M3]
required_claims:
  - Acme 使用 Standard Plan
  - Standard Plan 不支持导出审计日志
  - Standard Plan 可以查看最近 30 天日志摘要

这里保存的是可审计的子问题、证据和 claim,不需要保存或强迫模型输出隐藏的 chain-of-thought。模型可以采用不同推理路径,只要最终结论和引用能被证据验证。

多跳 RAG 需要在多个环节检查,

Hit@k 对多跳问题容易产生假象,只命中 M1 就已经等于 1。普通 Recall 能表示找回比例,但仍不能直接表达 “是否凑齐了一套可完成回答的证据”。因此需要 CompleteEvidence@k,再结合最终答案的 correctness、faithfulness 和 citation coverage。

ACL 要同时防越权和误拦

ACL 检查权限边界,不能用普通相关性指标代替。它验证证据是否符合当前 principal、租户、角色、项目、策略版本和时间条件,需要同时看两个方向。

  1. 越权暴露(Unauthorized exposure),无权限证据是否进入候选、最终 context、答案或引用。
  2. 错误拦截(False deny),本来有权限的 gold evidence 是否被错误过滤。

如果 Top-3 中的 X 只是普通无关文档,ACL 可以通过;如果这个位置出现另一租户的审计记录 U

Top3 = {A, U, B}
forbidden_evidence = {U}

此时 Recall@3 仍然是 2/2=1、Hit@3=1、完整证据集召回也等于 1,但 ACL 必须判失败。其他质量分再高,也不能抵消越权证据进入系统。

反过来,如果 A、B 都是当前用户有权访问的 gold evidence,却被 ACL 误删,属于 false deny。它既是权限错误,也会导致 authorized Recall 下降。

不同架构的 ACL 执行位置可能不同,有的在检索前过滤,有的在候选后过滤。评测报告应明确检查点;无论内部候选如何实现,无权限内容都不能进入生成模型、用户答案或引用,敏感候选和日志本身也必须处于受控边界。

四项放在一起看

检查 回答的问题 Top3={A,X,B} 的结果
Recall@3 两条相关证据找回了多少 2/2=1
Hit@3 是否至少找到一条相关证据 1
CompleteEvidence@3 必需组合 {A,B} 是否找齐 1
ACL 当前用户是否只接触允许的证据 X 普通则通过;X 为越权 U 则失败

不同阶段的 k 也要分开,Retriever 可能考察 Recall@50,Reranker 考察 nDCG@10,最终 Context 只保留 5 条并考察 CompleteEvidence@5。不能只写一个模糊的 Recall@k 而不说明 k 和测量阶段。

3. Reranker 怎么测

Reranker 只能重新排列已经进入候选池的内容,无法找回 retriever 漏掉的证据。因此测试时先确认候选池里存在 gold evidence,再隔离 reranker,

  1. 为每个 query 固定同一份候选池。
  2. 候选中同时放入 gold evidence、普通噪声和 hard negatives。
  3. 分别运行旧版和新版 reranker。
  4. 比较 gold evidence 的 rank 变化和 top-k 组成。

先运行生产系统里的 Query rewrite 和 Retriever,再把它们的输出固化为测试输入。所有待比较的 Reranker 使用同一份 query、候选 ID、文本和版本,才能判断分数变化是否来自 Reranker。

Hard negative 是 “看起来很像正确答案、实际不应该使用” 的文档,例如旧版制度、其他产品版本、其他租户资料或只匹配关键词但不支持结论的 FAQ。它比随机无关文档更能测出 reranker 的真实区分能力。

Reranker 常用检查包括,

排名分数以外还要看什么

Precision@k 看 Reranker 最终截取的 Top-K 中有多少是相关证据,

Precision@k = TopK 中相关证据数 / k

例如 Top-5 中有三条相关证据,Precision@5=3/5=0.6。Reranker 常用它观察噪声是否被排出最终窗口,但它不区分强相关和弱相关,也不关心这三条各自在第几名。

Gold rank delta 直接记录 gold evidence 排名改善了多少。假设项目采用下面的定义。

gold_rank_delta = candidate_rank - rerank_rank

例如 A 从候选第 17 名升到重排第 2 名,

gold_rank_delta = 17 - 2 = +15

正数表示改善,负数表示退化。存在多条 gold evidence 时,应分别保存每条 delta,并报告中位数、最差证据或关键证据的变化;不要只挑改善最大的一条。若 gold 根本不在候选池,delta 应记为 N/A: retrieval miss,不能算成 Reranker 的零分。

过期证据是否被压低 可以观察 stale evidence 的 rank delta、进入 Top-K 的比例或第一条过期证据排名。比如旧制度从第 2 名降到第 18 名是好现象,更可靠的做法通常是通过版本过滤直接移除,不能只依赖 Reranker 学会 “猜哪个版本新”。

禁止或越权证据 与过期证据不同。无权限内容不能进入最终 context、答案或引用。测试中可以把禁止证据作为受控 hard negative,验证 Reranker 不会抬高它;如果架构要求候选池也不得出现敏感 ID,再把候选阶段的 forbidden_hit@k 设为 0。

多跳证据在截取 Top-K 后是否完整 复用完整 evidence-set 检查。例如回答必须同时用 A、B,Reranker 后 A 排第 1、B 排第 8,而最终只取 Top-5,则 CompleteEvidence@5=0;如果 B 被提升到第 4,则变为 1。普通 MRR 可能在两种情况下都是 1,所以必须单独检查完整性。

延迟 要按线上 SLA 选择分位数,至少保留一个长尾指标,并记录 Reranker 给端到端请求增加的时间。流量和样本量足够时再看 p99。不同版本要在相同硬件、batch size、候选数量和文本长度下比较。

成本 包括第三方 API 费用、LLM token、GPU/CPU 时间、显存、吞吐量和并发容量。Reranker 通常需要逐个或分批给 query-document pair 打分,候选池从 20 扩到 200 时,成本和延迟可能显著上升。选择版本时要把质量收益、额外延迟和费用放在一起比较,不能只选 nDCG 最高的配置。

把两个版本并排后,可以直接看到质量收益是否值得新增的延迟和成本。

维度 旧版 新版 判断
nDCG@5 0.71 0.83 整体排序改善
MRR 0.76 0.82 第一条相关证据提前
Precision@5 0.60 0.72 Top-5 噪声减少
CompleteEvidence@5 0.58 0.69 多跳证据更完整
forbidden_hit@5 0 0 权限门禁保持通过
p95 latency 85 ms 190 ms 延迟明显增加,需判断是否可接受
单 query 成本 1.0× 2.4× 质量收益需要和预算一起决策

还要做确定性约束,reranker 输出必须是输入候选的子集,不能产生新 ID;不能重复;ACL 过滤不能被绕过;score/rank schema 必须合法。

固定候选池与真实候选池都要跑。前者隔离 Reranker 自身能力,后者验证它面对线上候选分布时是否仍有收益。

Reranker 排序指标怎样计算

这三个指标都与 “排序质量” 有关,但回答的问题不同,

继续使用上面的 qrels。令 A=plan-v3#audit-export,相关等级为 2;B=plan-v3#audit-view,相关等级为 1;X 是不相关文档。假设系统排序结果为,

第 1 名:B,相关等级 1
第 2 名:X,相关等级 0
第 3 名:A,相关等级 2
MRR 只看第一个相关结果

对一条 query,先计算 Reciprocal Rank,

RR = 1 / 第一个相关结果的排名

MRR 是所有 query 的 RR 平均值,

MRR = 所有 query 的 RR 之和 / query 数量

B、X、A 这个排序里,第一个相关结果 B 位于第 1 名,因此这条 query 的 RR=1。这个分数看起来完美,但真正直接回答问题的强相关证据 A 直到第 3 名才出现。MRR 看不到第二条、第三条相关证据,也不关心它们的重要程度,所以它适合 “只要尽快找到一条正确结果” 的任务,不适合单独评价多证据或多跳 RAG。

nDCG 同时考虑位置和相关等级

nDCG 是 normalized Discounted Cumulative Gain。可以拆成三步理解,

  1. 相关等级越高,gain 越大。
  2. 同一条证据排得越靠后,贡献会被折损。
  3. 用当前排序的 DCG 除以理想排序的 IDCG,把结果归一化到 0 到 1。

常见公式是,

DCG@k  = Σ (2^rel_i - 1) / log2(i + 1)
nDCG@k = DCG@k / IDCG@k

对于 B(1)、X(0)、A(2)

DCG@3 = 1 + 0 + 3/2 = 2.5

理想排序应该是 A(2)、B(1)、X(0)

IDCG@3 = 3 + 1/log2(3) ≈ 3.631
nDCG@3 = 2.5 / 3.631 ≈ 0.689

nDCG 发现了 MRR 没发现的问题,虽然第 1 名已经相关,但最重要的 A 排得太后,因此整体排序不是最优。它适合存在多条证据、相关性有强弱之分的任务。

需要固定 gain 公式和 relevance 等级定义。有的实现直接使用 rel_i,有的使用 2^rel_i-1;同样叫 nDCG,口径不同也不能直接比较。

Context Precision 有用上下文是否被排在前面

普通 Precision@k 只看 top-k 中相关项的比例。在 B、X、A 中,top-3 有两个相关项,因此,

Precision@3 = 2/3

RAG 评测工具中的 Context Precision 往往还考虑相关 context 的排名。以常见的 Average Precision 式口径为例,只在每个相关项出现的位置累计当时的 Precision,

Context Precision = (P@1 + P@3) / 2
                  = (1 + 2/3) / 2
                  ≈ 0.833

如果排序变成 X、B、A,仍然是三个 context 中两个相关,普通 Precision@3 还是 2/3;但相关项分别位于第 2、3 名,

Context Precision = (P@2 + P@3) / 2
                  = (1/2 + 2/3) / 2
                  ≈ 0.583

Context Precision 同时检查噪声数量和顺序,噪声挡在有用证据前面时会受到惩罚。这对 RAG 很重要,因为 context 有 token 预算,排在前面的内容通常更容易进入最终 Prompt,也更可能影响生成模型。

不过 Context Precision 不是唯一固定实现,

因此报告不能只写 context_precision=0.83,还要写清采用哪个实现、是否需要 reference、由哪个 Judge 判断、检索单位是什么。

三者怎样选
指标 最适合回答 主要盲区
MRR 第一条相关证据出现得是否足够早。 忽略后续证据和相关性强弱。
nDCG 多条、不同重要程度的证据整体排序是否合理。 依赖完整且可信的 graded qrels。
Context Precision 进入 context 的有用证据是否靠前、噪声是否靠后。 不证明所有必要证据都被找齐,也不证明来源真实或有权限。

它们通常需要和 Recall@k 或完整 evidence-set recall 一起看。一个系统可以 Context Precision 很高,却只找到两条必要证据中的一条;此时上下文很 “干净”,但仍然不完整。

4. “最终排序” 更准确地说是 Context 组装

Reranker 关心每条候选排第几,Context builder 则要把一组能够安全回答问题的材料真正装进 Prompt。它要处理多条证据之间的关系,不能简单理解成再次排序。

可以把它类比成准备会议材料,Reranker 给每份文件标出相关程度,Context builder 则要删掉无权查看和过期的文件、合并重复页、确保主规则和例外条款都在、控制总页数,并给每段材料标清来源,最后才交给回答模型。

一个从 Reranker 结果到最终 Context 的例子

假设 Reranker 给出下面的 Top-6,用户属于租户 T1,回答必须同时使用 A、B,Context 预算是 1,000 tokens,

Rank 证据 状态 tokens
1 A,当前版导出规则 T1、v3、强相关 420
2 A2,A 的大段重叠 chunk T1、v3、重复 380
3 B,标准版可查看日志摘要 T1、v3、必需补充证据 480
4 U,另一租户的真实审计记录 T2、越权 300
5 O,旧版导出规则 T1、v2、已被 v3 替代 350
6 C,审计日志术语解释 T1、v3、辅助相关 260

如果直接取 Reranker Top-5,总 tokens 为 1,930,不仅超预算,还包含重复 A2、越权 U 和过期 O。Context builder 会按约束处理,

  1. ACL 过滤 U。权限过滤可以按架构前置到检索阶段,进入 LLM 前仍要再做一次验证。
  2. 版本过滤 O,保留当前有效的 v3。
  3. 去重 A2,因为它和 A 大量重叠,继续保留只会浪费 token。
  4. 检查完整 evidence set,确认 A、B 必须同时进入。
  5. 在 1,000-token 预算下选择 A+B,共 900 tokens;辅助材料 C 因预算不足被排除。
  6. 按 “主规则 → 补充能力” 的阅读顺序放置 A、B,并保留原文 anchor。

最终应产生一份可审计的 context pack,不能只留下一段来源不明的拼接文本。

context_budget: 1000
tokens_used: 900
items:
  - evidence_id: A
    order: 1
    role: primary_rule
    source_version: v3
    anchor: section:审计日志导出权限
    tokens: 420
  - evidence_id: B
    order: 2
    role: required_support
    source_version: v3
    anchor: section:标准版日志能力
    tokens: 480
excluded:
  - {evidence_id: A2, reason: near_duplicate}
  - {evidence_id: U, reason: acl_denied}
  - {evidence_id: O, reason: superseded_version}
  - {evidence_id: C, reason: token_budget}

ACL 与租户过滤

它回答 “当前用户有没有资格让这段内容进入模型”。过滤条件可能包含 tenant、user、role、project、document ACL、policy version 和 query time。

权限过滤最好尽量前置到 Retriever,避免敏感文本参与向量召回、日志或缓存;Context builder 仍应在发送给 LLM 前再次验证。测试既要检查 U 是否从最终 context 消失,也要检查它是否泄漏到 Prompt、答案、引用和不受控 trace。

新旧版本过滤

同一制度可能同时存在 v1、v2、v3。系统应根据 valid_fromvalid_tosupersedes、文档状态和 query time 判断哪个版本有效。

如果用户问 “2024 年当时的规则”,旧版可能正是正确证据;如果问 “现在”,旧版通常应被排除。因此 “新版本永远优先” 也不准确,测试样本必须带时间条件。

去重

文档切 chunk 时常有 overlap,Retriever 可能返回同一段内容的多个近邻 chunk。去重包括,

去重也有边界。两份独立来源都支持一个高风险结论时,保留它们可能增加可验证性;真正要移除的是没有新增信息、只消耗 token 的重复。

文档多样性

多样性不等于机械规定 “每个文档只能取一条”。它让有限 Context 覆盖回答所需的不同信息。例如 A 负责主规则,B 负责例外条件,C 负责定义。

如果 top-5 全来自同一份长文的相邻 chunk,Context Precision 可能不低,但跨文档问题所需的另一条证据会被挤掉。Context builder 可以限制同一文档占用的名额,也可以按证据职责和主题覆盖选材。需要自动兼顾相关性与去重时,再使用最大边际相关性(MMR)。验收仍以必要 claim 是否覆盖为准,不能为了多样强行加入无用文档。

冲突证据

冲突证据需要单独处理。例如 v2 说 “允许导出”,v3 说 “不允许导出”,或者两个同级权威来源给出不同金额。

Context builder 至少要记录冲突组和处理理由,

测试应包含人工设计的冲突对,检查系统是否会盲从排名最高的一条旧证据。

Token 预算

模型的 context window 不能全部用来放检索证据。总预算还要留给 system Prompt、对话历史、当前 query、工具输出和回答空间,

evidence_budget
= model_context_window
- system_prompt
- conversation_history
- current_query
- answer_reserve
- safety_margin

例如模型窗口为 8,000 tokens,system Prompt 和规则占 1,000,历史对话占 1,500,query 占 200,预留回答 1,500,再保留 300 安全余量,真正能给证据的只有 3,500 tokens。

测试要验证不能因为从尾部粗暴截断,恰好把 evidence set 的 B 切掉。对于多证据问题,应先保证必需证据完整,再用剩余预算加入辅助材料。

Context 压缩

压缩是在保留证据含义的前提下减少 token,常见方式有两种。

压缩后必须保留到原始证据的映射。测试要比较压缩前后的 required claim coverage,检查数字、否定、例外、时间和主体是否保持一致;压缩器的幻觉不能被当作原文证据。

最终顺序

经过过滤和选择后,仍需决定 context 中的阅读顺序。常见做法是主证据在前、补充和例外随后,或按问题的推理顺序组织。不能只照搬 Reranker score,因为全局组装可能要求先放定义,再放规则,最后放例外。

顺序测试可以比较不同 context order 下的答案正确性、faithfulness 和完整性;如果模型对顺序非常敏感,说明系统需要更明确的分段标签、引用结构或 Prompt 约束,也需要检查 Reranker。

Context builder 怎样单独测试

像 Reranker 一样,组件测试时先固定输入,同一 query、同一份 reranked candidate list、相同 ACL、query time 和 token budget,再比较不同 builder 版本。

固定输入可以这样记录。

must_include: [A, B]
must_exclude:
  U: acl_denied
  O: superseded_version
duplicate_groups:
  - [A, A2]
max_context_tokens: 1000
required_evidence_sets:
  - [A, B]

确定性检查包括,

语义检查包括,

端到端评测还可以做三组对照,

Oracle Context:人工准备的理想证据包
Built Context:真实 Context builder 的输出
Raw Top-K:不做组装,直接拼接 Reranker Top-K

如果 Oracle 表现好、Built 表现差,问题在检索之后;如果 Built 明显优于 Raw Top-K,说明 Context builder 确实带来收益。

如果系统没有独立 Context builder

retrieved_docs[:k] 后直接拼成 Prompt,本身也是一种最小 Context 组装策略,只是没有独立模块。此时可以把 Reranker 与 Context 测试合并,但仍必须检查 ACL、版本、去重、token、完整 evidence set 和 citation anchor。没有独立类名,不代表这段质量责任不存在。

5. 最终回复怎么测

最终回复不应全部交给人逐条阅读,也不能完全交给 LLM-as-Judge。通常采用三层组合。

第一层是确定性检查,

第二层是 LLM-as-Judge,适合评估,

第三层是人工复核。普通样本可以抽样,高风险、Judge 分歧和发布阻断样本需要逐条仲裁。人工主要负责这些工作。

Judge 超时、限流、JSON 解析失败或 schema invalid 必须记录为 evaluator error,不能直接计成答案 0 分;否则评测基础设施不稳定会被误诊为模型质量下降。

四种容易混淆的回答结果

同一个审计日志问题可能出现四种相近的结果,修复位置却完全不同。

情况 Context 最终回答 应怎样判
答案正确,证据错误 旧版 O 写着可以导出 模型凭记忆回答不能导出 Correctness 可以通过,Faithfulness 与 Citation 失败,端到端失败
忠实复述过期证据 旧版 O 写着可以导出 回答可以导出 Faithfulness 可能通过,当前事实正确性与新鲜度失败
多跳证据不完整 有 M1、M2,缺少替代能力 M3 回答不能导出,没有说明可查看摘要 主结论部分正确,Completeness 与 Citation coverage 失败
使用越权证据 Context 中混入另一租户 U 回答引用 U 中的信息 ACL 直接失败,其他分数不再影响准出

把这些结果压成一个总分后,研发很难判断该修 Retriever、版本过滤、Context builder、Generator 还是 Judge。因此 Correctness、Faithfulness、Completeness、Citation 和 ACL 要分开记录。

LLM Judge 怎样校准

Judge 上线以前也要接受评测。领域专家先写清评分规则(rubric),再标注一批代表性样本。这批样本要覆盖正常回答、无答案、冲突证据、多跳问题、长 Context、权限边界和容易混淆的术语。

其中一部分样本用于调 Judge Prompt,另一部分保留为 holdout。不能在同一批标签上反复修改 Prompt,随后又用它证明 Judge 很准。

校准时重点看这些结果。

Judge model、Prompt、few-shot、temperature、输出 schema 和指标版本都要冻结。任何一项变化都可能让历史分数失去可比性。高风险类别更关心 false positive,宁可多交给人复核,也不能让错误答案轻易通过。

不同环境测到什么程度

环境和环节要分开看。开发、CI、预发布和生产保留的观测对象相同,执行深度不同。下面是一种常见分工。

环境 主要执行内容
本地开发 小规模组件用例,快速检查本次修改涉及的 rewrite、retriever、reranker、context 或 generator。
CI/发布前 固定版本的组件回归 + 端到端回归;包含 qrels、gold answer、Judge 校准和关键风险门禁。
Staging 使用接近生产的 corpus、索引、ACL、模型和并发配置,补充性能、成本和故障恢复测试。
Production 按风险全量执行低成本的 schema、ACL、引用 ID 等规则;抽样执行昂贵 Judge;采集用户反馈和业务结果并回流离线集。

系统真实存在的每个环节都应可观测、可单测,并在端到端运行中保留输出。系统没有 query rewrite、reranker 或独立 context builder,就不用为了凑齐评测形式去虚构这些环节。

qrels、ID、ACL、schema 确定性检查分别是什么

确定性检查使用固定规则计算结果,不需要 LLM 猜测语义。上游模型仍然可能产生不同输出,但 checker 本身可以重复执行,结果也能解释。

qrels 检查

把实际召回的 evidence_id 与 qrels 比较,用来回答正确证据有没有出现、排在什么位置、完整证据集是否找齐。它可以计算 Recall@k、Hit@k、MRR、nDCG 等指标。

例如 qrels 规定 plan-v3#audit-export 是强相关证据,但 top-5 只有旧版 FAQ,那么检索层直接失败,不需要 LLM Judge 再判断 “这些文档看起来是否相关”。

ID 完整性检查

ID 检查属于工程一致性检查,没有统一的学术指标定义。常见规则包括,

它解决的是 “证据链能不能对上账”,不判断文本语义是否正确。

ACL 检查

ACL 是 Access Control List,这里泛指访问控制规则。检查时要把当前用户、租户、角色、项目、策略版本和时间条件带入,验证,

涉及受保护信息时,越权使用或泄露通常会直接阻断发布。答案即使完全正确,也不能用平均质量分抵消这类安全失败。

Schema 检查

Schema 检查验证数据结构是否满足约定,例如用 JSON Schema、Pydantic 或数据库约束检查,

Schema 通过只说明 “格式合格”,不说明 “内容正确”。一个结构完整但引用错文档的答案会通过 schema,却应在 citation support 检查中失败。

这四类检查应优先于 LLM Judge,它们成本低、规则明确,还能先排除数据损坏、越权和证据记录断裂。之后再让语义评测判断 “答案是否真正受证据支持”“是否遗漏关键含义” 等程序难以完全覆盖的问题。

端到端样本

把前面的字段合在一起,一条端到端评测样本可以这样记录。

sample_id: rag-policy-001
query: "标准版账号可以导出审计日志吗?"
user_role: standard_admin
gold_answer: "不可以。审计日志导出仅企业版支持;标准版管理员只能查看最近一段时间的日志摘要。"
gold_evidence:
  - doc_id: product-plan-permissions-v3
    section: "审计日志与导出权限"
    expected_claim: "export_audit_log requires enterprise plan"
expected_behavior:
  answer: "说明标准版不支持导出,并给出可查看摘要的替代能力。"
  citation_required: true
  forbidden: ["引用旧版定价页", "建议用户绕过权限", "给出无证据的开通承诺"]
checker:
  retrieval: "gold_evidence must appear in top_5"
  generation: "answer must be faithful to cited context"
  citation: "citation must point to gold_evidence or equivalent current policy"
  permission: "context must not include enterprise-only customer data"

一次失败 run 可能长这样,

环节 实际结果 判断
文档入库 product-plan-permissions-v3 已入库。 文档已存在。
Retrieval top-k top-1 是旧版定价 FAQ,gold evidence 没进 top-5。 检索失败或 reranker 失败。
Generation 回答 “标准版支持导出”,并引用旧版 FAQ。 生成错误是检索错误的下游结果。
Citation 引用存在但不是当前有效政策。 citation accuracy 失败。
修复 owner 检索/文档治理 owner。 先修文档版本权重、metadata、reranker;不要先调 judge。

如果同一条样本的 top-k 已经命中 gold evidence,但回答仍说 “标准版支持导出”,失败就应改归因为生成不忠实或 prompt/citation 约束不足。同一个错误答案可能来自检索,也可能来自生成,只有保存每一层输出才能分清。

怎样比较两个 RAG 版本

版本比较要使用配对实验。同一条 query 同时运行基线版和候选版,语料快照、用户身份、时间条件和评分器保持一致。每条样本都能得到一组 delta,团队才知道新版本改善了哪些问题,又破坏了哪些问题。

模型生成和 LLM Judge 都可能波动。重要实验可以重复运行,报告均值、标准差或自助法(bootstrap)置信区间。自助法通过重复抽样估计结果的波动范围。分数只提高零点几分,置信区间却大面积重叠时,现有证据不足以证明真实提升。

假设基线版和候选版跑出下面这组结果。

维度 基线版 候选版 判断
Recall@10 0.82 0.87 候选召回改善
CompleteEvidence@5 0.61 0.72 多跳证据更完整
Faithfulness 0.92 0.90 生成忠实度轻微下降
无答案误答率 0.08 0.05 拒答改善
ACL 阻断失败 0 0 安全门禁保持通过
p95 latency 1.2 s 1.9 s 长尾延迟明显增加
单 query 成本 1.0× 1.35× 成本增加三成以上

这组数据不能直接导出 “候选版更好”。如果产品对延迟敏感,可以先缩小 Reranker 候选数,或者只在复杂 query 上启用昂贵路径。若 Faithfulness 的下降集中在高风险政策问题,即使平均变化很小,也应该暂停发布。

平均分之外还要查看切片。

一种实用的发布策略是把指标分成两类。软指标允许在阈值内权衡,例如平均正确率、成本和延迟。硬门禁不允许被平均分抵消,例如越权泄露、伪造引用、过期证据进入关键回答和 P0 样本退化。具体哪些问题必须阻断,要由业务风险决定。

进入生产以后,绝大多数实时 query 没有 gold answer。线上可以按风险全量运行低成本的 schema、ACL、citation ID 和错误状态检查,再抽样运行 Faithfulness、Answer Relevance 等 Judge。用户投诉、人工纠正、低置信回答和业务失败随后进入审核队列,确认后补进离线回归集。

常见失败和修复位置

失败类型 判断方式 修复方向
文档缺失 gold evidence 不在知识库 补文档或补索引
chunk 错误 文档在库中但上下文断裂 调整 chunking 和 metadata
检索失败 evidence 不在 top-k 调整 embedding、hybrid、reranker
权限过滤失败 无权限内容进入 context 或有权限内容被过滤 修权限规则
生成不忠实 context 有答案但输出编造 调 prompt、模型或引用约束
问题无答案 文档没有支撑答案 标注 unanswerable

RAG 失败了怎么查

看到错误答案时,先别急着调模型。沿着证据从上游往下查,通常更快找到问题。

  1. Gold evidence 是否存在,先固定 corpus、版本和权限范围;在这个前提下仍不存在,才归为知识缺口或样本设计错误。gold evidence 必须绑定稳定 evidence ID、原文位置、文档版本和 corpus/index snapshot。

  2. Gold evidence 是否可访问,存在但被权限过滤,先看角色、租户、ACL 和索引权限。

  3. Gold evidence 是否进 top-k,没进 top-k,优先排查 query rewrite、embedding、hybrid search、metadata、reranker。

  4. Context 是否干净,命中了证据但混入旧文档、重复片段或冲突片段,优先排查 chunking、去重、版本权重和上下文裁剪。

  5. Answer 是否忠实,context 有答案但生成错,排查 prompt、模型、answer constraint、citation requirement。

  6. Citation 是否真实,按 claim-evidence 可定位门禁检查,答案对但引用错不能算完全通过;继续排查 citation 选择和证据绑定。

  7. Review 是否一致,自动评分和人工分歧时,回到复核层修 rubric、judge prompt 或样本预期。


↙↙↙阅读原文可查看相关链接,并与作者交流