评测集设计
评测集设计
给 coding agent 的执行参考。每节结构:为什么 → 做法 → 判据 → 边界。
先建评测,再写文档。 顺序反过来,你会为了让它通过而改评测——评测集是唯一能防止你把 skill 写成一份没人读的 best practices 搬运的东西。
两套评测回答不同的问题,先跑触发率,再跑输出质量:description 触发失败时,输出评测全部无意义(skill 根本没被读)。
0. 目录
- 触发率评测
- 触发率的四轴变化
- 输出质量评测
- 断言强弱分级
- 审查断言本身
- 三个判读动作
- 变异诊断
- 防过拟合
- 成本判读
- harness 方差警告
- 最小评测集清单
- 反例速查表
1. 触发率评测
回答的问题:agent 会不会在该读这个 skill 的时候读它。
最小形态:20 条查询(10 正 10 近似错配负),每条跑 3 次(agent 是随机的,单次没有意义),算触发率。
通过线:should-trigger 的触发率 > 0.5 判过;should-not-trigger < 0.5 判过。
测试 prompt 必须足够"实质":agent 只会为超出它自己能力的任务去查 skill。像「读一下这个 PDF」这种一步请求,即使 description 完美匹配也不会触发。每条查询都要落在「agent 不查 skill 大概率会做错」的地带。
负例必须近似错配:共享概念、需要的是别的事情。零概念重叠的弱负例(「写个斐波那契函数」)测不出任何东西。
强负例的构造法:拿正例里的每个领域名词,换一个同样用它但场景不同的语境。
「自动化验收」→ 给 REST API 写测试;「交接文档」→ 写离职交接文档;「skill」→ 装一个 npm 包。
判据:每条负例能说出「它和正例共享哪个词或哪个概念,但需要的是别的事情」。说不出就不是近似错配。
2. 触发率的四轴变化
10 条正例按四轴变化,避免所有查询长得一样:
| 轴 | 变化 |
|---|---|
| 措辞正式度 | 正式书面 / 口语 / 带错别字 |
| 是否点名领域 | 明说领域名 vs 只描述需求 |
| 细节量 | 极简一句 vs 带路径、行数、背景 |
| 任务复杂度 | 单步 vs 多步链条里的一环 |
最有用的是关联不明显的正例:如果查询已经明说 skill 做什么,任何合格 description 都会触发,测不出东西。真正决定 description 措辞质量的是这类——用户没明说「提炼」这个动作,但诉求需要它。
多步链条里的一环是最真实的形态:前面几步与领域无关,中间某一步需要这个 skill。
判据:10 条正例里至少 3 条是关联不明显的,且四条轴各有 ≥2 条。
3. 输出质量评测
回答的问题:读了 skill 之后,产出是否更好。
方法:同一条任务跑两遍,除 skill 是否安装外所有变量相同,看断言通过率的差值(skill lift)。
流程:
cp -r <skill> baseline/快照当前版本当基线。- 每个 case 跑两遍:一遍装着 skill,一遍不装。
- 每遍用干净上下文(独立 session 或 subagent)。
- 打分,PASS 必须给具体证据。
PASS 必须给具体证据:断言说「包含一份总结」而输出真有个叫 Summary 的标题、里面只有一句空话——那是 FAIL。label 在但 substance 不在,是 FAIL。
case 的类型分布(8–10 个里各占若干):
| type | 例子 |
|---|---|
diagnostic |
用户带错误方向来,考验 skill 能否纠正而非附和 |
build |
让它产出某种产物,考察结构与判据 |
classify |
让它对一批材料做判断,考察抽象层次 |
refuse |
让它做一件不该做的事,考察它是否拒绝 |
判据:每个 case 都标了 type;diagnostic 类至少 2 条且用户都给了错误方向;每个 case 的 prompt 都落在「不查 skill 大概率做错」的地带。
4. 断言强弱分级
每条断言标 strength:
| strength | 含义 | 例子 |
|---|---|---|
good |
机械可查、判别力强 | 「输出里区分了三类中的至少两类,且各给了验证步骤」 |
weak_manual |
人工评审、半主观 | 「这条通则换一个项目还成立吗」 |
能用脚本查的就用脚本(字段齐全、条目数、禁用集为空、某个词的出现次数)。脚本更可靠且可跨轮复用,模型判断既贵又不稳。
标 UNMEASURED 的项不要编分数。 氛围、手感、留白质量这类半主观项很难拆成 pass/fail。编一个分数比留空更糟——它会让报告看起来完整而其实不可信。
断言数量控制:每个 case 4–6 条断言,其中 ≥2 条 good。断言越多,单个断言的信号越弱(总有一条会偶然命中)。
判据:每条断言都标了 strength;good 类断言能写成脚本检查;没有 UNMEASURED 项被编了分数。
5. 审查断言本身
三种坏断言:
| 类型 | 症状 | 后果 |
|---|---|---|
| 太容易 | 无论 skill 质量如何总是 pass | 抬高 with-skill 通过率,不反映价值 |
| 太难 | 好输出也总是 fail | 掩盖真实提升,或指错了方向 |
| 不可验证 | 两个评审员给出不同结论 | 判读阶段无法收敛 |
审查方法:拿两个明显有差别的输出(一份任意写、一份专家写)跑一遍断言。理想情况是差的那份 fail、好的一份 pass。两者都 pass 就是太容易,两者都 fail 就是太难。
不可验证的识别:把它交给另一个评审(人或模型),看结论是否一致。不一致的加具体判据(「至少两类」这种量化限定能救回大部分)。
判据:每个 case 至少有一条断言在「好输出 / 坏输出」对照下有区分度。
6. 三个判读动作
with/without 两组结果出来后,必须做这三件事,不要只给一个总分。
1. 删掉「两种配置下都总是 pass」的断言
它们抬高 with-skill 通过率,却没有反映 skill 的真实价值。留着它们会让 skill 看起来有效。
2. 查「两种配置下都总是 fail」的断言
两种可能:断言写错了,或者 skill 里缺了对应内容。后者是整个评测过程最值钱的发现——它直接指向 skill 该补什么。
3. 研究「只有有 skill 才 pass、无 skill 就 fail」的断言
这才是 skill 明确在创造价值的地方。 报告里把这三类分开列,并给 lift 加一句人话结论(「skill 让 X 类任务从不产出方案变成始终产出可执行步骤」)。
判据:报告里三类断言分开列,且给出了一条人话结论。
7. 变异诊断
同一 case 时好时坏(方差大)有两种原因,两种的处理完全不同:
- 评测本身 flaky——断言的边界模糊,判读随机。修断言。
- skill 的指令有歧义到模型每次理解不同——这是 skill 的缺陷。加例子或更具体的指引来降歧义,不要加更多规则。
这是区分「我该改文档还是改评测」的唯一诊断。 判断方法:看失败点在 case 之间是否随机分布——随机=flaky,集中在某几个 case=文档歧义。
判据:报告里标了方差大的 case,并区分了是断言问题还是文档问题。
8. 防过拟合
train / validation 60 / 40 固定划分,跨轮不变,跨轮打乱顺序。 validation 的结果必须隔离在调优流程之外——只能用 train 的失败来指导修改。
不要把失败查询里的具体关键词加进 description。 那是过拟合。要找的是这些查询代表的一般类别,然后用一般类别去写 description。
调优卡住时换结构而不是增量微调:换一个框架或换一种句子结构可能突破,continue 微调不会。卡住的现象通常是「改了措辞但通过率不动」。
按 validation 通过率选最优,不是按 train,也不是按最后一版。 最好的 description 很可能不是你最后写的那一版——这一点几乎每次都成立。
五轮迭代通常够了。
判据:某一版的 description 是按 validation 通过率选出来的,且它不是最后一版。
9. 成本判读
benchmark 报 pass_rate / time / tokens 的 mean±stddev 和 delta。判读规则:
- 多花 13 秒但通过率提升 50 个百分点 → 值得。
- token 用量翻倍换来 2 个百分点 → 不值得。
- 差值接近零 → 先确认 skill 到底有没有被触发。工具里常有
force_skill_invocation开关,它专门区分「指令写错了」和「发现机制失败了」。
成本判读不能只看通过率。 一份让 agent 多读 20k token 的 skill,如果 lift 只有 2 个百分点,它的净价值是负的——因为它挤掉了别的 skill 的预算。
判据:报告里同时给了 lift 与成本,并给出了一句「值不值」的结论。
10. harness 方差警告
harness 引入的方差可能比大多数 skill 效应还大。 所以:
- 单次测量基本没有意义,每条至少 3 次。
- 报告均值必须带 stddev,不带 stddev 的均值不可信。
- 小于 stddev 的 lift 视为噪声。
- 跨 harness 的数字不可比(不同 harness 的基线不同)。
这一条是评测纪律里最容易被违反的:跑 20 条 × 1 次然后报一个精确的触发率百分比,是评测里的常见自欺。
判据:报告里每个均值带 stddev;低于 stddev 的 lift 被显式标为噪声。
11. 最小评测集清单
写完文档前,这张表应该已经填满:
- 20 条触发查询(10 正 10 近似错配负)
- 正例按四轴变化,≥3 条关联不明显
- 每条负例能说出它与正例共享什么概念
- 8–10 个输出 case,标了 type
- 每条断言标了 strength,
good类可脚本化 -
UNMEASURED项没被编分数 - 每个 case 至少有一条断言有区分度(审查断言本身)
- train / validation 划分固定
- 每条至少跑 3 次
- 判读时做了三个动作
- 加规则后通过率不再上升时,删规则再看
12. 反例速查表
| 反例 | 为什么错 | 正确做法 |
|---|---|---|
| 「写个斐波那契函数」当负例 | 零概念重叠,测不出东西 | 用近似错配:共享领域词,换场景 |
| 每条查询跑 1 次 | agent 是随机的 | 每条至少 3 次 |
| 报一个没有 stddev 的触发率 | 方差可能比效应还大 | mean±stddev |
| 先写文档再补评测 | 会为了让它通过而改评测 | 先建评测 |
| 断言「包含一份总结」 | 空标题也算 pass | 加 substance 限定 |
| 给 UNMEASURED 项编分数 | 看起来完整而不可信 | 留空 |
| 把失败查询的关键词塞进 description | 过拟合 | 找一般类别 |
| 按最后一版定稿 | 最好的不一定是最后写的 | 按 validation 通过率选 |
| 加规则直到通过率不再上升 | 过度约束 | 删规则再看 |
| 报告只给总分 | 掩盖了「都总是 fail」的发现 | 三类分开列 |
| lift 为 2 个百分点但 token 翻倍 | 净价值为负 | 成本判读 |
| case 时好时坏就加规则 | 可能是断言 flaky | 先诊断(见第 7 节) |