RAG 系统进化论(九):RAG 评测,怎样证明系统真的变好了?

本文导读: RAG 增加了更多技术,并不代表效果一定更好。本文将从评测集开始,介绍 Recall@K、MRR、nDCG、答案正确性、忠实度、引用和拒答评测,再通过 Experiment(实验)、Trace(调用链)、Span(执行步骤)、用户反馈与 LangSmith,建立比较版本和定位问题的方法。
从 Naive RAG 到 Agentic RAG,系统不断增加新能力:
text
向量检索
→ 查询改写与混合检索
→ 动态路由和多数据源
→ 证据检查与纠错
→ 图关系与多模态
→ 自主规划和多步工具调用
能力越多,一个问题就越难回答:
系统真的变好了吗?
假设我们为 RAG 增加了 Reranker(重排序模型)。
一次测试中,正确文档从第五名上升到第一名,看起来效果很好。
但它也可能:
- 让其他问题的正确文档下降;
- 增加 300 毫秒延迟;
- 提高每次请求成本;
- 对某类文档有效,对另一类文档变差;
- 检索变准了,最终答案却没有改善。
如果没有固定测试集和指标,我们只能依赖几个演示问题判断效果。
当系统进入 Agentic RAG(智能体式 RAG)后,情况更复杂:
text
最终答案错误
可能来自计划、路由、查询改写、工具参数、
检索、重排、证据判断或生成中的任何一步
因此,RAG 需要两套互相配合的能力:
text
Evaluation(评测):
用固定数据和指标比较系统质量
Observability(可观测性):
记录一次请求经过了什么步骤,并定位失败位置
RAG 评测与可观测性的完整流程
评测不能只看最终答案
RAG 至少包含三个层次:
text
检索层:有没有找到正确证据?
生成层:有没有正确使用证据?
系统层:延迟、费用、稳定性和安全性怎样?
只评最终答案,会把不同失败原因混在一起。
例如:
text
问题:AX-2048-C 出现 E1007 应该怎么办?
情况一:
没有检索到故障说明
→ Retrieval Failure(检索失败)
情况二:
检索到了正确说明,模型却增加了错误步骤
→ Generation Failure(生成失败)
情况三:
答案正确,但调用了十几个无关工具
→ Workflow Failure(工作流失败)
不同失败需要完全不同的改进方式。
第一步:建立评测 Dataset
Dataset(评测数据集)是一组可重复使用的测试样本。
一条 RAG 样本通常包含:
text
输入问题
期望答案或关键事实
相关文档 ID
相关证据片段
是否应该拒答
问题类型和业务标签
ts
interface RAGEvaluationExample {
// 保存用户会真实提出的问题
question: string;
// 保存答案必须包含的关键事实,而不强制逐字一致
expectedFacts: string[];
// 保存应该被检索到的文档或证据标识
relevantEvidenceIds: string[];
// 标记知识库没有答案时系统是否应该拒答
shouldRefuse: boolean;
// 使用标签区分型号、政策、多跳、表格等问题类型
tags: string[];
}
数据集不能只收集简单成功案例,还要包含:
- 普通事实问题;
- 型号、错误码和专有名词;
- 多轮对话中的指代;
- 比较和多跳问题;
- 过期或冲突资料;
- 知识库没有答案的问题;
- 权限不足的问题;
- 容易触发错误工具的问题。
高质量数据集通常来自三部分:
text
产品设计阶段人工编写的核心问题
线上真实问题经过脱敏和审核后沉淀
针对已知风险生成的边界与对抗样本
第二步:评测检索是否找到正确证据
检索评测需要提前标注"哪些证据与这个问题相关"。
常见指标包括 Recall@K、Precision@K、MRR 和 nDCG。
Recall@K:正确证据找全了多少?
Recall@K(前 K 条结果召回率)表示:
text
前 K 条结果中找到的相关证据数
÷
这个问题全部相关证据数
假设一个问题需要三条证据,Top-5(前五条结果)找到了其中两条:
text
Recall@5 = 2 / 3
Recall@K 关注不要漏掉正确证据,特别适合评估候选召回阶段。
Precision@K:返回结果中有多少是相关的?
Precision@K(前 K 条结果精确率)表示:
text
前 K 条结果中的相关证据数
÷
K
如果 Top-5 中只有两条相关:
text
Precision@5 = 2 / 5
Precision@K 关注候选结果中的噪声。
Recall 和 Precision 可能互相拉扯:
text
返回更多结果
→ Recall 可能提高
→ Precision 可能下降
→ 上下文和 Token 成本增加
MRR:第一条正确证据排得多靠前?
MRR 的全称是 Mean Reciprocal Rank(平均倒数排名)。
对每个问题,只看第一条相关结果的位置:
text
第一条正确证据排名第 1 → 1 / 1 = 1
第一条正确证据排名第 2 → 1 / 2 = 0.5
第一条正确证据排名第 5 → 1 / 5 = 0.2
完全没有找到 → 0
再对所有问题取平均。
MRR 适合"找到一条正确证据就够了"的场景,不适合衡量多个相关结果的整体排序。
nDCG:多条证据的排序质量怎样?
nDCG 的全称是 Normalized Discounted Cumulative Gain(归一化折损累计增益)。
它同时考虑:
- 结果是否相关;
- 相关程度是高、中还是低;
- 高相关结果是否排在前面。
排名越靠后,贡献会被折损;再与理想排序比较,得到 0~1 之间的归一化结果。
nDCG 适合存在多条证据、而且相关程度不同的场景。
四个指标关注点不同:
| 指标 | 主要回答 |
|---|---|
| Recall@K | 应该找到的证据找全了吗? |
| Precision@K | 返回结果中有多少是有用的? |
| MRR | 第一条正确证据出现得够早吗? |
| nDCG | 多条不同相关程度的证据顺序合理吗? |
不要只选择一个指标代表全部检索质量。
第三步:评测生成答案
检索正确不代表答案一定正确。
生成评测常关注三个维度。
Correctness:答案是否正确?
Correctness(正确性)比较系统答案与参考事实是否一致。
它不应该只做字符串匹配,因为同一个答案可以有多种表达。
可以检查:
- 必要事实是否完整;
- 数值和单位是否正确;
- 适用条件是否一致;
- 是否包含与参考答案冲突的结论。
Faithfulness:答案是否忠于证据?
Faithfulness(忠实度,也常称 Groundedness,证据支持度)判断答案中的陈述能否由检索证据支持。
text
证据:
质量问题可以在 30 天内申请售后。
答案:
质量问题保证在 30 天内全额退款。
判断:
不忠实,因为"保证全额退款"没有证据支持。
正确性和忠实度也不同:
text
答案碰巧符合现实,但证据中没有
→ 可能正确,但不忠于当前证据
答案完整复述了一份旧政策
→ 忠于所给证据,但业务结论错误
Answer Relevance:是否真正回答了问题?
Answer Relevance(答案相关性)判断回答是否围绕用户问题,是否出现大量无关内容或回避核心问题。
一个答案可能事实都正确,却没有回答用户真正关心的部分。
第四步:评测引用和拒答
RAG 的价值之一是提供可检查证据,因此引用也需要评测。
Citation Accuracy
Citation Accuracy(引用准确率)检查:
- 引用的来源是否真实存在;
- 引用位置是否包含对应结论;
- 页码和区域是否正确;
- 答案中的关键事实是否引用了正确来源。
No-answer Accuracy
No-answer Accuracy(无答案识别准确率)检查系统在资料不足时能否正确拒答。
评测集需要同时包含:
text
应该回答的问题
应该拒绝回答的问题
只有部分证据的问题
证据互相冲突的问题
只测试有答案的问题,会鼓励系统在任何情况下都给出结论。
第五步:评测 Agentic RAG 的过程
Agentic RAG 不能只比较最终文字,还要评测执行过程:
| 维度 | 示例 |
|---|---|
| Plan Quality(计划质量) | 是否拆出了完成目标所需步骤 |
| Tool Selection(工具选择) | 是否选择了正确工具 |
| Tool Arguments(工具参数) | 参数是否完整、合法、符合用户意图 |
| Task Completion(任务完成度) | 是否满足全部完成条件 |
| Efficiency(执行效率) | 是否存在重复和无效调用 |
| Safety(安全性) | 是否越权或跳过人工确认 |
例如,最终退款率计算正确,但系统读取了用户无权访问的数据,这次任务仍然应该判定失败。
第六步:用 Experiment 比较版本
Experiment(实验)是在同一数据集上运行某个系统版本,并保存每条样本的输出、指标、延迟和配置。
例如比较:
text
实验 A:
纯向量检索,Top-5
实验 B:
BM25 + 向量检索 + RRF
实验 C:
混合检索 + Reranker
一次修改是否值得上线,不能只看平均分,还要检查:
- 哪些问题类型提升了;
- 哪些样本发生回退;
- P50(50% 请求不超过的延迟)、P95(95% 请求不超过的延迟)等延迟分位数;
- Token 和模型调用成本;
- 拒答率是否异常升高;
- 是否触发新的安全问题。
ts
async function runRAGExperiment(
version: RAGVersion,
dataset: RAGEvaluationExample[],
) {
// 对同一数据集运行当前版本,保证版本之间可以公平比较
const runs = await Promise.all(
dataset.map((example) =>
runRAGSystem(version, example.question),
),
);
// 分别计算检索、生成、引用、拒答和系统成本指标
const metrics = evaluateRuns(runs, dataset, {
retrieval: ["recall_at_k", "mrr", "ndcg"],
generation: ["correctness", "faithfulness"],
system: ["latency", "token_cost", "error_rate"],
});
// 按问题标签拆分结果,避免平均分掩盖局部回退
return buildExperimentReport(
version,
runs,
metrics,
{ groupBy: "tags" },
);
}
第七步:Trace 与 Span 定位一次请求
离线评测告诉我们"某个版本整体怎样",线上可观测性帮助解释"这一次请求发生了什么"。
Trace(调用链)记录一次请求从开始到结束的完整过程。
Span(调用片段)记录其中某一个步骤。
text
Trace:回答用户问题
├── Span:查询改写
├── Span:BM25 检索
├── Span:向量检索
├── Span:RRF 融合
├── Span:Reranker
└── Span:大模型生成
每个 Span 可以记录:
text
输入与输出
开始时间与耗时
模型和提示词版本
检索结果与分数
Token 与费用
错误信息
父子调用关系
用户反馈
ts
async function tracedRAGRequest(
question: string,
) {
// 创建根调用链,关联一次用户请求及其版本信息
return trace("rag_request", { question }, async () => {
// 单独记录查询改写,便于判断问题是否在这里被改变
const query = await span(
"query_rewrite",
() => rewriteQuery(question),
);
// 单独记录检索输入、候选结果、分数和耗时
const evidence = await span(
"retrieval",
() => retrieveEvidence(query),
);
// 单独记录最终提示词、模型输出和 Token 消耗
return await span(
"generation",
() => generateAnswer(question, evidence),
);
});
}
伪代码中的 trace 和 span 表达的是通用观测思想,不限定某个平台的具体 API。
LangSmith 应该在哪个阶段加入?
LangSmith 是面向大模型应用的追踪、评测和监测平台。
在这个系列里,它不需要从 Naive RAG 第一行代码就成为文章主角。
当系统开始出现多次模型调用、检索、重排、路由和智能体循环时,我们真正需要:
- 用 Trace 查看完整调用链;
- 用 Dataset 保存评测问题和参考结果;
- 用 Evaluator(评估器)计算正确性、证据支持度和相关性;
- 用 Experiment 比较不同系统版本;
- 把自动评测和用户反馈记录到具体运行;
- 过滤和分析线上失败、延迟与成本。
这正是引入 LangSmith 的合适位置。
根据当前平台能力,可以形成如下对应关系:
| RAG 需求 | LangSmith 中的作用 |
|---|---|
| 查看一次请求经过哪些步骤 | Tracing(追踪) |
| 保存固定评测样本 | Datasets(数据集) |
| 比较两个 RAG 版本 | Experiments(实验) |
| 计算自动或人工指标 | Evaluators 与 Feedback(评估器与反馈) |
| 分析线上质量、延迟和错误 | Observability 与 Monitoring(可观测性与监测) |
LangSmith 不会自动让 RAG 变准。
它提供的是记录、比较和定位问题的基础设施。指标怎样定义、测试集是否可信、失败怎样分类,仍然需要团队自己设计。
第八步:建立 Feedback 与失败分类
Feedback(反馈)可以来自:
text
用户点赞或点踩
用户修改后的正确答案
客服标记的错误类型
自动评估器分数
人工审核结论
工具调用是否成功
只有一个"差评"还不够,系统需要 Failure Taxonomy(失败分类体系):
text
query_understanding:问题理解错误
retrieval_missing:没有召回正确证据
retrieval_noise:无关证据过多
stale_data:使用过期资料
generation_unsupported:答案缺少证据支持
wrong_tool:选择了错误工具
permission_violation:发生权限问题
latency:延迟不可接受
线上失败应该经过审核后加入回归测试集:

RAG 评测与可观测性引入了哪些技术和方案?
这一阶段不再依靠"感觉回答不错",而是使用数据集、指标和调用链持续验证系统质量。
| 技术 | 主要作用 | 产生的结果 |
|---|---|---|
| Dataset(评测数据集) | 保存固定问题、期望答案和相关证据 | 可重复运行的测试样本 |
| Retrieval Metrics(检索指标) | 衡量正确证据是否被召回和排在前面 | Recall@K、Precision@K、MRR、nDCG |
| Generation Evaluator(生成评估器) | 检查答案正确性、相关性和证据支持度 | Correctness、Faithfulness 等分数 |
| Citation Evaluation(引用评测) | 检查引用是否存在并支持相应结论 | 引用准确率 |
| Experiment(实验) | 在同一数据集上比较模型、索引和工作流版本 | 可对比的评测结果 |
| Trace 与 Span(调用链与步骤) | 记录一次请求经过的节点、耗时和输入输出 | 可定位的执行链路 |
| Feedback(反馈) | 收集用户、人工和自动评估结果 | 线上质量信号 |
| Quality Gate(质量门禁) | 根据指标决定版本能否发布 | 通过、拒绝或继续修改 |
常见落地方式可以分成三类。
方案一:离线回归评测
建立一组固定问题,在每次修改检索器、模型或提示词后重新运行,对比质量、延迟和费用。
它适合开发和发布前验证,是所有 RAG 系统都应该具备的基础能力。
方案二:线上可观测性
text
一次用户请求
→ 查询改写 Span
→ 检索 Span
→ 重排 Span
→ 生成 Span
→ 最终回答与反馈
通过 Trace 找到失败发生在哪一步,适合已经进入真实用户环境的系统。
方案三:持续评测闭环
将经过人工确认和脱敏的线上失败加入评测数据集,修改系统后运行新实验,通过质量门禁再发布。
这样,线上问题会变成下一次迭代必须通过的回归测试。
这一阶段解决了什么?
RAG 评测与可观测性让团队能够:
- 区分检索错误、生成错误和工作流错误;
- 用固定数据集比较修改前后的质量;
- 观察延迟、Token、费用和失败节点;
- 将线上失败转化为可重复的回归测试;
- 用证据决定是否上线,而不是依赖主观感觉。
评测与观测还不等于可运营
即使我们已经发现:
text
某个新 Embedding 模型让 Recall@5 提高了 6%
但 P95 延迟增加了 40%
某些旧文档没有被正确删除
团队仍然要决定:
- 怎样迁移已有向量;
- 如何给索引、提示词和模型做版本管理;
- 怎样灰度发布;
- 指标下降时如何回滚;
- 如何控制权限、成本和数据更新;
- 线上反馈由谁处理。
"看见问题"不等于"长期治理问题"。
下一篇:可运营 RAG
下一篇是这个系列的最后一篇:可运营 RAG。
我们会把前面分散的能力收束成闭环:
text
数据进入
→ 解析与索引
→ 检索和生成
→ 评测与监测
→ 发布与回滚
→ 用户反馈
→ 重新改进数据和系统
RAG 评测与可观测性回答了"系统现在表现怎样、问题发生在哪里"。
可运营 RAG 要解决的是:
怎样让数据、权限、成本、版本、发布和反馈形成一套可以长期运行的工程体系?