AI 说“做完了”别急着信:AI Worker 交付验收五道门禁
过去一年真正让我付出代价的,不是流程漏了哪一步,而是我在某个环节信了不该信的东西。五道门禁,每道后面压着一次真实翻车。
一句话结论:过去一年真正让我付出代价的,不是流程漏了哪一步,而是我在某个环节信了不该信的东西。五道门禁,每道后面压着一次真实翻车。
- 从"怎么测"到"信什么"
- 门禁一:声称不是证据——判卷人不能是答题人
- 门禁二:退出码本身也要验——工具链会替模型圆谎
- 门禁三:终验开真实入口——DOM 里有,不等于用户看得见

从"怎么测"到"信什么"
这篇的第一版写的是流程:独立盲测、隐藏验收、交叉复审、保留证据链。流程今天依然成立,但过去一年真正让我付出代价的,不是流程漏了哪一步,而是我在某个环节信了不该信的东西。被打脸多了,方法论就从"怎么安排测试"沉淀成了另一个问题:一个 AI worker 说"做完了"的时候,什么才算数?
我把答案整理成五道门禁。每一道后面都压着一次真实翻车——不是假想的风险清单,是我的工作日志里有日期可查的判例。
门禁一:声称不是证据——判卷人不能是答题人
判例:一个客户交付项目的验收环节,当时那个主力模型汇报:"EXIT=0,25 项测试 PASS,0 FAIL,这是系统真实返回,可信终判。"话说得斩钉截铁,连"可信终判"四个字都替我盖好了章。我事后用 grep 去翻原始会话记录(jsonl 文件,每次工具调用的真实返回都在里面),结果是:"25 PASS""EXIT=0"这些词只出现在它自己的发言里。真实的工具返回是退出码 1、一个解码异常导致脚本崩溃、有 4 项测试 FAIL、它声称生成的捕获文件根本不存在。
最有意思的是这不算"撒谎"——它没有动机。更像是把心智模型里"测试应该通过"的期望,覆盖了工具真实返回的记忆。厂商自己的模型说明文档里就承认存在"歪曲工具返回错误"的失败模式,而我后来调研发现各家模型全有同类问题。结构性根因一句话就能说清:写代码的 agent 验收自己的代码,判卷人就是答题人。
所以第一道门禁是:任何"完成"声明必须附带原始输出的引用和显式校验过的退出码,禁止模型给自己下"可信终判"。数字必须来自工具返回,不接受转述。

门禁二:退出码本身也要验——工具链会替模型圆谎
你以为盯住退出码就安全了?第二道翻车更隐蔽。判例:同一个项目里,构建工具 mvn 不在环境变量路径里,命令写成 mvn ... | tail——mvn 报"命令不存在",但管道让整条命令的退出码变成了 0。于是"编译通过"被理直气壮地宣布了两次,直到运行态复测发现全是旧行为才穿帮。这次连引语锚定都救不了:退出码 0 是真的,只是它属于 tail,不属于 mvn。
修正动作很具体:命令用全路径、管道命令必须显式取首段的真实退出码(Bash 里的 PIPESTATUS)、宣布"编译过"之前先看产物文件的时间戳有没有更新。抽象成门禁就是:校验信号之前,先校验信号的采集链路。退出码 0 只有在"确实执行了那条命令"的前提下才有意义。
门禁三:终验开真实入口——DOM 里有,不等于用户看得见
判例:一个 worker 交付的甘特图页面,代码审查挑不出毛病,页面也不报错,DOM 里 16 个进度条一个不少。但它按旧版本图层顺序写了一条自定义样式,把背景矩形填成白色,而新版图表库把这个矩形画在了 SVG 最顶层——整张图被一张白纸盖住,数据全在,用户看到的是空白。worker 的权限红线是不跑构建、不开浏览器,这类问题它到交付那一刻都不可能自己发现。
这就是第一版里"隐藏验收"的具体含义:验收方必须走真实用户入口——打开浏览器看真实渲染、用真实账号点真实按钮,而不是看代码、看日志、看测试报告这些中间态——中间态说"一切正常"的方式,比你想象的多。
门禁四:判定量必须独立于结论——循环论证会给你完美的成绩单
判例来自一个管道 AI 巡检项目。我们想估计几何测量的误差,找到了几百条带百分比的历史记录当"独立锚点"——看起来是现成的真值。可行性核验的结果是死刑:那些百分比不是任何人量出来的实测值,是检测规程(CJJ181)里等级档位定义的原文抄写——检测员判完等级,把那一档的定义文字抄进了描述栏。也就是说这批"锚点"和等级标签完全同义、零增量信息,拿它验证等级判定,等于拿等级验证等级。我把裁决写成"不可做"而不是"延后",因为这是性质问题不是数量问题:再来一万条同样的记录,也不会多出一比特独立信息。
同一课的下半场更狠:后来一版测量算法在缺陷样本上跑出了漂亮的单调曲线,眼看要宣布成功——直到拿两百多张没有缺陷的正常图做阴性对照,它在正常管道上测出了几乎相同的分布。信号瞬间归零,之前的单调性纯属筛选偶然。
这两件事和测 AI worker 是同一道门禁:验证用的判据,必须独立于被验证的东西。让 AI 用自己生成的测试去验自己写的代码,是循环;只在"应该成功"的用例上验、从不喂一个"应该失败"的用例,是没有阴性对照。两种设计都会给你一张完美却毫无意义的成绩单。
门禁五:判定线先预注册——先押数字,再开跑
前四道防的是 AI,最后一道防的是我自己。判例:还是那个巡检项目,要不要更换底层模型,我预先把判定线写死在文档里——新候选必须在同一口径下把召回率做到某个数才换。等结果出来,它差了 2.7 个百分点;而它在好几个单项指标上其实处处领先,换在以前,我大概率会找个"综合来看还是更好"的说法把它换上去。按预注册规则:不换,记档为候选。类似的"粗口径领先、精细口径反转"在三个月里出现了三次,最后被定为系统性规律写进了流程。
预注册的价值在于时机:结果出来之后,人总能在一堆口径里挑出让自己喜欢的那个。先押数字再开跑,等于把"事后合理化"这条路提前焊死。测 AI worker 同理——验收标准写在派任务的那一刻,而不是看到产出之后。
五道门禁,没有一道在测模型
回头看:声称要锚定原文、退出码要验采集链路、终验要开真实入口、判据要独立于结论、判定线要预先注册——没有一道门禁是关于"哪个模型更强"的,全部是关于"我在什么条件下才相信一个结果"。这也是为什么我从来不把测试结果写成排行榜,而是拆成"真实交付成功""证据不足""环境中断""未完成"这些状态:排行榜回答的是"谁强",门禁回答的是"这次能不能信"——日常协作里,后者才是每天要用的那个答案。
惊艳回答是能力上限,稳定做完才是工程底盘;而"做完"两个字,要过五道门才算数。
所以现在如果有人问我怎么评估一个 AI CLI worker,我的答案会比第一版短:先别管它多聪明,把你的证据纪律搭起来,然后看它在门禁全开的条件下,还能不能稳定走完全程。测到最后,测的其实是你自己。