最近帮一个做企业知识库问答的团队重新过了一遍评测方案,发现一个很普遍的问题:他们的评测集是从公开数据集改巴改巴凑出来的,模型在评测集上跑出了90%多的准确率,一到真实业务场景就露馅了。多跳问题答不全,路由乱转,多轮对话第二句就开始丢上下文。
这个现象在企业级Agentic RAG落地阶段太常见了。Agentic RAG不再是简单的"检索-拼context-生成"三步走,而是让模型像调度员一样自主决策:走向量检索还是查SQL,检索完要不要再改写query重试,多轮对话里用户说"那家供应商呢"系统能不能知道指的是哪家。评测难度因此暴增——传统RAG那套"找个QA数据集跑分"的做法完全不够用,你必须针对自己的业务场景设计自定义Eval数据集。这篇文章我就把设计和落地过程中最核心的方法、步骤、坑全部摊开讲,适合正在搭评测体系、或者被评测集问题卡住的RAG工程师参考。
1. 为什么企业级Agentic RAG评测不能直接拿现成数据集用
1.1 传统RAG评测与Agentic RAG评测的本质差异
先把评测对象拆清楚。传统RAG的链路是固定的:query进来,向量检索,重排,拼context,生成答案。评测的核心是单跳——一个问题对应一段知识,答案质量取决于检索对不对、生成有没有忠实于上下文。对应的指标也很成熟,比如context recall、faithfulness、answer relevance,一行命令就能跑完。
Agentic RAG完全不是这个逻辑。模型拿到问题先要做路由决策:这个query是去向量库找制度文档,还是去数据仓库查指标,还是调工单系统的API?检索完发现信息不够,它要改写query再来一轮;多轮对话里还得记住上一轮提到的实体和条件,用户说"那B呢",它得自动补充出完整意图再去检索。评测维度从"答案对不对"扩展成了"决策对不对、链条顺不顺、效率高不高、状态丢没丢"。传统RAG的指标只看最终输出,中间过程的好坏根本看不见。
这也是为什么公开数据集没法直接用于企业级场景。公开benchmark的问题干净、背景自洽、领域通用,企业内部的知识库则是另一种画风:大量缩写和产品代号、新旧制度并存、数据散在多套系统里、问答还涉及权限隔离。拿通用case验证"模型在自己业务的脏数据上到底行不行",基本等于用驾校考题去考出租车司机跑不跑得明白早晚高峰。
1.2 现成数据集在真实业务场景下失效的三个表现
我见过的反面案例集中在三个表现。第一,检索弱的问题被生成能力掩盖了。公开QA数据往往一问一答,答案在文档里原样存在,模型只要定位到相关片段就能答好。企业场景的问题全是衍生式的,比如"华东区Q2库存周转天数相比去年同期改善了多少",要先定位库存报表、再定位去年同期数据、再做比较计算,答案在文档里根本没有现成句子,数据集的差异在这一步就彻底拉开。
第二,路由错误完全没被统计。Agentic RAG允许模型选择不同工具,公开数据集里几乎没有"该走SQL却去查了文档"这类样本。实际系统里路由错了很致命,用户要查发货状态,模型却调了知识库,答非所问算轻的,把数据搞错才是大事故。
第三,多轮场景基本为零。公开数据集大多是单轮问答,而企业办公助手天然是多轮流:用户先问"供应商A的账期政策",再问"那B呢",这里的"B"是实体切换,系统要带着上下文做第二轮检索。通用数据集完全测不到这个能力,模型多轮是否翻车,只有自己构造的case能暴露。
2. 设计评测集之前,先建立五类问题域的覆盖矩阵
2.1 路由与意图识别样本
设计评测集的第一步不是写问题,而是把业务里可能出现的问题域完整画一遍。我习惯至少划分五个路由类别:该走向量检索的(规章制度、产品文档类)、该走结构化查询的(数据库指标类)、该走外部API的(订单状态、工单流转类)、需要混合调用的(先查数据再拉文档类)、以及不该检索的(闲聊、情绪表达、通用知识类)。
每个类别最少20条起步,关键是必须有"边界样本"。比如"我们去年销售额是多少"表面看是结构化查询,但如果知识库里恰好有一份年报文档,模型很可能误走向量检索。评测集里专门放几条这种两个路由都可能命中的样本,才能把路由策略的模糊地带测出来。我实测下来的感受是,边界样本比标准样本更能反映线上真实体验,用户的问题从来不会规规矩矩贴着分类走。
2.2 多跳引用链与证据链查询样本
多跳样本是Agentic RAG的核心测试区。设计原则是让答案的证据链必须经过两个以上独立文档片段才能拼出来。比如"对比A和B两款产品的保修政策差异",要先召回A的保修条款、B的保修条款,再进入比较阶段;"上个月华南区退货率最高的SKU对应的产品描述和卖点",要先查退货报表拿到SKU列表,再去知识库拉产品描述,两个工具链上的调用必须串联起来。
这类样本每条都要标注"期望检索计划":第一步查什么、第二步查什么、两步能不能并行。这样评测时不只看最终答案,还能检查中间的工具调用序列是否符合预期。多跳样本的标注成本是单跳的好几倍,但价值也最高,它是区分"看起来懂"和"真的懂"的分水岭。实际项目里如果多跳case通过率低,通常不是生成模型的问题,而是检索规划和query改写出了问题,这个定位能力是评测集设计带来的隐性收益。
2.3 工具调用与外部动作样本
企业级Agentic RAG很少只检索文档,往往会接工单系统、CRM、ERP数据。评测集里必须设计"需要调用工具且调用后会影响后续检索"的样本。比如"打印最新的库存周报并总结风险项",系统要先调用报表接口拿数据,再对数据内容做总结,最终输出里必须存在来自工具的真实数据,不能是模型编的。
这类样本的golden answer要明确写出期望调用的工具名、期望传入的参数、期望的数据字段,例如:
{ "case_id": "tool-003", "type": "tool_call", "question": "最近7天有多少未处理的投诉工单?其中与物流相关的主要集中在前三个城市是哪些?", "expected_tools": [ {"name": "ticket_search", "params": {"status": "unresolved", "days": 7}}, {"name": "city_aggregation", "params": {"group_by": "city", "top": 3}} ] }只有把期望动作写死,才能确认模型真的走对了工具链路,而不是靠话术模板凑出一个"看似合理"的答案。评测集里工具类case建议配一个mock API环境,避免评测过程真的去操作生产系统,不然一次评测产生实际工单就麻烦了。
2.4 多文档冲突消解样本
企业内部知识库最麻烦的问题不是找不到答案,而是找到的内容互相矛盾:旧版制度没下架、不同地区执行标准不同、系统迁移前的历史数据和现在对不上。评测集必须涵盖冲突样本,比如"报销打车费的上限是多少",老文档写300元/月,新文档写500元/月,系统要先判断版本权威性,再给出"以新制度为准"的结论。
这类样本的golden answer通常包含两个层面:最终答案要正确,同时最好能体现冲突消解的迹象,比如回答里主动说明"系统以2024年最新版制度为准"。评测时我会单设一个conflict_resolution指标,统计模型有没有主动识别版本差异。不设这个指标的话,模型随便蒙一个数字可能碰巧对了,但完全没有"发现冲突并处理冲突"的过程,这在企业场景里是很危险的。
2.5 干扰项与负样本设计
最后一个维度特别容易漏,就是负样本——模型不应该回答、不应该检索的输入。比如用户说"你能帮我写一封辞职信吗",系统不该去检索知识库,应该作为通用对话处理;再比如用户抱怨"××系统太卡了",这里没给具体对象,模型要么澄清要么不答,而不是硬凑一段检索结果。
设计负样本的意义在于防止评测集虚高。如果评测集里全是正样本,模型随便给个回答都可能被judge判对,因为所有输入都期望有答案。我建议负样本占比控制在15%到20%,加入之后才能暴露"过度检索""乱调用工具""一本正经回答无关问题"这类毛病。另一类边缘负样本也值得放:问题本身合理但当前知识库里确实没有答案,模型应该诚实说不知道,而不是编造。这类case对企业场景特别重要,编造答案的代价往往比回答不上来高得多。
3. 单轮样本构造:从业务日志到评测case的可复现流程
3.1 素材来源:真实日志是最顶级的seed池
不要急着让大模型批量生成问题当评测集,那样产出的case和业务脱节。我推荐的做法是从业务日志里挖用户真实问题。实际环境中用户问得最多、答得最差的问题,恰恰是应该最先收进评测集的。拿日志里的query去重、脱敏、归类,得到一个seed池。产品上线后头两周的真实query,比三个人闷头写两周问题产出质量还要高。
拿到seed之后要清洗:去掉口语化的私货、脱敏掉用户姓名和敏感字段、把缺失主语的问题补完整。清洗后的QA对还不能直接用,日志里的query很多是脏的、带噪音的,直接当标准case会把评测标准拉低。我通常会在清洗环节专门存一个"raw_query"字段,保留原始问法,因为原始问法往往更适合当负样本或隐含版case的素材。
3.2 改写矩阵:让一个seed变成多个难度级别的样本
这是单轮样本构造最有价值的一步。同一个seed,通过改写矩阵可以生成多个难度级别的case:
- 基础版:原样复述或做同义词替换,考察基本检索能力。
- 扩展版:加入限制条件、比较对象、时间范围。"供应商付款周期"扩展成"对比A和B两家供应商的付款周期,并说明按新政策哪家更优"。
- 隐含版:不直接点名实体,用指代、缩写、业务话术表达,比如内部系统缩写随口就来。
- 反向版:故意用错误或不完整信息提问,考察模型会不会被误导。
改写矩阵要固化成表格或脚本,保证每条case能trace回原始seed。这样评测集不是一堆孤立问题,而是一棵问题树。难度升级时能清楚看到系统在哪一层崩掉。某团队跑完发现基础版基本都过,隐含版开始翻车,问题定位到query改写和实体识别,而不是检索本身。
3.3 标注规范与争议仲裁
单轮case要有统一的标注结构。我长期用的字段是:case_id、问题域、难度、期望token数量、golden_facts、归属知识库版本。golden_facts是一组原子事实,比如"供应商A的付款周期为45天""B的付款周期为30天""新政策要求优先选择付款周期短的供应商"。judge在打分时只和golden_facts比对,不依赖模型自由发挥。
标注争议是最容易卡进度的环节。两条case标注人A认为该走SQL,标注人B认为该走文档检索,这类分歧别靠一人拍板。我建议建一个争议池,超过两人无法达成一致的case放进去,每两周拉一次评审会。实测下来一次评审会能定掉六成争议,剩下的是真边界case,留着不删,它们最能反映路由歧义,当作模型鲁棒性的压力测试。
4. 多轮对话评测:状态追踪与追问纠错类样本怎么设计
4.1 多轮评测关注点:状态依赖到底测什么
多轮评测比单轮复杂一个量级,因为第N轮的输入依赖前N-1轮的上下文。网上很多多轮benchmark只是简单拼接对话历史,模型"看起来答得好"可能只是在重复上一轮的内容。真正要测的是状态追踪:系统能否记住当前讨论的实体、条件、时间范围,并在新一轮检索中自动带入。
一个典型的case流程是:第1轮"供应商A在深圳的那家叫什么";第2轮"它的账期政策是什么";第3轮"换成杭州的备选呢"。第2轮的"它"指代第1轮的供应商,第3轮的"杭州备选"要切换实体并重新查询账期政策。评测时如果只看第3轮答案对不对,很可能没测到状态。要检查系统在第3轮是否真带着"上一轮讨论了账期政策"这个状态去检索杭州供应商的信息。多轮case的标注里要写current_active_slots,比如owner=杭州供应商、topic=账期政策,judge再检查这些slot有没有被正确传递。
4.2 三类多轮样本模式:追问、纠正、上下位切换
按实际业务归纳,高价值的多轮模式有三类。
追问型:第一轮拿到答案后继续深挖细节。比如"我们华东区的库存周转率是多少",得到答复后追问"这个数相比上个月呢"。这类case考验系统能不能记住上一轮的实体和指标,不再让用户重复完整的限定条件。
纠正型:用户在第一轮说完条件后,第二轮推翻某个条件。比如"查一下研发团队的报销额度",紧接着纠正"是产品团队不是研发团队"。系统必须更新slot而不是叠加条件,如果新旧条件同时保留,就会检索出一堆不相关结果。
上下位切换型:从大类切到子类或反过来。比如先问"我们对外发布过的产品系列有哪些",再问"DeepCraft这个系列最新的固件版本呢"。这类是三类里最难的,跳变幅度大,系统如果靠拼接历史容易跑偏。
4.3 多轮样本的标注与难度定级
多轮case建议用JSON格式维护整段历史,而不是用"上一轮答案+本轮问题"的碎片结构。每条case包含完整对话轮次、每轮的任务类型、关键slot列表、每轮的golden_facts。评测时逐轮跑,每一轮都要独立判分,不能只判最后一轮。
难度定级按状态依赖强度来切:弱依赖是第二轮问题本身信息完整,不依赖上下文也能答;中依赖是需要继承一个slot才能答;强依赖是需要继承多个slot且要识别暗含的实体切换。我建议初始样本池里三类比例控制在3:5:2,强依赖不要太多,否则评测结果会被状态追踪能力拖低,反而不利于定位真正的业务短板。等系统多轮能力稳定了,再逐渐提高强依赖比例。
5. 答案构建与评判机制:谁来打分、按什么标准打分
5.1 golden answer的类型选择:要点型、对比型和排除型
golden answer不是写一个"标准答案文本"那么简单,按问题类型应该分成三种标注形态。
要点型适用于定义类、流程类问题,标注一组必须出现的要点。比如"报销流程必须包含提交申请、主管审批、财务复核"三点,模型漏掉一点就算不完整。对比型适用于差异比较类问题,标注正反两面事实。比如A和B的保修差异,golden要写"A为12个月""B为24个月""差异主要集中在屏幕和电池"三个事实,模型只答出"B更长"但没提具体差多少,只能算部分正确。
排除型适用于判断"不该说什么"的问题,标注禁止出现的内容。比如回答报销上限时不能提"实报实销"这种容易被误导的信息。排除型golden是很多人会漏的一类,但设计得当能非常有效地防止模型堆砌无关术语刷分。三类golden可以混合出现在同一条case里,比如问答既要覆盖要点,又不能引入某类错误说法。
5.2 LLM-as-judge的评分维度设计与prompt关键点
用大模型当裁判是目前Agentic RAG评测最可操作的方案,关键是judge的prompt必须把事实基座锁死。我踩过一个典型的坑:一开始judge prompt只写了"判断回答是否忠实于系统提供的context",结果judge自己带很强的先验知识,模型回答里出现"某型号手机S20 Pro有8GB运存"这句来自context,judge却习惯性补了一句"该系列手机的运存通常为8GB"来自自身记忆,系统分不清哪些事实真的来自文档,评分波动非常大。
后来我把prompt改成:不许使用自身知识,只根据提供的golden_facts判断回答是否覆盖所有事实点,是否有事实点与golden冲突,再额外加一个"是否引入context之外信息"的维度。四个评分维度固定下来是factual_correctness、completeness、groundedness、clarity,groundedness专门检查有没有引用或体现来自context的信息。一个通用的judge prompt模板:
你是一名RAG系统评测员。下面给出golden facts和模型回答。 请逐条判断: 1. 模型回答是否包含每条golden fact对应的关键事实; 2. 模型回答是否遗漏了关键事实; 3. 模型回答是否包含了golden facts中不存在的、且不能由golden facts推导出的信息; 4. 回答是否清晰、无歧义地解决了用户问题。 只依据golden facts判断,禁止使用你自身的知识。 对每个维度输出1-5分,并给出简要理由。judge模型本身选型也有讲究。我建议judge和被测评模型解耦,单独用一个能力更强、更稳定的模型当裁判。如果条件允许,用两个不同模型交叉打分,不一致的case再走人工仲裁,能明显减少judge自身偏好对结果的影响。
5.3 量化指标怎么选:从pass@k到agent轨迹评估
单轮评测的指标体系相对成熟:context recall、context precision、faithfulness,加上端到端的answer correctness。Agentic RAG在此基础上要增加三类指标:路由正确率,指的是模型选择的工具或检索类型是否和case期望一致;检索计划效率,看多跳步骤数是否最少、有没有做无用召回;动作执行成功率,看调工具时参数是否正确、API是否真的返回了可用数据。
pass@k适合单轮检索类case,一次评测允许多次采样,k次内有一次答案完整命中golden_facts就算通过。多轮和工具调用类case则更适合用轨迹级评估:对比预期工具序列和实际工具序列,用编辑距离或精确匹配计算轨迹得分。轨迹得分低但答案正确的case,往往说明系统绕了远路或者碰巧答对,这类信息在优化阶段特别有价值。
一份case的评估汇总结构大概是这样:
case_id route_match plan_steps tool_success groundedness completeness final_pass route-023 true 1 n/a 5 5 true multi-007 true 3 2/2 4 3 false tool-003 false 0 0/1 2 1 false回归的时候直接对比这个汇总表的平均值和分布,哪里退步一眼就能看出来。
6. 数据集上线后的维护:版本化、回归与防污染
6.1 每次发布都必须跑一轮全量回归
评测集不是一次性造完就收工的资产,它要随着知识库内容、模型prompt、路由策略的变化持续迭代。最典型的反面案例是:模型团队改了个prompt说效果提升了,评测集还是几年前的旧版本,里面的问题业务早就变了,跑出来的分数毫无参考意义。评测集上线后第一件事是定版本,每次模型或知识库有变更,必须用当前评测集跑一遍全量回归,和基线版本对比,任何指标明显波动都要先怀疑评测集再怀疑模型。
版本管理我用的方式很简单,整个评测集按目录维护,每条case是一个JSONL条目,改动全部记录变更说明,写清楚新增了哪类样本、删了几条过时case、为什么改。两周之后回头看,每个指标波动背后的数据变化都能查到,排查效率高非常多。评测集本身是软件资产,应该用对待代码的方式去管理和审查。
6.2 评测集的防污染与去重策略
评测集泄漏是隐蔽又致命的坑。模型训练语料里可能包含评测集的部分问题,哪怕embedding模型的微调数据里混进几条评测case,检索阶段就会出现"题目泄了答案"的假高分。防污染我做了三层:第一,评测集文档不进知识库索引,测试时从隔离的评测库读取,生产知识库和评测库物理分开;第二,每条case里的关键实体和专有名词做脱敏或改用虚构代号,既能防知识泄漏,也能防止embedding模型恰好见过这个新词;第三,定期跑相似度去重,用embedding把新case和已有case对比,相似度超过阈值就人工排查。
这部分容易被忽略但效果非常显著。有个团队评测准确率莫名其妙从92%爬到97%,查了很久才发现是评测集里的客户名进了索引,clean完仓库才恢复正常。评测集是可编程测试的等价物,测试集和训练集混在一起,再好的评测体系都是自欺欺人。
6.3 迭代节奏与样本增长速度
最后说迭代节奏。我建议两个维度都常态化:存量维度每周新增10到30条case,增量来源是本周业务日志里的新问题和线上badcase;每月做一次大扫除,删除因知识库更新而失效的case,比如旧制度文档已经下架、产品已经换代的。这样评测集始终保持一个跟随业务呼吸的状态。
样本增长速度也有讲究。刚开始先把覆盖七大问题域的case铺到200条左右,再慢慢追求每条case的标注质量。数量太少跑不出统计意义,太多又会维护不动。200条跑一次大型评测大概几分钟,团队能频繁跑,才能形成"评测-发现问题-改策略-再评测"的快循环。等评测集稳定到300到500条,再逐步引入更多冲突样本和多轮复杂样本,让评测集的平均难度和业务复杂度保持同步。
我在实际迭代里最深的感受是:评测集设计的工作量重点不在生成问题,而在维护问题的生命力。先跑起来再持续长,比憋大招做一版完美数据再上线要靠谱得多。Agentic RAG本身就在快速演化,评测体系如果比被测系统还僵化,那就失去了它存在的意义。