摘要 :当主 Agent 需要并行处理耗时任务或将工作委托给"助手"时,OpenClaw 提供了子 Agent(Sub-Agent)机制。本文深入解析 sessions_spawn 的完整生命周期:子 Agent 如何在独立的 session 中运行(agent:<agentId>:subagent:<uuid>),为何只能向父 Agent 汇报而非对等通信,以及当前架构的**设计限制(limitation)**如何影响多 Agent 协作的工程实践。你将看到:子 Agent 是"外包"而非"合伙人",这种不对称的通信模型既是安全特性,也是当前版本的约束边界。
关键词:OpenClaw;Sub-Agent(子智能体);sessions_spawn;隔离执行(Isolation);Announce(结果汇报);Nested Spawn(嵌套派生);Orchestrator Pattern(编排器模式)
系列文章:
- OpenClaw 深度解析与源代码导读 · 第1篇:系列导读------术语、版本与读源码方法
- OpenClaw 深度解析与源代码导读 · 第2篇:Skills------能力扩展平面与源码中的「目录即技能」
- OpenClaw 深度解析与源代码导读 · 第3篇:Gateway------常驻控制面、单端口多协议与进程骨架
- OpenClaw 深度解析与源代码导读 · 第4篇:Router------入站消息的分发中枢与决策逻辑
- OpenClaw 深度解析与源代码导读 · 第5篇:Brain------Prompt/Context/Harness Engineering 与执行框架
- OpenClaw 深度解析与源代码导读 · 第6篇:Hands------Shell、文件、浏览器与沙箱安全
- OpenClaw 深度解析与源代码导读 · 第7篇:Memory 子系统------持久化、内置记忆与「人格文件」分界
- OpenClaw 深度解析与源代码导读 · 第8篇:Learning & Adaptation------人格文件与软学习范式
- OpenClaw 深度解析与源代码导读 · 第9篇:Channels(通道桥接与 Gateway 耦合)
- OpenClaw 深度解析与源代码导读 · 第10篇:多 Agent 核心(agents.list、bindings 与隔离边界的可验证机制)
源码版本说明 :本文引用路径基于 openclaw/openclaw 仓库;本地阅读使用的 commit 为 0dd4958bc8a78d26b3b526b1f2e63b15110c64a2 (2026-04-11)。若你使用不同版本,符号名/文件路径可能略有漂移,以同 commit 的 docs/ 与 src/ 为准。
0. 开篇问题:为什么需要"子 Agent"?
在第10篇中,我们讨论了多 Agent 并列 的场景------多个独立的 Agent 共享一个 Gateway,通过 bindings 将不同渠道的消息路由到不同的"办公室"。
Gateway(单进程常驻)
sessionKey=agent:work:...
sessionKey=agent:home:...
Agent: home
workspace: workspace-home
agentDir: agents/home/agent
sessions: agents/home/sessions
Agent: work
workspace: workspace-work
agentDir: agents/work/agent
sessions: agents/work/sessions
Channels(I/O 边界)
Router:resolve-route(bindings 决策)
外部消息(Discord/Feishu/...)
除此之外,还有一种常见的需求:同一个对话流内,主 Agent 需要"派活"给助手 。这就是子 Agent(Sub-Agent) 的场景------不是开新办公室,而是在同一个办公室内雇佣"临时工"。
Depth 2: 孙 Agent(叶节点)
Depth 1: 子 Agent
Gateway 队列层
Depth 0: 主 Agent(用户对话入口)
① 调用 sessions_spawn
简单任务:直接派生
复杂任务:派生编排器
② 编排器派生工人
② 编排器派生工人
② 编排器派生工人
③ 直接向上汇报
③ 向编排器汇报
③ 向编排器汇报
③ 向编排器汇报
④ 汇总后向上汇报
agent:work:main
workspace: 完整8文件
工具权限: 全部含 sessions_spawn
Subagent 专用队列
lane: subagent | maxConcurrent: 8
普通子 Agent
agent:...subagent:abc
工具受限,无 session 工具
直接执行后台任务
编排器 Orchestrator
agent:...subagent:orch
含 sessions_spawn,可派生 Depth-2
项目经理角色
工人A
...subagent:worker-1
执行具体子任务
工人B
...subagent:worker-2
执行具体子任务
工人C
...subagent:worker-3
执行具体子任务
💡 编排器 vs 普通子 Agent:普通子 Agent 是"外包工人"------领活、干活、交活;编排器是"包工头"------领大活、分小活、监工、收齐后汇总上交。
两条派生路径详解
路径一:直接派生(简单后台任务)
用户请求:"分析这份PDF文档"
│
▼
┌─────────────────┐
│ 主 Agent │ 调用 sessions_spawn,指定简单任务
│ (Depth 0) │
└────────┬────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐
│ 普通子 Agent │────▶│ 独立执行分析任务 │
│ (Depth 1) │ │ 工具受限,无session工具 │
│ │ │ 直接操作文件/执行代码 │
└────────┬────────┘ └─────────────────┘
│
▼ 完成后
┌─────────────────┐
│ 向上汇报 (announce)│
│ 返回分析结果摘要 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 主 Agent 收到结果 │
│ 向用户展示报告 │
└─────────────────┘
特点:
- 一对一:一个主 Agent 派生一个子 Agent
- 单层级:只有 Depth 0 → Depth 1
- 直接汇报:子 Agent 直接向主 Agent 汇报,无中间环节
- 适用:单一耗时任务(PDF分析、数据查询等)
路径二:复杂任务(通过编排器派生)
用户请求:"对比A、B、C三个技术方案"
│
▼
┌─────────────────┐
│ 主 Agent │ 调用 sessions_spawn,启用编排器模式
│ (Depth 0) │ (maxSpawnDepth≥2)
└────────┬────────┘
│
▼
┌─────────────────┐
│ 编排器 │ "项目经理"角色
│ (Depth 1) │ 含 sessions_spawn 工具权限
│ │ 可继续派生 Depth-2 工人
└────────┬────────┘
│
├────────┬────────┐
▼ ▼ ▼
┌────────┐┌────────┐┌────────┐
│ 工人A ││ 工人B ││ 工人C │
│(Depth2)││(Depth2)││(Depth2)│
│分析方案A││分析方案B││分析方案C│
└────┬───┘└────┬───┘└────┬───┘
│ │ │
└─────────┼─────────┘
▼ 各自完成后
┌─────────────────┐
│ 向编排器汇报 │
│ 返回各自分析结果 │
└────────┬────────┘
▼
┌─────────────────┐
│ 编排器汇总 │
│ "综合对比:A成本低、B风险小、C速度快"
└────────┬────────┘
▼ 汇总后
┌─────────────────┐
│ 向上汇报给主 Agent│
└────────┬────────┘
▼
┌─────────────────┐
│ 主 Agent 展示 │
│ 最终对比报告 │
└─────────────────┘
特点:
- 一对多:一个编排器管理多个工人(3个并行子任务)
- 两层级:Depth 0 → Depth 1(编排器)→ Depth 2(工人)
- 两次汇报:工人→编排器(第一次),编排器→主 Agent(第二次)
- 适用:复杂并行任务(多方案对比、批量处理、MapReduce 模式)
两条路径对比
| 维度 | 直接派生 | 编排器模式 |
|---|---|---|
| 层级深度 | 2层(0→1) | 3层(0→1→2) |
| 并发数 | 1个子 Agent | 多个工人(默认最多5个) |
| 汇报次数 | 1次 | 2次(工人→编排器→主 Agent) |
| 汇总逻辑 | 无(直接返回结果) | 有(编排器整合多个结果) |
| 配置要求 | 默认即可 | 需 maxSpawnDepth≥2 |
| 典型场景 | 分析单个PDF | 对比多个方案、批量处理 |
💡 关键区别:直接派生是"外包给一个人干活",编排器模式是"雇一个项目经理,让他带一队工人分包干活"。
典型场景
| 场景 | 主 Agent 的困境 | 子 Agent 的解决方式 |
|---|---|---|
| 耗时研究 | 用户问"分析这100页PDF并总结",主 Agent 阻塞10分钟无法响应其他消息 | 派生子 Agent 后台处理,主 Agent 立即返回"任务已启动" |
| 并行任务 | "比较A、B、C三个方案",串行分析太慢 | 派生3个子 Agent 并行分析,各自汇报结果 |
| 工具隔离 | 主 Agent 需要执行高风险操作(如删除文件),但不想污染当前上下文 | 子 Agent 在隔离 session 中执行,仅汇报结果 |
| 编排器模式 | 复杂任务需要"项目经理"协调多个"专家" | Depth-1 编排器子 Agent 管理 Depth-2 工作子 Agent |
核心设计哲学
OpenClaw 的子 Agent 遵循三个核心设计原则:
- 隔离执行(Isolation):每个子 Agent 在独立的 session 中运行,拥有独立的上下文、工具权限和生命周期
- 向上汇报(Announce Upward) :子 Agent 完成后只能向直接父 Agent 汇报,无法与其他 Agent 对等通信
- 有限嵌套(Bounded Nesting):默认只允许 Depth-1(单层),可通过配置开启 Depth-2(编排器模式),Depth-3+ 被禁止
💡 理解要点 :子 Agent 是"外包工人"而非"合伙人"------它领取任务、独立工作、向雇主汇报,但不能主动发起协作 或横向沟通。
1. Session Key 的层级世界:主 Agent、子 Agent、孙 Agent
理解子 Agent 的第一步是理解其session key 的命名空间如何与主 Agent 区分。
1.1 三级 Session Key 结构
| 层级 | Session Key 形态 | 角色 | 能否 spawn? |
|---|---|---|---|
| Depth 0 | agent:<id>:main |
主 Agent(用户对话入口) | ✅ 总是允许 |
| Depth 1 | agent:<id>:subagent:<uuid> |
子 Agent(直接派生自主 Agent) | ✅ 仅当 maxSpawnDepth >= 2 |
| Depth 2 | agent:<id>:subagent:<uuid>:subagent:<uuid> |
孙 Agent(派生自子 Agent) | ❌ 永远禁止 |
💡 spawn 释义 :计算机术语中指"派生/生成"。在 OpenClaw 中,
sessions_spawn是主 Agent 非阻塞地创建子 Agent 的工具调用------就像母鸡下蛋后立即继续觅食,不等待蛋孵化。派生出的子 Agent 拥有独立的 session key 和生命周期,崩溃不影响父 Agent。
1.2 源码中的 Key 生成逻辑
在 openclaw/src/agents/subagent-spawn.ts 中,子 Agent 的 session key 生成核心逻辑如下:
typescript
// 简化示意
const parentKey = "agent:work:main";
const childUuid = crypto.randomUUID(); // "abc-123-..."
const childKey = `${parentKey}:subagent:${childUuid}`;
// 结果: "agent:work:main:subagent:abc-123-..."
对于 Depth-2(孙 Agent),则是在 Depth-1 key 基础上继续追加:
typescript
const depth1Key = "agent:work:subagent:ghi-789";
const grandchildUuid = crypto.randomUUID();
const depth2Key = `${depth1Key}:subagent:${grandchildUuid}`;
// 结果: "agent:work:subagent:ghi-789:subagent:jkl-012-..."
🔍 实际例子 :通过
parseAgentSessionKey解析 session key,可以准确判断当前 Agent 的嵌套深度(getSubagentDepthFromSessionStore在openclaw/src/agents/subagent-depth.ts中实现)。
2. 子 Agent 的完整生命周期:Spawn → Run → Announce
子 Agent 的生命周期可分为三个阶段:派生(Spawn) 、执行(Run) 、汇报(Announce)。理解这三个阶段是正确使用子 Agent 的关键。
2.1 Spawn:非阻塞的"任务外包"
当主 Agent(或用户通过 /subagents spawn 命令)调用 sessions_spawn 时:
json5
// 主 Agent 调用 sessions_spawn 工具
{
task: "分析 /workspace/report.pdf,提取关键数据点",
label: "PDF分析-1",
agentId: "work", // 可选,默认当前 agent
model: "anthropic/claude-sonnet-4-6", // 可为子 Agent 指定不同模型
runTimeoutSeconds: 300, // 5分钟超时
mode: "run", // "run" = 一次性任务,"session" = 持续对话
thread: false, // 是否绑定到 channel thread
cleanup: "keep", // "keep" | "delete"
sandbox: "inherit", // "inherit" | "require"
}
Spawn 阶段的关键特性:
| 特性 | 说明 | 源码位置 |
|---|---|---|
| 非阻塞 | 立即返回 { status: "accepted", runId, childSessionKey },不等待子 Agent 完成 |
sessions-spawn-tool.ts |
| 独立队列 | 子 Agent 进入 subagent 专用队列 lane,与主 Agent 任务并行 |
subagent-spawn.ts |
| 并发限制 | 全局并发上限 maxConcurrent(默认8),单父 Agent 并发上限 maxChildrenPerAgent(默认5) |
配置项 |
| 认证继承 | 子 Agent 使用目标 agentId 的 agentDir 中的 auth profiles,主 Agent 的 profiles 作为 fallback |
subagent-spawn.ts |
2.2 Run:隔离执行与受限工具
子 Agent 开始执行后,它在完全隔离的上下文中运行:
隔离维度
| 维度 | 主 Agent | 子 Agent(默认) | 说明 |
|---|---|---|---|
| Session Key | agent:work:main |
agent:work:subagent:<uuid> |
独立命名空间 |
| Workspace | 继承或独立配置 | 可继承主 Agent workspace 或独立 | resolveSpawnedWorkspaceInheritance |
| 上下文文件 | 全部8个文件(AGENTS.md/SOUL.md/...) | 仅 AGENTS.md + TOOLS.md |
子 Agent 不加载 SOUL/IDENTITY/USER/HEARTBEAT/BOOTSTRAP |
| 工具权限 | 全部可用 | 无 session 工具(见下表) | dangerous-tools.ts |
| 沙箱 | 可配置 | 继承或强制 | sandbox: "inherit" 或 "require" |
工具权限矩阵
| 工具 | Depth 0(主 Agent) | Depth 1(子 Agent,默认) | Depth 1(编排器模式,maxSpawnDepth=2) |
Depth 2(孙 Agent) |
|---|---|---|---|---|
read, write, exec, browser... |
✅ | ✅ | ✅ | ✅ |
sessions_list, sessions_history |
✅ | ❌ | ✅(管理子 Agent 需要) | ❌ |
sessions_send |
✅ | ❌ | ✅ | ❌ |
sessions_spawn |
✅ | ❌ | ✅(可派生 Depth-2) | ❌ |
subagents(slash 命令) |
✅ | ❌ | ✅ | ❌ |
🔍 实际例子 :这种工具限制是安全设计------默认情况下,子 Agent 无法"越级"操作其他 session,也无法继续派生更多子 Agent,防止权限扩散。
2.3 Announce:向上汇报的"单向通信"
子 Agent 完成后,必须 向父 Agent 汇报结果。这是子 Agent 架构的核心约束。
汇报流程
子 Agent 执行完毕后,Gateway 会构建 announce payload 并注入父 Agent 的 session:
- 子 Agent 在自身 session 内完成最后一步
- Gateway 捕获最后可见的 assistant 回复或 sanitized tool 结果
- 构建包含结果、状态、统计信息的 announce payload
- 根据父 Agent 的深度决定 delivery 方式:
- 若父 Agent 是 Depth-0(主 Agent):通过外部 delivery 发送给用户
- 若父 Agent 是 Depth-1(编排器):内部注入到父 Agent session,由编排器继续处理
Announce Payload 结构
汇报内容在子 Agent session 内构建,包含:
| 字段 | 内容 | 说明 |
|---|---|---|
Result |
最后可见的 assistant 回复,或 sanitized 的 tool/toolResult 文本 | 主 Agent 可据此继续推理 |
Status |
completed successfully / failed / timed out / unknown |
执行状态 |
Runtime |
执行时长(如 5m12s) |
性能参考 |
Token Usage |
input/output/total + 预估成本 | 成本追踪 |
sessionKey / sessionId / transcript path |
子 Agent 的完整引用信息 | 父 Agent 可通过 sessions_history 获取详细日志 |
关键限制:仅向上汇报
⚠️ 重要约束 :子 Agent 只能向直接父 Agent 汇报,无法:
- 向祖父 Agent 直接汇报(必须通过父 Agent 转发)
- 向其他平行子 Agent 发送消息
- 向用户直接发送消息(除非父 Agent 选择转发)
这种"向上汇报"的设计在源码中体现为 deliver: false 的内部注入机制,确保信息层级控制。
💡 理解要点 :这是不对称通信模型------信息只能沿"子→父"方向流动,无法横向或对等传输。这确保了层级控制,但也限制了协作灵活性。
3. 嵌套深度与编排器模式(Orchestrator Pattern)
默认情况下,子 Agent 不能 再派生自己的子 Agent(maxSpawnDepth: 1)。但 OpenClaw 提供了编排器模式,允许 Depth-1 子 Agent 作为"项目经理"管理 Depth-2"工人"。
3.1 配置开启深度-2
json5
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // 允许子 Agent 派生孙 Agent
maxChildrenPerAgent: 5, // 每个 Agent 最多5个活跃子 Agent
maxConcurrent: 8, // 全局并发上限
runTimeoutSeconds: 900, // 默认15分钟超时
},
},
},
}
3.2 两层架构:编排器 + 工人
工作流程:
- 用户请求复杂任务(如"对比三个PDF方案")
- 主 Agent 派生编排器(Depth-1)
- 编排器分析任务,派生多个工人(Depth-2)并行处理
- 各工人完成工作后向编排器汇报
- 编排器合成结果,向主 Agent 汇报
- 主 Agent 向用户呈现最终报告
3.3 深度限制的技术原因
为什么限制为 Depth-2(甚至 Depth-5 硬上限)?
| 限制因素 | 说明 |
|---|---|
| 复杂性爆炸 | 深度增加导致状态管理、错误处理、调试难度指数级增长 |
| Announce 链延迟 | 每层汇报增加一轮延迟,Depth-3 意味着 3 次汇报传递 |
| Token 成本 | 编排器需要聚合所有子结果,上下文膨胀 |
| 调试困难 | 深度嵌套导致日志分散、问题定位困难 |
| Gateway 资源 | 所有子 Agent 共享 Gateway 进程,深度无限增长可能导致资源耗尽 |
💡 工程建议:Depth-2 足以覆盖绝大多数"项目经理-工人"模式。如需更复杂编排,考虑外部编排器(如第12篇将讨论的 RFC)而非无限嵌套。
4. Thread-Bound Session:Discord 的特殊能力
在特定渠道(目前仅 Discord),子 Agent 可以绑定到一个持久化的 thread,实现更自然的协作体验。
4.1 使用场景
| 场景 | 传统模式 | Thread-Bound 模式 |
|---|---|---|
| 长期研究任务 | 子 Agent 完成后 announce,用户需切换回主对话查看 | 子 Agent 在独立 thread 中持续对话,用户可随时进入 thread 查看进展 |
| 多人协作 | 所有消息混杂在主 channel | 每个子任务有独立 thread,消息隔离 |
| 异步跟进 | 用户必须等待子 Agent 完成 | 用户可先离开,稍后进入 thread 继续对话 |
4.2 配置与使用
json5
{
channels: {
discord: {
threadBindings: {
enabled: true,
idleHours: 24, // 24小时无活动自动解绑
maxAgeHours: 0, // 0 = 无硬时间限制
spawnSubagentSessions: true, // 允许子 Agent 绑定 thread
},
},
},
}
派生时启用 thread 绑定:
json5
{
task: "研究量子计算最新进展",
thread: true, // 请求绑定到 channel thread
mode: "session", // "session" 模式允许持续对话(非一次性)
}
4.3 Slash 命令控制
| 命令 | 作用 |
|---|---|
/focus <subagent-label> |
将当前 thread 绑定到指定子 Agent |
/unfocus |
解除当前 thread 的绑定 |
/agents |
查看当前活跃子 Agent 及其绑定状态 |
/session idle 12h |
设置该 thread 12小时无活动后自动解绑 |
/session max-age 7d |
设置该 thread 最大生命周期7天 |
🔍 实际例子:Discord thread 绑定是目前唯一支持的 thread-bound 场景。这是渠道适配层的特性,取决于渠道 API 是否支持持久化 thread/topic。
5. 源码地图:子 Agent 的实现脉络
要深入理解子 Agent 机制,以下源码文件是核心阅读路径:
| 层级 | 文件 | 职责 |
|---|---|---|
| 工具层 | src/agents/tools/sessions-spawn-tool.ts |
sessions_spawn 工具的实现,参数校验、调用 spawn 逻辑 |
| 派生核心 | src/agents/subagent-spawn.ts |
子 Agent 派生的核心逻辑:key 生成、workspace 继承、能力解析、Gateway 调用 |
| 派生类型 | src/agents/subagent-spawn.types.ts |
SUBAGENT_SPAWN_MODES、SpawnSubagentMode 等类型定义 |
| Registry | src/agents/subagent-registry.ts |
子 Agent 运行的注册、计数、状态管理 |
| 深度管理 | src/agents/subagent-depth.ts |
从 session key 解析嵌套深度 |
| Capability | src/agents/subagent-capabilities.ts |
根据深度和配置决定子 Agent 的工具权限 |
| Attachments | src/agents/subagent-attachments.ts |
子 Agent 附件的 Base64 解码、文件落地 |
| Slash 命令 | src/auto-reply/reply/commands-subagents/action-spawn.ts |
/subagents spawn 命令的处理 |
| 安全配置 | src/security/dangerous-tools.ts |
子 Agent 默认拒绝 session 工具的安全策略 |
关键调用链(简化)
sessions_spawn 工具调用
↓
sessions-spawn-tool.ts:execute()
↓
spawnSubagentDirect() [subagent-spawn.ts]
↓
1. 解析/验证参数(task/model/agentId/mode/thread...)
2. 检查权限(allowAgents 白名单、sandbox 继承)
3. 检查深度(getSubagentDepthFromSessionStore)
4. 检查并发(countActiveRunsForSession < maxChildrenPerAgent)
5. 生成 childSessionKey(uuid)
6. 准备 workspace(继承或独立)
7. 调用 Gateway(agent.run)启动子 Agent
8. 注册到 registry(registerSubagentRun)
9. 返回 {status: "accepted", childSessionKey, runId}
↓
子 Agent 独立运行...
↓
任务完成 → 构建 announce payload → 注入父 Agent session
6. 与业界方案的对比:OpenClaw 的选择与限制
6.1 vs AutoGen 的 GroupChat
| 维度 | OpenClaw Sub-Agent | AutoGen GroupChat |
|---|---|---|
| 通信模型 | 严格层级:子→父单向汇报 | 对等网络:任意 Agent 可互相发送消息 |
| Agent 生命周期 | 配置声明,长期驻留 | 代码动态创建/销毁 |
| 持久化 | 内置 sessions 存储 | 需自行实现 |
| 渠道集成 | 内置 Channels 子系统 | 需自行接入 Discord/Slack 等 |
| 适用场景 | 常驻服务、自动路由 | 动态编排、一次性任务 |
6.2 vs CrewAI 的 Crew
| 维度 | OpenClaw Sub-Agent | CrewAI Crew |
|---|---|---|
| 定义方式 | 配置文件(agents.list + bindings) |
Python 代码(Agent, Task, Crew) |
| 执行触发 | 外部消息或 /subagents spawn 自动触发 |
代码显式调用 crew.kickoff() |
| 结果处理 | announce 注入父 Agent 上下文 | 返回 Python 对象,由代码处理 |
| 生产部署 | Gateway 常驻进程 | 脚本/容器运行 |
6.3 OpenClaw 当前的设计限制(Limitations)
根据官方文档 docs/tools/subagents.md,以下限制值得特别关注:
| 限制 | 说明 | 工程影响 |
|---|---|---|
| Announce 是 best-effort | Gateway 重启后,待发送的 announce 丢失 | 关键任务需设计重试或检查点 |
| 共享 Gateway 进程 | 子 Agent 仍占用 Gateway 内存/CPU | maxConcurrent 是安全阀,非性能保证 |
| 非阻塞但不保证完成 | sessions_spawn 立即返回,但不保证子 Agent 最终成功 |
需通过 /subagents list 或 announce 确认状态 |
| 上下文文件受限 | 子 Agent 仅加载 AGENTS.md + TOOLS.md |
无 SOUL/IDENTITY/USER/HEARTBEAT,人格不完整 |
| 最大深度 5 | maxSpawnDepth 上限 5,但推荐仅用 2 |
复杂编排需考虑外部方案 |
7. 例子以及配置表
7.1 基础场景:后台耗时任务
json5
// openclaw.json 配置片段
{
agents: {
list: [
{
id: "work",
name: "Work",
workspace: "~/.openclaw/workspace-work",
// 子 Agent 使用轻量模型
subagents: {
model: "anthropic/claude-haiku-3-5",
runTimeoutSeconds: 600,
},
},
],
},
}
用户对话:
用户:分析 /workspace/annual_report.pdf,提取所有财务数据
Agent:这是一个耗时的分析任务。我将启动一个后台子 Agent 来处理。
您可以继续问我其他问题,分析完成后会通知您。
[调用 sessions_spawn,5秒后返回]
✓ 子 Agent 已启动(session: agent:work:subagent:abc-123,预计5分钟)
... 5分钟后 ...
[子 Agent announce 消息注入]
Agent:分析完成!子 Agent 报告如下:
- 收入: $50M (+12% YoY)
- 净利润: $8M
- 现金流: ...
7.2 编排器模式:并行分析多个文件
json5
// 开启深度-2 编排器模式
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // 允许编排器派生工人
maxChildrenPerAgent: 5,
maxConcurrent: 8,
},
},
},
}
用户对话:
用户:对比 /docs/proposal_v1.md、/docs/proposal_v2.md、/docs/proposal_v3.md 三个方案
Agent:我将启动一个编排器子 Agent 来并行分析三个方案。
[调用 sessions_spawn 创建编排器]
✓ 编排器已启动(session: agent:work:subagent:orch-789)
... 编排器内部逻辑 ...
编排器 [Depth 1]:我需要3个工人分别分析3个文件。
[调用3次 sessions_spawn]
✓ 工人A(proposal_v1): agent:work:subagent:orch-789:subagent:worker-1
✓ 工人B(proposal_v2): agent:work:subagent:orch-789:subagent:worker-2
✓ 工人C(proposal_v3): agent:work:subagent:orch-789:subagent:worker-3
... 工人完成后向编排器 announce ...
编排器:收到工人A结果... 收到工人B结果... 收到工人C结果...
综合对比:
- 方案1 优势:成本低 | 劣势:周期长
- 方案2 优势:平衡 | 劣势:风险中等
- 方案3 优势:速度快 | 劣势:成本高
[向主 Agent announce]
... 主 Agent 收到编排器结果 ...
Agent:三个方案已完成对比分析:
1. 方案1(v1): ...
2. 方案2(v2): ...
3. 方案3(v3): ...
建议:如果预算充足且赶时间,选方案3;...
7.3 配置参数速查表
以下是子 Agent 相关的所有配置参数汇总,涵盖全局默认值、每 Agent 覆盖值,以及 sessions_spawn 工具调用的参数。
7.3.1 全局默认配置(agents.defaults.subagents)
json5
{
agents: {
defaults: {
subagents: {
// 1. 嵌套深度控制
maxSpawnDepth: 1, // 默认: 1 | 范围: 1-5 | 推荐: 2(如需编排器模式)
// 2. 并发控制
maxChildrenPerAgent: 5, // 默认: 5 | 范围: 1-20 | 每 Agent 最多活跃子 Agent 数
maxConcurrent: 8, // 默认: 8 | 全局 subagent 队列并发上限
// 3. 超时控制
runTimeoutSeconds: 0, // 默认: 0(无超时)| 子 Agent 默认运行超时
// 4. 模型与思考模式
model: "anthropic/claude-sonnet-4-6", // 子 Agent 默认模型(继承主 Agent 若未设置)
thinking: "off", // 子 Agent 默认思考模式
// 5. 白名单控制
allowAgents: ["*"], // 默认: ["*"] | 允许派生的目标 Agent ID 列表
requireAgentId: false, // 默认: false | 是否强制要求显式指定 agentId
},
},
},
}
7.3.2 每 Agent 覆盖配置(agents.list[].subagents)
json5
{
agents: {
list: [
{
id: "work",
// 覆盖全局默认值
subagents: {
model: "anthropic/claude-haiku-3-5", // work 的子 Agent 使用轻量模型
runTimeoutSeconds: 600, // work 的子 Agent 10分钟超时
maxSpawnDepth: 2, // work 允许编排器模式
allowAgents: ["work", "research"], // work 只能派生到特定 Agent
},
},
],
},
}
7.3.3 sessions_spawn 工具调用参数
| 参数 | 类型 | 必填 | 说明 | 默认值来源 |
|---|---|---|---|---|
task |
string | ✅ | 子 Agent 执行的任务描述 | - |
label |
string | ❌ | 任务标签,用于识别 | - |
agentId |
string | ❌ | 目标 Agent ID | 当前 Agent(若 requireAgentId: false) |
model |
string | ❌ | 覆盖子 Agent 模型 | agents.list[].subagents.model → agents.defaults.subagents.model |
thinking |
string | ❌ | 覆盖思考模式 | agents.list[].subagents.thinking → agents.defaults.subagents.thinking |
runTimeoutSeconds |
number | ❌ | 本次运行超时(秒) | agents.defaults.subagents.runTimeoutSeconds |
mode |
"run" | "session" | ❌ | 运行模式 | "run"(一次性任务) |
thread |
boolean | ❌ | 是否绑定 channel thread | false |
cleanup |
"delete" | "keep" | ❌ | 完成后是否清理 | "keep" |
sandbox |
"inherit" | "require" | ❌ | 沙箱要求 | "inherit"(继承父 Agent) |
lightContext |
boolean | ❌ | 使用轻量上下文 | false |
7.3.4 相关 session 配置(影响子 Agent 行为)
json5
{
session: {
// DM 隔离(影响子 Agent 的汇报目标 session)
dmScope: "per-channel-peer", // 默认: "main" | 推荐: "per-channel-peer"
// Thread 绑定(仅 Discord 等支持渠道)
threadBindings: {
enabled: true,
idleHours: 24, // thread 无活动自动解绑时间
maxAgeHours: 0, // thread 最大生命周期(0=无限制)
},
},
}
7.3.5 安全配置(tools.subagents)
json5
{
tools: {
subagents: {
// 子 Agent 工具白名单/黑名单
tools: {
allow: ["read", "exec", "browser"], // 若设置,仅允许这些工具
deny: ["write", "gateway", "cron"], // 拒绝这些工具(优先级高于 allow)
},
},
},
}
7.3.6 配置优先级总结
sessions_spawn 显式参数
↓(最高优先级,覆盖所有默认值)
agents.list[].subagents.{model/thinking/timeout}
↓(Agent 级覆盖)
agents.defaults.subagents.{model/thinking/timeout/maxSpawnDepth/maxConcurrent...}
↓(全局默认)
继承父 Agent 配置(若未设置任何默认值)
7.3.7 生产环境推荐配置模板
json5
{
agents: {
defaults: {
subagents: {
// 开启编排器模式(如需复杂任务)
maxSpawnDepth: 2,
maxChildrenPerAgent: 5,
maxConcurrent: 8,
// 子 Agent 使用成本更低的模型
model: "anthropic/claude-haiku-3-5",
runTimeoutSeconds: 600, // 10分钟默认超时
},
},
list: [
{
id: "work",
// work 使用强模型,但其子 Agent 保持轻量
model: "anthropic/claude-opus-4-6",
subagents: {
// 继承 defaults,无需覆盖
},
},
],
},
session: {
// 安全:确保子 Agent 汇报时上下文隔离
dmScope: "per-channel-peer",
},
tools: {
subagents: {
tools: {
deny: ["gateway", "cron"], // 子 Agent 不允许操作 Gateway 或定时任务
},
},
},
}
💡 配置要点:
maxSpawnDepth是安全阀,生产环境建议设为 2(足够应对绝大多数编排场景)model可分层配置:主 Agent 用强模型(Opus),子 Agent 用轻量模型(Haiku)节省成本dmScope影响子 Agent 的汇报目标,务必设为"per-channel-peer"防止上下文泄露
8. 小结与展望
8.1 一句话总结
OpenClaw 的子 Agent 是"外包执行单元"------在隔离的 session 中并行运行,通过
sessions_spawn派生,完成后向上汇报(announce),但无法横向通信或对等协作。这种设计确保了层级控制和资源隔离,也构成了当前架构的核心约束。
8.2 留给下一篇的问题(第12篇:Agent Teams RFC)
下一篇我们将讨论 OpenClaw 的 Agent Teams RFC------这是社区对当前子 Agent 限制的一种回应:
- RFC 提出了哪些原生编排能力来弥补子 Agent 的"仅向上汇报"限制?
- 与 LangGraph、Temporal 等外部编排器相比,RFC 的设计空间在哪里?
- 在 RFC 落地前,工程师应如何使用现有子 Agent + 外部工具实现复杂协作?
参考资料
文档(D1):
openclaw/docs/tools/subagents.md(完整的子 Agent 功能文档,本文主要引用来源)openclaw/docs/concepts/multi-agent.md(多 Agent 总览,含子 Agent 定位)openclaw/docs/tools/acp-agents.md(ACP 运行时的子 Agent 特殊处理)openclaw/docs/gateway/configuration-reference.md(maxSpawnDepth等配置项)
源码(S0):
openclaw/src/agents/subagent-spawn.ts(子 Agent 派生核心逻辑)openclaw/src/agents/subagent-spawn.types.ts(类型定义)openclaw/src/agents/subagent-registry.ts(子 Agent 注册管理)openclaw/src/agents/subagent-depth.ts(嵌套深度计算)openclaw/src/agents/subagent-capabilities.ts(工具权限矩阵)openclaw/src/agents/tools/sessions-spawn-tool.ts(sessions_spawn工具实现)openclaw/src/security/dangerous-tools.ts(子 Agent 默认拒绝 session 工具的安全策略)openclaw/src/auto-reply/reply/commands-subagents/(/subagents命令族实现)