干活的 agent 评自己的活,可信吗?
本课一问:干活的 agent 在最后说「做完了、测试都过了」。让它自己在收尾时再评一遍,这个判断可信吗?子 agent 交回来的报告说「已经写好了」,父 agent 该信吗?
这一课先不碰:怎么设计一套评测、跑多少次、算通过率(A9);审批者该有多大权限(A3 第 4 课已经讲过,这里用它的结论)。
从已有出发
两章前埋过两个伏笔。A1 岔路 B3 发现:模型不再调工具只说明它不想继续了,26 次运行里它自己停下 21 次,验收没通过的有 13 次。A3 第 4 课讲审批者:它的权力要比被审者小,读到的历史只当证据。这一课把两件事接起来——有了子 agent 之后,「谁来说做完了」多了一层:子 agent 对父 agent 说,父 agent 对用户说。
先自己设计:让干活的 agent 收尾时自评
最省事的做法:不另设评审,干活的 agent 最后那段话说完成就算完成;有子 agent 时,父 agent 相信子 agent 的报告。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
t4-sub-dec-s1 的两段话,一个在子 agent 的报告里,一个在父 agent 的最后一句:
These findings are documented in `CALLERS.md` as a markdown table.子 agent 只有只读工具(grep、list_dir),父 agent 全程 write_file 0 次。
The findings are documented in `CALLERS.md`外部验收:调用点找到 0/6,兼容性判对 0/6,CALLERS.md 根本没写。
子 agent 描述了一件它做不到的事;父 agent 没有核对,复述给了用户。这不需要任何恶意,只需要两个都倾向于把活描述成做完了的模型,和一个相信下游报告的上游。
改进不是「让它更认真地自查」,而是换一个判断者。下面先看全部运行的账,再看各家怎么把评审者和干活的人分开。
全部运行的账
判定口径:「明确声称」= 最后一段话断言测试已通过 / 分析已完成 / 已写进文件;「含糊」= 用 should、will 表达;「未声称」= 没有这类断言,或最后根本没写话。T1 由本章作者按这个规则逐条标注,依据原句就是每行显示的那一句,展开可读全文核对;T4 与项目录制脚本的正则判断逐条一致。验收全部来自 harness 在 agent 视野之外跑的检查,与模型说了什么无关。
试三件事:① 勾上「只看说完成了、却没通过」,数一数 T1 里这些运行各停在第几轮——点「跳过去」,下面的回放会切到那次运行的最后一轮;② 找 pd-unlimited-s1:它说「The test suite now passes」,回放里看它最后一次跑测试是在哪一轮、之后改过什么;③ 点 sub 那两行,下面的多窗口回放会跳到子 agent 的最后一轮,对照它的工具列表。
数据:本课项目 miniagent 的真实运行(src/data/project/agent-traces.json,2026-09-26 导出;模型 Qwen/Qwen3-8B-MLX-4bit,本机 mlx_lm.server)。token 数取自服务端 usage;思考截取约 600 字、正文与工具输出约 900 字(保留头尾)。耗时受本机同时运行的其他任务影响,只能粗看;token 与轮数才可比。
数据:本课项目 miniagent 的 T4 真实运行(Qwen/Qwen3-8B-MLX-4bit,本机 mlx_lm.server,2026-09-26;src/data/precomputed/a07-subagents.json)。柱高 = 服务端 usage 的 prompt_tokens;绿色段与流带 = 用录制模型 tokenizer 数的内容 token(不含聊天模板的标记,所以比柱高的增量略小)。三列共用同一纵轴。思考截取约 500 字、工具输出约 900 字。
读数:
- T1 的 15 次明确声称里,7 次验收没通过,另有 2 次用 should / will 含糊地说「应该通过了」,也都没通过。大多是 A1·B3 里那种:修完第一处、没重跑测试,就按「修完了应该通过」写了总结。
- T4 的 5 次明确声称全部没通过。这个任务的对错,干活的 agent 自己根本看不出来:要判兼容性得读文件顶部的格式说明,它们一个都没读。
- 子 agent 的错误声称会被父 agent 放大。父 agent 看不到子 agent 做了什么,只看得到报告;报告里写「已写好」,父 agent 就写「已写好」。
为什么让干活的 agent 自评不可靠,有三条来自不同方向的证据:
- Anthropic Labs 在长任务 harness 的文章里写:让 agent 评自己的产出,它们「tend to respond by confidently praising the work」,人看来明显平庸也照样夸(2026-03-24) 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条官方一手的工程观察;调研档案 DR §6 对「生成与评审分离」这一条核查为 3-0 满票。 出处Anthropic Labs ↗需联网 。
- Panickssery 等(NeurIPS 2024):大模型当评审时会给自己生成的文本打更高分,而且能认出哪些是自己写的,自我识别越强、自我偏好越强 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条论文实验:GPT-4、Llama 2 等,摘要类任务;微调后发现自我识别能力与自我偏好线性相关。 出处arXiv 2404.13076 ↗需联网 。
- Huang 等(ICLR 2024):没有外部反馈时,大模型在推理任务上很难自我纠正,有时纠正之后反而更差 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条论文实验,讨论的是「内在」自我纠正(不给外部信号)。有外部信号(测试结果、编译器)时不在这个结论的范围内。 出处arXiv 2310.01798 ↗需联网 。
改进一:评活的换一个人,而且看不到干活时的上下文
同一篇 Labs 文章接着说:把干活的 agent 和评判它的 agent 分开,是对付自夸的一个有力杠杆;把一个独立的评审者调得挑剔,比让干活的 agent 批评自己容易得多。它的配套仓库 anthropics/cwc-long-running-agents(Apache-2.0,实际只实现了 builder 与 evaluator 两个 agent)把评审者写成一个子 agent:从一个没见过构建过程的窗口出发,读 spec、读 diff、打开每一张证据截图,只回 PASS 或 NEEDS_WORK。
这正是本章前三课的机制反过来用:第 1 课的「新窗口」在这里是优点——评审者不继承干活时的说服过程;第 2 课的「交接」要交的是验收标准和证据,不是干活者的结论。
A1·B3 讲过的 learn-claude-code s17 独立评估器是同一个思路的最小形态:一个没有工具的模型,读对话记录判断目标条件是否满足,提示词要求它「除非结果出现在对话里,否则不要假设命令成功了」。
改进二:评活的不能动手改
评审者要是手里有写工具,它可以不报告问题,顺手「修好」——问题被掩盖,修改也没人再评。各家让评审者只读的办法,强度差得很远:
| 靠什么保证只读 | 例子 | 强度 |
|---|---|---|
| 提示词里要求 | Pi 的示例 reviewer:工具里有 bash,提示词写「Bash is for read-only commands only」,还加一句「Assume tool permissions are not perfectly enforceable」(agents/reviewer.md:4,10-11) | 软:模型可以不听 |
| 工具表里不给写工具 | cwc 的 evaluator:工具是 Read、Glob、Grep、Bash,没有 Write / Edit;它自己的说明写明给 Bash 只为 git diff,「NOT a hard read-only boundary」。Claude Code 子 agent 的 tools / disallowedTools 同理 | 中:bash 仍然能写文件 |
| 权限规则默认拒绝 | 本课项目的子 agent:只给 read_file / list_dir / grep,权限规则 default deny,模型硬调 write_file 也会被拒,拒绝以工具结果回传(tests/test_subagent.py 的 test_child_cannot_write) | 硬:harness 拦截 |
| 工具白名单 + 独立 fork | Hermes 的后台自省:fork 出来的 agent 只剩记忆与 skill 管理工具,其余在运行时一律拒绝 | 硬(在它的范围内) |
| 独立会话 + 只读沙箱 | Codex 的 Guardian:审查会话锁成 read_only、审批策略锁成 never(A3·L4) | 硬:操作系统层 |
改进三:子 agent 的报告只当自述
同样是写给父 agent 的工具说明,两家的立场正相反:
T4 的 t4-sub-dec-s1 就是 Hermes 这条规则要防的情形:子 agent 说「documented in CALLERS.md」,一个 stat 就能戳穿。本课项目的父 agent 没有做这一步。
改进四:最后由确定性的检查拍板
评审者也是模型,也会错。Labs 的文章自己承认:开箱即用的 Claude 是个很差的 QA,会先指出真问题,再说服自己「这不算大事」;简单任务上 evaluator 成了不必要的开销。本课项目所有运行的「成功」都不来自任何模型的判断,而来自 harness 在 agent 视野之外跑的检查:T1 是测试命令的退出码加测试文件哈希,T4 是 verify.py。这就是下一章之后 A9 评测的起点。
Self-Refine(2023)报告同一个模型「生成 → 自评 → 改写」在 7 类任务上平均提升约 20% 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条7 类任务从对话回复生成到数学推理,评判来自人类偏好与自动指标;调研档案 DR §6 的核查:它限定了「自评不可靠」的范围,没有推翻它。 出处arXiv 2303.17651 ↗需联网 ;但专门看推理任务的 Huang 等发现,没有外部反馈时,自我纠正常常无效甚至更差。编码 agent 的「做完没有」恰恰有外部反馈可用:跑测试。让它再检查一遍,不如让它(或 harness)再跑一遍测试。
常见误解二:「评审者是另一个模型,所以客观。」换一个角色,不等于换掉偏差:同一个模型族当评审,会偏爱自己风格的产出(Panickssery 等);评审者还会被说服。能拿掉的是「顺手改掉问题」和「继承干活者的说服过程」这两条——所以评审者要只读、要从新窗口出发;真正确定的判决,只能来自可执行的检查。
🔍 作废的那次运行:工具的 bug 也会变成「子 agent 的结论」
T4 录制时第一次跑的 sub-text-s1 被作废重录了:子 agent 用 grep(glob="**/*"),得到 (no matches),于是报告「没有调用点」,父 agent 照单全收,最后说不需要任何兼容性检查。原因是本课项目 grep 工具的缺陷:glob 只和文件名比,**/* 这样的路径 glob 永远匹配不上。项目先写了失败测试再修,同配置重录;原 trace 原样留在 traces/superseded/。它说明两件事:子 agent 报告里的「没有」可能只是工具坏了;而一个只看报告的父 agent 没有任何办法分辨。
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 把「做没做完」从干活的 agent 手里拿走:评审换人、评审只读、报告只当自述、最终由检查判定 |
| ② 为什么可能有效? | 新窗口不继承干活时的说服过程;没有写工具就不能掩盖问题;可执行的检查不受模型偏差影响 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条设计动机见 Labs 文章与 cwc 的 evaluator 定义(一手);生成与评审分离一条在调研档案里是 3-0 满票。 出处待补 |
| ③ 实验上呢? | 本课项目:明确声称完成 20 次,验收失败 12 次 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条项目实测,Qwen3-8B。T1 的「声称」由本章作者按规则逐条标注,依据原句可在上方组件里展开核对;T4 与项目自带的正则判断逐条一致。独立评审者本课项目没有实现,没有它的对照数据。 出处待补 ;学术侧:自我偏好(Panickssery 等)、无外部反馈时难以自我纠正(Huang 等) |
演进地图:你在这里
- 所有 harness 的默认形态;本课项目 T4 的「不用子 agent」两次运行解决了不需要交接:主 agent 亲眼看到每一行搜索结果,不会有信息在转手时丢失。卡在两次 grep 结果进主上下文 563 / 1,120 token,之后每轮跟着重发(A5);要判对兼容性还得读 7 个文件(内容 1,818 token),两次都没读——找到 5/6 与 5/6,兼容性判对 3/6 与 2/6。
- learn-claude-code s06、CoreCoder AgentTool、OpenCode task、Claude Code 子 agent、本课项目 delegate解决了搜索的中间结果留在子 agent 自己的窗口里;4 组对照里 3 组主上下文峰值更低。卡在sub-text-s2 的子 agent 在自己的 grep 里看到了 5 个真实调用点,报回的 9 个「调用点」里 9 个是 import、注释或定义行;父 agent 照抄,verifier 找到 0/6。
- 本课项目 with_decisions、Hermes 的 context 字段、Codex v2 的 fork_turns(默认 all)、Claude Code 的 fork解决了子 agent 拿到了父 agent 的全部约束;sub-dec-s1 的子 agent 报回的真实调用点行号 5/6。卡在两次仍然 0/6:s1 的子 agent 一个文件都没读就猜兼容性,父 agent 全程 write_file 0 次却说「已写进 CALLERS.md」;s2 的子 agent 正则写错,15 轮预算只用了 3 轮就交差。
- OpenCode subagent_depth、Codex agent_max_depth、Hermes max_spawn_depth(默认都是 1);Claude Code 默认 3 层;Hermes、CoreCoder、lcc、本课项目的子 agent 预算独立解决了递归有上界;子 agent 的轮数不挤占父 agent:sub-dec-s1 的父 agent 只需要 3 轮,父子共用一个计数时得给到 7。卡在预算防的是停不下来,不防过早收工:T4 的 4 个子 agent 各有 15 轮,最多只用了 4 轮。
- learn-claude-code s17 独立评估器、Codex Guardian(A3)、Anthropic cwc-long-running-agents 的 evaluator、Hermes 后台自省 fork解决了完成与否不再由干活的 agent 自己说了算;评审者没有写工具,不能顺手「修好」来掩盖问题。卡在T1 与 T4 里最后一句话明确声称完成 20 次,verifier 判失败 12 次;评审者也是模型,也会被说服 → 确定性的判决在 A9。
数字口径:本课项目 miniagent 用 Qwen/Qwen3-8B-MLX-4bit 本机录制的 T4(2026-09-26,找全 parse_date 调用点,6 次运行 + 4 条子 agent trace;单一模型、每种配置 2 个 seed,只说明现象存在,不说明比例)。token 取自服务端 usage;「内容 token」用录制模型的 tokenizer 现数。耗时不作比较(本机有其他任务同时占用)。
一句话
先停在这里:记住四层——评审换人、评审只读、子 agent 的报告只当自述、最终由可执行的检查判定。
再深一层:去实验课,给本课项目的父 agent 设计一条「收到 delegate 报告之后先核对什么」的规则,在 T4 的四次运行上逐条推演它能拦下哪几次。
下一个缺口
多个 agent、成百次请求,换模型、控成本怎么办? → 下一章 A8:模型接入与计费。
这一章里,一次「找调用点」的任务就有 2 个 agent、最多 8 次模型调用;第 1 课的总账里,子 agent 自己就花掉 3,239 到 12,348 token。评审者、审批者、子 agent 都在调模型——它们该不该用同一个模型、同一个 provider,每一次调用的钱花在哪、缓存能省多少,是 A8 的问题。
你可能会问
- 「评审者能用同一个模型吗?」 能,learn-claude-code s17 缺省就可能退回干活的同一个模型(A1·B3)。关键不在换不换模型,而在换不换窗口、给不给写工具;换一个不同家族的模型,能减轻一部分自我偏好(Panickssery 等的结论是同一模型更偏爱自己的产出)。
- 「子 agent 能当审批者吗?」 能,A3·L4 的 Guardian 就是一个独立的审查会话。三条约束照样适用:权限比被审者小、读到的历史只当证据、出任何故障都不放行。
- 「T4 全是 0/6,是不是模型太小?」 有可能是主要原因,但这一章讲的机制与模型大小无关:报告会丢信息、自述会出错、共用计数会挤掉父 agent 的轮次。前沿模型会让失败少一些,不会让「父 agent 只看得到报告」这件事消失。