评测集建设与离线/在线的鸿沟

T5-1模块 5 · 评测与可观测面试权重 更新于 2026-08-19

这篇学完你能回答什么

  1. AI 应用上线前怎么评测?评测集从哪来、多少条起步、怎么分层?
  2. 离线评测 92 分、上线投诉翻倍,你从哪里开始查?
  3. 换了新模型,评测集上涨了 2 个点,能上吗?

从一个真实故障讲起

一个企业内部知识库问答系统,上线前评测 92 分。评测集 120 条,判据是「答案是否命中标准答案的要点」,人工写的标准答案,GPT 系模型判分。所有人都觉得可以发了。

上线两周,客服工单里「这机器人答非所问」的投诉是灰度前的 2.3 倍

复盘时做了一件本该在上线前做的事:从线上抽 200 条真实 query,和评测集摆在一起对比。

维度 评测集 线上真实流量
完整问句 87% 39%
残句/关键词(「年假 几天」「病假条谁签」) ~0 61%
发生在第二轮及以后(带「上面那个」「那如果……呢」这类指代) 0 44%
问的是知识库里根本没有的内容 0 12%

这三条加起来解释了绝大部分差距。而这个评测集的来源是:产品经理和两个工程师,在需求评审后的一个下午,对着知识库目录写出来的 120 条题。

它测的是「知识库里有的东西,模型能不能答对」。线上要的是「用户实际会怎么问,以及问了知识库里没有的东西时会怎样」。这是两件不同的事,但两个 92 分看起来一模一样正当。

更要命的是第三行和第四行。多轮指代和「库里没有」这两类,在评测集里出现次数是零——不是分数低,是根本没有分数。一个指标为零的维度,在看板上是不可见的。团队看到的不是「多轮场景 30 分」,而是「多轮场景不存在」。

这个故障的真正教训不是「评测集要更大」,是「评测集的分布必须和线上一致,而且你必须真的把两个分布摆在一起看过」。 分数是不是 92 不重要,重要的是这 92 分是在什么样的输入上拿到的。


92 分是真的,考的不是同一批题
上线前 92 分,上线两周「这机器人答非所问」的投诉是灰度前的 2.3 倍

  1. 对着知识库目录出题断点

    产品经理和两个工程师,一个下午写了 120 条

  2. 离线评测 92 分

    判据是「答案是否命中标准答案的要点」

  3. 所有人都觉得可以发

    两个 92 分,看起来一模一样正当

  4. 投诉是灰度前 2.3 倍

    客服工单里全是「答非所问」

  5. 抽 200 条线上 query

    和评测集摆在一起,差距一眼看见

完整问句评测集 87%线上 39%
残句 / 关键词评测集 ~0线上 61%
第二轮及以后(带指代)评测集 0线上 44%
问库里根本没有的内容评测集 0线上 12%
多轮指代和「库里没有」这两类,在评测集里出现次数是零 —— 不是分数低,是根本没有分数。一个指标为零的维度,在看板上是不可见的。

核心概念:先打比方,再给定义

打比方:评测集不是期末考试,是回归测试套件(regression test suite)

期末考试考完就作废,回归测试套件是资产——每次改动都要跑,越攒越厚。而且没人会因为「这次单测全过了」就宣称系统没 bug,大家心里清楚它只证明一件事:已知的那些 bug 没有回来。

评测集完全一样。它的作用是防止已知问题复发,不是证明系统好。想明白这句,后面所有判断都会顺。

几个术语(首次出现,中英对照 + 人话):

  • 评测集(eval set / golden dataset,也叫黄金集):一组固定的输入 + 一套判分方式。判分方式可能是标准答案,也可能只是一条判据。人话:一套每次改动都要重跑的题。
  • 离线评测(offline evaluation):在固定评测集上跑。输入不变、可重复、可回归。人话:关起门来考试。
  • 线上评测(online evaluation):对真实流量采样打分。输入每天在变,通常没有标准答案。人话:在真实考场上抽卷子看。
  • 业务指标(business metric):转化率、工单解决率、人工复核通过率、退货率。人话:老板真正在意的那个数。

三条线(本章主线)

原文示意
线 A  离线评测集     固定输入 / 有标注 / 可重复   →  决定「能不能发」
线 B  线上采样评测   真实输入 / 无标注 / 分布在动 →  决定「发完之后有没有变坏」
线 C  真实业务指标   滞后但唯一真实               →  终审

三条线只能互相佐证,不能互相替代。 它们两两之间的背离各自对应一个明确的诊断:

现象 诊断
线 A 涨、线 B 不动 评测集与线上分布脱节(开篇故障就是这一类)
线 B 涨、线 C 不动 你在优化 judge,不是在优化产品
线 C 涨、线 A 不动 收益可能来自别的变更,别把功劳记在模型上
线 A 不动、线 B 掉 输入分布变了(新渠道、新活动),或者线上有离线复现不出的环境因素

这张表是本章最常被引用的东西——任何一个「这个改动要不要上」的问题,标准答案都是先说清楚你打算用哪条线来判。


一条决定能不能发,一条决定发完有没有坏
评测集是回归测试套件,不是期末考试 —— 它只证明已知问题没回来

关起门来考试

同一套题,改一次跑一次

考场安静、题目也不会变 —— 它测不到你从没出过的题

对应
线 A · 离线评测 offline

固定输入 / 有标注 / 可重复

决定「能不能发」。分数的绝对值几乎没有意义,有意义的是同一套题在两个版本之间的差值

golden dataset可回归集合版本号
在真实考场上抽卷子看

每天的卷子都不一样

没有标准答案,只能抽样看,且抽到的分布每天在动

对应
线 B · 线上评测 online

真实输入 / 无标注 / 分布在动

决定「发完之后有没有变坏」。对真实流量采样打分,输入每天在变

真实流量采样无标注分布在动
还有第三条线:真实业务指标(转化率、工单解决率、退货率)—— 滞后但唯一真实,是终审。三条线只能互相佐证,不能互相替代。

原理拆解

先把两份分布摆一张表,再谈别的
线 A 涨、线 B 不动,对应的诊断只有一个:评测集与线上分布脱节

线 A 涨、线 B 不动离线 92 分,投诉 2.3 倍
一个下午能做完的第一动作
两份 query 摆一张表长度 / 轮次 / 意图分布
差在哪,先看这一条
两份分布对不上① 输入分布不同最常见,因为它不报错
分布对得上再往下查三条判据 / 上下文 / 泄漏
按隐蔽度往下走
② 判据不同要点命中 vs 事办了没
③ 上下文不同单轮干净 vs 第 7 轮堆叠
④ 数据泄漏prompt 对着评测集调的
统计关:涨了两个点算不算结论
要回答的问题算法 / 口径算出来读法
多少条题才够n = z² · m̂(1 - m̂) / ε²95% 置信、±5%、预期 80% → n ≈ 246误差收到 ±3% 要 ~700 条
n=100 能分辨多大独立比例的置信区间基线 80% 时约 ±7.8 个百分点涨 2 个点连半个区间都没走出去
同一套题两个配置McNemar 只看结论翻转的题100 题里翻转 10 条:6 比 4远不显著;9 比 1 才开始有话说
跑一次算不算数K = 3~5,每个配置各跑 K 遍报 mean ± std采样参数退场后,单次只是一次采样

配对检验按数据形态选:二元(对 / 错、pass / fail)用 McNemar,连续分(0.0–1.0)用配对 t 检验,Likert(1–5)用 Wilcoxon 符号秩。同样 n=100,配对检验能分辨的差异比独立比例小得多 —— 「评测集不大也能用」的前提就在这里。

防泄漏三条:评测集 ≠ 开发集(开发集随便对着它调 prompt,评测集只在跑分时看);评测集与微调训练集必须异源;再留一份保留集 holdout,从不参与任何迭代,只在重大版本前跑一次。

没有配对检验、没有方差的「涨了两个点」不是结论,是噪声 —— 而 Opus 4.7+ / Sonnet 5 传非默认 temperature 直接返回 400,方差比过去更难按住。

一、离线/在线鸿沟的四个来源

原文示意
                    离线 92 分
                        │
        ┌───────────────┼───────────────┬───────────────┐
        ▼               ▼               ▼               ▼
   ① 输入分布不同   ② 判据不同      ③ 上下文不同     ④ 数据泄漏
   问法/长度/轮次   要点命中 vs      单轮干净输入 vs  评测集与开发集
   /比例/难度       解决了问题       历史+状态+工具    同源,prompt
                                     结果堆叠          对着它调出来的
        │               │               │               │
        ▼               ▼               ▼               ▼
      线上 2.3 倍投诉

① 输入分布不同 —— 最常见,也最容易被忽略,因为它不报错。检查方法很朴素:把评测集和线上采样的 query 各自统计长度分布、轮次分布、意图分布,摆在一张表里看(开篇那张表就是这么来的)。一个下午能做完,但绝大多数团队从来没做过。

② 判据不同 —— 离线判「要点命中」,用户判「有没有帮我把事办了」。要点全命中但结论埋在第三段,离线满分线上被骂。而且这个偏差会随着你对着判据优化而不断放大。

③ 上下文不同 —— 承接四种上下文失败形态(污染 / 干扰 / 混淆 / 冲突)。离线是一次干净的单轮调用;线上是第 7 轮,前面堆了 3 次工具返回、1 次压缩、和一条用户中途改主意的指令。只测第一轮的评测集,一种都测不出来。

④ 数据泄漏 —— 最隐蔽。典型形态是评测集和调 prompt 用的例子同源,或者更常见的,prompt 是对着评测集一轮轮调出来的。此时分数上涨里有多少是真提升,你分不清。

二、评测集的三层结构

不是一个评测集,是三个,跑的频率和拦截权限都不同:

规模 跑的时机 耗时 拦不拦发布
冒烟集 smoke 5–20 条 每次提交 秒级 拦(挂了说明链路断了)
门禁集 gate 几十 ~ 两百条 每次发布 分钟级
全量集 full 几百 ~ 上千条,含长尾 每周 / 大改动 小时级 不拦,只报告

判据:能进门禁集的,必须是「错了就该拦住发布」的用例。 把「锦上添花」的题放进门禁,结果一定是门禁天天红、所有人学会无视它——一个从不亮绿灯的门禁等于没有门禁。

三、评测集从哪来(四个来源,按含金量排序)

  1. 线上真实失败(最贵、最值钱)。每一条都是花了真实代价换来的。
  2. 线上真实成功流量的分层抽样。它保证的不是难度,是分布——开篇故障缺的就是这一类。
  3. 领域专家写的边界样例。覆盖罕见但后果严重的情况:越权、敏感、法规、极端数值。
  4. 模型批量扩写。最便宜。

铁律:第 4 类只能用来扩写,不能用来打底。 用模型生成的题去测模型,你测到的是「两个模型共同认为重要的部分」。真正会翻车的地方,恰恰是两个模型有共同盲区的地方——而合成数据在那里是空白的。所以听到「我们评测集有 5000 条」,第一句该问的是「谁标的」。

四、防泄漏三条

  • 评测集 ≠ 开发集。 开发集随便看、随便对着它调 prompt;评测集只在跑分的时候看,不允许逐条读着改 prompt。
  • 评测集与微调训练集必须异源(承接第 4 章的口径)。同源切分出来的评测集,测的是记忆不是能力。
  • 留一份保留集(holdout),从不参与任何迭代,只在重大版本前跑一次。它是回答「我们这半年是真变好了,还是只是把门禁集刷穿了」的唯一手段。

五、统计关:「涨了两个点」是不是结论

第一步,先算置信区间。 单个比例的样本量公式:

原文示意
n = z² · m̂(1 - m̂) / ε²
(z=1.96 对应 95% 置信;m̂ 是预期的指标值;ε 是可接受的误差半径)

95% 置信、误差 ±5%、预期准确率 80%  →  n ≈ 246

反过来算:n=100、基线 80% 时,95% 置信区间大约是 ±7.8 个百分点。 涨 2 个点连半个置信区间都没走出去。

第二步,别用独立比例的算法。 上面那个 ±7.8pt 是「两组独立样本」的口径,而评测通常是同一套题、两个配置各跑一遍——这是配对数据。配对检验只关心结论发生翻转的那些题

数据形态 该用的检验
二元(对/错、pass/fail) McNemar
连续分(0.0–1.0) 配对 t 检验
Likert(1–5) Wilcoxon 符号秩

举例:100 题里 90 题结论相同,剩下 10 题 A 对 B 错 6 条、A 错 B 对 4 条——远不显著;9 比 1 才开始有话说。同样 n=100,配对检验能分辨的差异比独立比例小得多——「评测集不大也能用」的前提,就是你得会用配对检验。

第三步,模型自己也是方差源,而且 2026 年你按不住它。

按已冻结的口径 7,Opus 4.7+ / Sonnet 5 上传非默认的 temperature / top_p / top_k 会直接返回 400 —— temperature=0 这条老路已经没了。这意味着单次跑分不再是「确定性结果」,而是一次采样。正确做法是:

K = 3~5
for cfg in [baseline, candidate]:
    for seed in range(K):
        scores[cfg][seed] = run(eval_set, cfg)
report  mean(scores[cfg]) ± std(scores[cfg])          # 每个配置报均值和方差
mcnemar(correct[baseline], correct[candidate])        # 只看结论翻转的题

一句话:没有配对检验、没有方差的「涨了两个点」不是结论,是噪声。


工程实践(截至 2026-08)

行业现状:看得见 ≠ 评得准

LangChain《State of Agent Engineering》(调研期 2025-11~12,n=1340):

全体 生产阶段团队
已上可观测 89% 94%
有细到单步/工具调用的 tracing 62% 71.5%
离线评测 52.4%
线上评测 37.3% 44.8%

可观测已经是基础设施,评测还不是。 这个落差就是本章存在的理由——大部分候选人能讲清楚 trace 长什么样,讲不清楚一个分数在什么条件下才配当决策依据。

评测集规模:三套数字,其实是三个阶段

面试里问「多少条起步」,标准答案不是一个数字,是先问处在哪个阶段

阶段 你在做什么 规模 判据
0 · 还不知道自己会怎么错 错误分析:人工看线上 trace,给每条失败写一句话,再归并成类别 先看 100 条;约 20 条不再出现新类别就可以停(理论饱和) 此时谈样本量毫无意义——你连指标是什么都还没定
1 · 已有失败分类,要建门禁 每个失败类别配用例 每类 20–50 条手工确认,总量几十到两百 这是判据集不是统计集:作用是钉死行为,不是估计比例
2 · 要拿分数做 A/B 决策 比较两个配置谁更好 ±5% 需 ~250,±3% 需 ~700 回到统计;能用配对检验则可显著下调

这里有一个值得如实写出来的分歧:

  • Anthropic 官方口径倾向 volume over quality——「更多题目 + 稍差一点的自动判分」优于「少量题目 + 高质量人工判分」,并鼓励用模型批量扩写测试用例;
  • **实践派主流(Hamel Husain、LangChain 官方 checklist)**主张 20–50 条手工确认的胜过几百条没人看过的合成数据

这两条不矛盾,差在「判分是谁做的」。 Anthropic 那条成立的前提是判分由代码做(精确匹配、schema 校验、单测)——此时每条样本边际成本接近零,多多益善。一旦判分要靠人或靠 judge,每条都有标注成本和噪声,小而精就重新占优

可直接引用的判据:判分越便宜越可靠,评测集就越该大;判分越贵越主观,评测集就越该小而准。

避坑清单

  • 别把评测集当期末考试。 分数绝对值几乎没有意义,有意义的是同一套题在两个版本之间的差值。跨评测集比分数(「我们 92 分,他们 88 分」)是纯粹的噪声。
  • 别让评测集只增不减。 定期把「最近所有版本都 100% 通过」的用例降级到冒烟集——它们已经失去区分度,只在消耗预算。这和行业级 benchmark 的饱和是同一个现象,只是发生在你自己的仓库里。
  • 别忘了把 effort 档位当成评测矩阵的一个维度。 提档位会改变输出 token 数、工具调用次数和成本——换档位和换模型一样,要走完整回归
  • 给评测集编版本号,并和跑分结果绑在一起存。 改了集合却不改版本号,历史分数曲线就全废了。

门禁天天红,等于没有门禁
不是一个评测集,是三个:跑的频率和拦发布的权限都不同

三层评测集
规模 / 时机 / 耗时拦不拦发布
冒烟集 smoke5–20 条 · 每次提交 · 秒级拦 —— 挂了说明链路断了
门禁集 gate判据最严的一层几十 ~ 两百条 · 每次发布 · 分钟级。能进这一层的必须是「错了就该拦住发布」的用例;锦上添花的题放进来,门禁就天天红
全量集 full几百 ~ 上千条含长尾 · 每周或大改动 · 小时级不拦,只报告
规模、来源与纪律
规模按阶段定
阶段 0 先看 100 条(约 20 条不再出新类别就停);阶段 1 每类 20–50 条;要做 A/B 决策,±5% 需 ~250
来源按含金量
线上真实失败 > 成功流量分层抽样 > 专家写的边界样例 > 模型批量扩写;第 4 类只能扩写,不能打底
行业现状 n=1340
LangChain 调研:已上可观测 89%,跑离线评测只有 52.4%,跑线上评测 37.3%
别让它只增不减
把「最近所有版本都 100% 通过」的用例降级到冒烟集 —— 它们已经没有区分度,只在消耗预算
effort 档位也是一维
提档位会改变输出 token 数、工具调用次数和成本,换档位和换模型一样要走完整回归
给集合编版本号
并和跑分结果绑在一起存。改了集合却不改版本号,历史分数曲线就全废了
判分越便宜越可靠,评测集就越该大;判分越贵越主观,就越该小而准 —— Anthropic 的 volume over quality 和实践派的「20–50 条手工确认」,分歧只在这一条上。

面试视角

被问「涨两个点」,反问才是答案
四刀顺序:怎么评测 → 集合哪来 → 离线高线上差 → 涨两个点敢不敢发

  1. ① 澄清这个应用的失败长什么样:答错、答漏,还是答得对但没用
  2. ② 基线现在的分数是多少,在多大的集合上,什么判据
  3. ③ 加挂要加什么(更大的集合 / judge / 线上采样),代价是什么
  4. ④ 评测怎么知道这个改动真的有效 —— 配对检验 + 方差
  5. ⑤ 演进线上失败怎么回流成新用例
只读过:这些回答会暴露你
  • 「评测集有 5000 条」—— 一被问「谁标的」就露馅
  • 「用 GPT 打分,准确率 92%」—— 没有分布、没有来源、没有区间
  • 「上线前跑一遍就行」—— 把评测当验收,不当回归
  • 线上失败修完就算完,没有一条回流成新用例
  • 「涨了两个点,效果挺明显的」—— 最容易被一句话问倒的地方
真做过:这些细节骗不了人
  • 报得出评测集的来源构成:多少来自线上失败、多少是抽样、多少是扩写
  • 说得出评测集分布和线上分布差在哪,以及是怎么发现的
  • 说得出门禁集和全量集的区别,以及某条用例为什么进了门禁
  • 讲得出一次漏到线上的问题,以及事后补了哪条用例
  • 反问「多少条题、是不是同一套题配对跑的、重跑几次方差多大」
能讲出「一次因为评测集没覆盖而漏到线上的问题、事后补了哪条用例」的人,才算真有数据飞轮 —— 那是它在运转的唯一证据。

面试官会怎么问

  • 「你们上线前怎么评测的?」(开场,几乎必问)
  • 「评测集多少条?从哪来的?」(第一刀:有没有真建过)
  • 「离线分很高但上线效果差,可能是什么原因?」(第二刀:有没有真踩过)
  • 「换个模型评测集涨了两个点,你敢发吗?」(第三刀:有没有统计直觉)

答题结构建议

沿用 Q2-25 的五步骨架,落到评测这件事上:

① 澄清   这个应用的失败长什么样?是答错、答漏、还是答得对但没用?
② 基线   现在的分数是多少,在多大的集合上,什么判据
③ 加挂   我要加什么(更大的集合 / judge / 线上采样),代价是什么
④ 评测   我怎么知道这个改动真的有效——配对检验 + 方差
⑤ 演进   线上失败怎么回流成新用例

分水岭信号

暴露只读过:

  • 「我们建了评测集,用 GPT 打分,准确率 92%」——只有分数,没有分布、没有来源、没有区间。
  • 「评测集有 5000 条」——一被问「谁标的」就露馅。
  • 「上线前跑一遍就行」——把评测当验收,不当回归。
  • 「涨了两个点,效果挺明显的」——没有统计直觉,这是最容易被一句话问倒的地方。

证明真做过:

  • 能说出评测集的来源构成(多少来自线上失败、多少来自抽样、多少是专家写的、多少是扩写的)。
  • 能说出评测集分布和线上分布的差在哪,以及是怎么发现的。
  • 能说出门禁集和全量集的区别,以及为什么某条用例进了门禁、某条没进。
  • 能说出一次因为评测集没覆盖而漏到线上的问题,以及事后补了哪条用例——这是数据飞轮真实运转的唯一证据。
  • 被问到「涨两个点」时,反问「多少条题上涨的两个点、是不是同一套题配对跑的、重跑几次方差多大」。这一句反问的杀伤力,大于前面所有回答。

小结与延伸

三句话小结:

  1. 评测集是回归测试套件,不是期末考试——它证明「已知问题没回来」,不证明「系统好」。
  2. 离线/线上鸿沟的四个来源里排第一的是输入分布不同,它不报错,只能靠把两个分布摆在一起看才能发现。
  3. 「涨了两个点」在没有配对检验和方差之前不是结论;而 2026 年采样参数退场后,方差比过去更难按住。

延伸阅读(本教程内):

  • T2-8(RAG 评测):把系统切成检索段和生成段分别打分,是本篇「组件级评测」的具体实例。
  • T5-2(LLM-as-Judge):当判据没法用代码写时,判分交给谁、它可不可信。
  • T5-3(trace 与线上质量监控):线 B 和线 C 怎么建。
  • T4-3(微调选型):为什么「没有评测集就不要开始」是四条技术路线共同的前置闸门。

继续深入

本篇归属第 5 章「评测与可观测」,去做这一章的题