多 Agent 之间如何通信和协调?OpenClaw 的 Gateway 在其中扮演什么角色?

魏远标 Lv7

参考答案

OpenClaw 里多 Agent 之间的通信主要靠两条路。

第一条是 Announce 机制(公告机制)。子 Agent 完成任务后,自动把结果发回父 Agent 所在的 session,本质上是异步通知,就像你派助手去办事,他办完了会主动回来汇报,你不需要每隔几秒打电话问”好了没”。

第二条是斜杠命令交互。通过 /subagents send 可以主动给子 Agent 发消息,用于父 Agent 需要追加指令或者中途纠偏的场景。

Gateway 在这里面扮演的是中央调度器的角色。所有 Agent 的运行都经由 Gateway 分发和排队,子 Agent 的 announce 消息也是通过 Gateway 路由到正确的 session。没有 Gateway,Agent 之间就是各跑各的,消息投递和执行顺序全乱套。

多 Agent 通信流程:

  1. 用户发消息到 Gateway,Gateway 路由到父 Agent 执行
  2. 父 Agent 需要子 Agent 协助时,通过 Gateway spawn 子 Agent
  3. 子 Agent 执行完毕后通过 Announce 机制将结果发回 Gateway
  4. Gateway 再路由到父 Agent 的 session
  5. 父 Agent 也可以通过 Gateway 的斜杠命令主动给子 Agent 发送指令。

agt.png

扩展知识

排队与并发控制

多 Agent 并发跑的时候,最容易出问题的就是同一个 session 被多个 Agent run 同时写。

OpenClaw 的 Gateway 用两级排队解决这个问题:

1)Session 级排队,通过 enqueueSession 保证同一个 session 同一时间只有一个 Agent run 在执行。比如父 Agent 正在跑,这时候子 Agent 的 announce 消息到了,不会直接插进来打断,排到 session 队列里等当前 run 结束。

2)全局排队,通过 enqueueGlobal 做总量控制。如果同时 spawn 了 10 个子 Agent,不会一下子全放出去,按全局并发上限分批执行。这防止大量 Agent 同时跑把 LLM API 的 rate limit 打爆。

幂等性保证

子 Agent 的 announce 消息用的是稳定的 idempotency key。网络抖动导致重复投递的时候,Gateway 通过 dedupe map 去重,保证父 Agent 只收到一次结果。

这在 Agent 场景下尤其重要。想想看,如果一个子 Agent 的执行结果被父 Agent 收到两次,后续的决策可能完全跑偏。比如子 Agent 返回了一份数据库查询结果,父 Agent 收到两次就可能重复处理,产生重复操作。

Runtime State 管理

src/gateway/server-runtime-state.ts 维护了一组全局状态,这些是多 Agent 协调的基础设施:

1)dedupe map 做请求去重,幂等性就靠它。

2)agentRunSeq 是 Agent 运行序列号,用来追踪每个 Agent run 的执行顺序和版本。当一个 session 里先后跑了多轮 Agent,序列号可以帮助判断哪个结果是最新的。

3)chatRunState 维护聊天的运行状态,记录当前哪些 session 正在执行、排队了多少请求。Gateway 做调度决策的时候,就是看这个状态来决定放不放行。

Gateway 的请求分发

handleGatewayRequest()req.method 分发到不同的 handler,包括 agent、chat、sessions、send、cron、nodes 等,每类请求都有独立的处理逻辑和错误处理。

子 Agent 的 spawn 请求走 agent handler,最终调用 dispatchAgentRunFromGateway()

这个分发机制让 Gateway 可以统一入口但灵活扩展,新增一种请求类型只要加一个 handler,不影响其他逻辑。

Node 系统

Gateway 还支持 nodes 的概念,允许注册远程节点并把工具执行分发过去。

比如某个工具需要 GPU 环境跑模型推理,Agent 本身跑在普通服务器上,可以把这个工具的执行请求通过 Gateway 路由到有 GPU 的节点。这是另一种维度的分布式协作,不是 Agent 之间的通信,是 Agent 跟计算资源之间的调度。

面试官追问

提问:如果父 Agent 正在等子 Agent 的结果,但子 Agent 挂了一直没返回,你怎么处理?

回答:设超时。给每个子 Agent 配一个最大执行时间,比如 300 秒。超时后 Gateway 主动发一条超时通知到父 Agent 的 session,父 Agent 收到后可以选择重试、换个策略、或者告诉用户这步失败了。关键是不能让父 Agent 无限等下去,不然整个会话就卡死了。同时 Gateway 要主动清理超时的 Agent run,释放队列位。

提问:Session 级排队保证串行,那如果一个 Agent 跑了很久,后面排队的请求全堵了怎么办?

回答:两个手段。一个是给单次 Agent run 设最大执行时间,超了强制终止。另一个是在排队时做优先级区分,用户主动发的消息优先级高于 announce 类的异步通知。如果队列长度超过阈值,可以丢弃低优先级的请求或者返回系统繁忙。本质上跟消息队列的背压策略是一回事。

提问:多个子 Agent 的结果到达顺序是不确定的,父 Agent 怎么保证处理逻辑的正确性?

回答:不要依赖到达顺序。每个子 Agent 的 announce 消息里带上任务 ID 和上下文信息,父 Agent 按任务 ID 匹配处理。如果业务上需要先处理 A 再处理 B,就在父 Agent 的逻辑里自己排序,不要指望消息天然有序。OpenClaw 的 Gateway 通过 agentRunSeq 提供了顺序信息,但怎么用取决于上层的 Agent 逻辑。

目录
多 Agent 之间如何通信和协调?OpenClaw 的 Gateway 在其中扮演什么角色?