裸 SDK 手搓编排:用子代理拆活、并行、隔离上下文
- 想清楚什么时候该派子代理——上下文隔离、并行、专门指令、工具限制四个用武之地
- 看懂子代理「独立会话、只回结论」这条铁律为什么省上下文
- 照着一段完整的代码骨架,把主 Agent 派两个子 Agent 并行干活再汇总搭出来
- 拿到一张「子代理委派失败」的排查清单,知道不触发/委派失败八成栽在哪
很多人一听「多 Agent 编排」,第一反应是去搜该上哪个框架——LangGraph、CrewAI、AutoGen,挑花了眼。但真相是:Claude Agent SDK 本身就带子代理原语,编排不一定要套框架。 你只要会建一个协调者 Agent、给它配一份「手下能派谁」的角色清单,剩下的拆活、并行、汇总,SDK 自己就管了。这一节我们不绕框架,直接用裸 SDK 把一个「主 Agent 派两个子 Agent 并行干活再汇总」的骨架搭出来,让你看清子代理到底省在哪、怎么写。
这篇适合谁:已经算清了编排成本、决定走「子代理委派」这条最省的路,现在要落到代码上的人。读完你会有一段能照着改的骨架,和一份委派不生效时的排查清单。
先想清楚:子代理的四个用武之地
别一上来就拆。拆之前先问自己——这活到底是不是子代理该干的?子代理真正的价值就四条,对上一条再派:
- 上下文隔离:某块任务会产生一大堆中间料(网页原文、长文档、检索结果),但下游只需要它的结论。让子代理在自己的会话里烧这些料,干完只回一段结论——中间料从不进主 Agent 的上下文。这是子代理最核心、最省钱的用法。
- 并行:几块任务互不依赖(查竞品 A、查竞品 B、查竞品 C),就同时派出去一起跑,而不是排队一个一个来。墙上时间直接除以并发数。
- 专门指令:每个子代理有自己的系统提示词。「研究员」只管调研、「审稿人」只管挑刺,各自的人设和规矩互不干扰,比把所有职责塞进一个超长系统提示词清爽得多。
- 工具限制:每个子代理只给它该用的工具。研究员只给联网搜索,写手一个工具都不给——既是安全边界,也减少模型"乱按按钮"的概率。
记住这条铁律,下面所有设计都从它来:每个子代理跑在自己独立的会话里,只把最终结果回给主 Agent,中间过程不占主 Agent 的上下文。
最小可用:主 Agent 派两个子 Agent 并行干活
任务定死:同时调研两个竞品,各自出一段结论,主 Agent 汇总成一句话对比。 这是「上下文隔离 + 并行」最典型的场景。
在 Claude Agent SDK 的托管 Agent 里,多 Agent 是这么搭的:先把每个子代理当成独立的 Agent 建出来,再建一个协调者(coordinator) Agent,在它的 multiagent 配置里列出「我手下能派谁」的角色清单。协调者跑起来后,会自己决定派谁、并行还是串行,每个子代理在自己的 thread(独立事件流、独立上下文) 里干活。
下面是一段结构完整、思路可跑的骨架。具体的类名、方法名、字段名以官方文档为准——不同 SDK 版本写法有差异,这里给的是「该有哪几步、每步在干嘛」,不是逐字复制就能跑的真实签名。
import anthropic
client = anthropic.Anthropic() # 读环境变量里的 ANTHROPIC_API_KEY
# ── 第 1 步:建一个「研究员」子代理 ────────────────────────────
# 关键点全在这:专门指令(只调研) + 工具限制(只给联网) + 只回结论
researcher = client.beta.agents.create(
name="研究员",
model="claude-opus-4-8",
system=(
"你只做一件事:调研。联网搜资料、读、提炼,"
"最后只回 300 字以内的结论要点,绝不贴原文、不解释过程。"
),
tools=[
# 只给它联网这一个工具——其它一概不给(工具限制 = 安全边界)
{"type": "agent_toolset_20260401",
"default_config": {"enabled": False},
"configs": [{"name": "web_search", "enabled": True}]},
],
)
# ── 第 2 步:建协调者,把研究员列进它的「手下角色清单」 ──────────
# multiagent 是协调者 Agent 上的「我能派谁」名册,不是 session 上的字段
coordinator = client.beta.agents.create(
name="主控",
model="claude-opus-4-8",
system=(
"你负责调研多个竞品并写对比。把每个竞品的调研分别委派给「研究员」,"
"几个竞品互不依赖时就同时派出去(并行)。拿回结论后自己汇总成一句话对比。"
),
tools=[{"type": "agent_toolset_20260401"}],
multiagent={
"type": "coordinator",
"agents": [researcher.id], # ← 名册:协调者可委派的子代理
},
)
# ── 第 3 步:开个环境 + 会话,把活丢给协调者 ──────────────────
env = client.beta.environments.create(
name="biaopai-env",
config={"type": "cloud", "networking": {"type": "unrestricted"}},
)
session = client.beta.sessions.create(
agent=coordinator.id, # 会话只引用协调者,子代理由名册解析
environment_id=env.id,
)
# ── 第 4 步:跑起来——先开流,再发任务(顺序很重要,见下文坑) ──
stream = client.beta.sessions.events.stream(session.id)
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.message",
"content": [{"type": "text",
"text": "同时调研竞品 Cursor 和 Windsurf,写一句话对比"}]}],
)
for event in stream:
if event.type == "session.thread_created":
print(f"[派出子代理] {event.agent_name}") # 看到两个 → 并行生效
elif event.type == "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="")
elif event.type == "session.status_idle":
if event.stop_reason.type != "requires_action":
break # 干完了
骨架的精神,不是这几个方法名,而是这三件事:子代理有自己的指令、自己的工具、自己的会话;它只回结论;主 Agent 因此不被中间料撑爆。 这就是子代理省钱的全部秘密——和上一节成本心智里"子代理便宜"对应的代码长相。
你应该看到什么
跑通之后,盯着输出里这几个信号,它们证明编排真的按你想的在走:
- 两条
session.thread_created:分别是派去查 Cursor 和查 Windsurf 的子代理。看到两条几乎同时出现,说明并行生效了——主 Agent 没排队,一次把两个都派了出去。如果只看到一条接一条慢慢冒,那是串行(不一定是错,但没吃到并行的红利,往下看变体)。 - 主 Agent 的最终
agent.message很短:就一句话对比 + 收尾。它上下文里没有两个竞品的网页原文——那些料烧在子代理的 thread 里,从不回流。 - 结束在
session.status_idle且stop_reason不是requires_action:表示协调者真的干完了、在等你下一句,而不是卡在「等子代理结果」的中间态。
如果你想看每个子代理内部到底搜了什么,那是它各自 thread 里的事件——主流程的事件流默认只给你「派出了/收回了」这种概览,不会把子代理的每次工具调用都灌进来。这正是上下文隔离在事件层面的体现。
原理:为什么「独立会话 + 只回结论」就省了
把上面发生的事拆开看,省钱的机制就一句话:子代理的中间上下文,永远不进主 Agent 的账。
主 Agent 调研竞品如果不拆,它得自己联网、自己把两个竞品的网页原文读进自己的上下文,然后在塞满原文的上下文里写对比。每多读一篇长文,它后续每一步调用都要把这堆原文重新塞回去——上一节讲过,你付的钱主要就是"同一段上下文反复进出模型"。
拆成子代理后:
- 每个子代理在自己的 thread 里读原文、烧 token——这些 token 它自己付,但只在它自己的会话里反复进出。
- 子代理干完,只把一段结论交回主 Agent。主 Agent 的上下文里始终只有「两段结论 + 写对比的指令」,干净、短。
所以同样一个任务,子代理模式下「贵的那部分上下文」被切成了几块互不污染的小账,而不是全堆在主 Agent 一个不断膨胀的大账里。这也是为什么子代理特别适合「中间料多、结论小」的活:调研、读长文档、批量检索——产出的料越大,隔离省得越多。
进阶:串行 vs 并行,两个变体
上面是并行(几块互不依赖、同时派)。但不是所有任务都能并行。看你的子任务之间有没有依赖:
变体一:并行(互不依赖)。 就是上面骨架的样子。协调者一次性把多个委派发出去,几个子代理同时在各自 thread 里跑。适合:查竞品 A/B/C、批量翻译多段、对多个文件分别做摘要。怎么促成并行:在协调者的系统提示词里明说"这几块互不依赖,请同时委派",模型才更倾向一次性派出去而不是排队。
变体二:串行(后一棒依赖前一棒)。 子任务有先后——必须先查清需求,才能据此设计方案,再据方案写文档。这时一个子代理的结论是下一个子代理的输入。协调者会先派研究员、拿到结论、再据结论派写手,天然是串行。代码上你不用改结构,只要在协调者的系统提示词里把依赖讲清楚:
coordinator = client.beta.agents.create(
name="主控",
model="claude-opus-4-8",
system=(
"流程有先后:先派「研究员」查清用户需求,拿到需求结论后,"
"再据此派「方案师」出设计,最后你自己据方案写一段总结。"
"后一步必须等前一步的结论,不要并行。"
),
tools=[{"type": "agent_toolset_20260401"}],
multiagent={"type": "coordinator", "agents": [researcher.id, designer.id]},
)
判断口诀:互不依赖 → 让它并行(省墙上时间);后一棒要前一棒的产出 → 串行(本质就是 handoff 接力的子代理版)。 别把有依赖的硬并行——下家拿不到上家结论,只会瞎编或返工。
子代理委派失败排查清单
这是本节最该收藏的一张表。多 Agent 调试最常见的不是报错,而是**「子代理压根没被派出去」或「派了但没干成」**——主 Agent 自己默默把活干了,或者卡住不动。八成栽在下面几条:
| 现象 | 最可能的原因 | 怎么破 |
|---|---|---|
| 子代理根本不触发,主 Agent 自己把活干了 | 协调者没拿到「能派谁」的名册,或名册里的 Agent ID 写错 | 确认子代理 ID 真的进了协调者的 multiagent.agents 名册;ID 拼错=名册为空=只能自己干 |
| 子代理不触发(名册没问题) | 协调者的系统提示词太泛,没说清「什么活该委派给谁」 | 在协调者系统提示词里点名:"把调研委派给「研究员」",别指望它自己悟出要委派 |
| 委派失败 / 子代理「没有工具可用」 | 子代理需要的工具没加进它的工具集——这是头号坑 | 给子代理显式开它要用的工具(研究员要 web_search 就得在它 tools 里 enable),别只在协调者上配 |
| 子代理被派出去了,却什么也搜不到 | 工具开了,但环境网络被限制(limited 没放行) |
调研类要联网,环境 networking 用 unrestricted,或把目标域名加进 allowed_hosts |
| 该并行的却在串行、慢 | 协调者没被告知「这几块互不依赖」 | 系统提示词明说"同时委派、它们互不依赖",模型才更愿意一次性派出 |
卡在 session.status_idle 不结束 |
把 idle 当成"干完了",但 stop_reason 其实是 requires_action(在等你) |
判断结束要同时看 stop_reason:不是 requires_action 才算真干完(见骨架第 4 步) |
| 先发任务后开流,开头的事件全丢了 | 流只推送「开流之后」的事件 | 先开 stream,再 send——顺序反了就漏掉开头的 thread_created 等事件 |
一句话总结这张表:委派不生效,先查名册(ID 对不对)和指令(说没说要派);委派了没干成,十有八九是子代理的工具没给全。
动手挑战
- 把上面的并行骨架跑起来,换成你关心的两个工具/竞品。盯着输出里有没有两条
session.thread_created——确认并行真的发生了,而不是悄悄变串行。 - 故意制造头号坑:把研究员的
web_search工具去掉再跑,观察它是怎么"委派了却干不成"的。然后加回来,体会"子代理工具要单独给全"这条。 - 改成串行变体:再建一个「方案师」子代理,让协调者先派研究员、据结论再派方案师。对比串行和并行在事件流里的不同长相。
- 进阶:给协调者和子代理都保持稳定的系统提示词(别把时间戳/随机 ID 混进去),让重复委派吃上 prompt 缓存,看成本又降多少。
常见问题
子代理之间能互相通信吗? 默认不能直接对话。它们各跑在自己的 thread 里、上下文隔离,协作要靠协调者居中传递——协调者把 A 的结论作为 B 的输入派下去。需要平级"接力"就是 handoff 的思路;需要反复磋商才考虑对话式(最贵,慎用)。
一个协调者最多能派多少个子代理? 名册和并发都有上限,具体数字以官方文档为准。实践上别贪多:拆得过头,光是来回委派的开销就把省下的吃回去了。先确认每一块都「中间料多、结论小」值得拆,再拆。
委派会不会比不拆还贵? 会——如果拆错了。子代理省的是"中间料不进主上下文"那部分;如果某块根本没多少中间料(结论和过程差不多大),拆它纯属多此一举,还多付一层委派开销。判断标准回到四个用武之地:对不上就别拆。
不用托管 Agent,自己写 loop 能实现子代理吗? 能。本质就是:开一个独立的对话会话给子代理跑、拿到它的最终输出、只把这段输出塞回主 Agent 的上下文。托管 Agent 帮你把 thread 隔离、并行调度这些都管了;自己手写就得自己管会话和上下文边界,逻辑一样,活多一些。
小结 · 你现在掌握了什么
- 你知道了子代理的四个用武之地:上下文隔离、并行、专门指令、工具限制——对上一条再拆,别为拆而拆。
- 你看懂了那条铁律:每个子代理独立会话、只回结论,中间过程不占主 Agent 上下文,这就是它省钱的全部机制。
- 你拿到了一段主 Agent 派两个子代理并行干活再汇总的完整骨架,以及"你应该看到什么"的验证信号。
- 你能区分串行(有依赖)和并行(无依赖) 两个变体,靠协调者的系统提示词控制。
- 你有了一张子代理委派失败排查清单:不触发先查名册和指令,干不成八成是子代理工具没给全。
编排不是非套框架不可。裸 SDK + 子代理原语,就能把最省的那条路落到实处。
下一步:手搓的子代理跑通了,接着可以看 Agent 之间更结构化的 RPC 式通信。继续看 AI Agent 智能体阶梯 的 L5 后续;想看全貌就对照三支柱路线图。
👉 看看 AI 数字员工落地指南,或了解 数字员工搭建实战课。需要为企业落地方案,欢迎找我们聊 企业服务。