验证与质量保证:别让「看起来对」蒙混过关 · Lesson 2 of 6

第 2 课:验什么:终态优先,过程兜底

学习目标:

  • 说清「录下正确步骤再逐步核对」这套办法为什么在 Agent 上必然误判,改用终态评估
  • 对复杂流程挑出几个离散的验证检查点,核对「该发生的状态变化有没有发生」,而不是校验每一步
  • 把一句模糊需求写成可测量、可达成的多维成功标准,并知道轨迹断言该加到什么程度

前置要求:读完第 1 课,知道没有可跑的检查时你自己就是验证环节 | 上一课 第 1 课 << | 下一课 第 3 课 >>

三次运行,三次判「不合格」

你决定给 Agent 上验收了。第一反应几乎人人一样:把「标准做法」录下来。自己手动跑一遍任务,把每一步记下来——第 1 步该调 search,第 2 步该调 fetch_page,第 3 步该调 write_note——存成一份标准答案。以后 Agent 每跑一次,就拿它的调用序列和这份答案逐步比对,一步对不上就判不合格。

跑了三次,三次都判「不合格」。

你去看产出:三份摘要,事实没错,来源可靠,该覆盖的角度都覆盖了。区别只在路上——第一次它搜了三个来源就够了,第二次搜了十个,第三次先查了一遍术语定义再去搜。Anthropic 在自己的多 Agent 研究系统里观察到的正是这个现象:即使起点完全相同,Agent 也可能走完全不同但都有效的路径去达成目标,一个搜三个来源而另一个搜十个,或者用不同的工具找到同一个答案1

不合格的是你的验收方式,不是 Agent。

你并不知道「正确步骤」是什么

传统评估有一个藏得很深的默认假设:给定输入 X,系统应该走路径 Y,产出输出 Z——每次都走同样的步骤1。这个假设在确定性系统上成立得太自然了,自然到大多数人从没意识到它是个假设。Agent 一来就把它掀了。

真正难受的不是「路径会变」这件事本身,而是下面这句:

因为我们并不总知道正确的步骤是什么,所以通常没法核对 Agent 有没有遵循我们预先规定的「正确」步骤。我们需要的是灵活的评估方法,判断它有没有达到正确的结果,同时过程是否合理1

「并不总知道正确步骤是什么」——这才是关键。你录下来的那条路径,不是唯一正确的路径,只是你那次碰巧走的路径。你把它升格成了标准答案,于是所有别的走法都成了错误。

也要注意后半句:「同时过程是否合理」。这不是说过程完全不看。是说别拿一条固定路径当尺子量。

终态评估:判结果,不判流程

Anthropic 给出的做法很直接:聚焦终态评估而不是逐轮分析——不判 Agent 有没有遵循某个特定流程,而是判它有没有达到正确的最终状态1。这种做法承认 Agent 可能找到通往同一目标的替代路径,同时仍然确保它交付了预期的结果1

先给「终态」一个白话定义:任务跑完之后,你能在环境里看到的、事后可以核对的状态。文件系统里多了哪些文件、数据库里那条记录的字段变成了什么、工单的标签是哪一个、返回的 JSON 里 status 是不是 resolved

一个好用的判别法:终态是名词,不是动词。「调用了 rename_file」是动词,「所有文件名都匹配某个格式」是名词。验收只收名词。

text
任务:把 downloads/ 里的发票 PDF 按「日期_供应商.pdf」重命名
步骤式验收(脆)                终态式验收(稳)1. 调 list_files               downloads/ 下不再有原始文件名2. 逐个调 read_pdf             每个文件名匹配 ^\d{8}_[a-z0-9-]+\.pdf$3. 调 extract_date             文件总数与开跑前一致,没丢没多4. 逐个调 rename_file          文件名里的日期与 PDF 内容的开票日期一致

左边那列,Agent 只要用一次批量读取代替四次单读,就全线判错,哪怕结果一模一样。右边那列,它怎么读都不影响判定——因为右边描述的是「downloads/ 现在长什么样」,跟它怎么变成这样无关。

写终态的时候有个容易漏的位置:不该变的东西也要写进去。上面那条「文件总数与开跑前一致」就是。Agent 把两个文件重命名成同一个名字、后一个覆盖前一个,从「文件名都合规」这一条看是完美通过的。终态断言要同时管住「该变的变了」和「不该变的没变」。

复杂流程:把评估拆到几个检查点上

终态评估不是「过程完全不看」。原文的下一句就给了退路:对于复杂的工作流,把评估拆成若干离散的检查点,在那些位置核对特定的状态变化应该已经发生,而不是试图校验每一个中间步骤1

注意它的措辞——「特定的状态变化应该已经发生」,仍然是状态,仍然是名词。只是把观察位置从「终点」挪到了「途中的几个点」。

名词打架提醒:本系列第 9 门课里的「检查点」指的是存现场——把 Agent 的运行状态落盘,崩了能从那里接着跑,目的是恢复。本课的「检查点」指的是验状态——在流程的某个位置核对该发生的状态变化有没有发生,目的是判定。两者的位置常常会重合(落盘的地方顺手验一下很自然),但解决的问题不是一回事。混着讨论一定会乱,所以下面统一叫「验证检查点」,第 9 门课那个叫「恢复检查点」。

什么时候值得加验证检查点,看三件事:

  • 流程长,终态离起点太远。失败了只知道「没到终点」,不知道从哪一步开始偏的。
  • 有不可逆操作。发出去的邮件、扣掉的库存、覆盖掉的文件,等到终态再发现错就来不及了。
  • 中间产物是后续步骤的地基。迁移脚本先建表再灌数据,表结构建错了,灌进去的全是废数据,返工成本按倍数涨。

三件都不占,就别加。

加在哪:加在状态发生实质变化的位置,不是每次工具调用之后。

text
任务:把用户表从旧 schema 迁到新 schema
验证检查点 1(建表之后):new_users 表存在,列与目标 schema 完全一致验证检查点 2(灌数之后):new_users 行数 == old_users 行数,主键无重复终态:应用读新表能跑通冒烟用例(smoke test,最基本的「能不能跑起来」检查),old_users 已改名为 old_users_backup
不做的事:不核对它是写 CREATE TABLE 还是从模板复制,不核对它是一次灌完还是分批灌、分了几批、每批多少条。

两个检查点,一个终态。三个断言管住整条迁移。要是按「校验每一个中间步骤」来做,这条流程能写出几十条断言,其中绝大多数在惩罚合法的做法差异。

停一下:这个提案哪里不对

成功标准怎么定:可测量、可达成、多维

「终态正确」这四个字得能落到具体数字或明确的判定上,否则绕一圈又回到「看起来对」。官方文档对成功标准给了两条硬要求:

  • 可测量:使用定量指标或定义良好的定性量表(量表就是一份打分用的判据清单,具体怎么写是第 4 课的内容)。数字带来清晰度和可扩展性,定性度量只要被一致地应用、并与定量度量搭配使用,也有其价值2
  • 可达成:把目标建立在行业基准、既往实验、AI 研究或专家知识之上。你的成功指标不该对当前前沿模型的能力来说不现实2

还有一条:多数用例需要沿几个成功标准做多维评估2

官方给的完整示例是这样一句话(括号里的标注是原文自带的):

情感分析模型应在 10,000 条多样化 Twitter 帖子的留出测试集(相关)上达到至少 0.85 的 F1 分数(可测量、具体),这比当前基线提升 5%(可达成)2

这句话值得拆开看,因为每个成分都在挡一种具体的失败方式:

成分它挡住了什么
F1 分数挡住「感觉还行」。F1(精确率与召回率的调和平均,0 到 1 之间)是能算出来的数,两个人算必须算出一样的结果
至少 0.85挡住事后挪门槛。跑完再定「多少算过」,那永远都能过
10,000 条挡住样本太少带来的偶然。这是官方示例里的规模,不是通用门槛
留出测试集挡住对着评测集调优——见过的题考出高分不算数
多样化 Twitter 帖子挡住只在干净样本上好看,真实分布一来就崩
比基线提升 5%挡住目标脱离现实。它锚在已经达到过的水平上,不是拍脑袋定的

最后那一行是「可达成」的具体做法:门槛不是从愿望倒推的,是从现状往前推一小步。你手上没有基线,就先跑一版最朴素的实现,把它的分数当基线;连基线都跑不出来的时候,别急着定数字。

还有一个更早的问题。Anthropic 在讲 Agent 适用场景时说:Agent 在这类任务上价值最大——既需要对话又需要行动、有清晰的成功标准能形成反馈回路、有有意义的人类监督3。这句话反过来读更有用:如果你怎么都写不出这个任务的成功标准,那不是验收环节没做好,是这个任务本来就不该整个交给 Agent 自己跑。写不出标准,你就得全程盯着——第 1 课说过,那时候你自己就是验证环节。

轨迹断言:可以加,但别写死

终态评估管住了「结果对不对」,但有一类问题它看不见:Agent 到底认不认识你新给它的那个工具。

官方文档给了一个可选加项:对每一组提示与响应的配对,你可以额外指定期望 Agent 在解题时会调用哪些工具,用来衡量它有没有在评测中成功领会每个工具的用途4。这就是轨迹断言——不判顺序,不判次数,只判某些工具有没有出现在轨迹里。

什么时候有用:你刚加了一个 search_internal_docs 工具,希望 Agent 在问到内部流程时用它。可它跑去搜公网,也搜到了一个差不多的答案,终态判定照样通过。这个差别只有轨迹能看见。

限度写在紧接着的一句:因为解对一个任务可能存在多条有效路径,要避免过度指定、避免对策略过拟合4

落到具体分寸:

  • 只断言「集合包含」,不断言顺序,也不断言次数
  • 只列你真正关心的那一两个工具,别把整条序列搬进去——那就退回成录制回放了
  • 轨迹断言没过但终态过了,记一条观察,不直接判整体失败
  • 它是可选加项,不是默认项。默认仍然是终态1

通过率之外还要记什么

一次评测跑完,只拿到一个通过率,你会发现自己无话可说——78% 意味着什么?下一步该动提示词还是动工具?

官方建议除了顶层准确率之外,还收集这些指标:单个工具调用与整个任务的总运行时长、工具调用的总次数、总 token 消耗、以及工具报错4。这些指标不参与判定,参与诊断

官方给了两条读法:

  • 大量冗余的工具调用,可能提示分页或 token 上限这类参数需要重新调整大小4
  • 大量因无效参数导致的工具报错,可能提示这些工具需要更清晰的描述或更好的示例4

这两条的共同点是:它们把矛头指向了工具设计,而不是模型。冗余调用多,往往是因为一次只能拿回 20 条、它不得不翻十页;参数报错多,往往是因为工具描述里没说清那个字段要什么格式。这两类问题的根子在工具那一侧——光在系统提示词里加一句「少调几次」「参数写仔细」,通常不管用,得去动工具的参数设计和描述本身。

顺着这个思路还能延伸出几条(下面这些没有官方背书,是从上面两条推出来的工程判断,自己在数据上验证):通过率没变但 token 消耗翻倍,说明这次改动不是免费的;某一类任务的时长方差特别大,里面大概率藏着重试或者兜圈子;报错集中砸在一个工具上,先看那个工具,别先怀疑提示词。

一次评测至少落这几列,第 6 课搭评测跑道时会直接用上(那边为了省列宽,会把 tokens 进出两列合成一列):

text
case_id | passed | duration_ms | tool_calls | tokens_in | tokens_out | tool_errors

分寸:三件不要做的事

一、不要试图校验每一个中间步骤1。这条是本课最容易破的戒,因为「多验一点更保险」的直觉太强了。实际结果相反:断言越细,被惩罚的合法差异越多,评测越吵,最后你会开始忽略红色——那时候它就彻底废了。

二、不要把轨迹断言变成默认项。加轨迹断言的动作太便宜了,随手就能多写一条 expectedTools。写到第十条的时候,你已经在实质上规定策略了,只是形式上还叫「断言」。每加一条都问自己:这个工具没被调用,产出真的会出问题吗?答案是「不一定」,就别加。

三、不要在跑完之后再定门槛。看着 0.82 的分数说「0.8 应该够了」,和看着 0.86 说「得上 0.85」,是同一种自我欺骗。门槛要在跑之前定,并且写下依据。

💻 练习

小结

  • 传统评估默认「给定输入 X 走路径 Y 得到输出 Z」,Agent 不满足这个假设:起点相同也可能走完全不同但都有效的路径,一个搜三个来源另一个搜十个1
  • 你并不总知道正确的步骤是什么,所以通常没法核对 Agent 有没有遵循你预先规定的步骤;要用灵活的评估方法,判断它有没有达到正确结果、过程是否合理1
  • 默认做法是评终态而非逐轮分析:不判它有没有走某个特定流程,判它有没有达到正确的最终状态1。终态是名词不是动词,而且要同时管住「该变的变了」和「不该变的没变」
  • 复杂流程把评估拆到几个离散检查点上,核对「特定的状态变化应该已经发生」,不要试图校验每一个中间步骤1。这里的「检查点」是验状态,和本系列第 9 门课那个存现场用的检查点不是一回事
  • 成功标准要可测量(定量指标或定义良好的定性量表)、可达成(把目标建立在行业基准、既往实验或专家知识上),多数用例需要多维评估2
  • 官方把「有清晰的成功标准、能形成反馈回路」列为 Agent 价值最大的任务条件3;反过来读——写不出成功标准的任务,别整个交给 Agent 自己跑,那时候你就得全程盯着
  • 轨迹断言是可选加项:可以标注期望它调用哪些工具,衡量它有没有领会工具用途,但因为有效路径不止一条,要避免过度指定、避免对策略过拟合4
  • 通过率之外还要记运行时长、调用次数、token 消耗、工具报错;冗余调用多考虑调整分页与 token 上限参数,无效参数报错多考虑把工具描述和示例写清楚4

>> 第 3 课:确定性验证器:能跑出 pass/fail 的检查才算数

Footnotes

  1. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system 2 3 4 5 6 7 8 9 10 11 12

  2. Define success criteria and build evaluations — Claude API 文档 — https://platform.claude.com/docs/en/test-and-evaluate/develop-tests 2 3 4 5

  3. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2

  4. Writing effective tools for agents — with agents — Anthropic Engineering — https://www.anthropic.com/engineering/writing-tools-for-agents 2 3 4 5 6 7

Exercises

01

下面四个任务,逐个写出:(1)你要验的终态是什么;(2)要不要加验证检查点,加在哪,为什么。

Level 1:给四个任务写终态(不写代码)
  1. 批量重命名:把 invoices/ 下 200 个 PDF 按「YYYYMMDD_供应商.pdf」重命名
  2. 调研并写摘要:调研三家竞品的定价策略,写一份带引用的摘要
  3. 修一个测试失败user.spec.ts 里的 should reject expired token 挂了,让 Agent 修好
  4. 工单分类打标:给过去一周的 500 条工单打上「计费 / 故障 / 功能请求 / 其他」标签
Done criteria · checked locally
02

需求原文只有一句:「帮我整理这周的会议纪要,引用要靠谱。」

Level 2:把模糊需求改写成多维成功标准(不写代码)

把它改写成可测量的多维成功标准。每一维写全四项:指标叫什么、怎么测、门槛定多少、为什么这个门槛是现实可达的。然后决定哪些维度验终态、哪些设中间检查点,并说明理由。至少三维。不用写代码。

Done criteria · checked locally

My note

Jot down thoughts, sticking points, things you didn't get. Written to this course's appendix only — the lesson file is never touched.