Swarm
Swarm 从 Code Mode 脚本中编排许多子代理。它默认启用,并提供显式退出选项。使用普通的 JavaScript 控制流(如 Promise.all、while 和 if)来分发工作、收集结果并做出决策。
没有图 DSL,也没有独立的工作流格式。程序即编排。Swarm 为该程序添加了可等待的收集器子代理、结构化结果、有界并发和进度报告。
何时使用 Swarm¶
对于一两个子代理,使用普通的 sessions_spawn 公告运行。将 Swarm 保留给大规模并行扇出:多个相似子代理(大约五个或更多),通常由 Code Mode 的 agents.run 配合 Promise.all 等控制流驱动。收集器子代理(collect: true)不发送完成通知,也无法被引导。其结果必须显式收集。使用 outputSchema 获取结构化结果,并使用 groupId 对一批子代理进行分组。
启用 Swarm¶
Swarm 无需启用设置。省略 tools.swarm、空对象或仅设置限制的对象都会保持 Swarm 启用。Code Mode 仍单独选择加入,且普通工具策略仍然适用。现有 Codex 会话可能保留旧的工具目录。参见下文中的新会话指南。
若要退出,请在设置 → 代理默认值 → 工具中禁用 Swarm,或在 openclaw.json 中设置 tools.swarm: false:
swarm: { enabled: false } 具有相同效果,同时保留已配置的限制。若要重新启用 Swarm,请移除显式退出设置,设置 swarm: true 或 swarm: { enabled: true },或在设置 → 代理默认值 → 工具中启用它。
若要调整限制,请使用对象形式。以下是默认值。你只需包含想要更改的值:
{
tools: {
swarm: {
maxConcurrent: 32,
maxChildrenPerGroup: 50,
maxTotalPerGroup: 200,
waitTimeoutSecondsMax: 600,
defaultAgentId: "",
},
},
}
| 字段 | 默认值 | 描述 |
|---|---|---|
enabled |
true |
在工具策略允许的情况下启用收集器功能;设置 false 可退出。Code Mode 有下文中的额外要求。 |
maxConcurrent |
32 |
一个 Swarm 组执行通道中并发运行的最大收集器子代理数。额外接受的子代理按 FIFO 排队。 |
maxChildrenPerGroup |
50 |
一个组中存活的收集器子代理最大数量。 |
maxTotalPerGroup |
200 |
一个组在其生命周期内可生成的收集器子代理最大数量。这是失控生成的兜底限制。 |
waitTimeoutSecondsMax |
600 |
一次 agents_wait 调用接受的最大超时时间。该调用默认值为 30 秒。 |
defaultAgentId |
"" |
当生成时省略 agentId 时使用的目标代理。空值使用请求方代理。现有子代理允许列表适用。 |
数值必须为正整数。OpenClaw 将 maxConcurrent 限制在 1–1000,maxChildrenPerGroup 限制在 1–10000,maxTotalPerGroup 限制在 1–100000,waitTimeoutSecondsMax 限制在 1–86400。
每个组都有自己独立的执行通道,独立于父级的普通子代理限制。为每个运行中的子代理预留一个模型流和一个 Code Mode 工作器隔离环境。提高 maxConcurrent 会增加模型和 Gateway 资源使用;它不会提高 maxChildrenPerGroup 或 maxTotalPerGroup。
你可以使用 agents.entries.*.tools.swarm 为某个已配置代理覆盖 Swarm。每个代理的值会合并到顶层设置之上。某个代理的 false 或 { enabled: false } 会禁用该代理的 Swarm。true 或 { enabled: true } 即使全局禁用也会启用它。仅包含限制的每代理对象会继承全局启用状态,因此不会重新启用全局 false。
要求¶
若要使用 agents.run、phase 和 log 来宾全局变量,请启用 OpenClaw Code Mode 并保持 Swarm 启用:
Code Mode 仅当其目录包含原生 OpenClaw sessions_spawn 工具且本次运行的执行允许列表允许时,才暴露这些全局变量、API.read("agents.d.ts") 和 Swarm 提示线索。同名 MCP 工具不符合条件。工具配置文件、允许/拒绝策略、提供商规则和沙箱策略可能会移除原生工具。如果缺少 Swarm API,请检查Code Mode 激活和子代理。
Code Mode 内部等待收集器结果。其 agents.run() API 不要求允许独立的 agents_wait 工具。底层工具流程 需要同时允许 sessions_spawn 和 agents_wait。启用 Swarm 绝不会授予工具或绕过策略。
defaultAgentId 和每次运行的 agentId 值必须指定请求方 subagents.allowAgents 策略允许的已配置目标。OpenClaw 会拒绝未知或不允许的目标,而不是回退到另一个代理。
编写 Swarm 脚本¶
当满足要求时,Code Mode 会暴露此来宾 API:
type AgentRunOptions = {
label?: string;
model?: string;
thinking?: string;
fastMode?: boolean | "auto";
agentId?: string;
schema?: Record<string, unknown>;
phase?: string;
};
agents.run(prompt: string, options?: AgentRunOptions & { schema?: undefined }): Promise<string>;
agents.run<T>(prompt: string, options: AgentRunOptions & { schema: Record<string, unknown> }): Promise<T>;
phase(title: string): void;
log(message: string): void;
没有 schema 时,agents.run() 会解析为子代理的最终文本。提供 JSON Schema 时,它会解析为子代理通过 structured_output 工具提交的值。失败、被终止、超时或 schema 无效的子代理会以一个错误拒绝该 Promise,该错误的 name 为 "SwarmAgentError",其 runId、status 和 message 用于标识失败的子代理及结果。不存在全局的 SwarmAgentError 构造函数。请检查捕获到的错误字段。生成或桥接失败可能以其他错误拒绝。在 Code Mode 中,从 API.read("agents.d.ts") 读取确切的生成声明和简短编排惯用法。
在会话记录中,使用 label 作为可识别的子代理名称。在选项中使用 phase,可立即在该子代理启动前发布一个阶段;或者当多个子代理属于同一阶段时,调用 phase()。log() 会发布一条简短的进度说明。进度调用是即发即忘的。如果 UI 不可用,它们不会延迟脚本。
并行扇出并返回结构化结果¶
此示例为每个主题启动一个研究员,等待所有结果,然后要求最后一个子代理综合成功的报告。即使综合也失败,失败的通道仍会保留在结果中:
const reportSchema = {
type: "object",
properties: {
finding: { type: "string" },
evidence: { type: "array", items: { type: "string" } },
confidence: { type: "number" },
},
required: ["finding", "evidence", "confidence"],
additionalProperties: false,
};
const topics = ["authentication", "storage", "recovery"];
phase("Independent review");
const settled = await Promise.allSettled(
topics.map((topic) =>
agents.run(`Review the ${topic} path. Return one finding with evidence.`, {
label: `review-${topic}`,
thinking: "high",
fastMode: "auto",
schema: reportSchema,
}),
),
);
const reports = [];
const failures = [];
for (const [index, outcome] of settled.entries()) {
if (outcome.status === "fulfilled") {
reports.push({ topic: topics[index], report: outcome.value });
} else {
failures.push({ topic: topics[index], error: String(outcome.reason) });
}
}
if (reports.length === 0) return { reports, failures };
phase("Synthesis");
log(`Collected ${reports.length} reports; ${failures.length} lanes failed.`);
try {
const synthesis = await agents.run(
`Reconcile these reports, explain disagreements, and disclose failed lanes:\n${JSON.stringify({ reports, failures })}`,
{ label: "synthesis" },
);
return { synthesis, reports, failures };
} catch (error) {
return { reports, failures, synthesisError: String(error) };
}
Promise.allSettled 在等待所有子代理时保留部分结果。Promise.all 会在第一个失败时拒绝,并且不会替你收集其余结果。保留已完成的工作并报告失败的通道。不要自动重新生成该批次。稍后的 provider 失败仍可能阻止最终模型回复,因此请保留已收集的结果以便恢复。
OpenClaw 会为组启动最多 maxConcurrent 个子代理,并按提交顺序将其余子代理排队。
Code Mode 使用 tools.codeMode.maxPendingToolCalls(默认 16,最大 128)单独限制并发的来宾桥接调用。当这些槽位已满时,Swarm 启动、进度说明和结果等待会自动排队。排队的请求在快照恢复期间保留其原始参数。停止运行会丢弃尚未被接纳的请求。maxConcurrent 仍限制正在运行的子代理数量,组子代理限制仍然适用。普通工具调用和定时器共享此来宾队列,但拥有自己的 128 个请求等待配额,独立于在途桥接上限。Swarm 启动、说明和结果等待不会消耗该配额,并保留其现有的组、VM 内存和快照限制。超出普通配额会在来自该配额的任何新调用被分发之前使同步前沿失败。改为等待更小的普通批次。有关队列、取消和资源限制语义,请参阅 Code Mode。
在决策门控上循环¶
当每一轮都需要判断是否还需要另一轮时,使用有界的 while 循环:
const gateSchema = {
type: "object",
properties: {
ready: { type: "boolean" },
reason: { type: "string" },
nextAction: { type: "string" },
},
required: ["ready", "reason", "nextAction"],
additionalProperties: false,
};
let pass = 0;
let decision = { ready: false, reason: "Not checked", nextAction: "Review" };
while (!decision.ready && pass < 4) {
pass += 1;
phase(`Decision pass ${pass}`);
decision = await agents.run(
`Check whether the release evidence is complete. Previous decision: ${JSON.stringify(decision)}`,
{
label: `release-gate-${pass}`,
schema: gateSchema,
},
);
log(decision.reason);
}
if (!decision.ready) {
throw new Error(`Gate still closed after ${pass} passes: ${decision.nextAction}`);
}
return decision;
始终为决策循环设置边界。maxTotalPerGroup 是最终的安全兜底,而不是清晰停止条件的替代品。
处理第一个完成的子代理¶
agents.run() 返回一个普通 Promise,因此 Promise.race 可以响应第一个 Code Mode 子代理。对于调用较低层工具的 harness,agents_wait 提供相同的“首个完成”边界:只要至少一个请求的运行完成,或有界超时到期,它就会返回。有关完整的排空循环,请参阅 从其他 harness 使用 Swarm。
收集器子代理的行为方式¶
收集器子代理是普通的隔离子代理会话,但具有不同的完成路径。它们会写入一个持久的收集器结果供父级等待,而不是将回复宣告或引导回父会话。已接受的生成回执描述了这一路径:使用 agents_wait 收集结果,或在 OpenClaw Code Mode 中等待 agents.run()。不要使用 sessions_yield 等待收集器子代理。它们不会发送完成通知。
嵌入式和 CLI 支持的收集器轮次不提供 sessions_yield。如果覆盖到达该工具,它会返回一个错误,说明收集器结果是显式收集的。尽管如此,如果某个收集器通过其他路径让出,它会在自己的终端处结算,而不是暂停,因此该轮次会结束,并且其收集到的结果会被记录给等待方。
目标代理按以下顺序解析:
- 生成或
agents.run()调用上的agentId。 tools.swarm.defaultAgentId。- 请求代理。
当收集器子代理需要更小的工具面、更便宜的模型或更严格的沙箱策略时,一个专用的精简 worker 代理很有用。OpenClaw 不附带内置的 worker 代理 id。在将其命名为默认值之前,请先配置一个。在其按代理配置中使用 tools.swarm: false 加固该 worker,使其可以被生成,但不能从它自己的顶级会话启动 swarm:
{
tools: { swarm: { enabled: true, defaultAgentId: "worker" } },
agents: {
entries: {
main: {
default: true,
subagents: { allowAgents: ["worker"] },
},
worker: { tools: { swarm: false } },
},
},
}
收集器审批采用失败关闭策略。子代理永远不会打开操作员审批提示。需要审批的工具操作会被拒绝,子代理可以在其结果中报告该拒绝,以便脚本决定下一步操作。
对于结构化输出,OpenClaw 会为子代理添加一个合成的 structured_output 工具,并针对提供的 JSON Schema 验证其负载。无效负载会收到一次纠正性提示。如果未提交负载,或者重试后仍无法通过验证,收集器完成会保留子代理的原始文本,保持 structured 未设置,并包含 schemaError。低层 agents_wait 结果会暴露这些字段,用于显式恢复逻辑。
保持收集器组扁平¶
收集器子代理可以递归委派,但常见的编排惯用法是将工作返回给父代理,而不是扩展收集器树:
const plan = await agents.run("Plan this job as independent tasks.", {
schema: {
type: "object",
properties: { tasks: { type: "array", items: { type: "string" } } },
required: ["tasks"],
additionalProperties: false,
},
});
return await Promise.all(plan.tasks.map((task) => agents.run(task)));
对于 Swarm,不鼓励嵌套收集器子代理。组上限、预算和可观测性都假设收集器组是扁平的。当工作流必须强制该结构时,请设置 agents.defaults.subagents.maxSpawnDepth: 1。
每个子代理都有一个准入所有者。Announce 和交互式子代理使用 agents.defaults.subagents.maxChildrenPerAgent(默认 5),并且不计入收集器子代理。收集器子代理仅使用 maxChildrenPerGroup 和 maxTotalPerGroup。它们不会消耗每会话子代理预算。生成深度保护仍然适用于这两种模式。
准入后,收集器子代理在 subagent:swarm:<schedulerGroupKey> 中执行,受该组解析后的 tools.swarm.maxConcurrent(默认 32)限制。额外的子代理按 FIFO 排队。它们不会消耗父代理的普通 subagent:<immediate session> 槽位,这些槽位仍受 agents.defaults.subagents.maxConcurrent(默认 8)限制。由收集器生成的普通子代理使用收集器自己的会话通道。超过任一组合准入上限的收集器生成会被拒绝,并在错误中包含相关配置键。
观察 Swarm¶
在 swarm 活动期间,请在 Chat 中保持父会话打开。Control UI 以及原生 Android、iOS 和 macOS 聊天界面会在转录和输入框之间显示一个紧凑的 Swarm 进度组件。
在 Control UI 中,卡片会显示排队、运行中、已完成以及 失败或已停止 的数量,并带有可见的状态标记。合并计数包括失败、超时和已取消的子代理;摘要不会单独报告这些结果。点击或轻点 子代理详情,或使用键盘激活它,以展开可用的子代理名称、状态图标和运行时长。该视图最多显示四个活动组以及最近完成的组;当有更多活动组时,会显示明确计数。每张卡片最多显示 64 个标记和 64 个子代理详情。其计数包括每个已接受的组成员。
最近完成组的计数在子代理完成后仍保持可见,即使父代理在写入最终响应之前失败也是如此。所有子代理都成功的组使用紧凑的完成行。激活该行以展开子代理详情和最终响应提醒。包含运行中、排队、失败或已停止子代理的组会保留其可见的状态标记和计数。这些是子代理结果,而不是父代理已生成综合结果的确认。计数来自保留的收集器记录,因此重新加载页面或清理子代理会话不会减少报告的总数。它们会随着现有收集器保留策略过期。这不是永久执行归档。
原生 Android、iOS 和 macOS 聊天界面仍显示仅活动的按阶段分组网格,每个阶段最多 256 个标记,并带有溢出计数。可访问标签会标识每个子代理的状态。原生客户端将已终止和超时的子代理显示为失败。当原生组没有任何子代理处于排队或运行状态时,它们会离开组件。当没有剩余活动组时,原生组件会消失。
收集器子代理会出现在其会话转录中。它们没有会话侧边栏行。它们的活动和未读失败仍会计入父代理的侧边栏环和注意力信号。持久生成的会话和分支保持其正常的侧边栏嵌套。
删除模式的收集器子代理可以在完成后立即清理其子代理会话,同时保留其可等待结果。这些收集器记录在组归档之前保持可用,归档发生在每个成员达到其保留期限之后。保留的子代理会话会在该时点作为一批归档。
重置子会话会在更改该会话之前持久地撤销已完成运行的清理,因此延迟的清理重试无法删除其替代会话。如果完成状态尚未稳定,或无法保存撤销操作,重置会失败。如果重置失败,或在撤销已保存后 Gateway 停止,原始会话可能仍会保留,且该清理功能处于禁用状态。Collector 结果和任务结果保持其正常保留期,活动中的重置延续会继续运行。
停止 Swarm¶
在父聊天中使用 Stop 取消正在运行的 Swarm。针对特定父级运行的 Stop 还会取消关联的 Collector 子项及其嵌套后代。Collector 模式改变的是结果投递方式,而不是取消范围。成功取消会阻止所选的排队子项启动,同时运行中的同级项停止。它不会取消来自无关父级轮次的工作。
如果 Stop 报告后代取消不完整,请使用 subagents 并设置 action: "list" 检查剩余工作,然后重试取消这些子项。仅父级停止并不能确认所有子项都已停止,取消确认也不保证运行时立即清理。
当父级正常完成、让出或超时时,已接受的子项仍保持独立。如果父级不再处于活动状态,请直接取消子任务。有关精确运行和全会话范围的 Stop 作用域,请参阅 子代理停止。
从其他 harness 使用 Swarm¶
你可以在不使用 OpenClaw Code Mode 的情况下使用 Swarm。其核心工具与 harness 无关:使用 sessions_spawn({ collect: true }) 启动 Collector 子项,并使用有界的 agents_wait 调用排空它们。这两个工具都必须被生效的工具策略允许。默认开启的 Swarm 不会将它们添加到限制性工具配置或允许列表中。
Codex Code Mode 会自动在 tools.* 下暴露符合条件的动态 OpenClaw 工具。它不使用 OpenClaw 的 guest API,也不要求 tools.codeMode,但仍必须启用 tools.swarm。Codex harness 的 agents_wait 调用支持完整的 600 秒超时。
Codex 会在原生线程启动时记录其动态工具目录。未包含 agents_wait 的线程仅通过启用 Swarm 或升级 OpenClaw 无法获得该读取器,因此 Collector 生成字段在该线程上仍不可用。对于普通未锁定聊天,请使用 /new 或 /reset 以当前工具开始。对于 受监督的、模型锁定的 Chat,请打开 Control UI 的全局 New Session 页面,并选择一个具体的 Codex 支持的模型,以启动一个独立的普通会话。保持受监督的 Chat 完整:/new、/reset 以及与父级关联的 New chat 在那里被阻止。新会话仍需要一个允许这两个 Collector 工具的工具策略。
在当前支持的 Codex 运行时中,动态 OpenClaw 工具结果会以 JSON 文本形式到达 Code Mode。在读取字段之前,请解析每个结果。Codex 还会串行化动态工具调用,因此 Promise.all 不会并发提交多个 sessions_spawn 调用。请在有界循环中启动 Collector 子项。已接受的子项仍可在后续启动提交时继续运行。
function parseToolResult(value) {
if (typeof value !== "string") return value;
return JSON.parse(value);
}
const tasks = [
"Check the authentication path.",
"Check the storage path.",
"Check the recovery path.",
];
const launches = [];
const failures = [];
for (const [index, task] of tasks.entries()) {
const launch = parseToolResult(
await tools.sessions_spawn({
task,
collect: true,
label: `review-${index + 1}`,
}),
);
if (launch.status !== "accepted") {
failures.push({ task, error: launch.error ?? "Collector spawn was not accepted." });
continue;
}
launches.push(launch);
}
const pending = new Set(launches.map((launch) => launch.runId));
const completed = [];
while (pending.size > 0) {
const ids = [...pending].slice(0, 1000);
const batch = parseToolResult(
await tools.agents_wait({
ids,
timeoutSeconds: 30,
}),
);
// Rotate this bounded window behind ids that have not been checked yet.
for (const runId of ids) {
if (pending.delete(runId)) pending.add(runId);
}
for (const item of batch.completed) {
pending.delete(item.runId);
if (item.status !== "done") {
failures.push(item);
} else {
completed.push(item); // Process each result as soon as it finishes.
}
}
for (const failure of batch.errors ?? []) {
pending.delete(failure.runId);
failures.push(failure);
}
}
return { completed, failures };
在综合成功结果并报告失败之前,请先排空待处理集合。被拒绝的启动或失败的子项不得丢弃其他已接受子项的结果。请保留返回的运行 ID 以便恢复。不要重复成功的启动,也不要自动重新运行失败的工作。
每个 agents_wait 调用接受 1–1000 个运行 ID。它返回:
type AgentsWaitResult = {
completed: Array<{
runId: string;
status: "done" | "failed" | "killed" | "timeout";
result: string;
structured?: unknown;
error?: string;
schemaError?: string;
sessionKey: string;
label?: string;
usage?: { inputTokens: number; outputTokens: number };
}>;
pending: string[];
errors?: Array<{
runId: string;
error: "not_found" | "not_owner";
}>;
};
已完成项可能包含部分 structured 数据,并且当提供商或运行时随后失败时仍具有 status: "failed"。在这种情况下,error 是权威的最终失败。恢复代码应优先使用非空 error,然后是 schemaError,再然后是非空 result,最后是运行/状态回退。
单个失败项不会使混合的 agents_wait 轮询成为顶层工具错误。该轮询仍保持为成功的 JSON 结果,因此调用方可以独立处理其 completed、pending 和 errors 数组。
当任一请求的子任务已经完成、至少一个待处理子任务完成、没有剩余有效待处理 id,或其超时到期时,该调用会立即返回。已完成记录是幂等的,因此传入一个已完成的 run id 会再次返回其结果。只有生成该收集器的会话或其授权父链可以等待该收集器。
这是有界长轮询,而不是忙等状态循环。持续只传入剩余的 run id,直到 pending 为空。收集器模式支持原生 OpenClaw 子代理。它不支持 ACP 运行时、线程绑定、可见会话或持久会话模式。
限制¶
Swarm 运行一次性收集器子任务。没有有状态的多轮 worker API。子任务在其组的 Swarm 泳道中的本地 Gateway 上运行,且生成没有云放置选项。保存的工作流定义和图 DSL 不属于 Swarm 的当前方向。
相关¶
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw