Skip to content

子代理是 OpenClaw 后台并行任务的核心机制。主代理通过 sessions_spawn 工具派生独立子代理会话处理耗时工作,完成时自动通告结果回发起频道。本页覆盖完整用法:/subagents 指令、工具参数、线程绑定(Discord)、嵌套编排(主 → 编排者 → 工作节点)、通告链、工具策略配置,以及并发和自动归档设置。

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、转录路径、清理信息)。 用 sessions_history 获取有界、安全过滤的历史视图;需要原始完整转录时检查磁盘上的转录路径。

派生行为

/subagents spawn 以用户命令方式启动后台子代理(而非内部中继),运行结束时向发起聊天发送一条最终完成通告。

  • 派生命令是非阻塞的,立即返回一个 run id。
  • 完成时,子代理向发起聊天频道通告摘要/结果消息。
  • 完成是推送式的。派生后,不要用轮询 /subagents listsessions_listsessions_history 的循环来等待完成;仅按需检查状态进行调试或干预。
  • 完成时,OpenClaw 尽力关闭该子代理会话打开的浏览器标签/进程,然后继续通告清理流程。
  • 对于手动派生,通告具有弹性:
    • OpenClaw 首先尝试带稳定幂等键的直接 agent 投递。
    • 直接投递失败则回退到队列路由。
    • 队列路由仍不可用则以短指数退避重试,最终放弃。
  • 完成交接给发起会话的内容是运行时生成的内部上下文(非用户编写的文本),包括:
    • Result(最新可见的 assistant 回复文本,或对应 sanitized 的最新工具/工具结果文本)
    • Statuscompleted successfully / failed / timed out / unknown
    • 紧凑运行时/token 统计
    • 投递指令,告知发起代理以正常助手语气重写(而非转发原始内部元数据)
  • --model--thinking 可针对该次运行覆盖默认值。
  • 完成后使用 info/log 检查详情和输出。
  • /subagents spawn 是一次性模式(mode: "run")。如需持久线程绑定会话,使用 sessions_spawn 并设置 thread: truemode: "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,默认 inheritrequire 在目标子运行时未沙箱化时拒绝派生)
  • sessions_spawn 接受频道投递参数(targetchanneltothreadIdreplyTotransport)。如需投递,从派生运行中使用 message/sessions_send

线程绑定会话

当频道启用线程绑定时,子代理可以保持绑定到某个线程,使该线程中的后续用户消息继续路由到同一子代理会话。

支持线程的频道

  • Discord(目前唯一支持的频道):支持持久线程绑定子代理会话(sessions_spawnthread: true)、手动线程控制(/focus/unfocus/agents/session idle/session max-age),以及适配器键 channels.discord.threadBindings.enabledchannels.discord.threadBindings.idleHourschannels.discord.threadBindings.maxAgeHourschannels.discord.threadBindings.spawnSubagentSessions

快速流程:

  1. 使用 sessions_spawn 派生,设置 thread: true(可选 mode: "session")。
  2. OpenClaw 在活动频道中创建或绑定一个线程到该会话目标。
  3. 该线程中的回复和后续消息路由到绑定的会话。
  4. 使用 /session idle 检查/更新不活跃自动解绑,/session max-age 控制硬性上限。
  5. 使用 /unfocus 手动解除绑定。

手动控制:

  • /focus <target> 将当前线程(或创建一个)绑定到子代理/会话目标。
  • /unfocus 移除当前绑定线程的绑定。
  • /agents 列出活跃运行和绑定状态(thread:<id>unbound)。
  • /session idle/session max-age 仅对已聚焦绑定线程生效。

配置开关:

  • 全局默认:session.threadBindings.enabledsession.threadBindings.idleHourssession.threadBindings.maxAgeHours
  • 频道覆盖和派生自动绑定键是适配器特定的,见上方支持线程的频道

白名单:

  • agents.list[].subagents.allowAgents:可通过 agentId 指定的代理 id 列表(["*"] 表示允许任意)。默认:仅发起代理。
  • agents.defaults.subagents.allowAgents:当发起代理未设置自己的 subagents.allowAgents 时使用的默认目标代理白名单。
  • 沙箱继承保护:若发起会话已沙箱化,sessions_spawn 拒绝会在非沙箱运行的目标。
  • agents.defaults.subagents.requireAgentId / agents.list[].subagents.requireAgentId:为 true 时,阻止省略 agentIdsessions_spawn 调用(强制明确选择配置文件)。默认:false。

发现:

  • 使用 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 = 无超时)
      },
    },
  },
}

深度层级

深度会话键形状角色可以派生?
0agent:<id>:main主代理始终可以
1agent:<id>:subagent:<uuid>子代理(深度 2 允许时充当编排者)仅当 maxSpawnDepth >= 2
2agent:<id>:subagent:<uuid>:subagent:<uuid>子子代理(叶工作节点)从不

通告链

结果沿链条向上传递:

  1. 深度 2 工作节点完成 → 向其父节点(深度 1 编排者)通告
  2. 深度 1 编排者收到通告,综合结果,完成 → 向主代理通告
  3. 主代理收到通告并投递给用户

每个层级只看到来自其直接子代理的通告。

操作指导:

  • 启动子任务一次后等待完成事件,而非围绕 sessions_listsessions_history/subagents listexec sleep 命令构建轮询循环。
  • 如果子任务完成事件在你已发送最终答案之后到达,正确的后续处理是精确的静默令牌 NO_REPLY / no_reply

按深度的工具策略

  • 角色和控制范围在派生时写入会话元数据,防止扁平或恢复的会话键意外重获编排权限。
  • 深度 1(编排者,当 maxSpawnDepth >= 2:获取 sessions_spawnsubagentssessions_listsessions_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,则不发布任何内容。
  • 若最新 assistant 文本恰好为静默令牌 NO_REPLY / no_reply,即使之前有可见进度,通告输出也会被抑制。
  • 否则投递取决于发起方深度:
    • 顶层发起方会话使用带外部投递的后续 agent 调用(deliver=true
    • 嵌套发起方子代理会话收到内部后续注入(deliver=false),使编排者可在会话内综合子结果
    • 若嵌套发起方子代理会话已消失,OpenClaw 在可用时回退到该会话的发起方
  • 对于顶层发起方会话,完成模式直接投递首先解析任何绑定的会话/线程路由和钩子覆盖,然后从发起方会话存储的路由中填充缺失的频道目标字段,确保即使完成来源只标识了频道,完成通告也能落到正确的聊天/话题。
  • 子完成聚合的范围限于当前发起方运行,防止陈旧的先前运行子输出泄漏到当前通告中。
  • 通告回复在频道适配器可用时保留线程/话题路由。
  • 通告上下文规范化为稳定的内部事件块:
    • 来源(subagentcron
    • 子会话键/id
    • 通告类型 + 任务标签
    • 从运行时结果派生的状态行(successerrortimeoutunknown
    • 来自最新可见 assistant 文本的结果内容,否则为 sanitized 的最新工具/工具结果文本
    • 后续指令,说明何时回复与保持沉默
  • Status 不从模型输出推断;它来自运行时结果信号。
  • 超时时,若子代理仅完成了工具调用,通告可以将该历史折叠为简短的部分进度摘要,而非重播原始工具输出。

通告载荷末尾包含统计行(即使被包装):

  • 运行时(例如 runtime 5m12s
  • Token 用量(输入/输出/总计)
  • 配置了模型定价时的估算费用(models.providers.*.models[].cost
  • sessionKeysessionId 和转录路径(主代理可通过 sessions_history 获取历史或在磁盘上检查文件)
  • 内部元数据仅用于编排;面向用户的回复应以正常助手语气重写。

sessions_history 是更安全的编排路径:

  • assistant 回调在规范化前:
    • 剥离 thinking 标签
    • 剥离 <relevant-memories> / <relevant_memories> 脚手架块
    • 剥离纯文本工具调用 XML 载荷块(<tool_call>...</tool_call><function_call>...</function_call><tool_calls>...</tool_calls><function_calls>...</function_calls>),包括未正常关闭的截断载荷
    • 剥离降级的工具调用/结果脚手架和历史上下文标记
    • 剥离泄漏的模型控制 token(<|assistant|>、其他 ASCII <|...|> token 和全角 <|...|> 变体)
    • 剥离格式错误的 MiniMax 工具调用 XML
  • 凭证/token 类文本被脱敏
  • 长块可能被截断
  • 非常大的历史记录可能丢弃较旧的行,或用 [sessions_history omitted: message too large] 替换过大的行
  • 磁盘上的原始转录是需要完整字节级转录时的回退方案

工具策略(子代理工具)

默认情况下,子代理获取除会话工具和系统工具之外的所有工具

被排除的工具:

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

maxSpawnDepth >= 2 时,深度 1 编排子代理另外获取 sessions_spawnsubagentssessions_listsessions_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.mdIDENTITY.mdUSER.mdHEARTBEAT.mdBOOTSTRAP.md)。
  • 最大嵌套深度为 5(maxSpawnDepth 范围:1–5)。大多数用例推荐深度 2。
  • maxChildrenPerAgent 限制每会话的活跃子代理数(默认:5,范围:1–20)。

常见问题

Q: 派生子代理后我要一直轮询状态吗?

A: 不需要。sessions_spawn 是非阻塞的,完成时会自动推送通告。不要用 sleep 循环轮询 sessions_listsessions_history——等待完成事件即可。如果在主代理已发送最终答案后收到子代理完成通告,用静默令牌 NO_REPLY 不回复即可。

Q: 子代理的 token 费用怎么算?

A: 每个子代理有独立上下文和 token 用量,与主代理完全独立计费。对于大量并行任务,通过 agents.defaults.subagents.model 为子代理设置更便宜的模型(如 haiku),主代理保持高质量模型以节省成本。

Q: 如何限制子代理的工具权限?

A: 通过 tools.subagents.tools.deny 指定要拒绝的工具列表;或通过 tools.subagents.tools.allow 设置仅允许列表。deny 始终优先于 allow。注意即使在 allow 列表中,sessions_spawn 等会话工具在深度 2 子代理中也始终被拒绝。