编排 Claude Code 智能体:幕僚长模式

HN Code LLM Research 2026-09-20T17:37:11.083492

一个会话负责协调与核验,其他会话负责执行,再由一块持久化的看板保存状态。这套「编排者—执行者」循环,专为长时间运行的 Claude Code 智能体设计。

长时间跨度的 AI 编程任务之所以失败,往往不是因为智能体不会写代码,而是因为它们的上下文转瞬即逝,自我汇报又不可靠。解决办法属于组织层面,而非技术层面:让一个会话负责协调与核验,其他独立会话负责执行,用一块持久化的外部看板保存状态,并且任何断言都要重新跑一遍才予以采信。这种结构早已为人所知,叫做「编排者—执行者」和「协调者—实现者—核验者」。我们只是给它起了个名字:幕僚长模式。本文将介绍这套循环、让它落地的工具,以及它专门用来捕捉的各类失效模式。

太长不看版

它解决了什么问题?

单个 AI 编程会话跑一小时没问题,再往后就开始退化。有三件事会出岔子。

  1. 上下文有限且有损。长时间会话会被压缩。三小时前还重要的细节,被压成一段摘要,而摘要丢掉了让那个细节有价值的全部具体信息。

  2. 自我汇报会偏离现实。智能体说「测试通过」,汇报的是它的意图和记忆,而不是当下的一次实际观察。会话越长,两者之间的差距越大。

  3. 知识不会自动累积。两小时前辛苦学到的一课,下一次会话就消失了——除非有人把它写下来,放在下次会读到的位置。

加更多 agent 解决不了这个问题,只会放大问题。你会有好几个不可靠的汇报者,却没人去核对。

真正的解法来自人类组织的分工方式:设一个角色,他的工作不是干活,而是搞清楚什么是真的。

这也是原型和正式产品之间的区别所在。瓶颈从来不在生成环节,而在检查环节。

什么是 Chief of Staff 模式?

Chief of Staff(幕僚长)是我们对一种 agent 编排方式的叫法:一个长期运行的会话充当协调者,负责分配任务、核实结论、维护共享状态;具体的实现工作则由一个个独立的短生命周期会话完成。

如果想快速理解,可以把它看成集成管理员(integration manager)。在 Git 的集成管理员工作流里,贡献者各自在自己的仓库里干活,由一位维护者拉取每个改动、在本地测试,然后决定哪些进入主参考仓库。这里协调者做的就是这件事,只不过对象从贡献者变成了 agent 会话。

这个名字只是个比喻,我们觉得好用而已。它不是标准术语,你也不需要认识它。它背后的模式早已广为人知,有好几个正式名称。

这个模式的常见叫法

说的都是同一件事:一个 agent 负责规划和检查,其他 agent 负责干活,共享状态存放在任何单个上下文窗口之外。如果你想找已有的资料,搜这些词,而不是搜我们起的这个名字。

这篇文章的重点不在于整体形态,而在于后面要讲的验证纪律,以及那些会让长时间自主运行崩溃的具体失效模式。

先澄清一个概念

“幕僚长智能体”(chief of staff agent)这个说法,通常指的是另一种东西:一个帮人打理日程、收件箱和优先级,并把工作分派给各类专用智能体的助手。Anthropic 的 cookbook 里就有一个这样的幕僚长智能体,专门为初创公司 CEO 打造。比喻相同,解决的问题不同。本文讲的是编码循环。

协调者的职责

负责协调的那个会话,有时被称作“overwatch”(监督者)。它的职责包括:

它明确不做的事,是写实现代码。协调者一旦开始编码,就不再验证了,整个模式会塌缩成一个超载的单一会话。

三个组成部分

你需要三样东西。具体用什么工具可以替换,但这些角色不能替换。

1. 智能体运行时:Claude Code

Claude Code 提供会话本身:工具调用、文件编辑、shell 访问,以及会话之间互发消息的能力。每个会话都有自己的上下文窗口,这正是关键所在。隔离是一种特性,因为一个会话的混乱不会污染另一个。

2. 会话底层环境:cmux

cmux 负责管理终端工作区,可以从命令行驱动,因此可脚本化。协调者这样开出一个新的执行会话:

cmux workspace create \
  --name project-session-12 \
  --cwd /path/to/repo \
  --command 'claude "Read docs/briefs/current.md and do exactly what it says."'

这条命令里有两个关键点,都是实打实花时间才摸出来的。

3. 持久状态存储:Plan Desk

Plan Desk 是一块通过 MCP 向 agent 开放的规划看板:项目、目标、带依赖关系的任务、关联的设计文档,以及评论。协调者和每个执行会话读写的是同一块看板。

这正是大家最容易跳过的一环,而跳过它,正是多 agent 系统撑不过一夜的原因。看板就是记忆。 会话可以随时丢弃,看板不行。

看板上有什么:

运行循环

一次一个工作项,一次一次派单,一次一次提交。

1. PULL     从看板上拉取下一个未被阻塞的任务
2. READ     动手之前先读它关联的设计文档
3. RED GATE 先跑验证器:它必须失败
4. DELEGATE 给一个执行会话下简报,或自己动手做
5. PROVE    重新运行每一条被声称执行过的命令;由退出码来定论
6. OBSERVE  逐块地读 diff
7. GATE     走完审批通道,把推理过程贴出来
8. SHIP     翻转状态,只提交这一项,记录进度

为什么红门测试要先跑

如果检查在开始之前就是绿的,那做的工作什么也证明不了。你没法分辨一个正确的实现,和一个根本不会运行的检查、一个匹配不到任何东西的过滤器、一个断言本身就成立的老测试之间有什么区别。

先跑校验器还能低成本地发现过期任务。实践中,队列里有相当一部分任务其实早就做完了——或者在另一个卡片下做完了,或者被之后的某个改动搞得不再需要了。一个红门测试一条命令跑下去变绿,花几秒钟,省下的是你本来要读代码、实现一个早就有东西的那一小时。

为什么每项一个提交

Git 历史和看板一一对应。每个提交的主题行就写明它对应哪个任务。三天后出了问题,从症状追溯到当时的决定,一条 git log 就够了。

验证纪律:这个模式的核心

这是把这种方法论和「同时跑几个 agent」区分开来的关键部分。

报告是证据,不是指令

当执行会话报告「套件全绿,49 项检查,零失败」时,协调者的任务是弄清楚这是不是真的。不是因为 agent 会撒谎,而是因为它们报告的对象和它们实际检查的对象经常是两个不同的东西。

有一个值得内化的模式:某个会话手动把一个提交哈希写进日志文件,然后用 git cat-file 去验证——但验证的是它 shell 里的短哈希,而不是它写进文件的那串字符串。两个检查都通过了。文件里那个哈希实际上解析不到任何东西。检查和记录是两个不同的对象,只有其中一个被真正测试了。

由此得出的规则是:验证产出物时,必须从产出物里把值读回来,绝不能用你以为自己写进去的那个变量。

要警惕的缺陷类型

Agent 工程中最常见的一类失败,是一个对自己没做的工作报告成功的工具。它有多种形态。

通用的防御手段是:每一个可能匹配失败的检查都必须明确说出来。计数为零和根本没运行必须能区分开。而一个断言「不存在」的检查,需要在同一次运行里有一个阳性对照——因为如果什么都没跑,「没有坏事发生」也会通过。

先证明正面,再相信负面

下结论说某个东西不存在之前,先证明你的检测手段能找到它。用一个已知可用的例子先验证一遍。报告“干净”的工具,和已经坏掉的工具,输出看起来一模一样。

持久通道胜过临时通道

会话之间可以直接发消息。这个通道确实有用,比如协调者在运行中途回答问题,或者执行会话发现矛盾时直接提出来,而不是绕过去。

但它不够可靠,不能当作依据。一条消息可能排在一个繁忙会话后面等很久,也可能因为接收方的权限模式而被拦下等待批准,还可能没送到就过期了。沉默不等于同意。

所以,凡是必须送达的内容,都走持久通道。

消息是提醒,文件是契约。

东西放在哪里

有条小规矩很值:持久策略和临时工作内容分开存放。

策略目录里放的是治理每个周期的契约,包括循环流程、路由规则和标准。长期存在、经过审阅、很少改动。一次性的简报、任务上下文、针对某个会话的指令,应该放在看板上或临时目录里。

混在一起,六个月后就没人分得清哪些文件还在起约束作用。

时间盒:浮出水面,但别停下来

长时间自主运行,应该按某个节奏汇报,而不是消失几个小时,回来甩出一大堆 diff。

让时间盒真正起作用的一条规则是:时间间隔只决定多久汇报一次,绝不决定工作在哪里停下。计时器在某个条目做到一半时到期,就先把这条做完、验证、提交,然后再汇报。半路截断,工作会卡在最难收拾的状态:只改了一半、没验证过,而且根本说不清楚。

检查点是一个汇报节点,不是请求批准的环节。汇报发出去,下一项就在同一轮里开始。如果你发现自己正在写"要我继续吗?",删掉。盯着你的那个人会主动打断你,而没盯着你的人,他这一轮已经被你的提问弄死了。

汇报已经验证过的结果,不是"尝试过"的动作。一条没有验证结果的条目只能算挂账,不算完成。

那些用时间换来的实践经验

这些都是小事,但每一个都有失败模式,而且看起来像是别的问题。

确认新起的会话真的起来了。 启动器会报告"工作区已创建",这跟"智能体在运行"不是一回事。要检查进程,还要检查它的工作目录:

launched_at=$(date +%s)
# ... spawn the session ...
# then accept only a process whose start time is after $launched_at

在启动之前立刻抓取参考时间戳。用"比上一个会话更新"来过滤,会把中间启动的无关会话也放进来;如果那个会话的工作目录不一样,一次正常的启动看起来就像是坏的。

会话名不是你猜得到的地址。 你给工作区起的名字,往往不是消息层实际用的名字。寻址之前重新列一遍活跃会话,别复用你之前读到的名字。

短标识符是显示用的前缀,不是键。 看板通常显示截断后的 ID。把它补全成完整长度的标识符,会得到一个格式合法但根本不存在的值。正确做法是搜一个标签里的独特子串来定位。

搜标签本身,别搜你的转述。 日志条目的标题,通常是写作会话自己对干了什么的表述,并不是卡片的真实标签。搜前者搜不到,还会读成"没有这张卡片"。

在共享工作树里,永远不要用裸 commit。git add <path> 之后再 git commit,会把整个索引都提交上去,包括其他并发会话暂存的内容。用 git commit -- <paths>,这样提交只包含你指定的文件。

什么时候该用这个模式,什么时候不该用

适合用的场景:

不适合用的场景:

这种开销本身就是目的。你买的是「能信任结果」的能力。

上手

  1. 搭一块持久化的看板。一个项目、几个目标、带依赖关系的任务。确保你的智能体能通过 API 或 MCP 访问它。

  2. 把约定写下来。用一个文件写清楚循环流程、「完成」的定义,以及各项标准。提交它。每个会话启动时都读一遍。

  3. 先跑一个协调者和一个执行者。不要一上来就六个。先把验证循环用两个跑通、跑诚实。

  4. 加一个交接产物。一个文件,协调者在每次会话结束时更新它,记录当前状态和学到的东西。正是这个东西让会话能够滚雪球式积累。

  5. 记一本经验日志。遇到意外时,趁会话结束前写下来,放到下一个会话会读到的地方。

判断它有没有奏效的标准,不是写了多少代码。而是任何时刻你问「这项工作现在什么状态?」,都能得到一个真实的答案。

结语

当 AI 编程智能体在长任务上表现不佳时,人们本能地会去找更强的模型或更大的上下文窗口。两者都有帮助。但两者都没碰到真正的约束——没人在做检查。这跟「70% 问题」背后是同一个缺口,也跟每一个在实时系统上操作却没有回读步骤的智能体是同一个缺口。

一个不写代码、却清楚真实情况是什么的协调会话,比再多一个执行者都更有价值。这是人类组织里早就总结出的经验,事实证明放到这里同样成立。

想让这套循环跑在你的产品上,而不只是工具链里?

我们以固定价格交付生产级软件,构建过程遵循本文介绍的编排与验证原则。完整源代码会部署到你的账号,归你所有。告诉我们你在构建什么,我们会给出范围、价格和时间表。

常见问题

查看原文