openclaw源码解读(14)——多agent协同1:sessions_spawn 完整实现
subagent-spawn.ts — 多 Agent 调度中枢
subagent-spawn.ts 是sessions_spawn 工具的完整实现。当 Manager Agent 调用 sessions_spawn 派任务给 Worker 时,就是这个文件在跑。
-
所属层级:Agent 运行时 → 多 Agent 协作层。
-
核心职责:接收来自用户或父 Agent 的“生成子代理”请求,校验权限和资源,创建独立的子会话,配置模型、提示词、附件、线程绑定等,最后触发子 Agent 的执行。
-
调用方式:通过网关的
"agent"方法(内部调用callSubagentGateway)触发。
总体结构
spawnSubagentDirect(params, ctx) ← 唯一入口 L1046-1140
│
├── ① 校验层
│ ├── 参数校验:task/label/agentId/model L144-167
│ ├── 模式解析:run vs session, fork vs isolated
│ ├── 深度限制:callerDepth >= maxDepth → 拒绝 L1132-1140
│ ├── 并发限制:activeChildren >= maxChildren → 拒绝 L1142-1150
│ └── 沙箱检查:sandboxed parent 不能 spawn unsandboxed child L1225-1248
│
├── ② 目标解析
│ ├── resolveSubagentTargetPolicy:允许 spawn 到这个 agent 吗?L1201-1209
│ ├── resolveSubagentCapabilities:子 Agent 的角色 + 控制范围 L1251-1254
│ └── 生成 childSessionKey = "agent:{target}:subagent:{uuid}" L1216
│
├── ③ Model/Thinking 决策
│ ├── readRequesterThinkingLevel:继承父的 thinking 配置 L379-436
│ └── resolveSubagentModelAndThinkingPlan:最终模型+thinking L1263-1278
│
├── ④ Session 准备
│ ├── patchChildSession:写 spawnDepth/subagentRole/工具白名单 L1280-1298, L290-343
│ ├── prepareSubagentSessionContext:fork vs isolated L456-554
│ └── persistInitialChildSessionRuntimeModel:写入初始模型 L1336-1359
│
├── ⑤ Thread 绑定 [可选]
│ └── bindThreadForSubagentSpawn:Discord/Slack 线程绑定 L714-727, L834-948, L1361-1395
│
├── ⑥ 附件物化
│ └── materializeSubagentAttachments:写入文件系统 L1427-1443
│
├── ⑦ 启动 Agent (L760-L830) ★ 核心
│ └── callSubagentGateway({ method: "agent", ... }) L1530-1560
│ 发送 childTaskMessage → run-loop 启动
│
├── ⑧ 注册追踪
│ └── registerSubagentRun:登记到 subagent-registry L1636-1689
│
└── ⑨ 生命周期事件
├── subagent_progress hook L1691-1709
├── subagent_spawned hook L1711-1738
└── emitSessionLifecycleEvent L1741-1746
核心概念:子agent(Subagent)
子agent是 OpenClaw 中一种特殊的 Agent 运行实例,它:
-
拥有独立的会话(
childSessionKey),可持久化对话历史。 -
可以继承父会话的上下文(通过
fork模式复制历史消息),也可以隔离(isolated模式)。 -
可以绑定到特定通信线程(如 Discord/Slack 线程),让用户在同一个线程中与子代理交互。
-
受深度和并发限制,防止资源滥用。
-
支持附件注入,允许在启动时传入文件内容(如代码片段、文档),供子代理分析。
工作流程(10 步详解)
1️⃣ 校验层:参数解析与校验
-
校验
taskName合法性(normalizeSubagentTaskName)。L1051-1057 -
校验
agentId是否符合命名规范(isValidAgentId)。L1066-1071 -
根据
mode和thread确定生成模式(run或session)。 L1076-1087, L670-679, L714-727, -
解析上下文模式(
fork或isolated),并处理线程绑定请求。L438-454, L456-554 -
获取当前会话的深度(
getSubagentDepthFromSessionStore),确保不超过配置的maxSpawnDepth。L1132-1140
深度限制 → ClawForge 的 4 Agent 架构天然满足
// L480
const callerDepth = getSubagentDepthFromSessionStore(requesterInternalKey);
const maxSpawnDepth = cfg.agents?.defaults?.subagents?.maxSpawnDepth
?? DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH; // 默认值
if (callerDepth >= maxSpawnDepth) {
return { status: "forbidden", error: "..." };
}
ClawForge 是单层 spawn(Manager → Worker),depth 最多到 1,完全在限制内。
-
获取当前会话已激活的子代理数量(
countActiveRunsForSession),确保不超过maxChildrenPerAgent。L1142-1150
并发控制 → 并发锁方案的底层机制
// L490
const maxChildren = cfg.agents?.defaults?.subagents?.maxChildrenPerAgent
?? DEFAULT_SUBAGENT_MAX_CHILDREN_PER_AGENT;
const activeChildren = countActiveRunsForSession(requesterInternalKey);
if (activeChildren >= maxChildren) {
return { status: "forbidden", error: "..." };
}
这就是"lane 并发控制" 的底层实现。countActiveRunsForSession 来自 subagent-registry.ts。
2️⃣ 目标解析:权限与资源检查
-
如果配置了
requireAgentId,则必须显式指定agentId。L1152-1165 -
检查目标 Agent 是否允许被生成(
resolveSubagentTargetPolicy)。L1201-1215 -
格式:
agent:{targetAgentId}:subagent:{UUID}。确保全局唯一性。 L1216
3️⃣ Model/Thinking决策:模型与思考级别解析
-
根据父会话的模型、目标 Agent 的配置、显式传入的
model/thinking参数,通过resolveSubagentModelAndThinkingPlan确定最终使用的模型和思考级别。L1263-1278
4️⃣ 准备子会话上下文(fork 或 isolated)
-
调用
prepareSubagentSessionContext:-
如果
contextMode === "fork",通过forkSessionEntryFromParent从父会话克隆历史消息到子会话,实现上下文继承。 -
如果
contextMode === "isolated",子会话从零开始。
-
上下文模式:fork vs isolated
// L335 prepareSubagentSessionContext
if (params.contextMode === "isolated") {
return { status: "ok", mode: "isolated" }; // 空白新 Session
}
// fork 模式:复制父 Session 的对话历史
const forkedResult = await forkSessionEntryFromParent({...});
ClawForge 用 isolated(Worker 不需要 Manager 的对话历史),但如果 Worker 需要参考前面的分析结果,应该用 fork。
5️⃣ 线程绑定(如果 thread=true)
-
调用
bindThreadForSubagentSpawn,通过getSessionBindingService()将子会话绑定到当前通信平台的线程(如 Discord 线程)。 -
绑定成功后,
deliveryOrigin会更新,子代理的回复将路由到该线程。
6️⃣ 处理附件与系统提示
-
调用
materializeSubagentAttachments将传入的附件(文件内容)写入磁盘,并生成系统提示后缀(告知 Agent 附件位置)。 -
构建完整的
childSystemPrompt,包含任务描述、上下文、附件信息等。
7️⃣ 注册并启动子agent :核心启动调用→ 这就是"派任务"
-
通过
callSubagentGateway调用"agent"方法,传递消息、会话键、系统提示等,触发子代理的 Agent 循环执行。
// L790
const response = await callSubagentGateway({
method: "agent", // ← 触发 agent-run-handler 的 9 阶段流水线!
params: {
message: childTaskMessage, // 子 Agent 收到的第一条消息
sessionKey: childSessionKey,
lane: AGENT_LANE_SUBAGENT, // 标记为子 Agent 车道
disableMessageTool: true, // 子 Agent 不能用 messaging tool
cleanupBundleMcpOnRunEnd: spawnMode !== "session",
extraSystemPrompt: childSystemPrompt, // 额外系统提示
thinking: thinkingOverride,
timeout: runTimeoutSeconds,
},
timeoutMs: resolveSubagentAgentGatewayTimeoutMs(runTimeoutSeconds),
});
调用 method: "agent" 后,整个 agent-run-handler 9 阶段流水线重新走一遍,然后进入 run-loop。这就是子 Agent 的完整执行链路。agent-run-handler 9阶段过程见:openclaw源码解读(9)—— Agent执行链路2:agent-run-handler.ts 核心 Pipeline 每个 Agent 的执行生命周期-CSDN博客
8️⃣ 注册追踪:注册并启动子代理
-
调用
registerSubagentRun将子代理运行信息注册到全局 registry(用于后续清理、状态跟踪)。
registerSubagentRun 的追踪机制,请见下一篇博客:openclaw源码解读之 subagent-registry.ts
9️⃣ 处理附件与系统提示
-
调用
materializeSubagentAttachments将传入的附件(文件内容)写入磁盘,并生成系统提示后缀(告知 Agent 附件位置)。 -
构建完整的
childSystemPrompt,包含任务描述、上下文、附件信息等。
附件传递 → AgentTeams 的 MinIO 替代方案
// L730 materializeSubagentAttachments
// 把 attachments: [{name, content, encoding, mimeType}]
// 写入子 Agent 的工作空间
const materializedAttachments = await materializeSubagentAttachments({
config: cfg,
targetAgentId,
workspaceDir: spawnedCwd ?? spawnedWorkspaceDir,
attachments: params.attachments,
mountPathHint,
});
这就是文件产物的原生传递机制!AgentTeams 用 MinIO shared/tasks/{task-id}/,而 OpenClaw 原生通过 attachments 参数直接传文件。
🔟 注册并启动子代理
-
调用
registerSubagentRun将子代理运行信息注册到全局 registry(用于后续清理、状态跟踪)。 -
通过
callSubagentGateway调用"agent"方法,传递消息、会话键、系统提示等,触发子代理的 Agent 循环执行。L1530-1560
ClawForge 映射
| spawnSubagentDirect 步骤 | ClawForge 对应 |
|---|---|
| targetPolicy 检查 | AgentTeams 的 Worker CRD 允许列表 |
| spawnDepth 限制 | 4 Agent 单层结构,depth≤1 |
| maxChildren 并发 | .processing 分布式锁的底层原理 |
| contextMode | Worker 用 isolated(不继承对话) |
| attachments 传递 | 替代 MinIO 的原生文件传递 |
| method: "agent" | 触发完整 run-loop,Worker 开始干活 |
| registerSubagentRun | AgentTeams 的 task 状态追踪 |
| subagent_spawned hook | 通知 Manager "任务已下发" |
一句话总结
subagent-spawn.ts就是一条流水线:校验 → 准备 → 下发 → 追踪。ClawForge 的 Manager 调用sessions_spawn时,这个文件负责确保子 Agent 在正确的上下文、正确的权限、正确的并发限制下启动,并全程追踪其生命周期。
注:本文中提到的ClawForge是我做的多agent协同的研发全流程代码自愈与审查系统,详见:openclaw源码解读——高阶与淬炼:1. 面向软件研发全流程的多Agent 协同代码审查与自愈系统设计(初稿)-CSDN博客
更多推荐
所有评论(0)