评测集构建:先有一把尺子,再谈调优

本系列一路讲了二十个调优手段:换切块、调 HNSW、加 reranker、上父子检索、建摘要树……这些手段有一个共同前提,本篇把它单独成文:你得有一把尺子,否则一切「优化」都是玄学。「感觉检索好了一些」是 RAG 工程里最贵的错觉——它让你为无效的改动付出工程成本,也让真正的退化(某次参数调整让某个查询类型崩了)长期不被发现。评测集(golden dataset)就是把「感觉」变成「数字」的基础设施:一组带标准答案/标准出处的问题集,任何改动都在它上面跑分对比。这篇讲怎么从零建一把够用的尺子。

查询从哪来:三个来源的优先级

第一优先:真实查询日志。 上线第一天就记录用户的原始查询(注意隐私脱敏),这是唯一反映真实分布的来源——用户的真实问法(口语化、有错别字、表述绕)与工程师生造的问题完全是两个物种。攒两三百条后抽样标注,就是评测集的主体。冷启动期没有日志怎么办:让业务侧同事假装自己是要查东西的用户,围绕真实文档各写十条「最想问的问题」——比让工程师生造强得多,因为业务者更贴近真实用户的心智。

第二优先:从语料反推。 让大模型读一个个 chunk,逆向生成「这个片段能回答的问题」——这是 LLM 辅助造集的标准打法,快、覆盖面均匀;但要知道它的偏差:生成的问题往往过于贴着片段措辞(查询与答案共享大量词汇,检索难度偏低),用它评出来的指标系统性偏乐观。缓解:生成时给扰动要求(用不同措辞、故意口语化、跨片段组合出多跳题)。

第三优先:对抗样本人工造。 真实日志给不了「恶意」「刁钻」的分布,这类题只能人工设计:改写绕远(同义改写、口语化、中英夹杂)、拼写噪声、多跳组合(「A 和 B 的共同点」)、无答案题(库里没有的问题——专测拒答,《拒答与校验》的阈值标定全靠它们)。

标注:每道题标什么

评测题的核心字段:查询文本 + 期望答案(或答案要点)+ 相关片段清单(q → chunk id 映射,检索层的黄金标准)+ 题型标签(事实/多跳/无答案/时间敏感…)。其中「相关片段清单」是 RAG 评测区别于普通问答评测的关键:它让检索层和生成层可以分开打分(《RAG 评测入门》的分卷原则)——检索层看「黄金片段有没有被召回、排多前」(recall@k、MRR),生成层看「答案对不对、有没有引用支撑」(要点覆盖率、groundedness)。标注工作量的大头在片段映射:一条题标 3~5 分钟是常态,50~100 条精心标注的题,价值远超 1000 条 LLM 生成未校验的题——评测集的信度比规模重要。

分层设计:一把尺子要有多种刻度

同质化的评测集会掩盖结构性问题,题集要按维度分层。按难度:易(一跳、措辞直白)、难(多跳、跨文档)、对抗(改写、噪声)。按题型:事实型、聚合型(《RAPTOR》的靶子)、精确标识符型(《Code RAG》与词法通道的靶子)、无答案型(拒答的靶子)。按路由:走不同检索通道的题各自成组(《查询路由》的分类器改进也要用对应组验证)。分层的目的:总分掩盖分项退化——「平均召回率持平」的背后可能是「易题变好了、多跳题崩了」,分层报告让这类事故无处藏身。

防泄漏与维护:评测集自身的纪律

两条纪律决定尺子的长期可信。防泄漏:评测题及其答案片段绝不能因为评测而进索引(比如为了「让系统答对」把标准答案文档补进知识库——评测集从此报废);同时评测查询不要打进业务日志形成缓存污染(《语义缓存》命中评测题会让后续评测虚高)。版本化与回流:评测集入库管理(格式、变更记录、与系统版本的对应关系),线上坏例(《引用与溯源》的校验失败、用户负反馈)定期清洗成新评测题——评测集是活的,随语料和查询分布的演化更新,每次改动记录版本,指标历史才可比。

生成层评测的自动化:LLM 裁判的用法与校准

检索层的指标是程序化算的(recall、MRR),生成层的「答案好不好」传统上靠人评——规模化必须自动化,工具是 LLM 裁判(judge):让一个模型按 rubric 给答案打分(要点覆盖率、groundedness、引用正确性分项打)。裁判法上线前必须做一次校准:抽 50~100 条人工评过的样本,量裁判与人工的一致率(分项相关系数或一致率)——一致率低的裁判比没有裁判更糟(它给出的是系统性偏差的「客观数字」,比「没数字」更误导)。校准技巧:rubric 要给正反例(few-shot 对裁判的作用比对生成还大)、打分要拆细项(「要点覆盖」比「总体质量」的可复现性高得多)、温度设 0。裁判模型的选型用「比被测系统生成模型强一档」的通用规则——裁判能力低于选手,分数就是噪声。校准过的裁判把生成层评测的边际成本从「人工十分钟一题」压到「几分钱一题」,评测才能融进每次调优的日常。

指标历史与回归门禁的工程化

「改动前后必跑、跑完存档」要落成基础设施而不是口头约定:评测 runner 接 CI(检索与组装相关的 PR 自动跑,报告贴在 PR 里);指标历史入库(时间、代码版本、配置指纹、分项指标——指纹里带索引参数与模型版本,否则历史不可比);回归门禁做成硬规则(任何分项跌破基线 2 个百分点即 CI 失败,豁免要在 PR 里显式声明理由并留档)。门禁阈值的两条经验:起点宽松(先 5 个百分点,团队习惯后收紧到 2)、分项别太多(指标数超过人能盯的量,告警疲劳会让门禁形同虚设——保留 6~8 个核心分项,其余进参考区)。评测基础设施的一次性投入大约一到两周,换回的是此后每一次调优的「敢改敢回滚」——这是 RAG 系统从手工作坊走向工程的分水岭。

评测的运行成本控制

评测自身也有账:每轮全量评测 = N 道题 ×(嵌入 + 检索 + 重排 + 生成 + 裁判)的调用费。控制成本的三个旋钮:分层抽跑——日常 PR 只跑「核心层」(50 道易题 + 对抗层各抽 10 道),夜间全量层(完整 200+ 道含多跳与聚合题)跑每日回归,发布前跑全量 + 历史回归题;裁判降档——日常跑用小裁判,发布前用强裁判复核(两档裁判的校准差异记在案);结果缓存——检索层指标只依赖索引状态,索引没变的重跑直接复用上次结果(按索引版本指纹判断),生成层才需要重跑。三个旋钮落地后,日常评测的成本通常能压到全量的十分之一以下——评测体系不再因为「跑不起」而被跳过,这才是它真正长出牙齿的标志。

最小可行 runner:50 行代码起步

评测不必上重型平台,一个脚本就能开始:

import json

def run_eval(dataset_path, retriever, k=5):
    cases = json.load(open(dataset_path))
    report = {}
    for case in cases:
        got = retriever.search(case["query"], top_k=k)
        got_ids = {r.chunk_id for r in got}
        gold = set(case["gold_chunk_ids"])
        if case["type"] == "unanswerable":
            report.setdefault("unanswerable", []).append(len(got) == 0)  # 该拒不拒
            continue
        hit = len(got_ids & gold) / len(gold)                    # 片段级召回
        mrr = next((1 / (i + 1) for i, r in enumerate(got)
                    if r.chunk_id in gold), 0.0)
        report.setdefault(case["type"], []).append((hit, mrr))
    for typ, vals in report.items():
        avg_hit = sum(v[0] for v in vals) / len(vals)
        avg_mrr = sum(v[1] for v in vals) / len(vals)
        print(f"{typ:12s} n={len(vals):3d}  recall={avg_hit:.3f}  mrr={avg_mrr:.3f}")

run_eval("golden_v1.json", my_retriever)   # 每次调优前后各跑一次,存档对比

规则只有三条:改动前后必跑(跑完存档,形成指标历史);分层看报告(总分只做参考);回归门禁(改动让任何一层的指标跌超过容忍带,就要解释或回滚——把这条写进团队流程,评测才真正长出牙齿)。

人工评与裁判的分工

LLM 裁判全面接管之前,人工评的角色要重新定位而不是取消:人工评做「锚」与「疑难仲裁」——校准集的人工标注定期更新(每季度几十条,覆盖新出现的题型),裁判一致性漂移时人工复核触发样本;裁判判低分的答案抽样人审(低分答案的裁判误判率远高于高分,「差在哪」比「好不好」更难判)。裁判做「量」——日常回归、参数扫描、分层报告全部由裁判出数。这个分工的本质是:人工的稀缺注意力花在「定义标准的边界」上,裁判的廉价算力花在「按标准跑量」上,标准漂移时由人工拉回来。两者的比例随系统成熟度调整:早期五五开,成熟后人工只碰校准与仲裁。

指标看板与团队协作

评测体系要长出牙齿,最后一步是让数字进入团队的日常视野:一个极简看板(指标历史折线 + 最近一次回归的红绿标记 + 各分层的当前基线值),挂在团队常看的地方(CI 报告页或内部仪表盘)。配套两条协作约定:调优提案必须带评测数字(「我把 chunk 调到 512,多跳题 recall 涨了 3 个点、易题没动」——没有数字的调优提案不进讨论);回归失败的解释义务(门禁红了,作者要么修复、要么在 PR 里写清「为什么这个回退可接受」——豁免留档,防止门禁被温水煮青蛙式地绕过)。评测的文化价值在于把「我觉得」变成「数据显示」,而文化靠机制固化——看板让数据可见,提案规则让数据必用,门禁让数据可拦。三件齐了,评测集才是团队的共同资产而非某个人的表格。

小结

评测集是 RAG 工程的元能力:本系列前十九篇的每一个手段,没有它都是赌博,有了它都是工程。构建路径一句话:真实查询日志打底(反映分布)、LLM 反推扩量(注意措辞偏差)、对抗样本人工造(专测边界);标注的核心是「查询-黄金片段」映射,50 条精标胜过 1000 条生成;分层设计防总分掩盖,防泄漏纪律保尺子干净,坏例回流让尺子随系统一起长大。第一版不必完美——50 条题、一个 50 行 runner、一条「回归门禁」的规矩,就从这里开始。

参考资料

← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?