📚 前言
开篇那篇我们说过,AI 基建里最被低估、面试最加分的,是「评测」。
原因很简单:
大部分人能把 prompt 调到「看起来还行」,但答不出「你怎么证明它行、改了之后怎么知道是变好还是变坏」。
而这恰恰是「会调 API」和「能做基建」之间最深的那道沟。
这一篇不空谈方法论,我们直接解剖一个真实存在、设计得相当讲究的评测系统——Claude Code 的 Skill Benchmark(给 AI skill 打分的那套机制)。
把它拆透,你就拿到了一套可以迁移到自己任何 AI 功能上的评测心智模型。
一、为什么 AI 评测和传统测试不一样
先说清楚「难在哪」,不然没法理解后面所有设计。
传统单测是这样的:
1 | expect(add(1, 2)).toBe(3); |
输入确定 → 输出确定,断言是精确相等。
但 LLM 是概率性的:
1 | 同样的输入,可能给出不同的输出 |
于是传统测试的三个前提全塌了:
- 不能用
===断言(输出不唯一) - 不能只跑一次(有随机性)
- 不能只看绝对值(得知道「相对没改之前是好是坏」)
AI 评测要解决的,就是在这种「测不准」的前提下,依然给出可信的、可对比的质量结论。
记住这三个塌掉的前提,下面每一处设计都是在补它们。
二、一个真实的评测系统:三个角色的「利益隔离」
Skill Benchmark 最值得学的,是它把评测拆成三个互不重叠的角色:
1 | ① 出题人 ── 写测试用例(任务 + 断言) ──▶ evals.json |
为什么非要拆开?一个词:利益隔离。
出题、考试、阅卷如果是同一方,分数就是「自己夸自己」。三者分离,分数才可信。
这套类比可以一直用下去:
- skill 本体 = 考生的「复习资料」(被测对象)
- executor = 带着资料进考场的考生
- grader = 阅卷老师
- 出题人 = 教务处(在 skill-creator 里是「主 agent 起草 + 用户审核」,不是 skill 自己出题)
特别注意第②点:评测不是直接评 skill,而是评「executor 用了 skill 之后跑出来的结果」。skill 是间接被考的——这点很关键,它决定了「好不好」要靠对比来证明(见第四节)。
测试用例长这样,独立存在 evals/evals.json,和 skill 平级:
1 | { |
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 立了三条很硬的规矩:
- 二元判定,没有部分分——要么 PASS 要么 FAIL。
- PASS 必须是「真做到」而非「表面合规」——文件名对但内容空 = FAIL;断言技术上满足但底层任务做错了 = FAIL。
- 存疑时举证责任在「通过」一方——拿不准就判 FAIL。
这三条本质都在对抗一件事:LLM-as-judge 容易「看着像对的就放过」。规矩越严,分数越可信。
更进一步,grader 还会做两件「超纲」的事:
- 抽取并验证隐含 claim:把输出里没被断言覆盖的事实/过程/质量陈述也揪出来验一遍。
- 反过来批判 eval 本身:发现「这条断言换个错误输出也能过,太水」就直接提出来。因为——
一条弱断言上的 PASS,比没有还糟,它制造虚假信心。
单次跑完,汇总成 summary:passed / failed / total / pass_rate。
四、A/B 基准:用 delta 证明价值,而非绝对分
这是整套系统的灵魂,也是第一节「不能只看绝对值」那个前提的解法。
一个 skill「好不好」,不看它绝对拿了多少分,而看它相对裸模型抬高了多少。所以每个用例要跑两遍:
1 | with_skill 带着 skill 做 |
然后对每个用例跑多次(默认 3 次),把结果聚合成三个维度的统计量:
| 维度 | 含义 | 统计 |
|---|---|---|
| pass_rate | 断言通过率(质量) | mean ± stddev / min / max |
| time_seconds | 单次耗时(速度) | 同上 |
| tokens | token / 字符数(成本) | 同上 |
为什么要跑多次还要算标准差?因为 LLM 有随机性——stddev 是用来看「这个结论稳不稳」的,高方差的 eval 可能是 flaky,不能当真。
最后算 delta,这才是结论:
1 | delta.pass_rate = with_skill - without_skill → "+0.50" |
一份真实的 benchmark 结论会长这样:
1 | 带 skill: pass_rate 85% ± 5% |
注意 delta 是会「带符号」的双刃:质量 +50% 是收益,但耗时和 token 也涨了——评测同时把代价摆出来,让你做权衡,而不是只报喜。
这正好呼应开篇说的「成本是 AI 工程的一等公民」。
五、什么是「好断言」:区分度(discriminating)
写过 eval 的人都会踩一个坑:写出一堆「带不带 skill 都能过」的废断言。
1 | 反例:「输出是一个 PDF 文件」 |
好断言的唯一标准是有区分度:
它在 skill 真做对时 PASS,做错时 FAIL。
benchmark 里专门有个 analyzer 角色会揪这种「无区分度」的断言(在两个配置里都 100% 通过的),把它标记出来——因为它对证明 skill 价值毫无贡献。
还有一条边界:主观的东西别硬塞断言。写作风格、设计美感这类没有客观对错的,走「定性人工评」,强行写成 pass/fail 只会得到一个假的分数。
六、出题有没有维度要求?
很多人以为出题要按一张「必须覆盖 N 个维度」的考纲。其实没有——它给的是原则,不是清单:
- 真实:像真实用户真会说的话,2~3 条起步
- 别太窄:题目要通用,不为某个特例量身定做
- 每题有明确考点:用例要起描述性的名字,说清在测什么
唯一有量化硬要求的是触发评测(测 skill 的 description 准不准):要造 20 条查询、正反各半(一半该触发、一半不该触发)。
但功能评测本身,刻意不定死维度。原因很本质:
好题的标准不是「覆盖了哪几个维度」,而是「带 skill 才能过、不带就挂」。只要有区分度,从哪个角度出都行;没有区分度,维度再全也是废题。
实操中,顺着「有区分度」这个原则,题目自然会落在几个面上:主路径能不能跑通、变体/边界扛不扛得住、过程是否合规、结果是否正确。但这是结果,不是规定。
小结
把 Skill Benchmark 抽象掉,你得到的是一套可迁移到任何 AI 功能的评测心智模型:
1 | 1. 三角色隔离:出题 / 执行 / 阅卷分开,分数才不是自己夸自己 |
回到面试那道题——如果被追问「你怎么保证 AI 功能的质量」,你现在可以这样答:
我给核心能力建了一套断言式 Eval:维护一份测试集,每条用例写可验证的断言,用模型做 judge 跑 pass/fail;每次 prompt 改动都跑回归,并和基线做 A/B,用 pass_rate 的 delta 来证明改动到底是变好还是变坏,同时盯着 token 和耗时的代价。
这就是「评测基建」该有的样子。
下一篇我们接着讲这条线的另一半——可观测性:当 AI 功能已经上线,怎么用 Tracing 和成本监控,把质量闭环从「上线前」延伸到「线上每一次真实调用」。