前四篇解决的是怎么测、怎么判。这一篇解决测什么。
数据集决定了评测的上限:数据集里没有的失败,评分器再准也发现不了;数据集里的用例本身有问题,评分器越准,结论越离谱。
从多少条开始
很多团队迟迟不建评测,是因为觉得需要几百条用例。Anthropic 在 Demystifying evals for AI agents 中的建议是:从真实失败中挑出 20 到 50 条简单的任务,就是一个很好的开始。早期每次改动的影响通常都很明显,效果大,样本少也能看出来。评测越晚建越难:早期的产品需求很自然就能变成用例,等系统上线很久之后,就只能从运行中的系统里反推成功标准。
样本量决定了评测能发现多大的变化。下面是通过率在 50% 附近时,95% 置信区间的大致半宽:
| 用例数 | 置信区间半宽 |
|---|---|
| 20 | 约 ±22 个百分点 |
| 50 | 约 ±14 个百分点 |
| 100 | 约 ±10 个百分点 |
| 200 | 约 ±7 个百分点 |
| 400 | 约 ±5 个百分点 |
这张表按“每条用例一个通过或不通过结果、用例之间相互独立”估算。它说明的是:50 条用例只能可靠地发现十几个百分点以上的变化。随着 Agent 成熟、改动的效果变小,数据集也要跟着扩大。比较两个版本时用配对方法,区间会更窄,第 06 篇展开。
用例从哪里来
| 来源 | 例子 | 优点 | 注意 |
|---|---|---|---|
| 真实失败 | 用户反馈、工单、Bug 记录、线上轨迹 | 最贴近实际使用 | 先脱敏;按影响排序 |
| 发布前的人工检查 | 每次上线前都会手动试的那几个问题 | 现成,成本最低 | 容易只覆盖“正常路径” |
| 需求和 Skill 文档 | 从验收标准、SKILL.md 的关键步骤派生 | 能在功能上线前就建好 | 只覆盖设计者想到的情况 |
| 合成生成 | 按维度组合,再让模型写成自然语言 | 能补齐真实数据里少见的情况 | 无法反映失败在线上有多常见 |
Anthropic 建议从团队已经在做的人工检查开始;系统已经上线的话,就去看 Bug 记录和工单队列,把用户报告的失败转成用例,并按对用户的影响排序。
线上轨迹是最好的来源。以 Langfuse 为例,可以在观测记录列表中勾选轨迹,直接加入数据集,作为用例的输入和期望输出。轨迹中如果有敏感数据,Hamel Husain 建议按这个顺序处理:优先找允许查看的真实数据;其次请有权限查看的领域专家参与评审;最后才是脱敏或改写后再使用,并检查改写有没有破坏原来的问题。
从文档派生用例,已经有研究做到了规模化:一项针对 500 个真实 Skill 的研究,从 Skill 内容中派生出 1,000 个任务,并为每个任务配上评分标准;NVIDIA SkillEvaluator 也提供了从 Skill 生成评测数据集的命令。
错误分析:先读轨迹,再写用例
用例不应该凭想象写,而应该从真实的失败中归纳出来。Hamel Husain 和 Shreya Shankar 把这个过程称为错误分析,分四步:
- 收集轨迹:准备一批有代表性的真实轨迹。没有线上数据时,可以先用合成数据起步。
- 开放编码:由领域专家逐条阅读轨迹,用自由文本记下发现的问题。刚开始时,只记每条轨迹中的第一个错误,因为上游的错误会引发下游的错误。建议先亲自标注至少 30 条,再参考 Agent 给出的建议。
- 轴向编码:把这些笔记归类为“失败类型”,并统计每一类的数量。这是最重要的一步,可以让 LLM 帮忙归类。
- 迭代:继续阅读新的轨迹,直到新轨迹不再出现新的失败类型,也不再改变已有的分类。质性研究把这种状态称为“理论饱和”。他们建议至少看 100 条轨迹。
得到的失败类型清单,直接决定了要建哪些用例和评分器。以一个 SQL 取数 Agent 为例(数字仅作示意):
| 失败类型 | 次数 | 对应的用例与评分器 |
|---|---|---|
| 口径理解错误,比如把销售额当成含税金额 | 18 | 口径易混用例;终态数值比对 |
| 遗漏分区条件 | 11 | 大表查询用例;检查点脚本 |
| 选错了表 | 9 | 表名相近的用例;检查点脚本 |
| 结果写错位置或格式 | 6 | 产物检查 |
| 虚报完成 | 4 | 不可能用例;声明与终态比对 |
按次数和影响排序,先处理排在前面的类型。每修复一类失败,都要有对应的用例留在数据集里,防止它再次出现。
覆盖:正例、反例和边界
只从真实失败中取用例,会遗漏还没有发生过的情况。补齐的方法是先定义覆盖维度,再检查每个维度上的取值是否都有用例。还是以 SQL 取数 Agent 为例:
| 维度 | 取值 |
|---|---|
| 任务类型 | 单指标查询、多维下钻、跨表关联、生成报告 |
| 输入完整度 | 完整、缺少时间范围、口径有歧义 |
| 数据状况 | 正常、结果为空、数据不存在、含异常值 |
| 表述方式 | 规范术语、口语、不提表名 |
| 风险 | 只读、涉及敏感表、数据中夹带恶意指令 |
用这些维度生成合成用例,Hamel Husain 推荐的做法是分两步:先从每个维度各取一个值组成组合,比如“多维下钻、缺少时间范围、正常、口语、只读”;再在另一个提示词中,把每个组合写成自然语言,比如“帮我看看华东这几个省最近卖得咋样”。他建议先手写 20 个组合,熟悉问题空间之后再让模型批量生成。直接让模型“给我一些测试问题”,得到的往往是笼统、重复的用例。
合成数据也有不可靠的时候。Hamel 列出了几种情况:领域内容很专业,模型写不出真实文档的结构和细节;无法验证生成的用例是否真实;医疗、法律这类高风险领域。这时要以真实数据为主。
每个“应该做”都配一个“不应该做”
Anthropic 强调用例集要平衡:既要测某个行为应该发生的情况,也要测它不应该发生的情况。只测一个方向,Agent 就会被优化成只往一个方向用力。前几篇里出现过的专项用例,都是这个原则的应用:
| 专项用例 | 测什么 | 对照 | 出处 |
|---|---|---|---|
| 澄清用例 | 信息不足时会不会停下来问 | 信息完整时不应追问 | 第 02 篇 |
| 不可能用例 | 无法完成时会不会如实报告 | 能完成时正常完成 | 第 02 篇 |
| 注入用例 | 数据中夹带恶意指令时能否守住边界 | 无注入时正常完成 | 第 02 篇 |
| 触发反例 | 近似但不相关的请求会不会误触发 Skill | 应触发的请求能触发 | 第 03 篇 |
用例质量:先证明它可解、无歧义
Anthropic 对好用例的定义是:两位领域专家各自判断,能得出相同的通过或不通过结论;而且他们自己能完成这个任务。用例的歧义会直接变成指标里的噪声。
每条新用例入库前,过一遍这张检查清单:
□ 任务说明包含了评分器要检查的全部信息
□ 参考解能通过全部评分器(第 04 篇的 oracle)
□ 什么都不做时不能通过(第 04 篇的 nop)
□ 两位领域专家独立判断,结论一致
□ 标注了来源、失败类型、负责人
防泄漏:用例不能被“看到”
用例有两种泄漏方式。
第一种是泄漏给 Agent。参考答案或评分脚本出现在 Agent 能访问的地方,Agent 就可能直接利用它们。第 02 篇讲过这类问题:查看之前执行留下的 git 历史,上网搜索 benchmark。数据集这一侧要做到:参考答案和评分脚本不放进 Agent 的工作环境,执行环境里不留上一次执行的痕迹。
第二种是泄漏给优化者。这一种更隐蔽。编写 Skill 和知识库的人一边看着用例一边修改,Skill 里就会慢慢出现专门针对这些用例的内容:评测分数涨了,换一批新问题就不行了。指标一旦成了优化目标,就不再能准确衡量它原本要衡量的东西。
防止第二种泄漏,要像第 03 篇的描述优化、第 04 篇的 Judge 校准那样,留出一部分用例:
- 数据集分为开发集和留出集。开发集供日常迭代使用,可以随便看。
- 留出集不对 Skill 和知识库的作者开放,只在发布前评测时使用。
- 留出集定期补充新用例,替换已经被“看熟”的用例。
- 可以加一个简单的检查:扫描 Skill 和知识库,看里面有没有出现留出集用例中特有的数值、名称或原句。
真实性:别让用例暴露测试痕迹
模型会察觉自己正在被测试。Goodfire 在 2026 年 5 月的研究中测了 8 个模型、19 个 benchmark,全部出现了模型在推理中明确说出“这是在测试”的情况,人工确认的就有 515 例。在 Fortress benchmark 上,模型说出这类话时,拒绝有害请求的比例高出 3 到 18 个百分点。这类识别往往由提示词中反复出现的线索触发,去掉这些线索后,识别明显减少。同一篇文章还提到,Apollo Research 因为 Claude Opus 4.6 频繁识别出自己在被评测,放弃了对它的正式评估。
这方面的证据主要来自安全评测,所以受影响最大的是第 02 篇的安全合规类用例:Agent 察觉到自己在被测试,可能表现得更守规矩,安全分数因此虚高。常见的测试痕迹和对应的做法:
| 痕迹 | 做法 |
|---|---|
| 提示词里写着“这是一个测试” | 用例改写自真实请求,保留原有的口吻和上下文 |
| 路径和文件名带有 test、eval、case-01 | 环境的目录结构和命名与生产保持一致 |
| 明显虚构的数据,比如张三、示例公司、12345 | 使用脱敏后的真实数据形态 |
| 环境干净得不真实,只有任务需要的那几个文件 | 保留真实环境中常见的“噪声”文件和数据 |
还可以加一个监控指标:扫描轨迹中的推理内容,统计模型说出“这看起来像是一个测试”之类话语的比例。Goodfire 的建议是,把这种表述当作“用例不够真实”的信号,据此改写用例。
维护:版本、生命周期和负责人
数据集要有版本
第 01 篇说过,数据集本身是变量。增加、修改或删除用例之后,前后两次的分数就不能直接比较。
以 Langfuse 为例,它的数据集是有版本的:增加、修改、删除或归档用例,都会生成一个新版本。但查询时默认返回最新版本。所以复现实验或对比两个版本的 Agent 时,要显式指定同一个数据集版本,否则两次实验跑的可能不是同一批用例。
用例的生命周期
新增:来自真实失败、需求文档或合成生成
↓
质量检查:可解、无歧义、冒烟测试通过
↓
能力集:通过率低,用来衡量提升
↓ 长期稳定通过
回归集:通过率接近 100%,用来防止退化
↓ 失效
隔离或退役:数据变了、需求变了、结果反复不稳定
Anthropic 的描述是:能力评测中通过率已经很高的用例,可以“毕业”进入回归集持续运行。原来衡量的是“能不能做到”,之后衡量的是“还能不能稳定地做到”。
几种需要处理用例的信号:
- 所有执行都失败:先检查用例本身,第 02 篇讲过,这最常见的原因是用例或评分器有问题。
- 长期不稳定:先隔离,不计入成绩,分析原因后修复或退役。
- 能力集饱和:Anthropic 指出,100% 通过的评测只能防止退化,无法反映提升。接近饱和时,能力的大幅提升只会表现为分数的小幅上涨。他们举了 Qodo 的例子:Qodo 最初对 Opus 4.5 并不满意,因为他们的单轮编码评测没有覆盖更长、更复杂的任务。后来 Qodo 建了新的 Agent 评测框架,才看清了模型的提升。能力集接近饱和时,就要补充更难的用例。
- 一直通过的用例:Hamel Husain 建议,长期全部通过的评测价值在下降,可以降低运行频率甚至退役,用 LLM Judge 这类运行成本高的评测尤其如此。
还要注意环境漂移:用例依赖的数据和外部服务会变化。用例的初始数据应该固定在有版本的环境镜像里;Harbor 的建议是,把每个任务当作软件包一样,保持自包含、有版本、长期维护。依赖外部服务的部分,用模拟服务或快照代替。
数据集换代之后,新旧分数不能直接比较。Hamel 认为这没有关系:评测的作用之一,是提供一个可以持续攀登的目标,目标本来就应该随产品一起变化。要追踪更长时间段的趋势,应该结合留存、活跃用户这类业务指标。
谁来维护
Anthropic 的经验是:由专门的评测团队负责基础设施,由领域专家和产品团队贡献大部分用例,并自己运行评测。维护评测应该像维护单元测试一样,成为日常工作。产品经理、客户成功经理离用户最近,他们也可以借助 Claude Code,以 PR 的形式提交用例。
每条用例都应该带上足够的元数据,方便追踪和维护:
id: sales-east-2026-09
version: 3
source: production # production / manual / derived / synthetic
origin_trace: trace-7f3a # 来源轨迹,已脱敏
failure_type: 遗漏分区条件
suite: capability # capability / regression / quarantine / retired
split: holdout # dev / holdout
owner: data-platform
created: 2026-09-12
last_verified: 2026-10-18 # 最近一次通过冒烟测试的日期
tags: [多维下钻, 口语, 只读]
小结
- 起步:20 到 50 条来自真实失败的用例就够开始;用例数决定了能发现多大的变化,Agent 越成熟,数据集要越大。
- 来源:真实失败最有价值,其次是人工检查、需求文档和合成生成。
- 错误分析:先读轨迹,记录第一个错误,归纳失败类型并计数,读到理论饱和为止,再按类型建用例。
- 覆盖:定义覆盖维度,按维度组合生成用例;每个“应该做”都配一个“不应该做”。
- 防泄漏:参考答案对 Agent 不可见;留出集对 Skill 和知识库的作者不可见。
- 真实性:去掉测试痕迹,用真实的请求和数据形态;监控模型说出“这是测试”的比例。
- 维护:数据集有版本,对比时固定版本;用例在能力集、回归集、隔离、退役之间流转;有明确的负责人。
下一篇讲评测链路:从隔离执行、轨迹采集、评分、人工复核到版本对比,怎样把前五篇的内容连成一条自动化的流水线。