Google ADK2 多智能体编排解析

依据:Google ADK 官方文档(google.github.io/adk-docs / adk.wiki 中文镜像)、Google Developers Blog《Why we built ADK 2.0》《Announcing ADK Go 2.0》《What Google I/O '26 means for developing agents on Google Cloud》、Google Codelabs《ADK 2 Orchestration: Graph, Collaborative & Dynamic Workflows》
版本基线:ADK Python v2.0.0 / Go v2.0.0 / TypeScript v2.0.0(Java、Kotlin 亦有支持,Kotlin 为 Android Beta)
整理时间:2026-10-14


目录

  1. ADK2 是什么
  2. 第一层:智能体与多智能体基础
  3. 第二层:编排的本质与 ADK 2.0 设计哲学
  4. 第三层:ADK 2.0 四大编排方式
  5. 第四层:协作工作流深入(多智能体协作核心)
  6. 第五层:生产级能力(HITL / 韧性 / 可观测)
  7. 第六层:数据与上下文管理
  8. 第七层:选型决策指南

1. ADK2 是什么

  • "ADK2" = Google Agent Development Kit 2.0,Google 官方的开源智能体(AI Agent)开发框架。

  • 定位:模型无关、部署无关、框架可互操作,"让智能体开发感觉更像软件开发"。

  • 多语言:Python(主力)、Go、TypeScript、Java、Kotlin(Android Beta)。

  • 安装:

    • Python:pip install google-adk
    • TypeScript:npm install @google/adk
    • Go: go getgoogle.golang.org/adk
    • Java:Maven `com.google.adk:google-adk
  • ADK 1.x 已具备:模型实例化、回调控制、上下文抽象、模板工作流(Sequential/Parallel/Loop)、LLM 动态转移。

  • ADK 2.0 的核心新增:结构化工作流运行时(Workflow runtime)+ 任务协作模型(Task Collaboration) ,即"图工作流 / 动态工作流 / 协作工作流"三大件。


2. 第一层:智能体与多智能体基础

2.1 智能体的五要素

一个 ADK 智能体 = 模型(Model)+ 指令(Instruction)+ 工具(Tools)+ 会话/上下文(Session)+ 执行循环(Runner / Event loop) 。模型负责推理,工具负责行动,会话承载历史与状态,Runner 驱动"思考→行动→观察"的循环。

2.2 单体智能体的四个瓶颈

把所有职责塞进一个智能体(一个大 prompt + 一堆工具)时:

瓶颈 表现
提示词膨胀 系统提示越来越长,指令互相干扰
上下文污染 所有子任务的历史混在同一会话,互相干扰
工具过载 工具越多,模型选择越困难、越容易选错
不可评估 无法对单一能力独立测试与度量

2.3 多智能体的核心收益与代价

收益:

  • 职责分离:每个智能体只干一件事,指令短而清晰
  • 上下文隔离:每个子智能体只携带自己需要的上下文(ADK 2.0 中 task/single_turn 子智能体跑在独立会话分支)
  • 独立开发/测试/评估:可单测、可灰度、可复用
  • 可组合:子团队可嵌进更大的团队(图可嵌套)

代价: 协调复杂度上升、多跳带来延迟与 token 成本、错误会在链路中传播。

2.4 常见多智能体拓扑(ADK 1.x 起沿用)

  • 协调者/调度器(Coordinator / Dispatcher) :根智能体把请求分发给专家
  • 层级团队(Hierarchical teams) :团队的子节点还是团队
  • 交接(Handoff / transfer_to_agent) :把对话控制权整体移交给另一个智能体
  • 智能体即工具(Agent as tool) :把子智能体包装成工具调用,结果返回给调用方

3. 第二层:编排的本质与 ADK 2.0 设计哲学

3.1 编排是什么

编排(Orchestration)= 决定控制流:谁在什么时候运行、数据怎么流转、失败了怎么办。 多智能体系统的全部难点都收敛到这一个问题。

3.2 两种极端路线

LLM 自主编排 确定性代码编排
做法 把流程写进 prompt,模型自己决定下一步 用代码/图显式定义流程
优点 灵活,能处理没预料到的情况 可预测、快、便宜、错误处理干净
缺点 非确定性(官方原文 exhibit variance):同一业务流程跑 100 次可能 95 次对;慢且贵(每步都要推理) 覆盖所有边缘情况很复杂

Google 的论点(《Why we built ADK 2.0》):

路由、调度、错误处理是传统代码擅长的事,不该让 LLM 做。如果 B 必须跟在 A 后面,就没有理由等模型去推断------那是白烧的 token 和秒数。
"The model makes the decision; the graph makes it reliable, observable, and resumable." (模型做决策,图保证可靠、可观测、可恢复。)

设计原则:能用确定性就用确定性,把 LLM 留给真正需要认知推理的步骤。

3.3 控制光谱(Spectrum of Control)

ADK 2.0 给出一个从"完全自主"到"完全确定"的滑杆:

复制代码
完全自主 ←────────────────────────────────────────→ 完全确定
① 单体 Agent + 提示词编排      LLM 决定一切
② 协作工作流(coordinator+模式) LLM 委派 + 模式约束
③ 动态工作流                  代码编排(内含 LLM 节点)
④ 图工作流                    声明式确定性图
⑤ 纯函数链 / 工具调用          全确定

4. 第三层:ADK 2.0 四大编排方式

4.0 总览

编排方式 引入 控制流归属 典型场景
模板工作流(Sequential/Parallel/Loop) 1.x(2.0 中 Python/Go 已被图/动态取代) 固定模板 简单流水线
基于图的工作流(Graph Workflows) 2.0 声明式边 + 路由 分支、扇出/扇入、循环
动态工作流(Dynamic Workflows) 2.0 编程代码 迭代循环、复杂分支、递归
协作工作流(Collaborative Workflows) 2.0(原 Task-based Agent Collaboration API) LLM 协调者 + 运行模式 自管理智能体团队

官方定位:三者互补------图 最适合确定性结构化流程;动态 最适合控制流过于复杂/需要迭代;模板是常见模式的高层构建块。

4.1 模板工作流(1.x 遗产)

  • SequentialAgent:子智能体一个接一个跑
  • ParallelAgent:子智能体全部并行(注意:是"全部",不是"选子集")
  • LoopAgent:反复执行直到终止条件
  • 2.0 文档明确:Python/Go 中模板工作流已被图工作流与动态工作流"superseded"(取代),能力更强。简单场景仍可用。
  • transfer_to_agent 是串行 交接;ParallelAgent 是全部并行------二者都做不到"LLM 选子集 + 并行",这个缺口正是 2.0 协作工作流补上的。

4.2 基于图的工作流(Graph Workflows)------ 2.0 新核心

核心概念

节点(Node)= 任何工作单元,ADK 提供类型化构造函数:

节点类型 作用
Function node 包装普通类型化函数(泛型自动推导输入/输出 schema)
Emitting function node 函数节点 + emit 回调,可流式发事件、可暂停请求人工输入
Agent node 把任意 Agent(如 LlmAgent)放进图
Tool node 把工具变成图的一步
Join node 扇入屏障:等所有前驱完成,把各前驱输出组成 map 交给你
Dynamic node 在代码里编排(见 3.3)
Workflow node 把整个子工作流嵌成一个节点------图可组合
Parallel workers 对列表逐项并发执行并聚合结果
State-bound node 从 session state 按 "state:" 标签拉值进类型化 Params

边(Edge)连接节点,可携带路由条件:节点发一个 routing value,匹配的边触发。由此得到全部控制流形态:

  • 顺序链:A → B → C
  • 条件路由:一个节点按值分发到不同分支(StringRoute / IntRoute / BoolRoute / MultiRoute / Default)
  • 扇出(Fan-out):一个节点触发多个下游同时开始
  • 扇入(Fan-in):JoinNode 等所有分支完成后才放行
  • 嵌套子图:Workflow node
  • 循环:已完成的节点可被重新触发,回边让 cycle 成为一等公民
  • LLM 当路由器:LlmAgent 分类 → 普通函数发 route → 图分发。模型只做"决策",执行交给图

Python 示例(分类路由)

ini 复制代码
from google.adk import Agent, Workflow, Event

process_message = Agent(
    name="process_message",
    model="gemini-flash-latest",
    instruction="""Classify user message into either "BUG", "CUSTOMER_SUPPORT",
      or "LOGISTICS"...""",
)

def router(node_input: str):
    routes = [r.strip() for r in node_input.split(",")]
    return Event(route=routes)

root_agent = Workflow(
    name="routing_workflow",
    edges=[
        ("START", process_message, router),
        (router, {
            "BUG": response_1_bug,
            "CUSTOMER_SUPPORT": response_2_support,
            "LOGISTICS": response_3_logistics,
        })
    ],
)

Go 示例(链 + 条件边 + Join)

css 复制代码
edges := workflow.Concat(
    workflow.Chain(workflow.Start, classifyNode),
    []workflow.Edge{
        {From: classifyNode, To: bugNode, Route: workflow.StringRoute("BUG")},
        {From: classifyNode, To: supportNode, Route: workflow.StringRoute("CUSTOMER_SUPPORT")},
    },
)
wf, _ := workflowagent.New(workflowagent.Config{Name: "pipeline", Edges: edges})
// 扇出/扇入:b.AddFanOut(planner, researchA, researchB, researchC); b.AddFanIn(join, ...)

数据处理

  • 每个节点可声明 input_schema / output_schema(Python 用 Pydantic,TS 用 Zod)做类型化契约
  • 节点返回值经 event.Output 自动 传给下一节点,无需手动读写 session state
  • 动态工作流中 RunNode 直接以类型化值返回子节点输出

官方优势与已知限制

  • 优势:精确定义逻辑 / 支持分支与状态 / 无需调用模型即可跑函数链 / 结构化定义提升可靠性
  • 限制:某些第三方集成与图工作流不兼容

4.3 动态工作流(Dynamic Workflows)

抛开图的路径结构,用编程语言的全部能力写编排:循环、条件、递归、对动态列表 fan-out。

  • Python:@node(rerun_on_resume=True) 装饰器 + await ctx.run_node(child, node_input=...)
  • Go:workflow.NewDynamicNode + workflow.RunNodeT(nc, node, in)
  • 编排主体就是普通代码:while / async-await / for,而不是图路由

Python 示例(代码修复循环)

ini 复制代码
@node
async def code_workflow(ctx: Context, user_request: str):
    code = await ctx.run_node(coder_agent, user_request)
    check_resp = await ctx.run_node(compile_lint_check, code)
    while check_resp.findings:
        yield Event(state={"code": code, "findings": check_resp.findings})
        code = await ctx.run_node(fixer_agent, {"code": code, "findings": check_resp.findings})
        check_resp = await ctx.run_node(compile_lint_check, code)
    yield Event(output=code)

动态 vs 图

图工作流 动态工作流
结构 声明式,Dev UI 可 1:1 可视化 代码,不可视化但无表达限制
适合 静态、分支/并行/循环 迭代循环、递归、运行时才知的路径
循环表达 回边 普通 while
数据传递 event.Output 自动流转 RunNode 直接返回类型化值
学习成本 需理解节点/边/路由 会用语言就行

rerun_on_resume 语义:动态节点默认在恢复后重跑 ;FunctionNode 是交接(handoff)语义。

4.4 协作工作流(Collaborative Workflows)

见第四层深入。一句话:一个 LLM 协调者 + 一组带运行模式的子智能体 = 自管理的智能体团队。


5. 第四层:协作工作流深入(多智能体协作核心)

5.1 定位

"某些复杂任务可能需要多个具有特定职责的智能体,并从较松散的程序中获益,特别是对于包含多个重要子任务的迭代过程。"

一个协调者智能体 负责向一个或多个子智能体 委派任务;子智能体处理特定任务,完成后自动返回父智能体。

5.2 声明方式(Python)

ini 复制代码
weather_agent = Agent(
    name="weather_checker",
    mode="single_turn",              # 无用户交互
    tools=[get_weather, user_info, geocode_address],
)
flight_agent = Agent(
    name="flight_booker",
    mode="task",                     # 可以向用户提问
    input_schema=FlightInput,
    output_schema=FlightResult,
    tools=[search_flights, book_flight],
)
root = Agent(
    name="travel_planner",           # 协调者
    sub_agents=[weather_agent, flight_agent],
    # ADK 自动注入以每个子智能体命名的委派工具:weather_checker、flight_booker
)

要点:

  • 委派工具自动注入:协调者看到的不是一堆 transfer_to_agent,而是每个子智能体各一个、以其命名的工具
  • description= 是路由依据:协调者靠子智能体的 description 字段选择派给谁;不写 description 就等于让模型只看名字猜
  • mode 只配给子智能体,根智能体不配

5.3 三种运行模式

维度 chat(默认) task single_turn
人在环中 完全交互 仅用于澄清提问 不允许
用户交互 用户自由与智能体聊天 智能体按需提问 无用户交互
控制流 智能体控制直到手动交接 智能体控制直到任务完成 任务完成后立即返回
并行执行 不支持 不支持 多个任务可并行
返回父智能体 手动(transfer_to_agent) 自动(finish_task) 自动(带结果)
本质比喻 "把对话交给专家" "为这项任务协作" "智能体即工具"

chat 模式:对话移交(串行、专家持话权)

chat 是默认模式,本质是 1.x 时代的 handoff 式委派:父智能体通过 transfer_to_agent 把整段对话的控制权交给一个专家,专家从此直接面对用户;父智能体退场,除非专家再显式 transfer 回去。

要点:

  • 协调者手里只有 transfer_to_agent 这一个工具(串行交接,一次给一个专家)
  • 专家直接跟用户对话,运行结束于此,不会自动返回父智能体
  • 无并行、无自动返回、无综合

例子:客服调度 SupportRoot,挂着 billing_specialist、tech_specialist、returns_specialist 三个 chat 子智能体。

  • 用户:"我的退款还没到账。"
  • SupportRoot 判断该转给退款专家,调用 transfer_to_agent → 整段对话交给了 returns_specialist
  • 之后退款专家直接对用户说话:"查到你的订单...退款已于 10/12 发出,3--5 天到账...",对话到这里结束,SupportRoot 不再驱动
  • 若用户接着问账单问题,退款专家得自己再 transfer_to_agent 给账单专家
  • 用 Codelab 的原话:"六个专家、一次转移------这不是 bug,是 chat 模式在做它该做的事。对话属于持有它的人,直到有人显式转让。"

chat 模式是把"话筒"递给专家、协调者退场。而下面的task模式 是协调者"派活儿"给专家、自己始终坐在导演椅上。

task 模式(把任务委派下去)

  • 协调者保持主导权:根会话上下文由协调者掌握,子智能体只是被"派出"执行一块工作。
  • 委派即开独立分支:每个 task 子智能体拿到一个隔离的任务上下文(有自己的会话分支),因此多个 task 可以并行执行。
  • 子智能体可主动澄清:执行中发现缺信息(比如"从哪个城市出发?"),可以向用户提问,用户补充后它继续干。
  • finish_task 自动交回:子智能体完成工作后调用 finish_task,自动把"结果 + 控制权"还回协调者------你不需要写任何回传/return 代码。
  • 协调者综合:拿到所有子任务结果后,协调者汇总成最终答复给用户。

官方把 task 称为 "best of both worlds" :既让 LLM 自主执行细节,又让协调者掌控全局、做综合决策------这是它和 chat 最本质的区别。

实例:智能旅行规划

假设有一个 travel_planner 协调者,下面挂三个 task 子智能体:flight_booker(查机票)、hotel_finder(找酒店)、itinerary_planner(排行程)。

用户说:"帮我规划 5 天东京家庭游,预算 2 万。"

  • travel_planner 并行委派 3 个 task;
  • flight_booker 发现缺"出发城市",向用户澄清 → 用户答"上海";
  • 三个专家各自完成后 finish_task 把结果交回;
  • travel_planner 综合三份结果,输出完整方案。

python

ini 复制代码
from google.adk.agents import Agent

travel_planner = Agent(
    name="travel_planner",
    model="gemini-2.5-pro",
    instruction=(
        "你是旅行规划协调者。把任务委派给专业子智能体,"
        "等它们用 finish_task 返回后,综合成完整方案交给用户。"
    ),
    sub_agents=[flight_booker, hotel_finder, itinerary_planner],
)

flight_booker = Agent(
    name="flight_booker",
    model="gemini-2.5-flash",
    instruction=(
        "查机票。若缺出发城市,主动向用户澄清;"
        "完成后调用 finish_task 返回结果。"
    ),
)
# hotel_finder、itinerary_planner 类似

下面这张双栏图把 chat 和 task 放在同一画面里对照,差异会非常直观。

single_turn 模式

  • 无用户交互、自动返回、可并行

  • 协调者一轮内发多个调用 → ADK 并行执行 → 各自自动返回 → 协调者综合

  • 每个 single_turn 子智能体跑在自己隔离的会话分支 :看不到对话、看不到同辈。因此协调者必须把完整输入(问题+策略+数据)分别转发进每次并行调用

  • 官方诚实的提醒:

    • 子集由模型选,确定性弱于硬编码 router,每次运行派中的专家可能不同
    • 偶尔会出现某个专家的输入校验错误------通常是协调者没把嵌套输入完整复现;ADK 把错误作为该工具的结果返回,协调者恢复后综合仍然成立(output_schema 由 Gemini 服务端强制,输出一般没问题)

5.4 同一子智能体,两种调用上下文(复用不改代码)

调用方式 任务完成后的控制流
作为工作流图节点(SequentialAgent / ParallelAgent / workflow.NewAgentNode) 推进到图中的下一个节点
作为 LlmAgent 的转移接收方(委派工具) finish_task → 回到原始智能体

运行时按智能体被调用的方式自动决定控制流。

5.5 与 1.x 的本质区别

1.x 里"LLM 选子集 + 并行"需要把每个专家包成 AgentTool 手工搭管道;

2.0 把它变成一句声明(sub_agents=... + mode="single_turn")。且 ParallelAgent 永远是"全部并行"、transfer_to_agent 永远是"串行"------协作工作流第一次让"选子集 + 并行 + 自动返回 + 综合"成为原生能力。


6. 第五层:生产级能力(HITL / 韧性 / 可观测)

6.1 人工在环(HITL)------ 内置

  • 任意节点都可以暂停图并向人类提问,工作流持久等待应答:
php 复制代码
event := workflow.NewRequestInputEvent(ctx, session.RequestInput{
    InterruptID: "approve_refund",
    Message: "Approve a $200 refund? (yes/no)",
    ResponseSchema: schema,
})
  • 人类在后续轮次应答后工作流恢复,两种恢复方式自选:

    • Handoff:回答直接流给下一个节点
    • Re-entry:被暂停的节点带着 ctx.ResumedInput(...) 重跑
  • 持久化恢复:运行状态存在 session 中,ADK 甚至能扫描会话历史重建暂停的工作流------

    • 进程重启后可恢复
    • 跨运行时也可恢复(中断格式在 Python ADK 与 Go ADK 间共享)
    • 恢复幂等;错误明确(ErrInvalidResumeResponse / ErrNothingToResume)
    • 应答按 schema 校验
  • Console launcher 与 Web UI 原生理解 HITL:工具确认提示 + 工作流输入请求都能展示

6.2 韧性(Resilience)

  • 每节点 retry policy:指数退避 + jitter,无外部依赖

    • 默认:5 次尝试、初始 1s、上限 60s、2x backoff、full jitter
  • 每节点 timeout

  • 图级并发上限:WithMaxConcurrency(n)

  • 并行分支隔离(WithIsolationScope):一个分支的嘈杂历史不会泄漏进另一个分支的 LLM 提示

  • 调度器负责 goroutine、channel、背压、取消

  • 细粒度选项:WithRunID(子节点身份)、WithUseSubBranch(历史隔离)、WithUseAsOutput(输出委托)

6.3 可观测性与运行时统一

  • 节点/智能体执行出现在同一棵 telemetry span tree,图到底做了什么一目了然

  • Go 2.0 统一 agent.Context:ToolContext / CallbackContext 合并为一个类型------写工具、回调、图节点学同一个上下文

    • 升级注意:节点/节点函数签名首参从 agent.InvocationContext 改为 agent.Context(它嵌入 InvocationContext,旧方法仍可用)
  • Agent modes(Chat / Task / SingleTurn) :runner now 用驱动工作流的同一套节点运行时来驱动普通 LlmAgent

    • 收益:单智能体应用与完整图共享一个执行模型;普通 LLM 智能体也支持 HITL
    • 按角色自动安装辅助工具(finish_task / single_turn / task)
  • 升级 2.0 是高度增量的:整个工作流引擎是可选新包;少量破坏性改动都是机械修复


7. 第六层:数据与上下文管理

  1. 类型化 I/O:input_schema / output_schema(Pydantic / Zod / Go struct)定义契约;Gemini 可服务端强制 output_schema
  2. 自动数据流:图节点间经 event.Output 自动传递;动态工作流 RunNode 直接返回类型化值------都不用手工 session state 管线
  3. 会话分支隔离:并行子智能体各跑各的分支,构建 LLM 上下文时只见自己分支的事件
  4. 状态最小化:动态工作流把值存局部变量,只有指令模板需要读回时才写 Event(state=...)
  5. State-bound 节点:需要时按标签把 session state 拉进类型化结构,而不是全局乱翻

8. 第七层:选型决策指南

vbnet 复制代码
需要多个步骤/多个角色?
│
├─ 控制流运行时才知道(循环次数、数据依赖、模型刚说了什么)→ 动态工作流
│
├─ 需要 LLM 动态决定"派给谁、派几个"?→ 协作工作流
│     ├─ 要专家直接面对用户自由对话 → chat
│     ├─ 专家可向用户澄清、完成自动返回 → task(注意:叶子智能体)
│     └─ 无交互、并行、完成即返回 → single_turn
│
├─ 分支/扇出/扇入/循环,且结构静态可见?→ 图工作流
│     └─ 超过两条分支就值得上图(官方原话:The graph model is worth the
│        learning curve as soon as you have more than two branching paths)
│
└─ 流程固定无分支 → 模板工作流(Sequential / Parallel / Loop)

经验法则:

  • 能确定就确定------路由/调度/错误处理交给代码,LLM 只做认知推理
  • 混合是常态:官方退款案例 = 工具节点(查库/退款/关单)+ LLM 节点(读懂投诉、写定制邮件)混编一张图
  • 官方建议的上手顺序(I/O '26):先玩 Managed Agents / Antigravity 建立原型 → 路由决策需要显式化时移植到 ADK 2.0 图模型

附:一页速查

  • ADK 2.0 = 图工作流 + 动态工作流 + 协作工作流 + HITL/韧性/可观测
  • 图:节点(函数/智能体/工具/Join/动态/子工作流)+ 边(路由/扇出/扇入/回边循环),event.Output 自动传数据
  • 动态:@node + ctx.run_node,用代码写编排,循环递归无限制
  • 协作:sub_agents + mode(chat 手动交接 / task 澄清+finish_task 自动返回 / single_turn 无交互并行自动返回),委派工具按子智能体名自动注入,并行子智能体会话分支隔离
  • 生产:任意节点可暂停问人(durable resume,跨重启跨运行时)、每节点 retry/timeout、图级并发上限、分支隔离、统一 telemetry span tree、统一 agent.Context
  • 哲学:模型做决策,图保证可靠、可观测、可恢复;把确定性留给代码,把认知推理留给 LLM
相关推荐
johnsong1 小时前
AI Agent 没有失控,是围栏断了
人工智能
神奇的代码在哪里1 小时前
Ling-3.1-flash 正式开源:560B 激活 25B,1M 上下文、MIT 许可
人工智能·开源·大模型·ai agent·moe
天远数科1 小时前
零信任架构实战:基于天远柠檬查出险构建自动化二手车延保车况资质核验网关
运维·人工智能·架构·自动化
for_ever_love__1 小时前
RAG 里的拒答:什么时候应该说‘我不知道
人工智能·rag·处理·拒答·不知道·怎么回答·检索不到
狄龙1 小时前
RLDS 数据格式详解:结构、下载与实操(九)
人工智能
狄龙1 小时前
动捕数据完整工作流:从公开动捕 / 单目视频到机器人训练数据(八)
人工智能
江湖中的阿龙1 小时前
AI Agent 调用工具怎么做才稳?参数校验、幂等与审计的 Python 实战
人工智能·python·ai agent·工具调用
陈然信息站1 小时前
食品日化产线铝箔袋检测集成:明治VDS20视觉传感器安装与通讯要点
人工智能