OpenClaw 多 Agent 通信机制解析:sessions_spawn 与 sessions_send

引言:Agent 之间如何"对话"?

想象你是一个项目经理(主 Agent),需要完成一个复杂项目。你有两种协调方式:

  1. 雇佣新员工完成任务(sessions_spawn):招募专家,分配任务,完成后自动提交报告
  2. 与现有同事实时沟通(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

技术创新

  1. 推送式通知:零轮询成本,实时响应
  2. 多轮 A2A 协商:Agent 间智能对话
  3. 层次化权限:深度限制、白名单、沙箱
  4. 线程绑定:持久化会话自动路由
  5. 结果冻结:网络故障重试不丢失

OpenClaw 的多 Agent 通信机制不仅适用于代码助手,更是构建自主 AI 系统的基础设施。

相关推荐
REI-2 小时前
黑马点评项目启动
java·后端
Cosolar3 小时前
AgentScope-Java ReActAgent 代码实现讲解
人工智能·后端·面试
KubeSphere3 小时前
为什么改了配置,Pod 却没重启?Kubernetes 真相来了
后端
gelald3 小时前
JVM - 垃圾回收
java·jvm·后端
不会写DN3 小时前
Go 中最主流 JWT 库 jwt -go
开发语言·后端·golang
2501_921649493 小时前
RESTful 金融数据 API 文档:设计原则与最佳实践
开发语言·后端·python·金融·restful
神奇小汤圆3 小时前
大家都在讲 Harness,但它到底该怎么理解
后端
学以智用3 小时前
Python 批量重命名文件工具(完整示例)
后端·python
人道领域3 小时前
Day | 12 【苍穹外卖 :导出Excel数据表】
java·后端·sql·servlet·mvc·intellij-idea