
图 1:一个 Eval 不是“Prompt + 分数”。Task、Trial、Trace、Outcome、Grader 与汇总报告共同构成证据链。
1. 为什么普通单元测试还不够
传统函数通常可以写成:
Agent 更像:
这里至少多出四类不确定性:
-
同样输入可能选择不同工具; -
前一步的小偏差会传递到后续步骤; -
外部工具、网络和状态可能发生变化; -
最终回复可以正确描述一件根本没有发生的事。
例如,一个预订 Agent 最后说“机票已经订好”,真正应该检查的是数据库里是否存在符合约束的订单。一个代码 Agent 说“测试通过”,真正应该检查的是退出码、测试报告和工作区 diff。
所以,单元测试没有失效。相反,它应该成为 Agent Eval 中最可靠的一类 Grader。变化在于:我们还要测试环境、行为路径、真实终态、重复运行和系统级约束。
2. 先把六个词分清
Anthropic 的 Agent Evals 工程文章给出了一组很实用的定义。结合本项目,可以整理成下面这张表:
其中最容易混淆的是 Task 和 Trial。
假设任务是:
运行三次,就会产生三个 Trial。它们可能分别是:
这不是“一个任务得了 66.7 分”那么简单。对内部制度、安全操作或生产写入而言,第二次误答本身就可能让版本不能发布。
3. 评什么:Outcome 优先,Trace 用来解释
我会把 Agent 的评测对象分为五层:
优先级不是“Trace 越细越好”,而是:
这也避免另一种常见误区:把“严格按我设想的步骤走”当成正确。Agent 可能找到一条同样安全、甚至更短的有效路径。除非顺序本身属于合规要求,否则不要把每个中间动作都写死。
本篇 Lab 检查 retrieve -> threshold_gate -> answer/abstain,是因为这是当前最小系统的结构契约。等系统拥有更多有效路径后,Trace Grader 也要从“固定顺序”升级为“必要事件和禁止事件”。
本篇的 Outcome 仍是代理指标
这个只读 Lab 没有真的修改外部世界,因此
status、answer和source只能证明“程序返回了什么”,不能证明数据库、文件、订单或工单已经处于正确状态。评测写入型 Agent 时,至少要在运行前后读取真实环境,把数据库行、文件 diff、API 回读结果或审批记录作为 Outcome;最终回复只能作为另一项输出质量检查。
4. 从系统契约长出第一版任务集
任务不应该从网上抄一组“常见问题”,而应该从四个地方来:
-
产品合同里明确承诺的行为; -
开发时每次手工检查的案例; -
生产日志、工单与用户投诉中的真实失败; -
高风险边界和容易被绕过的反例。
Anthropic 建议早期可以从 20-50 个来自真实失败或手工检查的简单任务起步,而不是等待几百条“完美数据”。OpenAI 的评测最佳实践同样强调任务特定、持续扩充,并反对只凭感觉判断。
本篇先写 20 个 Task,分成两组:
当前 Lab 没有生产用户流量,因此这 20 条主要从系统契约、手工检查和边界反例派生。它们能验证教程代码,却不能代表真实请求分布。上线后的正确动作是把脱敏后的失败、工单和人工接管案例持续补入数据集,而不是继续批量生成看起来丰富的同义句。
一个 Task 的真实结构如下:
这里有三个设计点。
第一,成功标准和输入放在同一条版本化记录中,避免 Grader 暗中检查 Task 没有声明的东西。
第二,同时测试应该回答与应该拒答的问题。只测“能不能答”,最容易优化出一个什么都敢答的系统。
第三,risk 不直接增加分数,而是让发布门禁可以声明:“安全任务的回归不能被其他任务的改善抵消。”
5. Grader 不是越智能越好
常见 Grader 可以分成三类:
Inspect 也采用 Dataset、Solver、Scorer 的可组合结构,并同时提供文本匹配、模型评分和自定义 Scorer。不同框架名字略有区别,工程问题是相同的:应该用哪一把尺测哪一种结果?

图 2:优先用代码检查真实终态和硬约束;开放质量再引入模型评分,并用人工样本持续校准。
本篇故意只用确定性 Grader:
这不是因为关键词匹配足够强,而是因为它便于先验证 Eval Harness 自己。评分基础设施还没跑通时就加 LLM Judge,会同时引入被测系统和评分系统两份不确定性。
6. 公平比较:一次只改一个主要变量
这次比较两个零模型、零 API Key 的系统:
候选版只增加一项能力:把真实提问里的表达映射到手册用词,例如:
两边保持相同:
-
同一个知识手册; -
同一组 20 个 Task; -
同一个 0.28检索阈值; -
同样的 Grader; -
每题同样运行 3 次; -
相同的报告与发布门禁。
这样,改善才能合理归因于查询归一化。若同时换模型、Prompt、Chunk、阈值和 Grader,即使分数提高,也很难知道哪一项有用。
7. 运行 Lab:从 Task 到报告
进入代码检查点:
运行评测:
再运行 Harness 自己的测试:
在该代码检查点应看到 Ran 14 tests 与 OK。这 14 个测试覆盖任务加载、版本对照、失败报告和发布门禁等路径;如果测试失败,应先修 Eval Harness,再解释 Agent 分数。
默认执行:
CLI 会原样输出嵌套 JSON,并在 reports/local/ 写入四个文件。为便于阅读,下面是从真实 JSON 提取的关键结果,不是终端原样排版:
本地目录默认被 Git 忽略,避免每次运行的机器延迟污染工作区。仓库中的 reports/保留代码检查点对应的参考证据。
8. 结果:60% 到 95%,但结论要收窄
这次固定实验得到:
所谓“严格 Task 通过”是:
它在直觉上接近一致性导向的 pass^k,但本文只汇报观察到的三次结果,不把 20 个教程任务包装成统计概率估计。
本文报告中的三个列表按下面的确定性规则生成:
因此,improvement 不是“某个评分略有上升”,而是候选版把一个三次均通过的严格 Task 从失败变成通过;unstable 也不等于措辞有任何微小变化都危险,它只是当前 Lab 采用的保守指纹。生产项目应根据任务语义决定哪些字段必须稳定。

图 3:候选版改善了 7 个同义表达任务,没有破坏原有任务或拒答边界;cap-008 仍然失败,因此 95% 不能写成“已经可靠”。
这组数据支持的结论是:
在当前 20 个任务、固定手册和固定阈值下,查询别名归一化相对基线带来了 7 个可复现改善,未观察到回归。
它不支持:
剩下的 cap-008 是“知识不够时,应该给提问者什么下一步?”。归一化后得分仍低于阈值,三个 Trial 都拒答。它没有被总分藏起来,而是明确进入下一轮改进列表。
9. 最有价值的一次失败,来自 Eval 自己
第一版 Eval Harness 跑出来时,两个系统都只有 40%,看起来很差。检查失败 Trial 后,我发现不是系统突然退化,而是评测写错了。
Bug 1:来源 Grader 拿不到章节名
知识解析器把 Markdown 标题和正文按空行拆开了。检索答案正确,但 source=None,于是来源 Grader 全部判错。
修复方式不是删掉来源 Grader,而是让 Eval Harness 按二级标题解析完整章节。
Bug 2:禁用词误伤否定句
最初我把 无限重试 设为禁用词,但手册的正确答案是:
简单子串匹配仍会命中“无限重试”,把安全答案判成违规。后来任务改为检查更完整的危险表述:
这件事说明两个问题:
-
Code Grader 很稳定,但稳定地写错仍然是错; -
失败报告不能只给一个红色分数,必须保留输入、输出、来源和每个 Grader 的理由。
Anthropic 的文章也强调:失败应该让人觉得公平。若任务含糊、环境不稳定或 Grader 拒绝有效解,就应先修评测。Eval 不是裁判席上的真理,它也是需要测试和维护的软件。
10. 为什么要重复 Trial
当前两个正式系统是确定性的,所以三次输出完全一致。重复运行仍然有价值,因为它先固定了 Harness 接口:未来接入模型或外部工具时,不必重写 Task、Grader 和报告。
为了验证门禁确实能抓住波动,Lab 还提供一个明确标注的故障模拟器:
这一行可直接在 PowerShell、Bash 和常见终端中运行。它故意让部分 capability 任务在偶数 Trial 拒答。结果是:
只看 83.3%,会觉得候选版明显变好;但它没有新增一个“三次都可靠通过”的任务,反而让 7 个任务的结果随运行变化。

图 4:总分不能抵消一致性问题。故障模拟命令按预期退出 1,可直接作为本地或 CI 门禁。
对于“多试几次,只要一次成功就行”的探索工具,可以关注 pass@k;对于用户每次都期待可靠结果的服务,更需要关注一致性。具体选哪种,不由排行榜决定,而由产品失败成本决定。
11. 把发布条件写成代码
本篇的发布门禁不是单一分数:
它表达了一个重要工程判断:
某些指标可以权衡,某些边界不能被平均分抵消。
真实项目还可以加入:
-
工具参数错误不能增加; -
未经批准的写操作必须为 0; -
p95 延迟不得超过预算; -
单任务成本不得超过上限; -
人工接管率不能无解释地上升; -
高风险 Slice 必须全部通过; -
Model Grader 与人工 Gold Set 的一致率达到门槛。
门禁通过也不是“自动全量发布”。它只表示候选版本获得进入灰度、人工验收或下一阶段验证的资格。
12. 什么时候引入 Model Grader
关键词和规则适合本篇的结构验证,但遇到下面任务就会很快不够:
-
研究报告是否有关键遗漏; -
回答是否真正被来源支持; -
代码改动是否过度设计; -
对话是否既解决问题又保持合适语气; -
两个都正确的答案,哪一个更清楚。
这时可以引入 Model Grader,但建议遵守五条规则:
-
一个 Rubric 只评一个清晰维度; -
尽量做分类、打分或 Pairwise,而不是开放式点评; -
提供 Unknown,证据不足时不要强迫评分; -
用领域专家标注的 Gold Set 校准; -
定期抽查 Grader 与人工判断分歧最大的样本。
OpenAI 的评测最佳实践建议把自动指标与人工判断结合;Anthropic 也建议确定性评分优先、模型评分按需使用,并持续阅读失败 Transcript。
如果 Grader 使用和被测 Agent 相同的模型、相同的上下文偏差,还要警惕“自己给自己打高分”。更稳妥的做法是保留代码检查、不同模型评分和人工抽样之间的交叉验证。
13. 如何映射到现有工具
本篇没有要求读者先选平台,因为核心结构可以迁移:
如果项目使用 OpenAI Agents SDK,其内置 Trace 可以记录模型生成、工具调用、Handoff、Guardrail 与自定义事件,再把这些事件接入行为 Grader。
Trace 不是天然安全的日志
截至 2026-07-28,OpenAI Agents SDK 文档说明,生成与函数调用 Span 可能包含模型、工具的输入输出,
trace_include_sensitive_data默认开启。接入真实业务前,应先做数据分类与脱敏,并按需要关闭敏感内容采集;不要为了评测完整性把密钥、个人信息或内部原文无差别写入 Trace。
若要做更真实的多轮工具 Agent 评测,可以继续研究开源的 τ-bench 系列。该仓库当前已经扩展到 τ³-bench,仍保留由领域 Policy、Tool、Task 和模拟用户组成的评测结构。
工具会越来越成熟,但迁移前仍要能回答:
回答不了这些问题,换一个漂亮 Dashboard 也不会自动得到可靠评测。
14. 把自己的 Agent 接入 Harness
读者最容易卡在这里:示例的 run_system() 调用本地检索函数,而自己的 Agent 可能返回 SDK 对象、工具事件或一段字符串。不要先重写整套评分器,先写一个薄适配层,把真实结果压到本文的 SystemOutput 契约:
这里的字段不是要求所有 Agent 都长得一样,而是给 Harness 一个稳定边界:
status
:取明确的完成、拒答或失败状态,不要从最终话术猜测是否成功; answer
:取最终用户可见输出,不要把整段内部 Trace 当答案; source
:取检索证据或工具回读的来源标识,不要让模型自己编一个来源名; trace_steps
:取 SDK Trace、工具事件或显式埋点,不要依赖自然语言复述执行过程; latency_ms
:由 Harness 在外层计时,不要使用模型估算的耗时。
接线时保留 baseline-v1 与 candidate-v2 两个逻辑版本名,在 run_system() 内分别调用旧版和新版适配器。这样 Task、Trial、Grader 和报告都不需要改变。若 Agent 会写数据库或文件,还要额外返回或读取 outcome,为它增加独立 Code Grader;不要把 answer 或 status 当成写入成功的证明。
最小迁移顺序是:
15. 45 分钟跟做练习
可以把自己的 Agent 项目按下面顺序补到最小可用:
第 0-10 分钟:写 5 个真实 Task
选择:
-
2 个最常见成功任务; -
1 个曾经出现的真实 Bug; -
1 个应该拒绝或接管的任务; -
1 个高风险边界任务。
第 10-20 分钟:为每个 Task 写成功标准
至少包括:
确保两位熟悉业务的人能独立得到相同判断。
第 20-30 分钟:先写确定性 Grader
优先检查:
-
退出码; -
数据库终态; -
文件内容与 diff; -
JSON Schema; -
工具名与关键参数; -
是否发生未经批准的写操作。
第 30-40 分钟:重复运行并读失败记录
每题先运行 3 次。不要只看通过率,手动阅读所有失败 Trial,区分:
第 40-45 分钟:写第一条发布门禁
一开始只需要一条真正有价值的规则:
然后随着真实失败增加任务,而不是为了让数字显得专业去堆合成样本。
16. 收藏清单
准备比较 Agent 版本前,逐项确认:
-
[ ] Task 来自真实工作、失败或风险,而不是泛化题库; -
[ ] 每个 Grader 检查的内容已在任务或系统契约中声明; -
[ ] 同时覆盖应该做与不应该做的案例; -
[ ] Capability 与 Regression 分开统计; -
[ ] 每个 Task 有独立、可复现的运行环境; -
[ ] Outcome 与最终话术分开验证; -
[ ] 关键行为和失败原因进入 Trace; -
[ ] 每个 Task 重复运行,不把单次成功当稳定; -
[ ] 报告列出 improvement、regression 和 unstable task; -
[ ] 安全回归不能被平均分抵消; -
[ ] Model Grader 有人工 Gold Set 校准; -
[ ] Eval Harness 自身有测试、版本和负责人。
17. 这篇真正建立了什么
本篇没有接入更强模型,却完成了一个更重要的升级:
Lab 的 60% -> 95% 不是卖点。真正值得保留的是:即使数字变化,Task、Trial、Grader、Trace、失败台账和 Gate 仍能让团队解释这次变化。
下一篇进入 Context Architecture。我们会继续使用同一个工程,把“Prompt 越写越长”拆成可观测的 Context Packet、来源优先级、Token 预算和缺失证据,并用本篇刚建立的 Eval Harness 验证:加入更多上下文,到底是在帮助 Agent,还是在制造噪声。
参考资料
-
OpenAI:Evaluate agent workflows -
OpenAI:Evaluation best practices -
OpenAI:Agents SDK Tracing -
Anthropic:Demystifying evals for AI agents -
UK AI Security Institute:Inspect -
Sierra Research:τ-bench 系列(当前 τ³-bench) -
Agent Reliability Lab ce601a1
订阅智宅客
AI / 技术 / 数字生活方式,新文章第一时间送到邮箱。









