AI 能力怎么做评测?从「断言式 Eval」到「A/B 基准」

📚 前言

开篇那篇我们说过,AI 基建里最被低估、面试最加分的,是「评测」。

原因很简单:

大部分人能把 prompt 调到「看起来还行」,但答不出「你怎么证明它行、改了之后怎么知道是变好还是变坏」。

而这恰恰是「会调 API」和「能做基建」之间最深的那道沟。

这一篇不空谈方法论,我们直接解剖一个真实存在、设计得相当讲究的评测系统——Claude Code 的 Skill Benchmark(给 AI skill 打分的那套机制)。

把它拆透,你就拿到了一套可以迁移到自己任何 AI 功能上的评测心智模型。


一、为什么 AI 评测和传统测试不一样

先说清楚「难在哪」,不然没法理解后面所有设计。

传统单测是这样的:

1
expect(add(1, 2)).toBe(3);

输入确定 → 输出确定,断言是精确相等。

但 LLM 是概率性的:

1
2
3
同样的输入,可能给出不同的输出
输出是一段自然语言,没有唯一正确答案
改一个 prompt 词,效果可能天翻地覆

于是传统测试的三个前提全塌了:

  • 不能用 === 断言(输出不唯一)
  • 不能只跑一次(有随机性)
  • 不能只看绝对值(得知道「相对没改之前是好是坏」)

AI 评测要解决的,就是在这种「测不准」的前提下,依然给出可信的、可对比的质量结论。

记住这三个塌掉的前提,下面每一处设计都是在补它们。


二、一个真实的评测系统:三个角色的「利益隔离」

Skill Benchmark 最值得学的,是它把评测拆成三个互不重叠的角色:

1
2
3
4
5
①  出题人      ── 写测试用例(任务 + 断言) ──▶  evals.json
② 考生 ── 带着 skill 实际去做这道题 ──▶ outputs + transcript
(executor)
③ 阅卷人 ── 对照断言逐条判 pass/fail ──▶ grading.json
(grader)

为什么非要拆开?一个词:利益隔离。

出题、考试、阅卷如果是同一方,分数就是「自己夸自己」。三者分离,分数才可信。

这套类比可以一直用下去:

  • skill 本体 = 考生的「复习资料」(被测对象)
  • executor = 带着资料进考场的考生
  • grader = 阅卷老师
  • 出题人 = 教务处(在 skill-creator 里是「主 agent 起草 + 用户审核」,不是 skill 自己出题)

特别注意第②点:评测不是直接评 skill,而是评「executor 用了 skill 之后跑出来的结果」。skill 是间接被考的——这点很关键,它决定了「好不好」要靠对比来证明(见第四节)。

测试用例长这样,独立存在 evals/evals.json,和 skill 平级:

1
2
3
4
5
6
7
8
9
10
{
"id": 1,
"prompt": "用户的任务提问",
"files": ["evals/files/sample.pdf"],
"expected_output": "成功的样子(人话描述)",
"expectations": [
"输出里包含 X",
"用了 skill 的脚本 Y"
]
}

expectations 数组里的每一条,就是一个断言。


三、断言式评分:pass/fail + LLM-as-judge

断言断言的,不是代码层面的 assert(x === y),而是关于「这次跑完的产物」的、可客观验证的自然语言陈述。

grader 拿到两样东西去判:输出文件(outputs)+ 执行轨迹(transcript)。

断言通常分两类:

类型 断言什么 例子
结果类 产出物对不对 「输出包含 John Smith」「B10 有 SUM 公式」
过程类 有没有按 skill 的方式做 「用了 skill 的 OCR 脚本」「走了第 3 步模板」

判定方是 LLM(所谓 LLM-as-judge),所以断言写成自然语言。但也正因为判定方是模型、容易被表面糊弄,这套系统对 grader 立了三条很硬的规矩:

  1. 二元判定,没有部分分——要么 PASS 要么 FAIL。
  2. PASS 必须是「真做到」而非「表面合规」——文件名对但内容空 = FAIL;断言技术上满足但底层任务做错了 = FAIL。
  3. 存疑时举证责任在「通过」一方——拿不准就判 FAIL。

这三条本质都在对抗一件事:LLM-as-judge 容易「看着像对的就放过」。规矩越严,分数越可信。

更进一步,grader 还会做两件「超纲」的事:

  • 抽取并验证隐含 claim:把输出里没被断言覆盖的事实/过程/质量陈述也揪出来验一遍。
  • 反过来批判 eval 本身:发现「这条断言换个错误输出也能过,太水」就直接提出来。因为——

一条弱断言上的 PASS,比没有还糟,它制造虚假信心。

单次跑完,汇总成 summary:passed / failed / total / pass_rate。


四、A/B 基准:用 delta 证明价值,而非绝对分

这是整套系统的灵魂,也是第一节「不能只看绝对值」那个前提的解法。

一个 skill「好不好」,不看它绝对拿了多少分,而看它相对裸模型抬高了多少。所以每个用例要跑两遍:

1
2
with_skill     带着 skill 做
without_skill 不带 skill 裸做(基线)

然后对每个用例跑多次(默认 3 次),把结果聚合成三个维度的统计量:

维度 含义 统计
pass_rate 断言通过率(质量) mean ± stddev / min / max
time_seconds 单次耗时(速度) 同上
tokens token / 字符数(成本) 同上

为什么要跑多次还要算标准差?因为 LLM 有随机性——stddev 是用来看「这个结论稳不稳」的,高方差的 eval 可能是 flaky,不能当真。

最后算 delta,这才是结论:

1
2
3
delta.pass_rate  = with_skill - without_skill   →  "+0.50"
delta.time → "+13.0s" (skill 让它更慢了)
delta.tokens → "+1700" (skill 更费 token 了)

一份真实的 benchmark 结论会长这样:

1
2
3
4
5
带 skill:  pass_rate 85% ± 5%
裸模型: pass_rate 35% ± 8%
delta: +0.50

→ skill 多花了 13s / 1700 token,但把通过率拉高了 50%

注意 delta 是会「带符号」的双刃:质量 +50% 是收益,但耗时和 token 也涨了——评测同时把代价摆出来,让你做权衡,而不是只报喜。

这正好呼应开篇说的「成本是 AI 工程的一等公民」。


五、什么是「好断言」:区分度(discriminating)

写过 eval 的人都会踩一个坑:写出一堆「带不带 skill 都能过」的废断言。

1
2
反例:「输出是一个 PDF 文件」
→ 裸模型也能输出 PDF,这条永远 PASS,等于没测

好断言的唯一标准是有区分度:

它在 skill 真做对时 PASS,做错时 FAIL。

benchmark 里专门有个 analyzer 角色会揪这种「无区分度」的断言(在两个配置里都 100% 通过的),把它标记出来——因为它对证明 skill 价值毫无贡献。

还有一条边界:主观的东西别硬塞断言。写作风格、设计美感这类没有客观对错的,走「定性人工评」,强行写成 pass/fail 只会得到一个假的分数。


六、出题有没有维度要求?

很多人以为出题要按一张「必须覆盖 N 个维度」的考纲。其实没有——它给的是原则,不是清单:

  • 真实:像真实用户真会说的话,2~3 条起步
  • 别太窄:题目要通用,不为某个特例量身定做
  • 每题有明确考点:用例要起描述性的名字,说清在测什么

唯一有量化硬要求的是触发评测(测 skill 的 description 准不准):要造 20 条查询、正反各半(一半该触发、一半不该触发)。

但功能评测本身,刻意不定死维度。原因很本质:

好题的标准不是「覆盖了哪几个维度」,而是「带 skill 才能过、不带就挂」。只要有区分度,从哪个角度出都行;没有区分度,维度再全也是废题。

实操中,顺着「有区分度」这个原则,题目自然会落在几个面上:主路径能不能跑通、变体/边界扛不扛得住、过程是否合规、结果是否正确。但这是结果,不是规定。


小结

把 Skill Benchmark 抽象掉,你得到的是一套可迁移到任何 AI 功能的评测心智模型:

1
2
3
4
5
1. 三角色隔离:出题 / 执行 / 阅卷分开,分数才不是自己夸自己
2. 断言式打分:对「产物 + 轨迹」写可验证的自然语言断言,LLM-as-judge 判,二元、严格、无部分分
3. A/B 基准:跑 with / without 两遍 + 多次,用 delta 证明价值,同时摆出成本代价
4. 区分度是命根子:好断言带 skill 才过、裸跑就挂;无区分度的断言是废题
5. stddev 看稳定性,多次运行压住 LLM 的随机波动

回到面试那道题——如果被追问「你怎么保证 AI 功能的质量」,你现在可以这样答:

我给核心能力建了一套断言式 Eval:维护一份测试集,每条用例写可验证的断言,用模型做 judge 跑 pass/fail;每次 prompt 改动都跑回归,并和基线做 A/B,用 pass_rate 的 delta 来证明改动到底是变好还是变坏,同时盯着 token 和耗时的代价。

这就是「评测基建」该有的样子。

下一篇我们接着讲这条线的另一半——可观测性:当 AI 功能已经上线,怎么用 Tracing 和成本监控,把质量闭环从「上线前」延伸到「线上每一次真实调用」。