Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RAG 评估体系:为什么 benchmark 85%,真实问题只有 62%

一个做电力 RAG 的朋友给我看过一组数字:他的系统在通用 benchmark 上跑到 85% 准确率,然后拉了两个老值班员,对着从检索日志里抽出来的 300 个真实用户问题逐条人工标注,答对率只有 62%。23 个点的差距不在模型上,全落在用户提问不规范、多文档冲突、上下文缺失这些地方——全是 benchmark 里不存在的东西。

把 chunk、filter、embedding 的参数全调完之后,拿什么证明系统真的行?这篇文章就是我的答案:先把那 23 个点拆开看清楚,再搭一套信得过的评估基准。

先把口径说清:85% 和 62% 各自是怎么测出来的

这两组数字经常被放在一起引用,但它们的测量条件完全不同,不说清楚后面的讨论都是空的。

85% 那侧:现成的公开数据集,query 是构造好的干净句子,文档库是题库式的同质语料,每道题有唯一一个标注正确的答案。62% 那侧:300 条 query 全部来自线上检索日志(脱敏后),两个在电力系统干了多年的老值班员逐条判断“这个回答放到值班现场算不算答对了“,允许答案来自多段文档。

所以这不是 benchmark 在骗你,是两场考试用的根本不是同一张卷子。问题在于,太多团队只考了第一场,就把分数当成了系统的真实水平。

通用 benchmark 的三个盲区

盲区一:query 太干净

先把三个名字掰开,它们经常被一锅端:MS MARCO 是数据集,BEIR 是检索 benchmark,MTEB 是 embedding 综合评测(检索只是它 8 类任务之一)。作为检索评测用的时候,它们的 query 比真实工作场景干净得多——但“干净“在哪,得说准。

说准的第一步是承认:这些 query 并不都是精心构造的。MS MARCO 的 query 来自 Bing 的真实搜索日志,短、关键词化、带口语——“define extreme”、“what fruit is native to australia” 这种;BEIR 里 NQ 来自 Google 真实搜索、Quora 来自社区提问,TREC-COVID、BioASQ 才是专家写的,ArguAna 的 query 平均近 200 词。BEIR 的设计初衷恰恰是覆盖从关键词到长段落的多样性。

后续的评测换过一轮名字——MMTEB 把 MTEB 扩成多语言版,BRIGHT 专测需要推理才能找到答案的 query,BrowseComp 测 agent 式的多轮浏览检索——但对本篇要讨论的问题,它们和三个前辈是同一类东西:query 自含、答案唯一、和你线上日志里的提问不是一个物种。

但即便是这些“真实搜索日志“,和企业里的真实提问仍有一层本质差别:它们是自含的。“What is the revenue of Microsoft in 2023 Q4?“这种格式完好的句子是 benchmark 里的理想形态——公司名、指标名、时间约束全在句子里;就算 query 再短再口语,它也把意图说全了,检索系统要做的只是语义匹配。

真实用户问的是“昨天那个跳闸的怎么处理““3 号主变那个告警”“上次那个操作票”。没有设备全名,没有告警类型,没有时间,没有上下文,指代全靠对话双方心照不宣。系统在自含 query 上能拿 85%,在这类 query 上可能不到 50%——注意这是推测,不是实测数,因为通用 benchmark 根本不测这种 query,你拿不到对照分数。

盲区二:文档库太单一

benchmark 的文档库是同质的:全是维基百科,或者全是新闻,或者全是论文。检索难度只来自一个维度——语义相似度,候选 chunk 之间比的是谁跟 query 更像。

真实的文档库是异质的:调度规程、设备说明书、操作票模板、检修记录堆在一起。难点有两个,而且 benchmark 一个都测不到。一是同类文档内部是孪生的,所有规程的章节结构一模一样,“总则”“职责”“操作流程“随处都是,靠语义相似度根本分不开;二是异类文档之间几乎零共同词汇,规程的术语体系和检修记录的写法完全是两套语言,跨类检索时 embedding 的区分度会塌掉。这是另一种难度,不在 benchmark 的题库里。

盲区三:正确答案只有一种

这是三个盲区里最容易被忽视、水分最大的一个。

benchmark 的每条 query 只有一个标注为正确的 chunk,评估就是判断“系统返回的是不是那一条“。真实场景里,同一个问题往往有多段文字都能答,但质量天差地别:一段是官方规程原文,一段是值长手写的操作笔记,一段是三年前的经验总结。三段都能把问题答上,权威性、时效性、细节程度完全不同。

benchmark 判不了“哪个答案更好“,只判“是不是标注答案“。于是系统返回了值长的手写笔记——对,但不权威——benchmark 照样记为正确。85% 里有一部分就是这么来的:系统答“对“了,但放到值班现场,老值班员会告诉你这个答案不能作为操作依据。口径不同的考试,分数自然对不上。

这个盲区有个流传挺广的极端版表述。一个做开发的同行聊起 RAG 时把话说得很绝:事实准不准、过没过期、完不完整都保证不了,与其从多源召回再排序,不如认准一个事实标准。这话偏激——多数场景根本没有唯一的“事实标准”可认——但它点中了盲区三的实质:评估缺的那一格不是相关性,是权威性。召回排得再靠前,排的也是“像不像”,从来不是“该不该信”。

自有评估基准的三层结构

benchmark 指望不上,就得自己建。我用的是三层结构,按成本和运行频率分开,各管一件事:第一层兜住“别退化“,第二层量出“真实水平“,第三层负责“发现新问题“。

第一层:基础能力测试(成本最低,持续跑)

评估项就三样。Recall@5 / Recall@10:正确答案是否稳定落在 top-5/10 里,用 30–50 条干净 query 就能跑。MRR:正确答案的平均排名,越接近 1 越好。检索延迟:盯 P50/P90/P99,确认没退化到用户能感知的程度。

这一层的定位是 CI 里的冒烟测试,不是水平考试。每次改 chunk 策略、换 embedding 模型、调 filter 之后跑一遍,作用只有一个:确认这次改动没把系统搞砸。它回答不了“系统好不好“,只回答“系统坏没坏“。

第二层:真实问题基准(成本中等,每月迭代)

这是整个评估体系的核心资产,也是唯一能反映真实水平的一层。做法分四步:

  1. 从检索日志里抽真实 query,脱敏。这些 query 带着用户所有的坏习惯——指代不明、缺时间、缺主语,这正是它们的价值。
  2. 人工标注每条的“理想 chunk“。定义要写准:是“包含回答该问题所需全部信息的那段文字“,不是“最相似的 chunk“。最相似的往往答不了题,两者经常不是同一段。必要时从文档库外手动找——找不到本身就说明库有缺口,这也是评估结果。
  3. 初始标 100 条,之后每轮迭代追加 30–50 条,专门覆盖新发现的 failure case。基准集不追大,追覆盖。
  4. 标注分三个维度,不只是对/错:准确性(数字和时间对不对)、完整性(有没有遗漏关键信息)、权威性(来源是不是最权威的那篇文档)。

第三个维度正好接住前面说的盲区三:只有把“权威性“单列出来,“对但不权威“的答案才会在评估里现形,而不是被记成一分正确。

第三层:线上反馈闭环(成本最低,自动运行)

每个回答下面加“有用/没用“按钮,检索日志全量记录:用户搜了什么、点了哪条、停留多久。日志字段怎么设计这类运维细节,第 16 篇会展开,这里只说它在评估里的角色。

先把边界划清:这一层不是用来算准确率的。用户不总能判断答案对不对,“有用“按钮按下去的也不都是认真判断过的。它的用途是发现 failure case——哪些 query 的“没用“比例异常高,哪些时间段检索延迟突然上去了。它报警,第二层定性,第一层防回退,三层是这么咬合的。

RAGAs 能干什么、不能干什么

RAGAs 这类自动评估框架的思路是用 LLM 评分代替人工标注,评估维度有 faithfulness、answer_relevancy、context_relevancy 等。问题出在 scorer 也是 LLM:LLM 评分和人工评分的相关性,在 faithfulness 这类维度上不错——“答案是否被上下文支持“是个相对客观的判断;在 answer_relevancy 上很差,因为 LLM 不知道用户的真实意图。用户问“那个跳闸的”,scorer 不可能知道“那个“指代什么,这条 query 的 relevancy 评分没有参考价值。

所以我的用法是划边界,不是一棍子打死:RAGAs 当第一层的自动化版本用,挂在 CI 上每次跑完自动算 faithfulness,省掉人工盯冒烟测试的功夫。但它替代不了第二层——对真实 query 的判断必须来自懂业务的人。好在人工标注不需要每条都标,100–300 条核心 query 就够撑起一个基准。

标注的效率技巧

300 条逐条标很花时间,三个省力的做法:

  • 标注分层。 第一遍用 GPT-4 自动标:给定文档库,让它判断 top-3 chunk 是否包含正确答案。第二遍人工只复核两类——GPT 标“不确定“的(大约 50–60 条),和标“没有答案“的(需要人确认库里是真没有,还是 GPT 没找到)。人的精力花在机器拿不准的地方。
  • 标注聚焦 failure case。 统计完“多少条正确“之后,更有价值的是“错的那些有什么共同特征“。全是指代不明的“那个 X“式 query?全是跨年份的?全是两本规程冲突的?分类统计比总体准确率更有诊断价值——准确率告诉你考了多少分,failure case 的分类告诉你该补哪门课。
  • 把“够用“和“完美“分开。 不只标对/错,区分“答案对但权威性低““答案对但不完整”“答案错但理由合理”。这三类 failure case 的解法完全不同:第一类要调文档优先级,第二类要改 chunk 粒度或召回数量,第三类可能只需要换 prompt。混在一起统计,就只剩一个没法行动的总分。

收尾:不是 benchmark 骗你,是你在拿别人的考卷考自己的学生

85% 掉到 62%,说明的不是你的 RAG 不行,是你的评估基准不对。别人的考卷再标准,考的也是别人的学生。三层体系里真正值得投入的是真实问题基准——100–300 条标注 query,维护得当能跑一两年,这是你对自己的用户和文档库的理解,沉淀下来的谁也拿不走。

有个前提要说清:这套体系要求你已经有真实流量,有检索日志可抽。冷启动阶段没有真实 query,只能先用第一层加 RAGAs 顶着——这是过渡方案,自己心里要清楚它的分数打了几折。

评估体系告诉你的是“坏了“和“坏在哪一层“,但它不告诉你具体怎么一层层查下去。下一篇《检索不到时,我的排查清单》,我按真实排查顺序给一份八步清单——从评估发现症状,到排查定位病因。