引言:Agent 之间如何"对话"?
想象你是一个项目经理(主 Agent),需要完成一个复杂项目。你有两种协调方式:
- 雇佣新员工完成任务(sessions_spawn):招募专家,分配任务,完成后自动提交报告
- 与现有同事实时沟通(sessions_send):向在职同事发消息,进行多轮讨论
OpenClaw 的多 Agent 系统就是基于这两个核心工具设计的。本文将解析它们的工作机制 和设计哲学。
一、核心概念:两种通信模式
1.1 sessions_spawn:创建新的 Agent 实例
typescript
sessions_spawn({
agent: "code-reviewer", // 要启动的 Agent
task: "审查 PR #123", // 任务描述
mode: "run", // run=一次性, session=持久化
thread: false // 是否绑定到消息线程
})
本质:Fork 一个新进程
- 创建独立的会话和执行环境
- 完成后自动推送结果给父 Agent
- 用户默认看不到子 Agent 的执行过程
1.2 sessions_send:向现有会话发送消息
typescript
sessions_send({
sessionKey: "agent:code-reviewer:subagent-abc",
message: "能再检查一下安全性吗?",
timeoutSeconds: 30 // 等待回复时间
})
本质:进程间通信(IPC)
- 向已存在的会话发送消息
- 可同步等待回复
- 支持多轮协商(最多 5 轮 ping-pong)
二、sessions_spawn 深度解析
2.1 完整执行流程:10 个阶段
css
用户请求 → 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
2.2 关键设计:三层安全防护
| 约束类型 | 默认值 | 作用 |
|---|---|---|
| 最大递归深度 | 1 层 | 防止无限递归 |
| 最大子进程数 | 5 个/会话 | 防止资源耗尽 |
| 白名单机制 | 需配置 | 跨 Agent 权限控制 |
配置示例:
json5
{
agents: {
list: [
{
id: "main",
subagents: {
allowAgents: ["code-reviewer", "doc-writer"] // 白名单
}
}
]
}
}
2.3 会话键(Session Key)的设计
ruby
主 Agent: agent:main:main
子 Agent: agent:main:subagent:<uuid>
孙 Agent: agent:main:subagent:<uuid>:subagent:<uuid>
为什么用 UUID?
- 全局唯一(跨机器、跨时间)
- 包含 Agent ID,便于路由
- 层次化结构,可追溯父子关系
2.4 mode: "run" vs "session"
| 特性 | mode="run" | mode="session" |
|---|---|---|
| 生命周期 | 一次性,完成即删除 | 持久化,等待后续消息 |
| 线程绑定 | 不支持 | 必需(thread=true) |
| 用户可见性 | ❌ 完全不可见 | ✅ 在线程中可见 |
| 适用场景 | 后台数据处理 | 多轮对话、代码审查 |
实际对比:
mode="run" 的场景(用户看不到)
css
用户: "分析这个日志"
Main Agent: "正在分析..."
→ sessions_spawn({ agent: "analyzer", mode: "run" })
→ [analyzer 后台执行,用户看不到]
→ 完成后推送结果给 Main Agent
Main Agent: "分析完成,发现 3 个错误..."
mode="session" 的场景(用户可见)
php
用户: "审查这段代码"
Main Agent: "已启动审查"
→ sessions_spawn({
agent: "reviewer",
mode: "session",
thread: true
})
→ Discord 创建线程 "Code Review"
用户(在线程中): "第 42 行有问题吗?"
Reviewer Agent: "是的,这里有空指针风险..."
用户: "如何修复?"
Reviewer Agent: "可以使用 Optional..."
2.5 推送式结果通知:为什么不用轮询?
轮询方案的成本:
ini
假设子任务运行 30 秒,每秒轮询 1 次
→ 30 次查询 × 500 tokens = 15,000 tokens 浪费!
OpenClaw 的推送方案:
ini
子 Agent 完成 → 结果冻结到 SubagentRegistry
↓
后台 Sweeper(1-8 秒检查一次)
↓
自动推送到父 Agent 会话(deliver=false)
↓
父 Agent 接收内部消息:
[Subagent Completion]
Status: ok
Result: <<<分析完成,发现 3 个错误...>>>
重试机制:
- 首次失败:5 秒后重试
- 二次失败:10 秒后重试
- 三次失败:20 秒后重试
- 超过 3 次:标记失败
三、sessions_send 深度解析
3.1 完整执行流程
css
Agent A 调用 sessions_send
↓
[1. 目标解析] → 通过 sessionKey 或 label 查找
↓
[2. 权限检查] → A2A 策略 + 沙箱限制
↓
[3. 消息投递] → 启动目标 Agent
↓
[4. 等待回复] → (可选) 同步等待
↓
[5. A2A 协商] → 多轮 ping-pong(最多 5 轮)
↓
[6. 最终通知] → 投递到原始频道
3.2 A2A 多轮协商流程
java
Agent A (requester) Agent B (target)
│
├─ "请格式化代码" ──────→ │
│ ├─ "需要哪种风格?"
│ ← ─────────────────── │
│
├─ "使用 Prettier" ─────→ │
│ ├─ "完成了"
│ ← ─────────────────── │
│
├─ REPLY_SKIP ─────────→ │ (结束协商)
│
│ ├─ 最终通知
│ ← ─────────────────── │
│
└─ 投递到用户频道 ────────→ User
"✅ 代码已格式化"
协商控制:
- 最多 5 轮(可配置)
- 任一方回复
REPLY_SKIP_TOKEN结束 - 最终可回复
ANNOUNCE_SKIP_TOKEN保持沉默
3.3 两种使用模式
模式 1:同步等待回复(timeoutSeconds > 0)
typescript
const result = await sessions_send({
sessionKey: "agent:formatter:session-123",
message: "格式化这段代码",
timeoutSeconds: 30 // 等待 30 秒
});
console.log(result.reply); // 同步获得回复
// 后台继续进行 A2A 协商流程
模式 2:异步投递(timeoutSeconds = 0)
typescript
sessions_send({
sessionKey: "agent:formatter:session-123",
message: "格式化代码",
timeoutSeconds: 0 // 立即返回
});
// 后台进行 A2A 协商,最终结果投递到频道
四、两者的协作:设计模式
4.1 Fork-Join(并行处理)
scss
Main Agent
├─ spawn analyzer-1 (处理分片 A)
├─ spawn analyzer-2 (处理分片 B)
└─ spawn analyzer-3 (处理分片 C)
↓ ↓ ↓ (并行执行)
← announcement 1
← announcement 2
← announcement 3
综合结果 → 回复用户
4.2 Master-Worker(主从协作)
typescript
// 创建专家 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);
4.3 Pipeline(流水线)
scss
PDF → Extractor → 原始文本 → Cleaner → 清洁文本 → Summarizer → 摘要
(spawn) (announce) (spawn) (announce) (spawn) (announce)
五、关键设计决策
5.1 为什么 mode="session" 需要 thread=true?
问题场景:
arduino
mode="session" + thread=false
→ 子 Agent 会话保持打开
→ 用户发送后续消息 "继续"
→ 消息去哪里?❌ 无法路由
解决方案:强制 thread=true
ini
mode="session" + thread=true
→ Discord 创建线程,绑定到子 Agent
→ 用户在线程中的消息自动路由 ✓
5.2 为什么附件是快照传递?
| 方式 | 优点 | 缺点 | 采用 |
|---|---|---|---|
| 引用传递 | 节省存储 | 父删除,子引用失效 | ❌ |
| 快照传递 | 独立生命周期 | 占用更多存储 | ✅ |
快照传递的优势:
css
Main Agent 传递附件 → 子 Agent 获得完整副本
→ Main Agent 清理 → 子 Agent 仍可访问 ✓
5.3 为什么跨 Agent 使用目标工作目录?
markdown
Main Agent (workspace: /project/main)
├─ 同类型子 Agent → 继承 /project/main ✓
└─ 跨 Agent 子 Agent (code-reviewer)
→ 使用 /project/reviews ✓
原因:
1. 每个 Agent 有自己的工作约定
2. 防止权限越界
3. 安全隔离
5.4 用户可见性矩阵
| 场景 | Mode | Thread | 用户可见性 | 原因 |
|---|---|---|---|---|
| 后台任务 | run |
false |
❌ 不可见 | deliver=false |
| 持久会话 | session |
true |
✅ 在线程中可见 | 线程绑定 |
| 嵌套子 Agent | run |
false |
❌ 不可见 | 父是子 Agent |
六、最佳实践
6.1 何时使用 sessions_spawn?
✅ 适合:
- 后台数据处理(mode="run")
- 并行任务分解(多个 spawn)
- 多轮交互(mode="session", thread=true)
❌ 不适合:
- 简单查询(直接在主 Agent 处理)
- 需要立即同步回复(用 sessions_send)
6.2 何时使用 sessions_send?
✅ 适合:
- Agent 间协作
- 实时反馈循环
- 多轮协商
❌ 不适合:
- 创建新任务(用 sessions_spawn)
- 长时间任务(会超时)
6.3 配置建议
基础配置:
json5
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 1, // 一层子 Agent
maxChildrenPerAgent: 5, // 最多 5 个并行
runTimeoutSeconds: 300 // 5 分钟超时
}
}
},
session: {
agentToAgent: {
enabled: true,
allow: ["*"], // 允许所有跨 Agent 通信
maxPingPongTurns: 5
}
}
}
高级配置(复杂任务):
json5
{
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 |
技术创新
- 推送式通知:零轮询成本,实时响应
- 多轮 A2A 协商:Agent 间智能对话
- 层次化权限:深度限制、白名单、沙箱
- 线程绑定:持久化会话自动路由
- 结果冻结:网络故障重试不丢失
OpenClaw 的多 Agent 通信机制不仅适用于代码助手,更是构建自主 AI 系统的基础设施。