AI Agent Orchestration 是什么:多 Agent 真正难的是共享状态和交接
如果你只用一个 Agent,很多问题其实都不复杂。给它任务、给它工具、让它跑测试,做完以后你看结果就行。真正开始变麻烦,往往是你同时把 Codex、Claude Code、Cursor,甚至一些自动化 worker 接进同一个仓库之后。
这时候最先暴露出来的问题通常不是“谁更聪明”,而是很朴素的协作问题:Claude 以为 Codex 还没开始,所以自己也改了同一个文件;一个定时任务已经被配置好了,另一个 Agent 就把它当成“已经成功执行”;某个任务在聊天里发出去了,但接收方根本没有真正确认;前一个 Agent 基于旧 commit 做完分析,后一个 Agent 接手时仓库已经变了,却还沿着旧状态继续做。
这些问题靠“再加一个 orchestrator”并不会自动消失。路由只解决了任务该交给谁,真正可靠的多 Agent 编排还要解决另一层:谁现在拥有这项工作,大家以哪份状态为准,交接是否被真正接收,执行能力是否匹配,完成以后又是谁验证的。
我最近在 GitHub 上看到一个很极端但很有参考价值的例子:microcredit-agent-testbed 的 central message board。这个项目把 Hermes、Claude Code 和 Codex / ChatGPT 分成不同工作 lane,用一个公开 issue 加一份 canonical world model 协调任务。它的业务背景并不是重点,我真正感兴趣的是里面反复强调的几条规则:一个 request 不等于对方已经接单,一个 schedule 不等于任务真的跑过,配置成功也不等于后续执行成功。
这让我重新看了一遍自己之前写的 Agent Orchestration。以前我更关注“怎么把任务拆给不同角色”,现在我觉得还少了一层:routing 只是编排的入口,shared state 和 handoff 才是多 Agent 真正开始工程化的地方。
编排不是“多叫几个 Agent”,而是先把 ownership 说清楚
OpenAI 现在的 Orchestration and handoffs 文档把两种模式分得很清楚。一种是 handoff:下一个 specialist 真正接管这段工作;另一种是 agents-as-tools:外层 manager 仍然负责最终结果,只把某个子任务交给 specialist。
这个区别很重要,因为它其实是在回答一个最核心的问题:到底谁拥有当前结果。
如果 manager 一直负责,那 specialist 更像一个函数,做完以后把结果交回来;如果发生 handoff,控制权就真的移动了。很多多 Agent 工作流之所以越来越乱,就是因为代码层面做了 delegation,状态层面却没有明确 ownership。每个 Agent 都知道“有人在做”,但没人能准确回答“现在究竟是谁负责”。
拿 Coding Agent 来说,一个最简单的 bug 修复流程可能是:
issue
-> triage agent
-> implementation agent
-> review agent
看起来已经很合理了。但如果 implementation agent 已经接手,triage agent 还能不能继续改同一个 scope?review agent 是只读,还是也能直接修?implementation agent 说 DONE 以后,算不算任务真正结束?如果 review 没过,是回到 WORKING,还是重新发起一个新任务?
这些问题如果只藏在 prompt 里,最后很容易靠模型“理解个大概”。我现在更倾向于把它们变成一份很小的协调契约。至少让每次 handoff 都能说清楚:request id、sender、receiver、owner、deliverable、source revision、dependency、acceptance test、需要的 capability、失败 fallback,以及当前 status。
这不是为了把 Agent 工作流做成另一个 Jira,而是为了让那些最容易产生误会的状态不再靠聊天上下文猜。
我最后给自己压出来的状态其实很简单:
REQUESTED
-> ACKNOWLEDGED
-> WORKING
-> DONE
-> VERIFIED
这里最关键的不是五个单词,而是不能偷跳。
消息发出去了,只能证明 REQUESTED;只有接收方自己确认,才算 ACKNOWLEDGED。定时任务被创建,也不能直接推断它已经 DONE。Agent 自己说做完了,可以进入 DONE,但只有拿到测试、diff、日志或其他验证证据,才应该进入 VERIFIED。
这看起来有点保守,可一旦 Agent 数量上来,它反而会让系统轻很多。因为每个人不需要重新读完整聊天记录来判断发生了什么,只要读 canonical state 和最近几条 receipt 就够了。
我把这些规则写成了一个很小的 validator
只讲协议还是太虚,所以我在 Content Lab 里做了一个第一方实验,没有运行上面那个第三方仓库的任何代码,只拿 synthetic fixture 测协调规则本身。
第一部分是一个 coordination-contract validator。我故意构造了几种最常见的坏状态:两个 Agent 同时声称自己是同一 scope 的 active owner;任务直接标成 DONE,但没有 receiver acknowledgement;handoff 绑定的是旧 source revision;分配给某个 Agent 的任务需要 merge capability,但它实际上只有 read / write;任务完成了却没有 verification evidence;同一个外部动作已经有 active request,又重复发起一次;以及一条已经被 supersede 的任务仍然保持 active。
8 组 fixture 全部按预期被识别。
这个结果本身不复杂,我也不会把它写成“已经证明多 Agent 冲突率下降”。它能证明的只有一件事:很多看起来像 Agent 智能问题的协作错误,其实是可以在模型之外做确定性检查的。
比如 capability mismatch 就很典型。我们平时很容易笼统地说“这个 Agent 有 GitHub 权限”,但实际运行里,read、edit、push、merge、deploy、访问 secret、对外发送消息,根本不是同一种能力。某次交互式 session 能 push,也不代表一个 scheduled worker 在另一个环境里同样能 push。
所以我现在越来越不喜欢用一个模糊的 has access 来描述 Agent。更合理的方式是让任务声明自己需要什么 capability,再由运行环境明确回答有没有。
这和 Claude Code 当前的设计方向其实也能对上。Claude Code 的 subagents 文档 现在明确把每个 subagent 做成独立 context,可以限制工具和 permission;如果需要隔离仓库修改,还可以放进单独 worktree。文档也建议,在任务需要大量独立探索、工具权限限制或能独立返回结果时使用 subagent;如果多个阶段共享大量上下文、需要频繁来回迭代,主会话反而更合适。换句话说,多 Agent 并不是越多越好,真正值得拆的,是那些边界本来就不同的工作。
我做的第二部分实验,则专门测 receipt replay。
我让一个 append-only event log 从 REQUESTED 一路走到 VERIFIED,然后故意测试几种非法跳转。REQUESTED -> WORKING 会被拒绝,因为“发出任务”不能自动推断“对方已经接单”;REQUESTED -> DONE 也会被拒绝,因为调度、配置或者触发请求本身都不是执行结果;如果 ACKNOWLEDGED 不是 receiver 自己写的,也不算有效;VERIFIED 没有 evidence 同样过不了。
7 组 replay 检查全部通过,而且删除 derived state 以后,可以只靠 event log 重新推导出最终 VERIFIED 状态。
这点对长时间运行的 Agent workflow 很重要。状态如果只存在某个聊天窗口里,窗口一断、上下文一压缩、执行换到另一个机器,很容易就开始靠推断继续工作。可只要 request、ack、done、verify 这些 receipt 是持久化的,新的 Agent 不需要“相信前一个 Agent 说了什么”,它只需要读事实。
GitHub 很适合做这层控制面,但别把它当成万能数据库
做到这里,我反而觉得 GitHub 很适合个人开发者先把这层搭起来。
不是因为 GitHub 天生就是 Agent orchestration 平台,而是它刚好有几个很适合做控制面的属性:状态能版本化,修改有作者和时间,commit 可以当 revision,issue / PR 能挂证据,仓库文件又能被 Codex、Claude Code 这类工具直接读。对小团队或者个人项目来说,你不一定需要先上一个专门的 orchestration backend,先把 canonical state 固定在仓库里,就已经能解决不少跨会话问题。
我自己的 Content Lab 现在其实就在这么做。当前 topic、active Dossier、上一条 command、下一条 command 都会持久化;Dossier 的状态从 DISCOVERED、SCORED、RESEARCHING、READY_FOR_TEST 一路追加,不靠某一个聊天窗口记住“我们现在做到哪了”。这次实验也顺手验证了:active pointer、explicit next command 和 append-only state history 都可以在同一套 GitHub-backed 工作流里稳定使用。
但我不建议把所有运行时状态都一股脑塞进仓库。高频锁、毫秒级 lease、大规模消息队列、临时 token、敏感凭据,这些显然不是 Git 的强项。GitHub 更适合保存那些需要跨 session、跨 Agent、可追溯的 durable facts。
我会把它想成两层:
runtime state
-> 临时执行、锁、流式消息、短生命周期状态
canonical coordination state
-> owner、revision、handoff、receipt、evidence、最终 decision
前一层可以是数据库、队列、SDK session,后一层则需要“过几天再回来还能知道当时发生了什么”。
OpenAI 当前的 Running agents 也把 state 明确拆成不同 continuation strategy:你可以自己保存 history,也可以用 session、server-managed continuation,或者恢复一个被 interruption 暂停的 run。与此同时,Agents SDK 的 observability 文档 会记录 model call、tool call、handoff、guardrail 等 trace。对我来说,这两层刚好说明了一件事:执行状态和可审计状态都需要设计,不能只靠 prompt。
真正应该先补的,是“谁做了什么”的证据链
回头看原来那篇 orchestration,我现在还是认同一个原则:如果一个 Agent 就能稳定做完,不要为了架构好看硬拆成五个 Agent。OpenAI 当前文档也直接建议,能从一个 Agent 开始就先从一个开始,只有在 capability isolation、policy isolation、prompt clarity 或 trace legibility 真正需要时再加 specialist。
但一旦你已经开始用多个 Agent,我会比以前更早补 shared state。
不是先上更复杂的 supervisor,也不是先研究谁来做 planner、谁来做 reviewer,而是先把几个很基础的问题钉死:一个 scope 同一时间谁负责;接收方有没有真的确认;任务基于哪个 revision;这个 Agent 到底具备什么能力;DONE 后有什么 evidence;出了问题以后能不能从 receipt 重新还原发生过什么。
这层东西不酷,也不会让 demo 看起来更“智能”。可真正长期运行以后,它比多加一个 Agent 更重要。
因为多 Agent 系统最怕的并不是某个模型偶尔答错,而是每个 Agent 都各自合理,合在一起却没人知道真实状态。一个 Agent 以为任务没人做,一个 Agent 以为自己已经完成,一个自动化以为 schedule 已经执行,一个 reviewer 又在旧 revision 上验收——最后所有局部判断都说得通,整体却已经失真。
所以现在如果有人问我 Agent Orchestration 到底是什么,我不会只回答“让多个 Agent 分工协作”。
我会更愿意把它说成:把任务、状态、权限和证据组织成一条不会靠猜的工作流。
路由决定下一步交给谁;ownership 决定谁现在负责;handoff 负责把上下文和边界交过去;receipt 证明对方真的接了;capability boundary 防止任务交给一个根本做不了的人;trace 和 evidence 则让你以后还能解释这件事为什么变成现在这样。
如果你正在继续把 Coding Agent 往真实项目里接,前面那篇 CLAUDE.md 太长怎么办:我重新拆了一遍 AGENTS.md、Skills 和 CI 的边界 更偏“规则应该放在哪里”;这篇解决的是下一层问题:当不止一个 Agent 开始一起工作以后,这些 Agent 怎么共享一份可信的现实。