编排 Claude Code Agents:幕僚长模式

Hacker News Top 新闻

摘要

本文介绍了幕僚长模式,这是一种通过将协调与执行分离来编排 AI 编程代理的组织方法,旨在提高长期任务中的可靠性和状态管理。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/09/20 09:31

# 协调Claude Code代理:幕僚长模式 来源:https://asyncdot.com/blog/chief-of-staff-pattern-orchestrating-claude-code-sessions/ 长时间的AI编码任务失败,往往不是因为代理无法编写代码,而是由于其上下文信息转瞬即逝,且自我报告并不可靠。解决方案在于组织而非技术层面:一个会话负责协调与验证,其他独立会话负责执行;状态保存在持久的外部任务板上;并且每一条声明在采信前都需要重新验证。这种模式通常被称为协调器-工作者或协调者-实现者-验证者结构。我们称之为“幕僚长”模式。 本文将介绍该模式的工作循环、支撑其实用的工具体系,以及它旨在捕获的故障模式。 ## 摘要 - **协调与执行分离**:协调会话负责撰写任务简报、验证声明并审阅差异。它不承担实现工作。 - **状态存于持久化存储,而非上下文中**:任务板或任何具有API的外部任务系统,能够经受会话压缩、会话终止和任务交接。而会话上下文则不能。 - **将每个代理报告视为证据,而非指令**:重新运行命令。退出码才是权威依据,摘要只是意图表述。 - **写入持久化通道**:会话间的消息可能延迟、被截留或过期。已提交的文件或任务板卡片则总能送达。 - **设置时间盒是为了浮现问题,而非截断任务**:固定时间间隔决定报告频率,但绝不作为工作的停止点。 - **不要信任你自己的检测工具**:代理工作中最昂贵的错误,来自于那些报告“成功”但实际并未完成工作的检查。 ## 此模式解决什么问题? 单个AI编码会话在一小时内表现良好,之后便会退化。主要会出现三类问题: 1. **上下文有限且会损失**:长时间会话会被压缩。三小时前重要的细节会变成摘要,而摘要又丢失了使细节有用的具体信息。 2. **自我报告偏离现实**:代理报告“测试通过”时,它报告的是其意图和记忆,而非新鲜的观察结果。随着会话延长,两者之间的差距会越来越大。 3. **无法积累经验**:在第二小时痛苦学到的教训,除非被记录在下一个会话能读取的地方,否则会在下一次会话中消失。 增加更多代理并不能解决此问题,反而会加剧问题——现在你有多个不可靠的报告者,且无人进行协调整合。 解决之道是借鉴人类组织的劳动分工:**有人的工作不是去做事,而是去知道什么是真实的**。 这正是区分原型与已发布产品(https://asyncdot.com/blog/vibe-coding-is-fine-vibe-shipping-is-not)的纪律。生成步骤从来不是瓶颈,检查步骤才是。 **幕僚长是我们对一种代理协调模式的命名,其中一个长期存在的会话充当协调者,负责分配任务、验证声明和维护共享状态,而独立的短期会话则负责执行实现工作。** 如果你需要最快的心智模型,可以将其视为一个**集成经理**。在Git的集成经理工作流(https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows)中,贡献者在自己的仓库中工作,而一名维护者拉取每个更改,在本地测试,并决定哪些内容合并到参考仓库。协调者做的就是这份工作,只是对象从贡献者变成了代理会话。 这个名称是我们觉得有用的一个比喻。它并非公认术语,你无需熟悉它。其背后所指的模式是众所周知的,并有几个正式名称。 ### 此模式的通常名称 - **协调器-工作者**,亦称**监督器**或分层协调。 - **协调者-实现者-验证者**。 - **制作者-检查者**,或验证链,借自金融和运营领域。 - **集成经理**,人类版本,在Git分布式工作流文档中早有记载。其开源变体被称为*仁慈独裁者及其副官*。 - **团队负责人与队友**,这是Claude Code自身的子代理文档所采用的表述。 它们表达的是同一个意思:一个代理负责规划与检查,其他代理负责工作,而共享状态存在于任何单一上下文窗口之外。 如果你在寻找类似实践,应搜索这些术语,而非本文的命名。本文增添的并非模式本身,而是下文详述的验证纪律,以及会中断长时间自主运行的特定故障模式。 ### 一个澄清说明 “幕僚长代理”一词常被用于指代另一事物:一个负责管理个人日历、收件箱和优先事项,并将工作分流给专业代理的助手。Anthropic的示例库中就有一个此类幕僚长代理(https://platform.claude.com/cookbook/claude-agent-sdk-01-the-chief-of-staff-agent),专为初创公司CEO打造。同样的比喻,不同的问题。本文讨论的是一个编码循环。 ### 协调者的职责 协调会话有时被称为*监视者*。其职责包括: - **从持久化队列中拉取并分配工作**,遵循既定顺序。 - **撰写任务简报**,使较弱模型无需协调者判断也能遵循。 - **验证声明**,通过重新运行执行会话声称已运行的命令。 - **审阅差异**,而非日志。最终生效的内容才是重要的,代理的描述并非如此。 - **在会话结束前,将教训记录到持久化制品中**。 - **引导**偏离轨道的会话,但不剥夺其工作。 协调者明确*不*做的事是编写实现代码。一旦协调者开始编码,它就停止了验证工作,该模式会退化为一个过载的单一会话。 ## 三个核心组件 你需要三样东西。具体工具可替换,但角色不可替代。 ### 1. 代理运行时:Claude Code Claude Code(https://docs.claude.com/en/docs/claude-code/overview)提供会话本身:工具使用、文件编辑、Shell访问以及会话间消息传递能力。每个会话拥有自己的上下文窗口,这正是要点所在。隔离性是一项特性,因为一个会话的混乱不会污染另一个会话。 ### 2. 会话基座:cmux cmux(https://github.com/manaflow-ai/cmux)管理工作终端,可通过命令行驱动,使其可脚本化。协调者按如下方式创建新的执行会话: ```bash cmux workspace create \ --name project-session-12 \ --cwd /path/to/repo \ --command 'claude "Read docs/briefs/current.md and do exactly what it says."' ``` 此命令中有两个关键点,学习它们都需要付出时间成本: - **`--command`向工作区的Shell发送文本**。它不会启动代理。你必须显式调用代理。裸指令会被输入到无法运行它的Shell中,而启动器仍会报告成功。 - **保持提示词简短并指向文件**。过长的命令字符串执行不可靠。指向已提交简报的短提示更健壮,且使简报可审查、可重新运行,而埋在Shell历史记录中的字符串则做不到。 ### 3. 持久化状态存储:Plan Desk Plan Desk(https://plandesk.asyncdot.com/)是一个规划看板,通过MCP(https://modelcontextprotocol.io/)向代理暴露:项目、目标、带有依赖关系的任务、关联的设计文档以及评论。协调者和每个执行会话读写同一块看板。 这是人们常跳过的组件,而跳过它正是其多代理设置无法过夜的原因。**看板就是记忆。**会话可丢弃,看板则不行。看板上存放的内容: - **作为构建契约的任务**:问题陈述、行动项、接口、验证契约、非目标。需足够详细,确保执行会话无需阅读父文档即可完成工作。 - **随工作原子性翻转的状态**:开始即`in_progress`,验证通过即`done`。绝不在会话结束时批量更新,因为只在散会时才准确的看板不是真正的看板。 - **设计文档**:链接到它们所管辖的任务。 - **评论**:人类在此留下指导,代理在此留下推理过程。 ## 操作循环 一次处理一个工作项。一次分派。一次提交。 ``` 1. 拉取 从看板上拉取下一个未阻塞的任务 2. 阅读 在动手前阅读其链接的设计文档 3. 红门 先运行验证器:它必须失败 4. 委派 简报一个执行会话,或自己构建 5. 证明 重新运行所有声称的命令;退出码决定结果 6. 观察 逐块阅读差异 7. 门控 解决审批环节,发布理由 8. 交付 翻转状态,单独提交该项,记录进展 ``` ### 为何“红门”步骤在前 **如果检查在开始前已是绿色,那么工作本身并未证明任何事。**你无法区分正确的实现与一个从未运行的检查、一个匹配不到任何内容的过滤器,或一个断言本就成立的测试。 先运行验证器也能廉价地捕获过时的工作。实践中,相当一部分排队任务实际上已完成——可能是在另一张卡片下构建的,或因后续更改而变得无关紧要。一个耗时仅需数秒的“红门”检查若返回绿色,就能为你节省本应花在阅读代码、去实现一个已存在功能上的整整一小时。 ### 为何每项只提交一次 Git历史与看板保持一对一关系。每个提交的标题都注明其任务。当三天后出现问题时,从症状到决策的路径只需一个`git log`即可追溯。 ## 验证纪律:模式的核心 这是该方法与“同时运行多个代理”相区别的关键部分。 ### 报告是证据,而非指令 当执行会话报告“测试套件通过,49项检查,0失败”时,协调者的工作是查明这是否属实。不是因为代理会撒谎,而是因为**它们所报告的对象与它们所检查的对象往往是两个不同的东西**。 值得内化的一种模式:一个会话手动将一个commit哈希写入日志文件,然后使用`git cat-file`进行验证,但对照的是其Shell中的短哈希,而非它所写入的字符串。两项检查都通过了。该文件包含的哈希无法解析到任何内容。检查与记录是两个不同的对象,且只有一个被测试了。 由此产生的规则是:*通过制品读回值来验证制品本身*,绝不要从你认为已写入的变量来验证。 ### 需要警惕的缺陷类别 代理工程中最常见的单一故障是**一个检测工具报告其未完成的工作“成功”**。它有多种表现形式: | 形式 | 表现 | 如何误导你 | |---|---|---| | 空洞断言 | 测试通过与否与功能是否正常无关 | 删除被测功能仍显示绿色 | | 静默无匹配 | grep、过滤器或谓词匹配不到任何内容 | 零结果被解读为“干净” | | 出错检查 | 命令根本未能运行 | 错误被吞没,缺失被当作证据 | | 错误引用 | 过滤器基于“晚于X”来筛选 | 期间发生的任何事件都会漏网 | | 过时前提 | 检查的预期值是从损坏的代码中读取的 | 它通过了本应捕获的缺陷 | | 范围不匹配 | 对子集的绿灯检查被呈现为对整体的检查 | 从未说明分母是什么 | **通用防御措施**:每个可能失败的检查都必须能明确报告失败。零计数与运行失败必须可区分。并且,一个缺失断言需要在同一轮运行中有一个阳性对照,因为如果什么都没运行,“没有坏事发生”也会通过。 ### 在相信“无”之前,先证明“有” 在得出某物不存在之前,先证明你的工具在它*存在*时能够找到它。先将检查指向一个已知的良好案例。一个报告“干净”的工具与一个损坏的工具可能产生完全相同的输出。 ## 持久化通道优于临时通道 会话可以直接彼此发消息。这个通道确实有用,是协调者在运行中途回答问题的方式,也是执行会话标记矛盾而非绕过矛盾的方式。 **但它并不可靠,不能依赖。**消息可能因会话繁忙而排队,根据接收会话的权限模式被暂扣,或未送达即过期。沉默不代表同意。 因此,任何必须送达的内容都应通过持久化通道传输。 - **已提交的文件**:简报、交接文档、约束条件。会话在启动时读取仓库。 - **任务板卡片和评论**:特定工作上下文应放在这里。 - **共享链接**:大多数任务板可以将任务或文档渲染为代理就绪的文本,并提供URL。在启动提示中放入`Context: `,而非将上下文粘贴进去。这样提示保持简短,上下文则留在其被维护的地方。 消息是提醒。文件是契约。 ### 内容存放位置 一条能带来回报的小纪律:**将持久化策略与临时工作内容分开存放**。策略目录存放控制每个循环的契约,即循环本身、路由规则和标准。它们长期有效、经过审查、很少更改。 一次性的简报、任务上下文和特定会话指令应放在任务板上或临时目录中。混合存放意味着六个月后,没人能分辨哪些文件仍在起约束作用。 ## 时间盒:浮现问题而非停止工作 长时间的自主运行应按节奏报告,而不是消失数小时后带着一大堆差异返回。使时间盒有效的规则是:**时间间隔决定你浮现的频率,但从不决定工作的停止点**。当计时器在任务中途到期,应先完成该项任务,验证它,提交它,*然后*报告。 在任务中途截断运行,会使工作处于最难恢复的状态——半完成、未验证、且无法诚实描述。检查点是浮现时刻,而非许可请求。报告发出,下一项工作在同一轮次中开始。 如果你发现自己在写“是否继续?”,请删掉它。正在关注的人类会打断你,不在关注的人类则被你用问题终止了他们的运行。 报告*已验证的成果*,而非尝试的内容。没有验证结果的任务只是被携带,而非完成。 ## 需要时间学习的实用技巧 这些细节虽小,但每种都有一个看似其他问题的故障模式。 **验证生成的会话确实已启动**。启动器报告工作区*已创建*,但这与代理*运行*不同。检查进程,并检查其工作目录: ```bash launched_at=$(date +%s) # ... 生成会话 ... # 然后只接受启动时间晚于 $launched_at 的进程 ``` 在启动前立即捕获参考时间戳。一个基于“晚于上一个会话”过滤的筛选器,会愉快地接纳一个在此期间启动的不相关会话,如果该会话的工作目录不同,一次健康的启动看起来就像出了故障。 **会话名称不是你可以猜到的地址**。你给工作区取的名称,通常不是消息层使用的名称。在寻址一个会话前,请重新列出活跃会话,不要重用你早先读取过的名称。 **短标识符是显示前缀,不是键**。任务板通常显示截断的ID。将其补全为全长标识符会产生一个格式正确但不存在的值。通过搜索有特色的标签子串来解析它。 **搜索标签,而非你的转述**。日志条目的标题通常是撰写会话对其所做工作的框定,而非卡片的真实标签。搜索前者会一无所获,并被解读为“无此卡片”。 **在共享工作树中,切勿使用裸提交**。`git add`后跟`git commit`会提交*整个索引*,包括并发会话已暂存的任何内容。使用`git commit <files>`。

相似文章

shanraisshan/claude-code-best-practice

GitHub Trending (daily)

一份全面的Claude Code最佳实践指南,涵盖子代理、命令、技能和编排工作流,帮助从'氛围编码'过渡到'代理工程'。