数据截至 (上游 commit aa6a07bc97f1)
第 4 章:Task API、agent 委派,与全局收尾
本章讲多 agent 怎么协作:一个 agent 怎么把活儿交给另一个。再给巧妙之处、边界、横向对比和代码地图(给 agent/人 的跳转表)。
4.1 三种委派模式(mode)
LlmAgent.mode(agents/llm_agent.py:365)决定一个 agent 被「指挥」的方式:
| mode | 含义 | 默认场景 |
|---|---|---|
chat | 标准对话 agent,可经 transfer_to_agent 接管对话 | 作为根 / 子 agent 默认值 |
task | 任务 agent:会多轮和用户对话来完成一个任务 | 显式指定 |
single_turn | 不和用户对话、一锤子完成一个子任务 | 作为 workflow 节点时默认 |
注释明确(llm_agent.py:373):「作为子 agent 默认 chat,作为 workflow 节点默认 single_turn」。Runner 强制根 LlmAgent 必须是 chat(runners.py:1292)。
4.2 sub-agent 按 mode 自动变成工具
关键设计:把子 agent 加进 sub_agents,框架会按子 agent 的 mode 自动把它包成不同的「工具」挂到父 agent 上。看 LlmAgent 构造期(llm_agent.py:1064-1080):
# 真实源码节选 agents/llm_agent.py:1066-1080
if self.sub_agents:
for sub_agent in self.sub_agents:
if isinstance(sub_agent, LlmAgent):
mode = getattr(sub_agent, 'mode', None)
if mode is None:
sub_agent.mode = 'chat'; mode = 'chat'
if mode == 'single_turn':
self.tools.append(_SingleTurnAgentTool(sub_agent)) # 包成单轮工具
elif mode == 'task':
self.tools.append(_TaskAgentTool(sub_agent)) # 包成任务工具
chat子 agent → 经AutoFlow的agent_transfer处理器,模型可transfer_to_agent(name)把控制权整体转交(第 1 章)。single_turn子 agent → 包成_SingleTurnAgentTool:父 agent 像调普通工具一样调它,拿到一次性结果。task子 agent → 包成_TaskAgentTool:支持多轮任务委派。task模式 agent 自己构造时还会自动加一个FinishTaskTool(llm_agent.py:1176),让它能显式宣告「任务完成、产出结果」。
4.3 委派的底层:ctx.run_node + isolation_scope
两种委派最终都落到第 2 章的动态节点机制上。看任务委派分发(workflow/_llm_agent_wrapper.py:213,_dispatch_task_fc):
# 真实源码节选 workflow/_llm_agent_wrapper.py:153-159
await ctx.run_node(
task_agent,
node_input=fc.args, # 模型给的任务参数
override_isolation_scope=fc.id, # 用 function-call id 作隔离作用域
)
isolation_scope 的直觉: 被 委派的 task agent 要和用户多轮对话,但这段对话不该污染主协调者的会话视图。isolation_scope(Context 属性,agents/context.py:255)给每个委派一个独立作用域(这里用工具调用的 fc.id),让任务对话与父对话/同侪节点的事件隔离开。task/single_turn agent 共享父分支,靠 isolation_scope 而非 branch 来隔离(_llm_agent_wrapper.py:142-144 注释)。
委派结果被合成回一条 function-response 事件(_synthesize_task_fr_event,_llm_agent_wrapper.py:243),回灌给协调者的对话,模型据此继续。
节点输入转 Content。 _node_input_to_content(_llm_agent_wrapper.py:188)把任意 node_input(str/dict/BaseModel)转成模型能吃的 types.Content,这是「图节点的数据」和「LLM 的对话内容」之间的桥。
4.4 A2A:跨进程的 agent
a2a/ 模块(29 文件)实现 Agent-to-Agent 协议,把远程 agent 暴露/消费为标准接口;agents/remote_a2a_agent.py 是「本地看起来是个 agent,实际请求远端」的代理。依赖可选包 a2a-sdk(pyproject.toml 的 optional-dependencies.a2a)。本仓库里它建立在同一套 Event/Session 抽象上,细节超出本篇核心范围。
4.5 巧妙之处(可借鉴)
- mode 驱动的 「自动布线」。 你只声明子 agent 的 mode,父 agent 自动把它包成 transfer / 单轮工具 / 任务工具(
llm_agent.py:1184)。多 agent 拓扑不用手写胶水。 - 委派 = 动态节点。 transfer 之外的委派全部复用
ctx.run_node(动态节点),和工作流是同一套调度/恢复机制,而不是另起炉灶——所以任务委派也天然可恢复、可中断。 - isolation_scope 而非分叉分支来隔离会话。 委派任务共享主分支但用作用域隔离视图(
_llm_agent_wrapper.py:142),既隔离上下文又不切断与主对话的关联,便于把结果合成回去。 - FinishTaskTool 让「任务完成」是显式信号。 task agent 用一次工具调用宣告产出(
llm_agent.py:1176),而不是靠启发式猜「它说完了没」。
4.6 边界与局限
- task 模式不能当静态图节点(
_workflow.py:184,_validate_no_task_mode_graph_nodes):调度器重入时会覆盖node_input,任务简报会丢。只能作 chat 协调者的子 agent,或经ctx.run_node动态调起。 - 老的
SequentialAgent/LoopAgent/ParallelAgent已@deprecated(agents/sequential_agent.py:77),功能被Workflow取代;新代码别再用。 AgentConfigYAML 加载器与from_config也已@deprecated(base_agent.py:686)。- 强 Google 取向:默认模型是 Gemini(
llm_agent.py:239,DEFAULT_MODEL,本提交实 测值为'gemini-3.5-flash'——注意 README 示例里的gemini-2.5-flash只是演示串,不是这个常量的值),很多可选集成是 GCP 服务(pyproject.toml的optional-dependencies.all)。
4.7 横向对比(同 shelf 兄弟)
| 维度 | ADK 2.0 | 典型对照 |
|---|---|---|
| 编排模型 | 一切皆节点的图:agent/函数/子图统一 BaseNode,Workflow._run_impl 即调度循环 | LangGraph 也是图,但 ADK 把单个 agent 也直接做成节点、并把委派复用同一调度 |
| 控制流 | 顺序/扇出/扇入/路由/循环都是同一「触发器邮箱」机制的特例 | 多数框架为不同控制流提供不同原语 |
| 恢复 | 状态=事件重放结果 + invocation_id 续跑;HITL/长时工具共用暂停通路 | 不少框架靠序列化检查点 |
| agent 委派 | mode 驱动自动布线(transfer / task / single_turn 工具),底层是动态节点 | 通常需手写「agent as tool」胶水 |
4.8 代码地图(导航索引)
按符号名 grep 比按行号更抗漂移。
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 一切皆节点的基类 | src/google/adk/workflow/_base_node.py | BaseNode、BaseNode.run、BaseNode._run_impl、START |
| Agent 基类(继承 BaseNode) | src/google/adk/agents/base_agent.py | BaseAgent、run_async、_handle_before_agent_callback、clone |
| LLM Agent | src/google/adk/agents/llm_agent.py | LlmAgent、canonical_model、canonical_tools、_run_async_impl、_run_impl、mode |
| 单 agent 的 agentic 循环 | src/google/adk/flows/llm_flows/base_llm_flow.py | BaseLlmFlow、run_async、_run_one_step_async、_preprocess_async、_postprocess_async |
| 请求处理器链 | src/google/adk/flows/llm_flows/single_flow.py | SingleFlow、_create_request_processors;auto_flow.py 的 AutoFlow |
| 工具调用执行 | src/google/adk/flows/llm_flows/functions.py | handle_function_calls_async、get_long_running_function_calls、REQUEST_EUC_FUNCTION_CALL_NAME |
| 函数→工具自动包装 | src/google/adk/tools/function_tool.py | FunctionTool、_get_declaration |
| 图定义/编译 | src/google/adk/workflow/_graph.py | Graph、Edge、from_edge_items、get_next_pending_nodes、DEFAULT_ROUTE、RouteValue |
| 图调度循环 | src/google/adk/workflow/_workflow.py | Workflow、_run_impl、_run_loop、_schedule_ready_nodes、_buffer_downstream_triggers、_make_schedule_dynamic_node、_LoopState |
| 动态节点调度器 | src/google/adk/workflow/_dynamic_node_scheduler.py | DynamicNodeScheduler、ScheduleDynamicNode |
| 跑单个节点 | src/google/adk/workflow/_node_runner.py | NodeRunner、_create_child_context、_enrich_event、_flush_deltas |
| 汇合节点 | src/google/adk/workflow/_join_node.py | JoinNode、_requires_all_predecessors |
| 函数节点/参数绑定 | src/google/adk/workflow/_function_node.py | FunctionNode、_bind_parameters;workflow/_node.py 的 node、Node |
| 节点状态机 | src/google/adk/workflow/_node_status.py | NodeStatus(PENDING/RUNNING/WAITING/COMPLETED/FAILED/CANCELLED) |
| 节点运行期把手 | src/google/adk/agents/context.py | Context、run_node、output、route、isolation_scope、state |
| 入口 | src/google/adk/runners.py | Runner、run_async、_run_node_async、_find_agent_to_run、InMemoryRunner |
| 事件模型 | src/google/adk/events/event.py | Event、EventActions、is_final_response、_accept_convenience_kwargs、NodeInfo |
| 请求人类输入 | src/google/adk/events/request_input.py | RequestInput |
| 会话/状态存储 | src/google/adk/sessions/base_session_service.py | BaseSessionService、append_event、_update_session_state;sessions/session.py 的 Session |
| 应用容器 | src/google/adk/apps/app.py | App、resumability_config、events_compaction_config |
| 委派分发(task) | src/google/adk/workflow/_llm_agent_wrapper.py | _dispatch_task_fc、_synthesize_task_fr_event、_node_input_to_content、prepare_llm_agent_context |
| task agent 工具 | src/google/adk/tools/agent_tool.py | _TaskAgentTool、_SingleTurnAgentTool |
| 完成任务工具 | src/google/adk/agents/llm/task/_finish_task_tool.py | FinishTaskTool;_task_models.py 的 TaskRequest、TaskResult |
| 跨进程 agent | src/google/adk/a2a/、src/google/adk/agents/remote_a2a_agent.py | A2A 协议接入(可选依赖 a2a-sdk) |
| 工作流样例(最佳学习入口) | contributing/samples/workflows/ | route/、fan_out_fan_in/、loop/、state/、request_input/、dynamic_nodes/、retry/ |