4 minutes
任务委派:Subagent 与并行执行
要让 Agent 干大工程,单 loop 是不够的。这一章讲如何把"长任务",拆给多个 subagent 并行执行;讲怎么避免"群里每个 agent 都在重复劳动"的灾难。这是后面第 28 章:实战多 Agent 系统 的方法论基础。
13.1 Subagent 是什么
Subagent 是 harness 内部又开出来的一个 Agent,它本身的 LLM 调用是独立的,自己去拿工具、自己做 ReAct、自己结束。能并行 = 能在一台机器上同时让 3 个 Agent 都在工作。
主 Agent (Build / Sisyphus)
│
├─ task → explore "找叫 lock 的所有文件"
├─ task → explore "find all TODO 与 FIXME"
└─ task → librarian "查 anthropic Messages API 当前最大 token"
│
并行 (.await asyncio.gather)
│
合并 sub-agent 的最终输出 → 给主 Agent
主 Agent 与 subagent 的差别只有一点:
| 维度 | 主 Agent | subagent |
|---|---|---|
| 对话历史 | 你写下的 | 一个全新的对话流 |
| 心智窗口 | 整个会话上下文 | 它自己 system prompt + 它做的 task |
| 工具 | 拿到开放 | 看 system prompt 限定的子集 |
| 终止 | user 认 YES | 任务自报完成 (DONE) |
| 成本 | 继续累积 | 单 task 的 token,结束后不再算 |
13.2 何时用 subagent
1. 探索任务 (explore):多个独立方向可同时找
2. 文档查询 (librarian):外部知识 / API / OSS 库
3. 复杂推理 (oracle):把"想清楚"的任务外包给一个强推理 sub
4. 多步骤执行:拆成 5 个,每个 sub 独立写自己报告
合并出 "5 个并列 PR-able 子任务" 后再合并
13.3 派发模式:3 种
13.3.1 Parallel Exploration(并发探索)
async def parallel_explore(query: str) -> list[str]:
tasks = [
explore("find files matching: " + query, scope="src"),
explore("find files matching: " + query, scope="tests"),
explore("find files matching: " + query, scope="scripts"),
]
return await asyncio.gather(*tasks)
Tool 调用并行:每个 subagent 独立 token 预算,并发降低墙钟。
13.3.2 Sequential Refinement(串行精化)
async def sequential_refine(goal: str) -> str:
plan = await metis(f"plan: {goal}")
critique = await momus(f"review plan: {plan}")
revised = await metis(f"adjust plan with: {critique}")
return revised
下一步的输入依赖上一步。不是为加速,是为质量。
13.3.3 Fan-out / Merge(同一任务多方案)
async def multi_draft(prompt: str, k: int = 3) -> str:
drafts = await asyncio.gather(*[
build_subagent(f"draft {i+1}:{prompt}")
for i in range(k)
])
return await oracle(f"挑 3 稿中最优的一部分,合并出 final: {drafts}")
代价 = 多一次调用的成本。优势:通过对比降低幻觉——这是 [2026 年 Easy Hard Tasks]的常见 boosting。
注意 Token 预算:Fan-out k=3kuje。模型每次不是免费,超 k=5 后边际回报小于 Premium Opus 一次性给。
13.4 派发 prompt 的 6 段式
每个 subagent prompt 包括 6 块:
[CONTEXT]
project: ai_learning/ai-course, hugo.laozhang.work repo
[GOAL]
找出所有 .md 中文 front matter 不规范的文章(少了 slug)
[DOWNSTREAM]
我要把结果汇报给主 Agent, 它要修这些文章
[REQUEST]
列表 → 每行一个文件路径 + 标题 + 缺的 field
[REQUIRED TOOLS]
rg / Glob / Read
[MUST DO]
- 不修改任何文件(read-only)
- 不输出冗长 markdown, 仅列表
[MUST NOT DO]
- 不要解读为何缺
- 不要并行修改文件
Vague prompt → subagent 摸鱼,最终返回的是大使意:“我已找到 ~30 个文件”——主 Agent 又得返工。结构化 = 失败指数级减少。
13.5 OpenCode 派 Pattern 的工具化示范
OpenCode 内置 6 种 subagent 角色,对应 6 类任务:
───────┬─────────┬─────────────────────────────────────
role │ cost │ typical use
───────┼─────────┼─────────────────────────────────────
explore │ free │ 找文件、grep 模式、survey 某区域
librarian│ cheap │ 文档 / OSS / 库内幕
oracle │ expensv │ 当局迷呼救:根基架构 / bug
metis │ expensv │ plan 前把"意图不清晰"的部分祛
momus │ expensv │ 挑 plan 毛病
build │ default │ 主执行
───────┴─────────┴─────────────────────────────────────
调用方语法是 task(subagent_type="explore", prompt="...") 或 task(category="quick", prompt="..."),见你的实际 harness 文档。核心都是异步 dispatch + 等回应的一类事。
13.6 合并多个 subagent 结果
async def collect(sources: list) -> str:
results = await asyncio.gather(*sources, return_exceptions=True)
return "\n\n".join(
f"### {src.__name__}\n{r if not isinstance(r, Exception) else f'[ERROR]{r}'}"
for src, r in zip(sources, results)
)
四件事:
- return_exceptions=True - 单个错别毁整读;异常当数据回
- 结构化标签 - 主 Agent 拿到 “### explore T1 / ### librarian T2 …” 可一一识别
- 误差隔离 - 失败的一方不报失败,主 Agent 可重试或选择不用
- 限并发 - 一次 ≤ 5 个 subagent,超过的话排队避免 rate-limit
13.7 失败模式:委派出会出的坑
派 Agent 写 Skill 的幻觉
[NOTE] 让一个 sub-agent 写 skill 体系时,它倾向于:
- 若只读文案符合工作流,写得很好
- 若需要"实际经验感"(知道哪些 prompt 真起效),就写些听起来扎实但实战无效
⇒ 写 skill 的任务保留给主 Agent,不要外包给 subagent。sub 用来找 / 读,但写产出交给主 thread。
派 7 个 subagent 做同一事 vs 1 个仔细做
“7 个 explore 同时找 README 不一致"听起来很酷——其实3 个就够,7 个会让 grep 重复触发甚至 hit rate limit。
enkel经验:3 是 sweet spot,超过 5 才在大型重构里见到收益。
把主 Agent 当 dispatcher 用
主 Agent 是决策 chairs,自己不要下场做实际操作。如果主 Agent 每轮自己 sed/grep,你的 subagent 调度 没起作用——直接让 sub 去干 grep,主收结果。
13.8 实战示例:写一个 “double check” 套娃
需求:写信 commit message 前先做双重确认(grep + Lint verify):
async def double_check(commit_msg: str) -> tuple[bool, str]:
# 并行派两个 sub:一个 grep 找 secret 风险,一个跑 ruff/basedpyright
secret_check, lint_check = await asyncio.gather(
explore_sub("[CONTEXT] 当前 staged diff\n"
f"[GOAL] 找任何可能 secret 泄漏痕迹\n"
f"[MUST DO] 只看 git diff\n"
f"[OUTPUT] 单文字 `clean` / `risk: <理由>`"),
build_sub("[CONTEXT] 当前 staged diff\n"
"[GOAL] 跑 ruff check + basedpyright\n"
"[OUTPUT] two-line summary")
)
if "clean" not in secret_check or "0 errors" not in lint_check:
return False, secret_check + "\n" + lint_check
return True, commit_msg
读完 29 章:AI 测试与 CI 集成 你会发现这玩意儿正是 GitHub Action 内的 pre-commit hook。
13.9 小结
- Subagent = 独立 LLM session,独立 token 预算
- 三种派发:Just Parallel / Sequential / Fan-out Merge
- 6 段式 prompt:Context/Goal/Downstream/Request/Required Tools/Must Do
- 并发不超过 5,sweet spot = 3
- 写产出保留给主 Agent,subagent 找 / 读 / 比较
下一篇:《14 Agent 调试与可观测性》 - 把 trace / log / replay 做好,让你的 Agent 真的能查出错、能改进。
Summary: Subagent = 5 个并发上限,3 个 sweet spot,6 段式 prompt 沉淀,主 Agent 只决策不下场。