酷壁壁纸
52.05M · 2026-04-01
想象你是一个项目经理(主 Agent),需要完成一个复杂项目。你有两种协调方式:
OpenClaw 的多 Agent 系统就是基于这两个核心工具设计的。本文将解析它们的工作机制和设计哲学。
sessions_spawn({
agent: "code-reviewer", // 要启动的 Agent
task: "审查 PR #123", // 任务描述
mode: "run", // run=一次性, session=持久化
thread: false // 是否绑定到消息线程
})
本质:Fork 一个新进程
sessions_send({
sessionKey: "agent:code-reviewer:subagent-abc",
message: "能再检查一下安全性吗?",
timeoutSeconds: 30 // 等待回复时间
})
本质:进程间通信(IPC)
用户请求 → Main Agent → 调用 sessions_spawn
↓
[1. 权限验证] → 检查深度、并发数、白名单
↓
[2. 会话创建] → 生成唯一 session key
↓
[3. 线程绑定] → (可选) 绑定到 Discord/Slack 线程
↓
[4. 附件处理] → 快照传递附件内容
↓
[5. 系统提示] → 注入任务上下文和能力说明
↓
[6. 工作目录] → 继承或使用目标 Agent 配置
↓
[7. Agent 启动] → 通过 Gateway RPC 启动
↓
[8. 运行注册] → 记录到 SubagentRegistry
↓
[9. 钩子触发] → 通知插件(如 Discord)
↓
[10. 结果返回] → 返回 childSessionKey 给父 Agent
| 约束类型 | 默认值 | 作用 |
|---|---|---|
| 最大递归深度 | 1 层 | 防止无限递归 |
| 最大子进程数 | 5 个/会话 | 防止资源耗尽 |
| 白名单机制 | 需配置 | 跨 Agent 权限控制 |
配置示例:
{
agents: {
list: [
{
id: "main",
subagents: {
allowAgents: ["code-reviewer", "doc-writer"] // 白名单
}
}
]
}
}
主 Agent: agent:main:main
子 Agent: agent:main:subagent:<uuid>
孙 Agent: agent:main:subagent:<uuid>:subagent:<uuid>
为什么用 UUID?
| 特性 | mode="run" | mode="session" |
|---|---|---|
| 生命周期 | 一次性,完成即删除 | 持久化,等待后续消息 |
| 线程绑定 | 不支持 | 必需(thread=true) |
| 用户可见性 | 完全不可见 | 在线程中可见 |
| 适用场景 | 后台数据处理 | 多轮对话、代码审查 |
实际对比:
用户: "分析这个日志"
Main Agent: "正在分析..."
→ sessions_spawn({ agent: "analyzer", mode: "run" })
→ [analyzer 后台执行,用户看不到]
→ 完成后推送结果给 Main Agent
Main Agent: "分析完成,发现 3 个错误..."
用户: "审查这段代码"
Main Agent: "已启动审查"
→ sessions_spawn({
agent: "reviewer",
mode: "session",
thread: true
})
→ Discord 创建线程 "Code Review"
用户(在线程中): "第 42 行有问题吗?"
Reviewer Agent: "是的,这里有空指针风险..."
用户: "如何修复?"
Reviewer Agent: "可以使用 Optional..."
轮询方案的成本:
假设子任务运行 30 秒,每秒轮询 1 次
→ 30 次查询 × 500 tokens = 15,000 tokens 浪费!
OpenClaw 的推送方案:
子 Agent 完成 → 结果冻结到 SubagentRegistry
↓
后台 Sweeper(1-8 秒检查一次)
↓
自动推送到父 Agent 会话(deliver=false)
↓
父 Agent 接收内部消息:
[Subagent Completion]
Status: ok
Result: <<<分析完成,发现 3 个错误...>>>
重试机制:
Agent A 调用 sessions_send
↓
[1. 目标解析] → 通过 sessionKey 或 label 查找
↓
[2. 权限检查] → A2A 策略 + 沙箱限制
↓
[3. 消息投递] → 启动目标 Agent
↓
[4. 等待回复] → (可选) 同步等待
↓
[5. A2A 协商] → 多轮 ping-pong(最多 5 轮)
↓
[6. 最终通知] → 投递到原始频道
Agent A (requester) Agent B (target)
│
├─ "请格式化代码" ──────→ │
│ ├─ "需要哪种风格?"
│ ← ─────────────────── │
│
├─ "使用 Prettier" ─────→ │
│ ├─ "完成了"
│ ← ─────────────────── │
│
├─ REPLY_SKIP ─────────→ │ (结束协商)
│
│ ├─ 最终通知
│ ← ─────────────────── │
│
└─ 投递到用户频道 ────────→ User
" 代码已格式化"
协商控制:
REPLY_SKIP_TOKEN 结束ANNOUNCE_SKIP_TOKEN 保持沉默const result = await sessions_send({
sessionKey: "agent:formatter:session-123",
message: "格式化这段代码",
timeoutSeconds: 30 // 等待 30 秒
});
console.log(result.reply); // 同步获得回复
// 后台继续进行 A2A 协商流程
sessions_send({
sessionKey: "agent:formatter:session-123",
message: "格式化代码",
timeoutSeconds: 0 // 立即返回
});
// 后台进行 A2A 协商,最终结果投递到频道
Main Agent
├─ spawn analyzer-1 (处理分片 A)
├─ spawn analyzer-2 (处理分片 B)
└─ spawn analyzer-3 (处理分片 C)
↓ ↓ ↓ (并行执行)
← announcement 1
← announcement 2
← announcement 3
综合结果 → 回复用户
// 创建专家 Agent(持久化)
sessions_spawn({
agent: "security-expert",
label: "security",
mode: "session"
});
sessions_spawn({
agent: "performance-expert",
label: "performance",
mode: "session"
});
// 主 Agent 向专家提问
const security = await sessions_send({
label: "security",
message: "这段代码有安全风险吗?"
});
const performance = await sessions_send({
label: "performance",
message: "性能瓶颈在哪?"
});
// 综合专家意见
return synthesize(security, performance);
PDF → Extractor → 原始文本 → Cleaner → 清洁文本 → Summarizer → 摘要
(spawn) (announce) (spawn) (announce) (spawn) (announce)
问题场景:
mode="session" + thread=false
→ 子 Agent 会话保持打开
→ 用户发送后续消息 "继续"
→ 消息去哪里? 无法路由
解决方案:强制 thread=true
mode="session" + thread=true
→ Discord 创建线程,绑定到子 Agent
→ 用户在线程中的消息自动路由
| 方式 | 优点 | 缺点 | 采用 |
|---|---|---|---|
| 引用传递 | 节省存储 | 父删除,子引用失效 | |
| 快照传递 | 独立生命周期 | 占用更多存储 |
快照传递的优势:
Main Agent 传递附件 → 子 Agent 获得完整副本
→ Main Agent 清理 → 子 Agent 仍可访问
Main Agent (workspace: /project/main)
├─ 同类型子 Agent → 继承 /project/main
└─ 跨 Agent 子 Agent (code-reviewer)
→ 使用 /project/reviews
原因:
1. 每个 Agent 有自己的工作约定
2. 防止权限越界
3. 安全隔离
| 场景 | Mode | Thread | 用户可见性 | 原因 |
|---|---|---|---|---|
| 后台任务 | run | false | 不可见 | deliver=false |
| 持久会话 | session | true | 在线程中可见 | 线程绑定 |
| 嵌套子 Agent | run | false | 不可见 | 父是子 Agent |
适合:
不适合:
适合:
不适合:
基础配置:
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 1, // 一层子 Agent
maxChildrenPerAgent: 5, // 最多 5 个并行
runTimeoutSeconds: 300 // 5 分钟超时
}
}
},
session: {
agentToAgent: {
enabled: true,
allow: ["*"], // 允许所有跨 Agent 通信
maxPingPongTurns: 5
}
}
}
高级配置(复杂任务):
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // 两层嵌套
maxChildrenPerAgent: 10, // 更多并行
runTimeoutSeconds: 600 // 更长超时
}
}
}
}
| 原则 | 实现 | 收益 |
|---|---|---|
| 推送优于轮询 | 自动 announcement | 零轮询成本 |
| 隔离优于共享 | 独立会话、工作目录 | 避免冲突 |
| 声明优于命令 | 工具调用 | LLM 友好 |
| 异步优于同步 | 后台执行 | 高并发 |
| 快照优于引用 | 附件复制 | 独立生命周期 |
| 场景 | 工具 | 模式 |
|---|---|---|
| 后台任务处理 | sessions_spawn | mode: "run" |
| 并行数据分析 | sessions_spawn | mode: "run" |
| 多轮代码审查 | sessions_spawn | mode: "session", thread: true |
| Agent 间协作 | sessions_send | timeoutSeconds: 30 |
| 实时问答 | sessions_send | timeoutSeconds: 15 |
OpenClaw 的多 Agent 通信机制不仅适用于代码助手,更是构建自主 AI 系统的基础设施。