跳转到内容

03-多Agent · 01 委派机制

预计阅读:12 分钟 适用版本:公开稳定包 OpenClaw 2026.5.2;作者端已验证 2026.5.7 · 最后审核:2026-05-09 前置:已读 03-多Agent/00-协作拓扑 本章深化:sessions_send / sessions_spawn 的细节、超时、重试、并发上限、subagent 生命周期管理


  • 派发是”发出去等结果”还是”发出去就不管”?两者怎么选?
  • subagent 跑一半卡了怎么办?能不能 kill?
  • 一个 agent 能同时派多少个 subagent?
  • 派了之后怎么知道它跑到哪了?
  • 派出去的结果怎么带回 main 的上下文?

决策轴两个选项记忆口诀
目标 session 存在否sessions_send(存在)/ sessions_spawn(新建)送到旧的 / 造个新的
要不要等结果阻塞(send 或 spawn 等待)/ 异步(spawn run 后 detach)等 / 不等
要不要持久 sessionmode="session"(留)/ mode="run"(不留)存 / 不存
目标有飞书 bot有(用户能直接看到)/ 没有(后台 agent)见光 / 不见光

四个 2 的组合 = 实际场景矩阵(见 shared/AGENTS.md 第二节)。


已存在 session,需要追加一轮对话,等对方回。

典型场景:

  • main ↔ planner 之间有持续任务线,main 补充信息给 planner 接着推进
  • 你在飞书群里 @ 了另一个 agent,main 把这条消息转给它

sessions_send 是阻塞的。调用方会等待对方回复才继续。

风险:

  • 对方 agent 卡住了,调用方也卡住
  • 对方的上下文已经污染(前面对话塞了无关内容),但你没意识到

缓解:

  • 设超时(具体字段以当前 CLI 版本为准,openclaw doctor 或 sessions_send --help 查询)
  • 超时后自动降级 —— 调用方继续、记一条”派发失败”记忆

sessions_spawn(target="planner", mode="run", prompt="...") ← 一次性,不留痕
sessions_spawn(target="planner", mode="session", prompt="...") ← 留 session,可以后续 send 接着聊
sessions_spawn(target="reflector", mode="run", prompt="周日整理") ← 异步触发,不等结果

sessions_spawn 本身默认阻塞(调用方等 subagent 跑完)。

怎么做真正的非阻塞(fire-and-forget):

  • 把 subagent 的任务设计成不需要回报(比如 reflector 跑完直接写文件)
  • 或者用 mode="run" + 短 timeout + 调用方忽略返回

为什么 OpenClaw 默认不提供”发了就不管”:因为任何真正异步的派发都应该有心跳日志 + 超时自愈,没有这些兜底的 fire-and-forget 会变成沉默失败。


~/.openclaw/openclaw.json 的 agents.defaults.subagents 节里有硬上限:

{
"subagents": {
"maxConcurrent": 8,
"maxSpawnDepth": 2,
"maxChildrenPerAgent": 8
}
}
参数含义作者实际值
maxConcurrent全系统同时活跃的 subagent 数8
maxSpawnDepth派发嵌套层数(main → A → B → C 是 3 层)2
maxChildrenPerAgent单个 agent 可同时有多少直接 subagent8

为什么深度限 2?

作者踩过坑:allow depth 3+,遇到 bug 时 agent 之间互相派发形成循环,8 个 subagent 3 层深 = 已经占满所有资源,gateway 假死。限深 2 之后,即使逻辑错也最多 main → A → B,影响面可控。

什么时候该调高 / 调低:

  • 调高:你确实有复杂工作流(如 planner 拆解 → 业务 agent 执行 → 专项 agent 兜底)
  • 调低到 1:你的架构简单,main 只派给直系 subagent,不允许子 agent 再派

shared/AGENTS.md 规定:所有派发必须走派发前确认流程,不允许直接 sessions_send / sessions_spawn。

完整流程:

用户说"让 X 去做 Y"
↓
agent 自动诊断(3 个 Y/N 问题)
↓
匹配场景(①/②/③/④)
↓
向用户展示卡片:
1. 确认,按这个方式派发
2. 换成其他方式
3. 取消派发
↓
用户选择后执行

为什么必须:因为 LLM 经常误判”是否需要上下文连续”、“持续还是一次性”。给用户一次确认的机会,误派发率下降 80%+。

症状:main 说”我派给 planner 了”,但其实 planner 在另一个 session 还没收口,被污染了一半。 根因:main 跳过确认流程,直接 sessions_send 到 planner 的活跃 session。


问 main:"当前有哪些活跃 subagent"
main → 调用 subagents list 工具
返回:subagent id / 起始时间 / 当前状态 / 所属父 agent

subagent 在跑中,想追加指令 / 调整方向但不想重启:

问 main:"让 planner 把拆解侧重点改成'成本优先',别中断"
main → 调用 subagents steer,追加消息

subagent 卡死、跑偏、或者你改变主意了:

问 main:"kill 掉那个 planner"
main → 调用 subagents kill

⚠️ kill 是强制的,subagent 不会有机会保存状态。如果它正在做改文件 / 发消息的活儿,可能留半成品。

作者的建议:能 steer 就不 kill。kill 前先确认”半成品”可接受。


这是多 agent 协作最容易”断链”的环节。

显式(推荐):subagent 回复时附上结构化摘要,父 agent 提取关键字段。

subagent 回复格式:
---
TASK_ID: wk17-minsu-reprice
STATUS: Done
RESULT: 已更新 12 条房价,平均提升 8%
FILES: memory/2026-04-17-minsu-reprice.md
NEXT: 等待用户确认是否开放外部预订
---

父 agent 按 TASK_ID / STATUS 关键字提取,写回自己的 proactivity 或 memory。

隐式(不推荐):subagent 自然语言叙述,父 agent 靠 LLM 理解提取 —— 每次表现不稳定。

父 agent 上下文快爆时(agents.defaults.compaction.memoryFlush.softThresholdTokens=12000),会触发 memoryFlush:

1. 当前任务结论写入 memory/YYYY-MM-DD.md
2. 稳定决策更新 memory/config-decisions.md
3. 通过 memory_store 存入结构化记忆
4. 未完成任务写交接上下文(目标/进度/决策/下一步/约束)
5. 回复 NO_REPLY 表示收口完成

父 agent 在派发后也要感知这点:subagent 的结果如果太长,别全塞回父 agent 的 context,让 subagent 自己先存 memory,父 agent 只拉回关键摘要。


派发可能失败,常见原因:

失败类型触发条件降级做法
超时subagent 跑 > 设定时长父 agent 记”派发超时”,问用户是否 retry
目标不在 allowAgents配置没加向用户报错,让用户自己加 allowAgents + restart
并发已满> maxConcurrent等待现有 subagent 结束,或用 subagents list 手动排空
深度超限> maxSpawnDepth架构问题,用户需要调整任务拆分
subagent bootstrap 失败该 agent 的 SOUL/workspace 不对父 agent 回报错误 + 建议修复路径

场景:用户问 main”帮我规划下周民宿运营任务”。

main → 立即 sessions_send 到 planner
main 等待
planner 回"好的,开始拆"(但没真拆)
main 回给用户"planner 在拆了,稍等"
用户等 5 分钟,发现啥都没发生
main 识别到派发意图
↓
自动诊断:
Q1 目标有 bot? 有(planner 有飞书 bot)
Q2 需要上下文连续? 不需要(是新任务)
Q3 持续 or 一次性? 一次性
↓
匹配场景 ③:sessions_spawn(mode="run")
↓
发卡片给用户:
"🤖 准备派给 planner(场景③,独立一次性任务)
1. 确认 2. 换方式 3. 取消"
↓
用户点 1
↓
main → sessions_spawn(target="planner", mode="run",
prompt="拆解:下周民宿运营任务。按 TASK_ID/STATUS/RESULT 结构回复")
↓
planner 跑,期间 main 可以用 subagents list 看状态
↓
planner 回:
---
TASK_ID: minsu-wk18
STATUS: Done
RESULT: 拆成 5 条子任务(见 memory/2026-04-20-minsu-plan.md)
NEXT: 等待用户审阅后派给 minsu 执行
---
↓
main 提取 RESULT + NEXT
main 回给用户:"拆解完成,5 条子任务见 memory 文件。要派给 minsu 执行吗?"
↓
用户决定

配好多 agent 后,跑这一遍:

检查项怎么验
派发前确认流程说”派给 planner”,看有没有卡片让你选方式
sessions_send 阻塞让 main 派一个长任务给 planner,观察 main 是否等
sessions_spawn run 模式派一次性任务,subagent 回复后是否真”消失”(subagents list 看不到)
subagents steersubagent 跑中追加一条指令,subagent 应吸收
subagents kill强杀后 subagents list 立即移除
结果提取subagent 用结构化返回,main 能正确提取 RESULT 字段
并发上限连续派 10 个 spawn,第 9 个应被拒绝(maxConcurrent=8)
深度上限main → A → B → C 应被拒绝(maxSpawnDepth=2)

坑 1:subagent 卡住,父 agent 也卡住

Section titled “坑 1:subagent 卡住,父 agent 也卡住”

因:用了 sessions_send(阻塞),subagent 卡在某个工具调用。 修:subagents kill,或预设超时,或改用 sessions_spawn(mode="run") + 异步拉结果。

因:subagent 的回复内容原样回灌给父 agent 的 context。 修:让 subagent 自己写 memory,只回摘要。父 agent 通过 memory_recall 按需拉。

现象:A 说”这事该 B 做”,B 说”不对,该 A 做”。 修:检查 shared/AGENTS.md 第一节的”派发决策树”是否清晰。作者的规则是:收到消息的 agent 如果不匹配任何 sub-agent 规则,自己回复,不再转派。

坑 4:main 派给 planner 的任务被 planner “变形”了

Section titled “坑 4:main 派给 planner 的任务被 planner “变形”了”

现象:main 让 planner”只拆解,不执行”,planner 自己开始执行。 修:明确在 prompt 里写”禁止动手,只拆成 task 清单”,并设 mode="run" 避免 planner 记忆累积歪风。



本章准确性保证 maxConcurrent / maxSpawnDepth / maxChildrenPerAgent 数值来自作者 openclaw.json 的 agents.defaults.subagents 真实配置(2026-04-17)。memoryFlush.softThresholdTokens=12000 同样取自真实配置。结构化返回格式为作者实际在用的约定,非官方强制。


导航:← 协作拓扑 · 📖 目录 · → 共享规范