Day 13 / 共 20 天 · 第 3 周 ADK 智能体开发

多智能体协作

一个 Agent 搞不定复杂任务时,让多个专精 Agent 协作。今天讲 Eino 的两种协作方式,以及官方为什么推荐 Agent-as-Tool 而不推荐 Transfer。

📍 你在整门课的位置 · 第 3 周 Agent 套件(共 4 周 · 20 天)
D11 ADK 抽象 D12 ChatModelAgent D13 多智能体 D14 中断恢复 D15 ReAct 精读
L01

为什么要多智能体

把一个"全能 Agent"拆成多个"专精 Agent",各管一摊,好处:提示词更聚焦、工具集更小(模型不会在 50 个工具里选晕)、可独立测试和复用。

🤔 痛点:一个 Agent 塞满 50 个工具、提示词写成万言书,会怎样? 模型在几十个工具里频繁选错、提示词太长导致遵循度下降、一处改动牵连全部功能、也没法单独测某块能力。任务越复杂,"单 Agent 全能王"越不可靠。答案是拆分:多个专精 Agent 各管一摊。
💡 本质:官方推荐"子 Agent 当工具调"(Agent-as-Tool),父 Agent 始终握着控制权 Eino 让子 Agent 通过 adk.NewAgentTooladk/agent_tool.go:93)包成一个普通 Tool,父 Agent 像调工具一样"调用—返回"它。与之相对的 transfer/handoff(把控制权整个交出去)在源码里被大量标注 NOT RECOMMENDEDadk/flow.go:72adk/deterministic_transfer.go:40 等多处)。一句话:优先"调用返回",慎用"移交控制"。
类比:就像生活中的一家公司 多智能体就像生活中的一家公司:让一个人既当客服、又当程序员、又当会计,他啥都会一点但都不精,还容易忙中出错。拆成"客服 Agent + 编程 Agent + 财务 Agent",各自提示词专业、工具精简,由一个"主管 Agent"根据问题分派。一句话复述:分工 = 每人只干一摊,整体反而更能干、更可靠。
L02

两种协作方式

Eino 提供两种让 Agent 之间协作的机制:

✅ Agent-as-Tool(推荐)

  • 把子 Agent 包装成一个工具
  • 主 Agent 像调普通工具一样"调"子 Agent
  • 子 Agent 干完把结果返回给主 Agent,控制权回到主 Agent

⚠️ Transfer 转交(不推荐)

  • 当前 Agent 通过 Action 把控制权整个转交给另一个 Agent
  • 转交后不再回来,由新 Agent 接管
  • 类似"踢皮球"式的接力
对应代码:Agent-as-Tool 用 adk.NewAgentTool(把 Agent 包成 Tool,adk/agent_tool.go:93);Transfer 用 AgentAction 里的 TransferToAgentadk/flow.go 相关,多处标 NOT RECOMMENDED)。官方文档明确标注 Transfer 为 NOT RECOMMENDED——L05 讲原因。
✅ Agent-as-Tool(调用—返回) 父 Agent 子 Agent A 子 Agent B 控制权始终回到父 Agent(可综合、可组合、可测) ⚠️ Transfer(单向移交 · NOT RECOMMENDED) Agent 1 Agent 2 Agent 3 棒交出去不回来,链一长就搞不清"现在谁在负责"
两种拓扑对比:左边是"星形调用—返回"(父始终是中心),右边是"链式单向移交"(控制权一路漂走)。Eino 推荐左边。
L03

Agent-as-Tool(推荐)

把子 Agent 包成工具,加进主 Agent 的工具集(adk/ 相关):

// 子 Agent(专精财务)
financeAgent, _ := adk.NewChatModelAgent(ctx, &financeConfig)
// 包装成工具
financeTool := adk.NewAgentTool(ctx, financeAgent)
// 主 Agent 把它当普通工具用
mainAgent, _ := adk.NewChatModelAgent(ctx, &ChatModelAgentConfig{
    Tools: []tool.BaseTool{financeTool, weatherTool, ...},   // 子Agent 和普通工具混在一起
})
读法:子 Agent 被 NewAgentTool 变成一个 Tool,和普通工具平起平坐加进主 Agent。主 Agent 的模型在需要时"调用"这个工具(其实是运行子 Agent),拿到结果继续自己的推理。子 Agent 有自己独立的对话上下文和工具集。
直觉:就像生活中的"项目经理外包" Agent-as-Tool 就像生活中的项目经理把一块活外包出去:经理遇到财务问题,"打电话咨询财务专家"(调工具),专家给出意见后,经理继续主导整个项目,还亲自验收结果。控制权始终在经理手里——清晰、可控。而 transfer 则像"直接把客户整个转给别人",转出去经理就不管了。
📝 举例:客服主管接到"我要退款并开发票" 主 Agent(客服主管)先调 退款 Agent 这个工具拿到退款单号,再调 发票 Agent 工具拿到发票号,最后自己综合成一句"已退款(单号 R123),发票已开(票号 F456)"回给用户。两个子 Agent 各跑各的、互不知情,主管负责串起来——这就是 Agent-as-Tool 的"分包 + 验收 + 汇总"。
⚠️ 小白常误以为:"把 Agent 包成工具"是什么高级新机制。其实:它就是 Day 12 那个普通 Tool 接口——子 Agent 被 NewAgentTool 塞进一个实现了 tool.BaseTool 的壳里,主 Agent 的模型根本分不清它调的是"查天气"还是"另一个 Agent"。没有新魔法,全是复用。
L04

Transfer(不推荐)

Transfer 是子 Agent 通过发出 AgentAction{TransferToAgent: "另一个Agent"} 把控制权彻底交出去:

// 概念:Agent 运行中产出一个转交动作
event.Action = &AgentAction{TransferToAgent: &TransferToAgentAction{
    DestAgentName: "specialistAgent",
}}
// Runner 收到后,切换到 specialistAgent 接管,原 Agent 退场
读法:转交后控制权归了新 Agent,原 Agent 不再参与。像接力赛交棒——棒交出去就不回来了。多个 Agent 之间可能一路 transfer 下去。
🧯 没有"调用—返回"、只用 transfer,会出什么事故? 设想报销场景:用户问"我这笔差旅能报吗",主 Agent transfer 给财务 Agent,财务又 transfer 给合规 Agent,合规发现缺发票又 transfer 回财务……链路绕了 5 手,最后用户收到的答复到底代表谁、上下文丢没丢,谁也说不清;想在中间加一步"经理审批"更是无处下手。这正是官方把 transfer 标 NOT RECOMMENDED 的现实代价——控制权一旦漂走就难收回。Agent-as-Tool 则天然没这问题:每次调用都会返回到主 Agent。
L05

为什么推荐 Agent-as-Tool 而非 Transfer

  • 控制流清晰:as-Tool 是"调用-返回",控制权总回到主 Agent,行为可预测。Transfer 是"单向移交",链路一长就难追踪"现在到底是谁在负责"。
  • 上下文可控:as-Tool 时主 Agent 决定给子 Agent 看什么、拿回什么。Transfer 时上下文怎么传递更含糊。
  • 可组合:工具能任意嵌套组合,主 Agent 能"综合多个子 Agent 的结果"再决策;Transfer 更像状态机跳转,难综合。
  • 可测试:子 Agent 作为工具能单独测;Transfer 的整链行为更难隔离测试。
💬 小白连环问 👶 小白:既然 transfer 也能让别的 Agent 干活,为啥不直接用它、更省事?
👨‍🏫 老师:省的是"当下这一步",赔的是"整条链的可控性"。transfer 交棒后你就失去了对结果的把关点。
👶 小白:那我用 Agent-as-Tool,子 Agent 会不会看到主 Agent 的全部对话历史?
👨‍🏫 老师:不会。子 Agent 有独立上下文,主 Agent 决定"喂它什么、拿回什么"——这正是它可控的原因。
👶 小白:那 transfer 是不是就完全没用?
👨‍🏫 老师:不是"没用",是"默认别用"。少数需要彻底移交所有权的场景才考虑,且要接受它难追踪的代价。
一句话:Agent-as-Tool 用"函数调用"的心智模型(调了会返回),符合程序员直觉、可控可组合;Transfer 用"控制权移交"心智模型,容易失控。所以 Eino 官方推荐前者。这也呼应 Day 01 的设计哲学——可控、可组合优先。
L06

Supervisor 模式

基于 Agent-as-Tool 最常见的结构就是 Supervisor(主管)模式——一个主管 Agent 统筹,多个专精子 Agent 作为它的工具:

Supervisor 主管 Agent(负责理解需求、分派、综合)
↓ 按需"调用"(Agent-as-Tool)↓
🔎 检索 Agent💰 财务 Agent💻 编程 Agent✍️ 写作 Agent
怎么搭 每个子 Agent 用 NewChatModelAgent 建好(各自的 Instruction 和工具),再全部 NewAgentTool 包成工具,塞进 Supervisor 的工具集。Supervisor 的 Instruction 写"你是主管,根据用户需求选择合适的下属工具来完成任务"。用 Day 12 学的单 Agent 机制拼出多 Agent 系统——没有新魔法。
L07

子 Agent 的事件冒泡

子 Agent 运行时也会产出自己的 AgentEvent。这些事件会带着 AgentName(是哪个子 Agent 发的)冒泡到最外层的迭代器,所以你能在 UI 上显示"财务 Agent 正在查账……"这种嵌套进度。

因为每个 AgentEvent 都带 AgentName(Day 11),前端就能区分"这条是主管说的还是某个子 Agent 说的",画出层级化的执行过程。事件流的设计让多 Agent 的可观测性天然成立——你能看到整个团队每个成员在干嘛。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 为什么要多智能体?(分工、聚焦、可复用可测)
  • 两种协作方式?各自的控制流特点?
  • 为什么官方推荐 Agent-as-Tool 而不推荐 Transfer?
  • Supervisor 模式怎么搭?
  • 子 Agent 的事件怎么冒泡到外层?

✋ 动手

grep -rn 'NewAgentTool\|AgentTool' adk/ | head
grep -rn 'TransferToAgent\|Transfer' adk/ | head
grep -rn 'Supervisor\|supervisor' adk/ | head
明天预告 · Day 14:Agent 跑到一半需要人工审批怎么办?中断与恢复(Interrupt/Resume)——Agent 暂停、把现场存下来、等人类批准后从断点继续。看它怎么和图执行结合。
← Day 12 ChatModelAgent Day 14 · 中断与恢复 →