On the Phased Handoff当一个 Agent 不够用时, 不是堆人, 是分工
有阵子, "多 agent 协作"这个说法到处都是。
我见过不少这样的描述: 开三个 agent 并行写同一个功能, 听着很猛。但真按这个路子跑过就知道, 每个 agent 都只看见自己那一摊, 输出互相覆盖, 合并冲突比一个人从头写还多。最后还是得有个人坐下来, 把三份东西一行行对齐、捏回一个能跑的版本。那这一圈下来, 到底省了什么。
我做的不是这种。
真正的多 agent, 是接力, 不是并排
我现在常走的流程大概是这样: Claude 写主线实施, 到某个节点把当前状态整理成一份交接说明, 切到 Codex 做一轮独立外审, 再开一个 Claude 新会话接手验收, 最后部署。
整条链里没有"两个 agent 同时打字"的画面。每一个时刻, 都只有一个在干活, 区别在角色不同 —— 一个负责往前推, 一个负责挑刺, 一个负责收。
为什么非得这样。因为模型一次能装进脑子里的上下文是有边界的。一个真正复杂的任务做到底, 单个会话常常装不下: 做到后半程, 前半程的细节已经被挤出窗口, 模型自己都记不全早先的决定。唯一的办法是把状态写到会话之外 —— 落进文档, 落进版本记录 —— 让下一个会话从那里重新捡起来。
这不是被技术逼出来的妥协。它是一条得自己守住的纪律: 该交接的时候, 老老实实把状态外化, 而不是硬撑着在一个会话里做完。
自己审自己, 不够
最早我以为模型自己审自己就够了 —— 先把背景调研一遍, 出一版方案, 再来回深审几轮收敛, 这事就稳了。
直到有一次, 我手上是一个塞了二十多个 bug 的修复方案。模型自己来回审了几轮, 跟我说: 差不多收敛了, 可以动手了。
我没立刻动手, 把这份方案原样丢给 Codex 跑了一轮独立审查。第一轮就拎出来好几个会直接卡住流程的硬伤, 外加一串次级问题。
不死心, 又跑一轮, 又是几个全新的硬伤。再跑, 还有。一轮一轮下来, 累计几十个修正项, 每一项都是前面自审完全没碰到的。
不是它不努力, 是它看不见自己看不见的东西。
自己写的方案自己审, 心智已经被锁死在这套方案的内部逻辑里了。它会反复确认"我这样想是对的", 却很难跳出来问"我会不会从一开始就站错了地方"。这跟人改自己刚写完的稿子一个道理 —— 错别字能挑出来, 真正的结构性毛病, 自己几乎看不到。
一个新会话冷读, 能看见什么
列几类反复出现的盲点, 都是真发生过的。
把事务边界看错。 模型在几十行的阅读窗口里看到一句提交事务的调用, 就认定这个函数自己是事务安全的。换个会话把整个文件搜一遍才发现, 真正提交事务的是外层那个调用方, 函数体里那句是早先测试留下的残骸。窗口太小, 它只看见局部, 就把局部当了全貌。
凭印象编出一个不存在的接口。 方案里大大方方写"调用某个返回对象上的某个字段拿历史 id"。那个字段名听着特别顺、特别合理, 翻代码却根本没有这个东西。它是从训练记忆里"想"出来的 —— 一个看上去理应存在、实际不存在的字段。
枚举值大小写对不上。 代码里那个枚举的真实取值是小写, 方案里反手写成了全大写。光读不跑测试看不出来, 一跑, 数据库的约束直接拦下。
凭直觉编出一个文件名。 方案里写"回填某个初始化脚本", 文件名编号煞有介事。实际仓库里那个目录的脚本编号根本不从那个数字起头, 压根没有这个文件。名字听着对, 列一下目录就穿帮。
这些都不是随机抽风。它们是结构化的盲点 —— 模型在自己写的方案里就是看不见, 可一旦放进一个没有记忆的新会话冷读, 配上全文搜索、逐文件细读、对着真实环境实查, 当场就能揪出来。差别不在谁更聪明, 在一个站在方案内部, 一个站在外面, 不信任何现成叙述, 每条结论都要落到现网去核对。
交接说明是一份协议, 不是工作总结
要让接手方能独立审查, 这份交接说明就不能只是"我干了啥"的流水账。它得是一份协议: 写清楚你接手后能做什么、不能做什么, 以及怎么自己把当前状态查出来。
来源: 上一个会话
去向: 下一个会话 (人或 agent)
边界: 只验证, 不实施
代码版本: <待定: 提交后回填>
## 已完成
以版本记录的实际历史为准, 不要信下面这段快照里的数字.
## 恢复步骤
拉取最新代码
查看最近的提交历史
对着真实环境查一遍当前状态
## 待办
先跑上面的恢复步骤拿到最新状态, 再据此判断.
这里有两个点是吃过亏才写进去的。
一是代码版本那一栏, 绝不写当时的实际值。接手方第一件事一定是拉最新代码, 你把旧值写死在那, 不是帮忙, 是误导他对着一个已经过时的锚点做判断。但凡会随时间漂的元信息 —— 版本号、部署状态、还剩几项没做 —— 一律标成待定, 并且明确告诉接手方: 以你自己实查的结果为准, 别信我写的时候那一刻的状态。这一条是真摔过才长记性的: 有一份交接写的时候某些信息还成立, 等上一个会话提交完, 那些数字全陈旧了, 接手方要是照单全收就被带偏。
二是那个边界一栏, 必须把话说死 —— "你只验证, 不实施"。少了这句, 审查方看完方案手一痒, 直接改了一堆文件提交上去, 整条链就乱了。它的职责是冷眼挑刺, 不是顺手接管。
写这种东西的讲究, 和当年学着好好写一条提交说明是同一回事 —— 它不是写给此刻的自己看的。它真正的读者, 是另一个时刻的某个 agent, 也可能是几个月后早就忘光细节的我自己。给那个人留下的痕迹, 得让他能不靠追问就接上。
那几个真摔进去的坑
这条路上踩实了的几个坑, 留给后面的人。
一个是接到"全做"的指令就硬扛着把一个跨多个服务的大改动在单会话里做完, 一路撑到上下文爆掉, 结尾草草收场, 留下半拉子。
一个是不写交接说明, 直接一句"切到 Codex"。接手方两眼一抹黑, 第一件事只能从头重做调研、重出方案, 前一个会话辛辛苦苦做出来的东西全打了水漂。
还有一个是新会话接手, 不读交接说明就直接上手, 轮子重造一遍, 前面会话里好不容易踩出来记下的坑, 又原样踩一遍。
这几个我都亲手踩过。所以现在每次切会话之前, 我都强迫自己先把交接说明写完再动手, 哪怕只有十行。十行也比让下一个人从零摸索强。
看一条多 agent 流程, 先看角色分没分清
回头看, "多 agent 协作"这件事的内核, 从来不是"人多力量大", 是角色边界划得够不够清。
主实施的那个, 走得最深, 也最容易陷在自己的方案里出不来。挑刺的那个, 没有记忆, 不认任何现成说法, 每句话都要去现网核一遍 —— 它接手时什么都不知道, 这恰恰是它的价值, 不是缺陷。而我自己是那个调度的: 决定什么时候该切, 什么时候该收, 哪一段交给谁。
最划算的多 agent 协作, 不是逼一个 agent 做更多, 是让每个 agent 只做它最擅长的那一段, 同时给彼此留下能严丝合缝对上的痕迹。前半句决定上限, 后半句决定这套配合到底立不立得住。
「独 学 而 无 友, 则 孤 陋 而 寡 闻」
礼 记 · 学 记