子代理
子代理是从现有代理运行派生的后台代理运行。它们在自己的会话中运行(agent:<agentId>:subagent:<uuid>),完成后公告其结果回请求方聊天频道。
斜杠命令
使用 /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 ttl <duration|off>
/subagents info 显示运行元数据(状态、时间戳、会?ID、记录路径、清理)?
派生行为
/subagents spawn 将后台子代理作为用户命令启动(不是内部中继),并在运行结束时向请求方聊天发送一条最终完成更新?
- 派生命令是非阻塞的;它立即返回运?ID?
- 完成后,子代理向请求方聊天频道公告摘?结果消息?
- 对于手动派生,交付具有弹性:
- OpenClaw 首先尝试使用稳定的幂等键进行直接
agent交付? - 如果直接交付失败,则回退到队列路由?
- 如果队列路由仍然不可用,则在最终放弃之前以退避重试短指数公告?
- OpenClaw 首先尝试使用稳定的幂等键进行直接
- 完成消息是一条系统消息,包括?
Result(助手回复文本,或如果助手回复为空则使用最新的toolResult?- 状态(
completed successfully/failed/timed out? - 紧凑的运行时/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 代理?
主要目标?
- 并行?研究/长时间任?慢速工?工作而不阻塞主运行?
- 默认保持子代理隔离(会话分离 + 可选沙箱)?
- 保持工具表面难以误用:子代理默认**?*获取会话工具?
- 支持可配置的嵌套深度以实现编排器模式?
成本说明:每个子代理?*自己?*上下文和 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?
线程绑定会话
当频道启用线程绑定时,子代理可以绑定到线程,以便该线程中的后续用户消息继续路由到同一个子代理会话?
支持线程的频?
- Discord(目前是唯一支持的频道):支持持久的线程绑定子代理会话(
sessions_spawn配合thread: true)、手动线程控制(/focus、/unfocus、/agents、/session ttl),以及适配器键channels.discord.threadBindings.enabled、channels.discord.threadBindings.ttlHours?channels.discord.threadBindings.spawnSubagentSessions?
快速流程:
- 使用
sessions_spawn配合thread: true(和可选的mode: "session")派生? - OpenClaw 在活动频道中创建或绑定一个线程到该会话目标?
- 该线程中的回复和后续消息路由到绑定的会话?
- 使用
/session ttl检?更新自动取消聚焦 TTL? - 使用
/unfocus手动分离?
手动控制?
/focus <target>将当前线程(或创建一个)绑定到子代理/会话目标?/unfocus移除当前绑定线程的绑定?/agents列出活动运行和绑定状态(thread:<id>?unbound)?/session ttl仅适用于聚焦的绑定线程?
配置开关:
- 全局默认:
session.threadBindings.enabled、session.threadBindings.ttlHours - 频道覆盖和派生自动绑定键是适配器特定的。参见上面的**支持线程的频?*?
白名单:
agents.list[].subagents.allowAgents:可以通过agentId定位的代?ID 列表(["*"]允许任何)。默认:仅请求方代理?
发现?
- 使用
agents_list查看当前允许用于sessions_spawn的代?ID?
自动归档?
- 子代理会话在
agents.defaults.subagents.archiveAfterMinutes(默认:60)后自动归档? - 归档使用
sessions.delete并将记录重命名为*.deleted.<timestamp>(同一文件夹)? cleanup: "delete"在公告后立即归档(仍通过重命名保留记录)?- 自动归档是尽力而为的;如果网关重启,待处理的定时器会丢失?
runTimeoutSeconds不会自动归档;它只是停止运行。会话保持到自动归档?- 自动归档同样适用于深?1 和深?2 的会话?
嵌套子代?
默认情况下,子代理无法派生自己的子代理(maxSpawnDepth: 1)。你可以通过设置 maxSpawnDepth: 2 来启用一级嵌套,这允?编排器模?:主代理 ?编排器子代理 ?工作子子代理?
如何启用
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // 允许子代理派生子级(默认??
maxChildrenPerAgent: 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)发布到请求方聊天频道? - 公告回复在频道适配器支持时保留线程/主题路由?
- 公告消息规范化为稳定模板?
Status:派生自运行结果(success、error、timeout?unknown)?Result:公告步骤的摘要内容(如果缺失则为(not available))?Notes:错误详情和其他有用上下文?
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 以便管理其子级?
通过配置覆盖?
{
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范围?-5)。大多数用例推荐深度 2? maxChildrenPerAgent限制每个会话的活动子级(默认?,范围:1-20)?