Appearance
Sub-agents(子代理)
Sub-agents 是从现有 Agent 运行中派生出来的后台 Agent 运行实例。它们在独立会话(agent:<agentId>:subagent:<uuid>)中运行,完成后会将结果**通告(announce)**回发起请求的聊天频道。
把它想象成给你的龙虾雇了几只帮手——主龙虾继续工作,小龙虾在后台并行处理耗时任务,完成后把结果汇报回来。
Slash 命令
使用 /subagents 检查或控制当前会话的子代理运行:
/subagents list/subagents kill <id|#|all>/subagents log <id|#> [limit] [tools]/subagents info <id|#>/subagents send <id|#> <message>/subagents steer <id|#> <message>/subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]
线程绑定控制(适用于支持持久线程绑定的频道,详见下方支持线程的频道):
/focus <subagent-label|session-key|session-id|session-label>/unfocus/agents/session idle <duration|off>/session max-age <duration|off>
/subagents info 显示运行元数据(状态、时间戳、会话 ID、转录路径、清理信息)。
派生行为
/subagents spawn 以用户命令方式启动后台子代理(而非内部中继),运行结束时向发起聊天发送一条最终完成通告。
- 派生命令是非阻塞的,立即返回一个 run id。
- 完成时,子代理向发起聊天频道通告摘要/结果消息。
- 对于手动派生,通告具有弹性:
- OpenClaw 首先尝试带稳定幂等键的直接
agent投递。 - 直接投递失败则回退到队列路由。
- 队列路由仍不可用则以短指数退避重试,最终放弃。
- OpenClaw 首先尝试带稳定幂等键的直接
- 完成交接给发起会话的内容是运行时生成的内部上下文(非用户编写的文本),包括:
Result(assistant回复文本,或 assistant 回复为空时取最新toolResult)Status(completed successfully/failed/timed out/unknown)- 紧凑运行时/token 统计
- 投递指令,告知发起代理以正常助手语气重写(而非转发原始内部元数据)
--model和--thinking可针对该次运行覆盖默认值。- 完成后使用
info/log检查详情和输出。 /subagents spawn是一次性模式(mode: "run")。如需持久线程绑定会话,使用sessions_spawn并设置thread: true和mode: "session"。- 对于 ACP 运行时会话(Codex、Claude Code、Gemini CLI),使用
sessions_spawn并设置runtime: "acp",参见 ACP Agents。
主要目标:
- 在不阻塞主运行的情况下并行化"研究/长任务/慢工具"工作。
- 默认隔离子代理(会话分离 + 可选沙箱)。
- 保持工具接口难以误用:子代理默认不获取会话工具。
- 支持可配置的嵌套深度以满足编排模式需求。
费用提示:每个子代理有其独立上下文和 token 用量。对于重度或重复性任务,为子代理设置更便宜的模型,主代理保持高质量模型。可通过 agents.defaults.subagents.model 或每代理覆盖配置。
工具
使用 sessions_spawn:
- 启动子代理运行(
deliver: false,全局通道:subagent) - 然后运行通告步骤,将通告回复发布到发起聊天频道
- 默认模型:继承调用方,除非设置了
agents.defaults.subagents.model(或每代理agents.list[].subagents.model);显式sessions_spawn.model仍优先。 - 默认思考级别:继承调用方,除非设置了
agents.defaults.subagents.thinking(或每代理agents.list[].subagents.thinking);显式sessions_spawn.thinking仍优先。 - 默认运行超时:若省略
sessions_spawn.runTimeoutSeconds,OpenClaw 使用agents.defaults.subagents.runTimeoutSeconds(若已设置),否则回退到0(无超时)。
工具参数:
task(必填)label?(可选)agentId?(可选;若允许,在另一个代理 id 下派生)model?(可选;覆盖子代理模型;无效值被跳过,子代理以默认模型运行并在工具结果中警告)thinking?(可选;覆盖子代理运行的思考级别)runTimeoutSeconds?(默认为agents.defaults.subagents.runTimeoutSeconds,否则为0;设置后,子代理运行在 N 秒后终止)thread?(默认false;为true时请求为该子代理会话绑定频道线程)mode?(run|session)- 默认为
run - 若
thread: true且省略mode,默认变为session mode: "session"需要thread: true
- 默认为
cleanup?(delete|keep,默认keep)sandbox?(inherit|require,默认inherit;require在目标子运行时未沙箱化时拒绝派生)sessions_spawn不接受频道投递参数(target、channel、to、threadId、replyTo、transport)。如需投递,从派生运行中使用message/sessions_send。
线程绑定会话
当频道启用线程绑定时,子代理可以保持绑定到某个线程,使该线程中的后续用户消息继续路由到同一子代理会话。
支持线程的频道
- Discord(目前唯一支持的频道):支持持久线程绑定子代理会话(
sessions_spawn加thread: true)、手动线程控制(/focus、/unfocus、/agents、/session idle、/session max-age),以及适配器键channels.discord.threadBindings.enabled、channels.discord.threadBindings.idleHours、channels.discord.threadBindings.maxAgeHours、channels.discord.threadBindings.spawnSubagentSessions。
快速流程:
- 使用
sessions_spawn派生,设置thread: true(可选mode: "session")。 - OpenClaw 在活动频道中创建或绑定一个线程到该会话目标。
- 该线程中的回复和后续消息路由到绑定的会话。
- 使用
/session idle检查/更新不活跃自动解绑,/session max-age控制硬性上限。 - 使用
/unfocus手动解除绑定。
手动控制:
/focus <target>将当前线程(或创建一个)绑定到子代理/会话目标。/unfocus移除当前绑定线程的绑定。/agents列出活跃运行和绑定状态(thread:<id>或unbound)。/session idle和/session max-age仅对已聚焦绑定线程生效。
配置开关:
- 全局默认:
session.threadBindings.enabled、session.threadBindings.idleHours、session.threadBindings.maxAgeHours - 频道覆盖和派生自动绑定键是适配器特定的。见上方支持线程的频道。
白名单:
agents.list[].subagents.allowAgents:可通过agentId指定的代理 id 列表(["*"]表示允许任意)。默认:仅发起代理。- 沙箱继承保护:若发起会话已沙箱化,
sessions_spawn拒绝会在非沙箱运行的目标。
发现:
- 使用
agents_list查看当前sessions_spawn允许的代理 id。
自动归档:
- 子代理会话在
agents.defaults.subagents.archiveAfterMinutes(默认:60)后自动归档。 - 归档使用
sessions.delete,并将转录文件重命名为*.deleted.<timestamp>(同一文件夹)。 cleanup: "delete"在通告后立即归档(仍通过重命名保留转录)。- 自动归档是尽力而为的;网关重启后待处理的定时器会丢失。
runTimeoutSeconds不自动归档;它只停止运行,会话保留至自动归档。- 自动归档同等适用于深度 1 和深度 2 的会话。
嵌套子代理
默认情况下,子代理不能派生自己的子代理(maxSpawnDepth: 1)。你可以通过设置 maxSpawnDepth: 2 启用一级嵌套,允许编排模式:主代理 → 编排子代理 → 工作子子代理。
如何启用
json5
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // 允许子代理派生子代理(默认:1)
maxChildrenPerAgent: 5, // 每个代理会话的最大活跃子代理数(默认:5)
maxConcurrent: 8, // 全局并发通道上限(默认:8)
runTimeoutSeconds: 900, // sessions_spawn 省略时的默认超时(0 = 无超时)
},
},
},
}深度层级
| 深度 | 会话键形状 | 角色 | 可以派生? |
|---|---|---|---|
| 0 | agent:<id>:main | 主代理 | 始终可以 |
| 1 | agent:<id>:subagent:<uuid> | 子代理(深度 2 允许时充当编排者) | 仅当 maxSpawnDepth >= 2 |
| 2 | agent:<id>:subagent:<uuid>:subagent:<uuid> | 子子代理(叶工作节点) | 从不 |
通告链
结果沿链条向上传递:
- 深度 2 工作节点完成 → 向其父节点(深度 1 编排者)通告
- 深度 1 编排者收到通告,综合结果,完成 → 向主代理通告
- 主代理收到通告并投递给用户
每个层级只看到来自其直接子代理的通告。
按深度的工具策略
- 角色和控制范围在派生时写入会话元数据,防止扁平或恢复的会话键意外重获编排权限。
- 深度 1(编排者,当
maxSpawnDepth >= 2):获取sessions_spawn、subagents、sessions_list、sessions_history,以便管理其子代理。其他会话/系统工具仍被拒绝。 - 深度 1(叶节点,当
maxSpawnDepth == 1):无会话工具(当前默认行为)。 - 深度 2(叶工作节点):无会话工具——
sessions_spawn在深度 2 始终被拒绝,不能派生更多子代理。
每代理派生限制
每个代理会话(任意深度)最多可以同时有 maxChildrenPerAgent(默认:5)个活跃子代理,防止单个编排者失控扩张。
级联停止
停止深度 1 编排者会自动停止其所有深度 2 子代理:
- 在主聊天中发送
/stop会停止所有深度 1 代理并级联到其深度 2 子代理。 /subagents kill <id>停止特定子代理并级联到其子代理。/subagents kill all停止发起方的所有子代理并级联。
认证
子代理认证按代理 id 解析,而非会话类型:
- 子代理会话键为
agent:<agentId>:subagent:<uuid>。 - 认证存储从该代理的
agentDir加载。 - 主代理的认证配置作为回退被合并进来;代理配置在冲突时覆盖主配置。
注意:合并是附加式的,因此主配置始终作为回退可用。目前尚不支持每代理完全隔离认证。
通告
子代理通过通告步骤回报结果:
- 通告步骤在子代理会话内部运行(而非发起方会话)。
- 若子代理回复恰好为
ANNOUNCE_SKIP,则不发布任何内容。 - 否则投递取决于发起方深度:
- 顶层发起方会话使用带外部投递的后续
agent调用(deliver=true) - 嵌套发起方子代理会话收到内部后续注入(
deliver=false),使编排者可在会话内综合子结果 - 若嵌套发起方子代理会话已消失,OpenClaw 在可用时回退到该会话的发起方
- 顶层发起方会话使用带外部投递的后续
- 子代理完成聚合的范围限于当前发起方运行,防止陈旧的先前运行子输出泄漏到当前通告中。
- 通告回复在频道适配器可用时保留线程/话题路由。
- 通告上下文规范化为稳定的内部事件块:
- 来源(
subagent或cron) - 子会话键/id
- 通告类型 + 任务标签
- 从运行时结果派生的状态行(
success、error、timeout或unknown) - 来自通告步骤的结果内容(若缺失则为
(no output)) - 后续指令,说明何时回复与保持沉默
- 来源(
Status不从模型输出推断;它来自运行时结果信号。
通告载荷末尾包含统计行(即使被包装):
- 运行时(例如
runtime 5m12s) - Token 用量(输入/输出/总计)
- 配置了模型定价时的估算费用(
models.providers.*.models[].cost) sessionKey、sessionId和转录路径(主代理可通过sessions_history获取历史或在磁盘上检查文件)- 内部元数据仅用于编排;面向用户的回复应以正常助手语气重写。
工具策略(子代理工具)
默认情况下,子代理获取除会话工具和系统工具之外的所有工具:
sessions_listsessions_historysessions_sendsessions_spawn
当 maxSpawnDepth >= 2 时,深度 1 编排子代理另外获取 sessions_spawn、subagents、sessions_list 和 sessions_history,以便管理其子代理。
通过配置覆盖:
json5
{
agents: {
defaults: {
subagents: {
maxConcurrent: 1,
},
},
},
tools: {
subagents: {
tools: {
// deny 优先
deny: ["gateway", "cron"],
// 若设置 allow,变为仅允许模式(deny 仍优先)
// allow: ["read", "exec", "process"]
},
},
},
}并发
子代理使用专用进程内队列通道:
- 通道名称:
subagent - 并发:
agents.defaults.subagents.maxConcurrent(默认8)
停止
- 在发起方聊天中发送
/stop会中止发起方会话,并停止从中派生的所有活跃子代理运行,级联到嵌套子代理。 /subagents kill <id>停止特定子代理并级联到其子代理。
限制
- 子代理通告是尽力而为的,若网关重启,待处理的"回报通告"工作会丢失。
- 子代理仍共享同一网关进程资源;将
maxConcurrent视为安全阀。 sessions_spawn始终是非阻塞的:立即返回{ status: "accepted", runId, childSessionKey }。- 子代理上下文仅注入
AGENTS.md+TOOLS.md(无SOUL.md、IDENTITY.md、USER.md、HEARTBEAT.md或BOOTSTRAP.md)。 - 最大嵌套深度为 5(
maxSpawnDepth范围:1–5)。大多数用例推荐深度 2。 maxChildrenPerAgent限制每会话的活跃子代理数(默认:5,范围:1–20)。