2026 年,AI 助手正在从「单一对话」走向「多角色协作」。但多 Agent 不是把几个 AI 放在一起就行------你需要理解两种截然不同的协作机制。
引言:你以为的多 Agent,和真正的多 Agent
很多人第一次听到「多 Agent」,脑子里浮现的画面是这样的:一个 Agent 负责写代码,一个负责调研,一个负责审核,它们像真人团队一样自动协作。
这个画面没错,但只对了一半。
在 OpenClaw 的架构中,「多 Agent」实际上包含两种完全不同的机制:
- Multi-Agent Routing:多个隔离的 Agent 并行运行,各管各的
- Sub-Agents:一个 Agent 在运行中派生出子任务,后台并行执行
这两者解决的是完全不同的问题。混淆它们,是大多数人踩坑的起点。
一、Multi-Agent Routing:一台服务器,多个大脑
1.1 它解决什么问题?
想象一下:你用 OpenClaw 连接了 WhatsApp 和 Telegram。WhatsApp 用来处理日常琐事,Telegram 用来做深度技术思考。你不希望它们共享记忆、混淆人格------你需要两个完全隔离的 Agent。
这就是 Multi-Agent Routing 的核心:一个 Gateway 进程,托管多个互不干扰的 Agent。
1.2 一个 Agent 到底包含什么?
每个 Agent 是一个完全独立的作用域,拥有自己的:
| 组成部分 | 路径 | 说明 |
|---|---|---|
| Workspace | ~/.openclaw/workspace-<id> |
工作目录,存放 AGENTS.md、SOUL.md 等人格文件 |
| State Directory | ~/.openclaw/agents/<id>/agent |
认证配置、模型注册 |
| Session Store | ~/.openclaw/agents/<id>/sessions |
对话历史、路由状态 |
| Auth Profiles | ~/.openclaw/agents/<id>/agent/auth-profiles.json |
独立的认证凭据 |
关键点 :Agent 之间的认证配置不共享 。主 Agent 的凭据不会自动传递给其他 Agent。如果需要共享,你得手动拷贝 auth-profiles.json。
1.3 Bindings:消息路由的核心
Bindings 决定了一条入站消息应该发给哪个 Agent。路由是确定性的,按以下优先级从高到低匹配:
peer匹配(精确到某个人/某个群)parentPeer匹配(线程继承)guildId + roles(Discord 角色路由)guildId(Discord 服务器)teamId(Slack 团队)accountId匹配(频道账号)accountId: "*"(频道通配)- 兜底到默认 Agent(
agents.list[].default或列表第一个)
同一优先级内,配置文件中先出现的规则先匹配。多个匹配字段之间是 AND 关系。
1.4 实战配置:按频道分流
最经典的场景------WhatsApp 用快速模型处理日常,Telegram 用强模型做深度工作:
json5
{
agents: {
list: [
{
id: "chat",
name: "Everyday",
workspace: "~/.openclaw/workspace-chat",
model: "anthropic/claude-sonnet-4-5",
},
{
id: "opus",
name: "Deep Work",
workspace: "~/.openclaw/workspace-opus",
model: "anthropic/claude-opus-4-6",
},
],
},
bindings: [
{ agentId: "chat", match: { channel: "whatsapp" } },
{ agentId: "opus", match: { channel: "telegram" } },
],
}
1.5 实战配置:同频道精确路由
在同一个 WhatsApp 号码上,把某个特定联系人路由到不同 Agent:
json5
{
bindings: [
// peer 匹配优先级最高,放在前面
{
agentId: "opus",
match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551234567" } },
},
// 其余所有 WhatsApp 消息走 chat
{ agentId: "chat", match: { channel: "whatsapp" } },
],
}
Peer 级别的匹配永远优先于频道级别。所以把精确规则放在前面。
1.6 实战配置:多人共享一台 Gateway
不同的人通过不同的 WhatsApp DM 进来,路由到各自的 Agent:
json5
{
agents: {
list: [
{ id: "alex", workspace: "~/.openclaw/workspace-alex" },
{ id: "mia", workspace: "~/.openclaw/workspace-mia" },
],
},
bindings: [
{
agentId: "alex",
match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551230001" } },
},
{
agentId: "mia",
match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551230002" } },
},
],
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15551230001", "+15551230002"],
},
},
}
注意:DM 访问控制是全局的(per WhatsApp account),不是 per agent。
1.7 CLI 操作
bash
# 添加新 Agent
openclaw agents add coding
openclaw agents add social
# 查看所有 Agent 及绑定
openclaw agents list --bindings
# 绑定路由
openclaw agents bind --agent coding --bind telegram:ops --bind discord:guild-a
# 解绑
openclaw agents unbind --agent coding --bind telegram:ops
# 设置 Agent 身份
openclaw agents set-identity --agent main --name "OpenClaw" --emoji "🦞"
# 删除 Agent
openclaw agents delete coding
# 重启生效
openclaw gateway restart
1.8 Per-Agent 安全隔离
每个 Agent 可以独立配置沙箱和工具权限:
json5
{
agents: {
list: [
{
id: "personal",
workspace: "~/.openclaw/workspace-personal",
sandbox: { mode: "off" }, // 不沙箱化
// 不限制工具
},
{
id: "family",
workspace: "~/.openclaw/workspace-family",
sandbox: {
mode: "all", // 始终沙箱化
scope: "agent", // 每个 Agent 独立容器
},
tools: {
allow: ["read"],
deny: ["exec", "write", "edit", "apply_patch"],
},
},
],
},
}
一句话总结 Multi-Agent Routing:它不是「让 Agent 协作」,而是「让多个独立 Agent 互不干扰地服务不同场景」。
二、Sub-Agents:后台并行的任务分身
2.1 它解决什么问题?
你正在和 Agent 对话,突然需要它同时做三件事:查一份资料、写一段代码、整理昨天的笔记。
单线程模式下,它只能一件一件来。你等。它做。你再等。
Sub-Agents 的思路是:从当前对话中派生出后台任务,并行执行,完成后自动汇报回来。
2.2 核心机制
Sub-Agent 的本质是:在独立 session 中运行的后台 Agent。
- Session Key:
agent:<agentId>:subagent:<uuid> - 运行方式:非阻塞 ,
sessions_spawn立即返回{ status: "accepted", runId, childSessionKey } - 结果回传:完成后通过 Announce 机制自动向发起者的聊天频道发送结果
2.3 斜杠命令
bash
/subagents list # 查看当前 session 的子 Agent
/subagents spawn <agentId> <task> # 启动子 Agent
/subagents kill <id|#|all> # 终止子 Agent
/subagents log <id|#> [limit] [tools] # 查看子 Agent 日志
/subagents info <id|#> # 查看运行元数据
/subagents send <id|#> <message> # 向子 Agent 发消息
/subagents steer <id|#> <message> # 引导子 Agent 方向
/focus <target> # 将当前线程绑定到某个子 Agent
/unfocus # 解除绑定
/subagents spawn 是用户命令,one-shot 模式。执行完成后,结果会自动 announce 回来。
2.4 sessions_spawn 工具详解
这是 Agent 在运行时通过 tool_use 调用的工具(不是外部 API):
参数列表:
| 参数 | 必填 | 说明 |
|---|---|---|
task |
✅ | 任务描述 |
label |
否 | 标签,用于追踪 |
agentId |
否 | 指定在哪个 Agent 下运行(需 allowAgents 授权) |
model |
否 | 覆盖子 Agent 使用的模型 |
thinking |
否 | 覆盖 thinking 级别 |
runTimeoutSeconds |
否 | 超时秒数(0 = 不限时) |
thread |
否 | true 时绑定到频道线程 |
mode |
否 | run(默认,one-shot) / session(需 thread: true) |
cleanup |
否 | keep(默认) / delete(完成后立即归档) |
sandbox |
否 | inherit(默认) / require(要求沙箱化) |
关键行为:
- 立即返回,不阻塞当前对话
- 子 Agent 继承父级模型,除非你显式覆盖
- 完成后自动运行 Announce 步骤,将结果推送回发起者
- 子 Agent session 默认 60 分钟后自动归档
2.5 Announce 机制:结果如何回来
这是 Sub-Agents 最精妙的设计。子 Agent 完成任务后:
- 在子 Agent session 内运行一个 announce 步骤
- 生成标准化的结果消息,包含:
- Status :
completed successfully/failed/timed out(来自运行时信号,不是模型自述) - Result:助手回复文本(如果为空,取最后一个 toolResult)
- Stats:运行时间、Token 用量、预估成本、sessionKey、transcript 路径
- Status :
- 投递到发起者的聊天频道
- 发起者 Agent 收到后,用自己的风格重新表述(不是转发原始内容)
投递有容错机制:先尝试直接 agent delivery → 失败则回退到队列路由 → 再失败则指数退避重试。
如果子 Agent 回复 ANNOUNCE_SKIP,则静默不汇报。
2.6 嵌套 Sub-Agents:编排模式
默认 maxSpawnDepth: 1,子 Agent 不能再派生子 Agent。设为 2 可以启用编排模式:
scss
Main (depth 0)
└─ Orchestrator (depth 1) ← 有 sessions_spawn 权限
├─ Worker A (depth 2) ← 叶子节点,无法再派生
└─ Worker B (depth 2)
配置:
json5
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // 允许嵌套一层(最大可设 5,推荐 2)
maxChildrenPerAgent: 5, // 每个 session 最多 5 个活跃子 Agent
maxConcurrent: 8, // 全局并发上限
runTimeoutSeconds: 900, // 默认超时 15 分钟
archiveAfterMinutes: 60, // 完成后 60 分钟自动归档
},
},
},
}
结果流向:
scss
Worker (depth 2) 完成 → announce 到 Orchestrator (depth 1)
Orchestrator 综合所有 Worker 结果 → announce 到 Main (depth 0)
Main 收到后 → 回复用户
每一层只看到直接子级的 announce,不会越级。
2.7 工具权限策略
Sub-Agents 的工具权限设计遵循最小权限原则:
| 深度 | 可用工具 | 不可用工具 |
|---|---|---|
| Depth 0(主 Agent) | 全部 | --- |
Depth 1(maxSpawnDepth=1 时) |
全部工具 减去 session 工具 | sessions_list/history/send/spawn |
Depth 1(maxSpawnDepth≥2 时,编排者) |
全部工具 + sessions_spawn/list/history + subagents |
--- |
| Depth 2(叶子 Worker) | 全部工具 减去 session 工具 | sessions_spawn 永远被拒绝 |
可通过配置进一步收紧:
json5
{
tools: {
subagents: {
tools: {
deny: ["gateway", "cron"], // deny 永远优先
// allow: ["read", "exec"], // 设置后变为白名单模式
},
},
},
}
2.8 跨 Agent 派生
Sub-Agent 默认只能在自己的 Agent 下派生。如果想让 Agent A 派生任务给 Agent B 执行:
json5
{
agents: {
list: [
{
id: "main",
subagents: {
allowAgents: ["coder", "researcher"], // 允许派生到这些 Agent
// ["*"] 表示允许任意 Agent
},
},
],
},
}
安全约束:如果发起者 session 是沙箱化的,sessions_spawn 会拒绝派生到非沙箱化的目标。
用 agents_list 工具可以查看当前 Agent 被允许派生到哪些 Agent。
2.9 级联停止
停止操作会自动向下传播:
/stop:停止主 Agent 当前运行 + 所有 depth-1 子 Agent + 级联到 depth-2/subagents kill <id>:停止指定子 Agent + 级联到它的子级/subagents kill all:停止所有子 Agent + 级联
2.10 Sub-Agent 的上下文限制
一个容易忽略的细节:Sub-Agent 的 session 只注入 AGENTS.md + TOOLS.md。
以下文件不会被加载:
SOUL.md(人格)IDENTITY.md(身份)USER.md(用户信息)HEARTBEAT.mdBOOTSTRAP.md
这意味着 Sub-Agent 是一个「干活的工具人」,它不继承主 Agent 的人格和社交习惯。这是有意为之的设计------减少上下文消耗,专注于任务本身。
三、两种机制的本质区别
理解了细节之后,让我们拉远视角看全局。
| 维度 | Multi-Agent Routing | Sub-Agents |
|---|---|---|
| 本质 | 多个独立大脑并行存在 | 一个大脑派生出临时工 |
| 关系 | 平级,互不知晓 | 主从,子向父汇报 |
| 隔离级别 | 完全隔离(Workspace + Auth + Session) | Session 隔离(共享同一 Agent 的 Auth) |
| 触发方式 | 由消息来源自动路由 | 由 Agent 主动 spawn |
| 生命周期 | 持久存在 | 任务完成后归档 |
| 上下文 | 完整加载所有 workspace 文件 | 仅加载 AGENTS.md + TOOLS.md |
| 典型场景 | 工作/生活分离、多人共享、按频道分流 | 后台调研、并行任务、编排复杂工作流 |
一个常见误解:用 Multi-Agent Routing 来实现「统筹者分发任务给工程师」。
错了。Routing 是基于消息来源(哪个频道、哪个账号、哪个联系人)的确定性路由。它不会「分析需求然后选择合适的 Agent」。
如果你想要的是「一个 Agent 分析需求,然后分派给不同角色去执行」------这是 Sub-Agents 的活。
正确的组合方式:
vbnet
Multi-Agent Routing(按场景隔离)
├─ Agent "work"(工作场景)
│ └─ Sub-Agent: 调研任务
│ └─ Sub-Agent: 代码任务
├─ Agent "personal"(生活场景)
│ └─ Sub-Agent: 订餐查询
└─ Agent "family"(家庭共享,受限工具)
四、实战建议
4.1 先路由,再编排
不要一上来就搞复杂的多 Agent 编排。先问自己:
- 我有几个互不相干的使用场景?→ 用 Routing 隔离
- 在某个场景内,我需要并行处理多个子任务?→ 用 Sub-Agents
大部分个人用户,2-3 个 Routing Agent + 偶尔的 Sub-Agent 就够了。
4.2 模型成本策略
Sub-Agent 有自己独立的上下文和 Token 消耗。推荐:
json5
{
agents: {
defaults: {
subagents: {
model: "anthropic/claude-sonnet-4-5", // 子 Agent 用便宜模型
},
},
list: [
{
id: "main",
model: "anthropic/claude-opus-4-6", // 主 Agent 用强模型
},
],
},
}
主 Agent 负责理解和决策(用好模型),Sub-Agent 负责执行具体任务(用快模型)。
4.3 设置合理的超时和并发
json5
{
agents: {
defaults: {
subagents: {
runTimeoutSeconds: 300, // 5 分钟超时,避免跑飞
maxChildrenPerAgent: 3, // 每个 session 最多 3 个并行子任务
maxConcurrent: 5, // 全局最多 5 个并发子 Agent
archiveAfterMinutes: 30, // 完成后 30 分钟归档
},
},
},
}
不要把并发开太大。Sub-Agent 共享同一个 Gateway 进程资源,maxConcurrent 是安全阀。
4.4 注意 Announce 的局限性
Sub-Agent 的 announce 是尽力投递(best-effort):
- Gateway 重启 → 未完成的 announce 会丢失
- Announce 成功不代表用户一定看到了(取决于频道状态)
- 对于关键任务,完成后主动用
/subagents log <id>确认结果
4.5 Session 可见性控制
默认配置下,session 工具的可见范围是 tree(当前 session + 它派生的子 session)。如果需要扩大:
json5
{
tools: {
sessions: {
visibility: "agent", // 可选: "self" | "tree" | "agent" | "all"
},
},
}
对于沙箱化的 session,可见性会被进一步收紧到 spawned(仅派生的子 session),即使你配了 all 也会被降级。
五、一个完整的配置示例
把上面所有知识串起来,一个真实可用的配置:
json5
{
agents: {
list: [
{
id: "work",
default: true,
name: "Work",
workspace: "~/.openclaw/workspace-work",
model: "anthropic/claude-opus-4-6",
identity: { name: "Work Brain", emoji: "🧠" },
subagents: {
allowAgents: ["work"], // 只允许在自己的 Agent 下派生
},
},
{
id: "personal",
name: "Personal",
workspace: "~/.openclaw/workspace-personal",
model: "anthropic/claude-sonnet-4-5",
identity: { name: "Daily Helper", emoji: "☀️" },
},
{
id: "family",
name: "Family",
workspace: "~/.openclaw/workspace-family",
identity: { name: "Family Bot", emoji: "👨👩👧👦" },
sandbox: { mode: "all", scope: "agent" },
tools: {
allow: ["read", "exec", "sessions_list", "sessions_history"],
deny: ["write", "edit", "apply_patch", "browser"],
},
},
],
defaults: {
subagents: {
model: "anthropic/claude-sonnet-4-5",
maxSpawnDepth: 1,
maxChildrenPerAgent: 5,
maxConcurrent: 8,
runTimeoutSeconds: 300,
archiveAfterMinutes: 60,
},
},
},
bindings: [
// 家庭群路由到 family agent
{
agentId: "family",
match: {
channel: "whatsapp",
peer: { kind: "group", id: "120363999999999999@g.us" },
},
},
// 工作 Telegram 路由到 work
{ agentId: "work", match: { channel: "telegram" } },
// 其余 WhatsApp 消息路由到 personal
{ agentId: "personal", match: { channel: "whatsapp" } },
],
tools: {
sessions: { visibility: "tree" },
agentToAgent: { enabled: false },
},
}
写在最后
Multi-Agent Routing 和 Sub-Agents 是两把不同的刀:
Routing 解决的是「我有多重身份」------工作的我、生活的我、面对家人的我,各自独立,互不干扰。
Sub-Agents 解决的是「我需要分身术」------一边调研、一边写代码、一边整理笔记,并行推进,最终汇总。
理解这个区别,你就不会犯「拿路由当编排」或「拿编排当隔离」的错误。
而真正高效的用法,是两者组合:先用 Routing 划清边界,再在每个边界内用 Sub-Agents 提升并行度。