RAG 知识库问答实战(8):评测 RAG 效果的指标与数据集
2026/8/9 22:35:21 网站建设 项目流程

上一篇用证据充分性、声明级引用和服务端校验减少幻觉。要知道这些措施究竟改善还是退化,必须建立覆盖检索、生成、端到端体验与性能的评测。本篇从数据集设计开始,给出可回放、可切片的回归流程。

一、痛点:单一“答案正确率”无法指导修复

答案错误可能由解析缺失、检索漏召回、上下文噪声、生成不忠实或引用映射错误造成。如果只让评审模型打一个总分,团队不知道应该改哪层。相反,检索 Recall@K 很高也不代表系统好:正确证据虽然进入前 20,却可能未进入最终上下文,或者模型没有使用。

评测要形成指标树。数据层看解析成功率和片段覆盖;检索层看 Recall@K、MRR、nDCG 与过滤正确性;上下文层看必要证据是否齐全及冗余;生成层看答案正确性、忠实度、引用精确率/完整率和拒答;系统层看 p50/p95/p99、错误率、token、成本与并发容量。每个线上变化都应能回到具体指标。

二、原理:数据集必须代表真实分布和业务风险

高质量样本至少包含 query、可接受答案要点、相关 evidence IDs、是否可答、用户权限、时间条件、类别和难度。答案文本不是唯一真值,同义表达很多,因此最好标注事实要点与证据,而非只做字符串完全匹配。多跳问题标出所有必要证据;库外问题明确answerable=false

样本来源可以是脱敏后的真实查询、客服工单、搜索日志与专家编写。随机生成问题能扩大覆盖,但容易过于贴近文档措辞,造成虚高。应加入口语、拼写错误、缩写、错误前提、旧版本、跨文档、精确编号和攻击样本。训练、调参和最终测试集分开,避免阈值对测试集过拟合。

下面计算检索 Recall@K、MRR 与拒答准确率,并按样本逐一输出,便于定位失败而不是只看平均数。

fromdataclassesimportdataclass@dataclass(frozen=True)classCase:query_id:strrelevant:frozenset[str]retrieved:tuple[str,...]answerable:boolanswered:boolcases=[Case("q1",frozenset({"c1"}),("c1","c8"),True,True),Case("q2",frozenset({"c2","c3"}),("c4","c2"),True,True),Case("q3",frozenset(),("c9",),False,False),]k=2recalls,reciprocal_ranks,refusal_hits=[],[],[]forcaseincases:ifcase.answerable:hits=set(case.retrieved[:k])&case.relevant recall=len(hits)/len(case.relevant)rank=next((ifori,iteminenumerate(case.retrieved,1)ifitemincase.relevant),None)recalls.append(recall)reciprocal_ranks.append(0.0ifrankisNoneelse1/rank)print(f"{case.query_id}recall={recall:.2f}first_rank={rank}")refusal_hits.append(case.answerable==case.answered)print(f"Recall@{k}={sum(recalls)/len(recalls):.3f}")print(f"MRR={sum(reciprocal_ranks)/len(reciprocal_ranks):.3f}")print(f"decision_accuracy={sum(refusal_hits)/len(refusal_hits):.3f}")

运行输出:

q1 recall=1.00 first_rank=1 q2 recall=0.50 first_rank=2 Recall@2=0.750 MRR=0.750 decision_accuracy=1.000

对多证据问题,平均 Recall 0.5 可能意味着只找到一半,仍无法回答。可增加 all-required-hit 指标。拒答则要分别计算不可答问题的 precision 与 recall:系统总是拒答也能避免幻觉,却毫无业务价值。指标必须配业务门槛和失败样本列表。

三、实现:自动评分与人工评审相互校准

确定性评分优先:证据 ID 命中、JSON 合法性、引用归属、延迟和成本都由代码计算。语义正确性与忠实度可以使用 LLM-as-a-judge,但需固定评审提示和模型版本,要求输出分项理由,并用双盲人工样本测一致性。评审模型不能看到候选系统名称,避免位置或品牌偏差。

连续分数应配置信区间。两个方案差 0.5 个百分点,可能只是样本噪声。下例用固定随机种子的 bootstrap 估算正确率 95% 区间,结果可复现。

importrandomdefbootstrap_interval(values:list[int],rounds:int=5000)->tuple[float,float,float]:rng=random.Random(42)means=[]for_inrange(rounds):sample=[rng.choice(values)for_invalues]means.append(sum(sample)/len(sample))means.sort()low=means[int(rounds*0.025)]high=means[int(rounds*0.975)]returnsum(values)/len(values),low,high outcomes=[1,1,0,1,1,1,0,1,1,0]mean,low,high=bootstrap_interval(outcomes)print(f"accuracy={mean:.3f}")print(f"95% interval=[{low:.3f},{high:.3f}]")

运行输出:

accuracy=0.700 95% interval=[0.400, 1.000]

宽区间说明十个样本不足以证明细小提升。优先扩充高风险和高频切片,而非盲目追求总量。每条样本保存语料快照或索引版本,否则源文档变化后真值失效。争议标注由第二位专家复核,并记录判定依据。

评测流水线应保存配置、代码提交、模型与提示版本、索引版本、逐样本输入输出、分项分数、延迟和用量。CI 可运行小型稳定集作为回归门,夜间运行全量集。外部模型的非确定性无法完全消除,因此同一配置可重复多次,并对严重失败采用零容忍测试。

数据集也需要生命周期。文档更新后,自动找出引用受影响片段的样本,交给业务专家确认真值;不再有效的问题标记退役而不是直接删除,以保留历史可比性。新增线上失败进入候选池,经过去重、脱敏和标注后再进入测试集,不能让系统自动用自己的错误答案制造真值。

四、踩坑:平均数、数据泄漏与评审偏差

整体平均会掩盖权限越权或数字错误。报告至少按问题类型、部门、语言、可答性、单跳/多跳和文档格式切片。性能同时展示分位数,不能只看平均延迟。成本要包含嵌入、重排、生成、评审和失败重试。

若问题由目标片段直接自动生成,检索器很容易依赖相同措辞;需要人工改写或从真实日志采样。LLM 评审可能偏好更长、更自信的答案,应给出证据和细化量表,交换候选顺序,并抽样人工审计。线上点赞存在选择偏差,只能作为一个信号,不能取代黄金集。

对比实验还需控制缓存与预热。质量评测应固定语料快照,性能评测区分冷启动、热缓存和稳定负载;模型服务先完成预热,再采集正式数据。请求超时也计入结果,不能只统计成功样本的延迟。每次报告写明硬件、区域与并发,否则数字无法复现。

五、验证:用发布门把评测接入迭代

为关键指标设双边门槛:质量不得低于基线,p95 和成本不得超过预算,权限测试必须全部通过。每次变更先跑消融,只改变一个主要变量;失败报告包含 query、预期证据、实际候选、最终上下文和答案,开发者可直接复现。线上金丝雀再监测真实分布漂移。

本篇把“感觉更好”变成了可追溯的指标与数据集。下一篇将面对生产负载:设计语义缓存、并发控制、批处理、超时与降级,同时保证权限和索引新鲜度不被缓存破坏。

参考来源

  • RAGAS:Metrics
  • BEIR:异构信息检索基准
  • Stanford HELM:整体语言模型评测

👍 觉得有用就点个赞 + 收藏,方便回头查阅;有疑问直接在评论区留言,我看到都会回。

🚀 本文属于《RAG 知识库问答实战》系列,持续更新,关注不迷路。

📌 文章里的代码都能直接跑。想要可直接 clone 的完整工程 + 配套部署脚本 / 踩坑清单?评论一声或发邮件到cj2664@qq.com,我免费发你。
如果你正好在做类似系统、或有工程化难题想找人做,也欢迎邮件聊一句——我按实际情况评估,能落地的就接单或出方案。评论和邮件都能直接找到我,不用跳别的平台。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询