ADK 的 LlmAgent Task 模式全解:结构化委托、finish_task 工具与子代理协作
【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python
本文以
docs/guides/agents/llm_agent/task.md为核心骨架,结合 ADK 源码(src/google/adk)与官方示例(contributing/samples/multi_agent/task_sub_agent/)展开。读完本文,你将掌握:task 模式与 chat / single_turn 模式的本质区别、如何用input_schema/output_schema定义结构化任务接口、finish_task工具的校验与重试机制、task 子代理如何在多代理层级中"以工具形式"被父代理调用,以及如何在 workflow 中托管 task 模式代理的生命周期。
导语
在 ADK 中,LlmAgent的mode="task"面向"被委派的、目标明确的一次性任务"场景:任务代理自己运行思考循环、按需调用工具、必要时与用户对话澄清,最终必须显式调用内建finish_task工具并返回经过output_schema校验的结构化结果。本文从行为模型、配置写法、底层实现到完整示例逐步展开,帮助你用它构建可靠的多代理委托流水线。
1. Task 模式是什么:三种委托模式对比
LlmAgent.mode字段(定义于 llm_agent.py)支持三种取值:
| 模式 | 语义 | 典型用途 |
|---|---|---|
chat | 标准对话代理,可通过transfer_to_agent转交控制权,支持持续的你来我往 | 前台客服、多代理平级协作 |
task | 被委派一个具体任务,与用户对话以完成任务,最终必须调用finish_task返回结构化结果 | 子代理委托、结构化数据抽取 |
single_turn | 无状态、一次调用立即完成,不与用户来回对话 | 单轮查询、即时工具化调用 |
从源码注释看,默认值也有讲究:作为子代理时默认chat,作为 workflow 节点时默认single_turn(见 llm_agent.py)。当子代理是LlmAgent且未显式声明mode时,框架会在model_post_init中将其自动置为chat(llm_agent.py)。
task 模式代理的四个核心特征:
- 运行到完成:它执行"思考 → 调工具"的循环,直到自己判定任务结束;
- 可与用户对话:任务不清晰时可以提问澄清,框架负责跨轮次暂停与恢复;
- 显式结束:必须调用内建
finish_task工具,否则任务无法成功收尾; - 结构化返回:最终输出在返回给调用方前,会依据
output_schema做校验。
2. Task 模式作为子代理:工具化委托机制
2.1 行为模型
task 子代理与 single_turn 子代理一样,是以工具的形式暴露给父代理的,而不是转移目标(transfer_to_agent对它无效)。调用链如下:
- 父代理在思考循环中决定调用该子代理对应的工具;
- 父代理执行被挂起,框架在子分支(sub-branch)中运行 task 代理;
- task 代理运行自己的循环、使用自己的工具,直到调用
finish_task; finish_task传入的输出被校验后,作为工具结果返回给父代理。
源码佐证:在 llm_agent.py 的model_post_init中,框架遍历sub_agents:mode == 'single_turn'的包装为_SingleTurnAgentTool,mode == 'task'的包装为_TaskAgentTool(两者定义于 agent_tool.py)。
_TaskAgentTool有几个值得注意的实现细节(agent_tool.py):
- 若子代理未定义
input_schema,默认使用_DefaultTaskInput(含request字段,见 agent_tool.py); - 工具描述会追加一段强调文案:"此工具将执行委托给一个专门代理,不要与其他工具并行调用"(
_TaskAgentTool._get_declaration,见 agent_tool.py); run_async直接返回None——真正执行由 LLM flow 中的"框架委托分发"接管(见 basic.py 及 workflow/_llm_agent_wrapper.py 中_dispatch_task_fc与_synthesize_task_fr_event的实现),这保证了任务历史按 function-call 隔离作用域独立管理。
2.2 定义与委托示例(官方文档原例)
from google.adk.agents import LlmAgent from pydantic import BaseModel, Field # 1. 定义输入与输出 Schema class ResearchInput(BaseModel): topic: str = Field(description="The topic to research.") depth: str = Field(default="brief", description="Depth of research: brief or detailed.") class ResearchOutput(BaseModel): summary: str = Field(description="A summary of the findings.") sources: list[str] = Field(description="List of sources used.") # 2. 定义 Task 代理 researcher_agent = LlmAgent( name="researcher", instruction="Research the given topic and provide a structured summary.", mode="task", input_schema=ResearchInput, output_schema=ResearchOutput, # Add tools needed for the task tools=[...] ) # 3. 定义父代理 writer_agent = LlmAgent( name="writer", instruction="Write a blog post. Use the researcher agent to get info on the topic.", sub_agents=[researcher_agent] # Exposes 'researcher' agent to writer )要点补充:
input_schema决定父代理调用该子代理工具时所需的参数结构;output_schema决定finish_task必须返回的数据结构。output_schema支持的类型很宽(见 llm_agent.py 的字段文档):type[BaseModel]、list[type[BaseModel]]、list[primitive]、原生 dict schema,以及 Google 的Schema类型。ADK 支持output_schema与tools同时使用——思考循环中照常暴露工具,只在最终输出上强制结构(见 llm_agent.py)。- 特别地,task 模式代理不会在基础 flow 中把
output_schema作为模型的 response schema 下发,因为结构化输出是通过finish_task工具的参数 schema 收集的(见 basic.py 的注释与条件判断)。
2.3 用户交互与跨轮次恢复
task 代理不是"一锤子买卖",任务不清晰时可以与人对话:
- 提问:代理输出面向用户的文本,而不是调用
finish_task; - 暂停:框架检测到代理"交回控制权但未完成任务",暂停执行并把消息送达用户;
- 恢复:用户回复后,框架自动把回复路由回 task 代理,恢复其执行循环;
- 完成:代理继续交互,直到最终调用
finish_task提交结果。
这种"暂停-恢复"由框架的 runner 与 LLM flow 协同完成,任务输出(TaskResult)与请求(TaskRequest)的数据模型定义在 _task_models.py,两个模型都启用 camelCase 别名并禁止额外字段,保证跨会话序列化后依旧可被严格校验。
3. finish_task 工具:任务完成的唯一出口
3.1 自动注入
任何mode="task"的代理都会在初始化时自动获得finish_task工具。源码位于model_post_init(llm_agent.py):
if self.mode == 'task': from .llm.task._finish_task_tool import FinishTaskTool self.tools.append(FinishTaskTool(self))工具名为常量FINISH_TASK_TOOL_NAME = 'finish_task'(见 _finish_task_tool.py)。
3.2 工作机理(结合源码)
系统指令注入:FinishTaskTool.process_llm_request在每次出站 LLM 请求时追加一段指令(_finish_task_tool.py),核心内容为:
不要在任务未完成时过早调用
finish_task。请先用可用工具完整完成被委派任务的每一个方面;如果任务不清晰,先向用户提问澄清;任务彻底完成后,单独调用finish_task,不要附带任何文本输出。
参数 Schema 包装:finish_task的 function declaration 依据代理的output_schema生成。若 schema 本身是对象(如 BaseModel),直接用作参数;若是原始类型或列表(如list[str]),则包装到result键下(get_output_wrapper_key,_finish_task_tool.py),并在包装时把$defs提升到根层以保持$ref引用有效(_finish_task_tool.py)。
校验与失败重试:当模型调用finish_task(output=...)时,工具用TypeAdapter按output_schema校验参数。校验失败会返回错误字典,提示模型"可以重试该工具调用,但必须提供全部必填参数且类型正确"(_finish_task_tool.py)。校验成功后返回固定成功串'Task completed.',框架依据is_finish_task_terminal_fr(_finish_task_tool.py)识别该结果为终止信号:校验失败的非终止 FR 会让循环继续,给 LLM 重试机会。
默认 Schema:未指定output_schema时,默认采用_DefaultTaskOutput——一个仅含必填result: str字段的模型,即"返回一个简单字符串"(_task_models.py)。
3.3 输出在事件流中的落点
在 workflow 包装层,task 代理运行结束时,_llm_agent_wrapper.py会嗅探finish_task的 function call 参数,结合终止 FR 事件把最终输出写到该次运行的事件output上(见 workflow/_llm_agent_wrapper.py 附近逻辑),从而保证父代理拿到的是"校验通过的结构化结果",而非中间的对话文本。
4. Task 模式在 Workflow 中的应用
task 模式在 workflow 中完全受支持:可以把 task 模式代理作为 workflow 图里的静态节点。workflow runner 会自动管理任务生命周期,包括为等待人工输入而暂停,以及用正确上下文恢复执行(见 workflow/_llm_agent_wrapper.py 对节点模式下 task / single_turn / chat 三种模式的区分处理:LlmAgent作为节点仅支持这三种模式,task 模式会以节点输入覆盖用户内容)。
作为节点时,task 代理的输入来源与"被委托"场景不同:没有来自父代理的委托 function call,因此直接使用节点的node_input(源码注释中明确区分了这两种路径,见 workflow/_llm_agent_wrapper.py)。
5. 限制与注意事项
- 不可直接转移:不能通过
transfer_to_agent转移到 task 代理,它们必须以工具形式被调用(源码中_TaskAgentTool正是"框架委托标记"而非转移目标,见 agent_tool.py)。 - 必须调用
finish_task:若 task 代理因 bug 或达到调用上限(如max_llm_calls耗尽)始终未调用finish_task,任务将无法成功完成。这一点与_TaskAgentTool返回None的设计呼应——没有终止 FR,就没有输出落点。
6. 官方示例:task_sub_agent 完整实战
仓库提供了可直接运行的示例 task_sub_agent,演示"task 模式代理作为子代理,从对话流中抽取结构化数据"的完整闭环。
6.1 场景与图结构
协调者coordinator委托两个 task 子代理:
order_collector:收集用户订单(菜单仅有 Pizza / Burger / Salad),返回list[OrderItem];payment_collector:收集信用卡号与 CVV,返回PaymentInfo。
任务完成后,协调者用两个代理返回的结构化数据调用place_order工具。
6.2 关键代码(agent.py 节选)
核心实现位于 agent.py:
class OrderItem(BaseModel): name: str = Field(description="Name of the food item ordered") quantity: int = Field(description="Quantity ordered") class PaymentInfo(BaseModel): """Output schema for the payment collection task.""" credit_card_number: str cvv: str order_collector = Agent( name="order_collector", mode="task", output_schema=list[OrderItem], # 列表类型也受支持 instruction=( "You are an order collection assistant...\n" "Ask the user what they would like to order and collect their choice and quantity.\n" "If the combined quantity of items exceeds 5, you MUST use the `confirmation` tool ...\n" "Once you have their final order and confirmation if needed, finish your task." ), description="Collects the food order from the user.", tools=[FunctionTool(confirmation, require_confirmation=True)], ) payment_collector = Agent( name="payment_collector", mode="task", output_schema=PaymentInfo, instruction="You are a payment collection assistant. Ask the user for their credit card number and CVV. Once you have both pieces of information, finish your task.", description="Collects credit card and CVV from the user.", ) root_agent = Agent( name="coordinator", sub_agents=[order_collector, payment_collector], tools=[place_order], instruction="You are a helpful coordinator for a food delivery service. You need both order and payment information to place an order.", )示例要点:
- 输出 Schema 用
list[OrderItem]:验证了上文"list[type[BaseModel]]属于受支持的 output schema 类型";由于它是列表而非对象,finish_task的参数会自动包装在result键下。 - 任务内嵌工具:
order_collector拥有自己的confirmation工具(且标记require_confirmation=True),说明 task 代理在执行循环中完全可以使用自己的工具集。 - 与用户多轮对话:示例输入依次为
I would like to order some food please.→I want 2 pizzas and 1 salad.→My credit card is 1234-5678-9012-3456 and my CVV is 123.,完整展示了"父代理委托 → 子代理向用户提问 → 用户回复 → 子代理恢复执行 → finish_task 收尾"的跨轮次协作流程。测试用例目录tests/(含3_burgers.json、credit_card.json、order_food.json等)可进一步验证各输入组合下的行为。 - 不要与其他工具并行调用:协调者同时持有两个 task 子代理工具,示例代码与
_TaskAgentTool的工具描述都强调串行委托,避免并行调用造成任务状态混乱。
7. 延伸阅读
- 指南原文:LlmAgent Task Mode
- 完整示例:task_sub_agent README 与 agent.py 实现
- 核心实现:LlmAgent 定义与 mode 字段、FinishTaskTool、TaskRequest/TaskResult 模型、子代理工具包装、workflow 节点包装
- 相关子代理机制:
single_turn模式与transfer_to_agent转移机制可在 agents 目录 与 agents 指南 中进一步查阅。
【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考