当前位置: 首页 > news >正文

ADK(Agent Development Kit)【2】调用流程详解

文章目录

  • ADK基础调用流程
    • 配置模型
    • 定义一个极简Agent
    • 创建Session
    • 创建智能体执行器(Runner)
    • 执行对话

  • ADK项目主页
  • ADK项目说明文档

  1. 安装ADK最新稳定版:pip install google-adk
  2. 导入基础库
import os
import asyncio
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm 
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
from google.genai import types

ADK基础调用流程

配置模型

  • 作为工业级Agent开发框架,ADK的一个基本调用流程如下:
  • 首先需要创建一个模型(ADK的模型调用适配器),需要采用ADK中封装的LiteLlm库来完成,需要注意的是,这个适配器负责配置好 model、认证、连接参数,然后统一管理模型调用接口。
    LiteLlm?
    

核心参数如下:

参数名类型是否必填说明
modelstr 字符串✅ 必填指定要调用的模型名称(例如 openai/gpt-4o, deepseek/deepseek-chat, ollama/qwen2.5
llm_clientLiteLLMClient对象❎ 可选默认自动创建一个内部的客户端;高级用法允许你传自己定制的客户端(一般开发初期用不到)
  • 创建一个ADK能够识别的DeepSeek模型
from google.adk.models.lite_llm import LiteLlm
OPENAI_API_BASE="https://dashscope.aliyuncs.com/compatible-mode/v1"
OPENAI_API_KEY="sk-xxx"
MODEL="deepseek/deepseek-r1-0528"model = LiteLlm(model=MODEL,  api_base=OPENAI_API_BASE,api_key=OPENAI_API_KEY
)

定义一个极简Agent

  • 接下来创建一个Agent对象。和一般Multi Agent框架类似,ADK也是通过Agent类来创建一个个能够独立完成一些功能的代理,而在实际工作中,会通过创建多个代理来协同完成复杂任务。
    Agent是 Google ADK 中管理LLM推理+工具使用+多Agent协作的标准组件,其功能概述如下:
    • 封装一个模型(例如 LiteLlm 连接的模型)
    • 定义这个Agent的指令说明(Instruction)
    • 注册可以调用的工具(Tools)
    • 支持子Agent管理(比如自己不能完成就转交子Agent)
    • 支持调用前后回调(比如修改请求、监控日志)
    • 支持输入输出Schema校验(结构化输入输出)
    • 可以嵌套在更大系统中(比如成为子Agent)
Agent?
  • 核心参数如下:
参数名类型说明中文解释
namestrAgent的名称,必须唯一代理的名字(必填)
descriptionstrAgent的简短描述,通常在多Agent系统中用于路由/选择代理的简短介绍
parent_agentBaseAgent or None父Agent(如果这个Agent是子代理的话)父代理,默认无
sub_agentslist[BaseAgent]这个Agent下面挂载的子Agent们子代理列表
before_agent_callbackCallable or None在Agent处理输入前,进行预处理的回调处理前的自定义函数
after_agent_callbackCallable or None在Agent完成任务后,进行后处理的回调处理后的自定义函数
modelstr or BaseLlm关联的模型,可以是字符串名或模型实例(如LiteLlm)使用的模型(必填)
instructionstr or Callable给Agent的详细指令,可以是固定文本,也可以是函数动态生成指令说明(必填或推荐填写)
global_instructionstr or Callable在整个Agent树范围共享的指令(全局指令)全局指令(少用)
toolslist[Callable or BaseTool]这个Agent可以调用的外部工具列表工具列表
generate_content_configGenerateContentConfig or None控制模型生成内容时的一些配置,比如最大Token数、温度等生成设置(选填)
disallow_transfer_to_parentbool禁止把任务转给父Agent(防止死循环)禁止转移到父代理
disallow_transfer_to_peersbool禁止把任务转给同级Agent禁止转移到同级代理
include_contents‘default’ or ‘none’是否在提示中包含历史对话内容是否包含上下文
input_schemapydantic.BaseModel or None限定输入必须符合某种结构(Pydantic模型)输入校验模型
output_schemapydantic.BaseModel or None限定输出必须符合某种结构(Pydantic模型)输出校验模型
output_keystr or None指定模型输出结果中的哪个字段作为最终输出输出字段名
plannerBasePlanner or None自定义计划器(比如动态规划步骤)规划器(进阶功能)
code_executorBaseCodeExecutor or None允许Agent执行代码(如Python沙盒环境)代码执行器(进阶功能)
exampleslist[Example] or BaseExampleProvider or None示例对话或行为示范,帮助模型更好完成任务示例数据
before_model_callbackCallable or None在发送给模型推理前,修改请求内容模型请求前回调
after_model_callbackCallable or None在收到模型响应后,修改或处理响应模型响应后回调
before_tool_callbackCallable or None在调用工具前修改参数或做拦截工具调用前处理
after_tool_callbackCallable or None在工具返回结果后做处理工具调用后处理

其中四个核心参数:

  • model 是必须指定的(不指定Agent就不会工作)
  • instructiondescription 是推荐填写的(帮助大模型更好理解自己要干什么)
  • tools 是选填的(如果需要调用外部API、数据库等,就注册工具)
  • sub_agents 是选填的(需要多Agent协作时再用)

  • 创建一个简单的Agent对象方法如下:
import os
import asyncio
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm 
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
from google.genai import typesOPENAI_API_BASE="https://dashscope.aliyuncs.com/compatible-mode/v1"
OPENAI_API_KEY="sk-xxx"
MODEL="deepseek/deepseek-r1-0528"model = LiteLlm(model=MODEL,  api_base=OPENAI_API_BASE,api_key=OPENAI_API_KEY
)agent = Agent(name="simple_agent",model=model,instruction="你是一个乐于助人的中文助手。",description="回答用户的问题。"
)

创建Session

  • 紧接着创建一个Session对象,用于保存Agent运行过程中的多轮对话内容。ADK提供了一个InMemorySessionService类。
  • 其核心作用如下:
    • 保存每轮用户输入(user messages)
    • 保存每轮模型输出(assistant messages)
    • 保存工具调用过程中的中间数据(如果有工具的话)
    • 提供历史对话上下文,让模型能基于完整对话继续推理,而不是每次都从空白开始
  • 可以创建一个InMemorySessionService()实例。对话管理示例实际会在内存中进行历史会话信息管理。而具体的会话信息会保存在.sessions属性里,默认为空:
    from google.adk.sessions import InMemorySessionService
    session_service = InMemorySessionService()
    print(session_service.sessions)
    
  • 在正式开启对话之前,需要创建一个初始session对象,为了区分不同的会话,该对象需要设置APP名称、用户ID和对话ID,方便后续进行查找和调用。
    from google.adk.sessions import InMemorySessionService
    session_service = InMemorySessionService()
    session_service.sessions
    APP_NAME = "test_app"
    USER_ID = "user_1"
    SESSION_ID = "session_001"session = session_service.create_session(app_name=APP_NAME,user_id=USER_ID,session_id=SESSION_ID
    )
    print(f"Session created: App='{APP_NAME}', User='{USER_ID}', Session='{SESSION_ID}'")
    
  • 目前session对象是空的,而在后续执行过程中,伴随着上下文生成器存储了更多的会话信息,也可以将更多的上下文信息保存在session中。需要注意的是,在创建session对象的同时,对话生成器session_service.sessions也发生了变化,其内容与session基本一致。
  • 需要注意的是,在后续对话中,我们实际上是带入session_service进行对话,并读取session_service.sessions里面的历史对话信息作为上下文。这里可以将单独创建的session对象视作一个中间对象或者一个备份。

创建智能体执行器(Runner)

  • 接下来进一步创建Runner对象,Runner 是 ADK 中真正让 Agent“动起来”的引擎,其核心功能和Agents SDK中的Runner类似,具体职责如下:
职责说明
会话管理自动读取/写入 SessionService,维护历史
Agent调用调用指定的 Agent 完成推理和工具调用
输入输出流转把用户输入交给Agent,把Agent输出返回
流程控制支持多轮对话、子Agent委托、工具调用等
生命周期管理处理每一次对话流程的完整生命周期
  • Runner:Agent的管理者,负责组织每一次对话交互的完整生命周期。
Runner?
Init signature:
Runner(*,app_name: 'str',agent: 'BaseAgent',artifact_service: 'Optional[BaseArtifactService]' = None,session_service: 'BaseSessionService',memory_service: 'Optional[BaseMemoryService]' = None,
)
Docstring:     
The Runner class is used to run agents.It manages the execution of an agent within a session, handling message
processing, event generation, and interaction with various services like
artifact storage, session management, and memory.Attributes:app_name: The application name of the runner.agent: The root agent to run.artifact_service: The artifact service for the runner.session_service: The session service for the runner.memory_service: The memory service for the runner.
Init docstring:
Initializes the Runner.Args:app_name: The application name of the runner.agent: The root agent to run.artifact_service: The artifact service for the runner.session_service: The session service for the runner.memory_service: The memory service for the runner.
File:           c:\programdata\anaconda3\envs\jupyter_env\lib\site-packages\google\adk\runners.py
Type:           type
Subclasses:     InMemoryRunner

其核心参数解释如下:

参数名类型说明中文翻译
app_namestr应用程序的名称,用于标识不同的应用实例应用名称
agentBaseAgent要运行的根 Agent,负责执行实际的任务和推理要运行的主代理
artifact_serviceOptional[BaseArtifactService]可选的文件存储服务,用于处理生成的工件(如文件、模型)文件存储服务(可选)
session_serviceBaseSessionService必需的会话服务,用于管理和维护对话历史会话服务(必须)
memory_serviceOptional[BaseMemoryService]可选的内存服务,用于长期和短期记忆管理内存服务(可选)
  • Runner类有个直观重要的方法:Runner.run_asyncb
Signature:
Runner.run_async(self,*,user_id: 'str',session_id: 'str',new_message: 'types.Content',state_delta: 'Optional[dict[str, Any]]' = None,run_config: 'RunConfig' = RunConfig(speech_config=None, response_modalities=None, save_input_blobs_as_artifacts=False, support_cfc=False, streaming_mode=<StreamingMode.NONE: None>, output_audio_transcription=None, input_audio_transcription=None, realtime_input_config=None, enable_affective_dialog=None, proactivity=None, session_resumption=None, max_llm_calls=500),
) -> 'AsyncGenerator[Event, None]'
Docstring:
Main entry method to run the agent in this runner.Args:user_id: The user ID of the session.session_id: The session ID of the session.new_message: A new message to append to the session.run_config: The run config for the agent.Yields:The events generated by the agent.
File:      c:\users\kongyue\.conda\envs\langchain_stu\lib\site-packages\google\adk\runners.py
Type:      function

  • runner.run_asyncRunner 类的核心方法之一,用于以异步方式执行 Agent 的任务。这个方法接收用户输入的消息,并将其添加到会话中,随后启动 Agent 来处理该消息,并生成一系列的事件(Event)。

具体参数解释如下:

  1. user_id (str):

    • 该参数表示用户的唯一标识,用于标记当前会话是属于哪个用户的。每个用户可以有多个会话实例。
    • 示例:user_id="user_123"
  2. session_id (str):

    • 该参数表示会话的唯一标识,用于区分不同用户或同一用户的不同对话会话。每次创建会话时,都会为其分配一个唯一的 session_id
    • 示例:session_id="session_456"
  3. new_message (types.Content):

    • 这是 ADK 中的一个核心对象,表示传递给 Agent 的新消息。types.Content 是一个包含了消息的具体内容的对象,通常它包含 role(角色)、text(消息文本)等字段。
    • 示例:new_message=types.Content(role="user", parts=[types.Part(text="今天天气如何?")])
  4. run_config (RunConfig, 可选):

    • 这是一个配置对象,用于定制执行时的参数设置。可以根据需求设置一些如语音配置、响应方式、最大模型调用次数等参数。其默认值为 RunConfig(),这是一个内置的默认配置类。

    RunConfig 的核心字段解释

    • speech_config: 用于配置语音识别和语音输出的相关设置(例如语音转文本、语音输出等)。通常与语音助手相关。
    • response_modalities: 配置响应的方式,例如,返回文本、语音等。
    • save_input_blobs_as_artifacts: 是否将输入文件保存为工件(例如,将用户上传的图片保存为文件以供后续处理)。默认值为 False
    • support_cfc: 是否支持 CFC(Custom Function Calling),即是否允许 Agent 调用自定义函数。
    • streaming_mode: 设置流模式(例如是否开启流式输出),用于处理长时间生成的响应。
    • output_audio_transcription: 配置输出的音频转录设置(如果支持语音输出)。
    • max_llm_calls: 配置在一次会话中最大可以调用 LLM(大语言模型)次数的上限。默认值为 500。

import asyncio
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm 
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
from google.genai import typesOPENAI_API_BASE="https://dashscope.aliyuncs.com/compatible-mode/v1"
OPENAI_API_KEY="sk-xxx"
MODEL="deepseek/deepseek-r1-0528"model = LiteLlm(model=MODEL,  api_base=OPENAI_API_BASE,api_key=OPENAI_API_KEY
)agent = Agent(name="simple_agent",model=model,instruction="你是一个乐于助人的中文助手。",description="回答用户的问题。"
)session_service = InMemorySessionService()
session_service.sessions
APP_NAME = "test_app"
USER_ID = "user_1"
SESSION_ID = "session_001"session =await session_service.create_session(app_name=APP_NAME,user_id=USER_ID,session_id=SESSION_ID
)runner = Runner(agent=agent, # The agent we want to runapp_name=APP_NAME, # Associates runs with our appsession_service=session_service # Uses our session manager
)
print(f"Runner created for agent '{runner.agent.name}'.")
Runner created for agent 'simple_agent'.

执行对话

  • 接下来创建call_agent_async的函数来获得Agent响应,其代码如下:
async def call_agent_async(query: str, runner, user_id, session_id):"""将查询发送给代理并打印最终响应。"""print(f"\n>>> User Query: {query}")# 准备用户的ADK格式消息content = types.Content(role='user', parts=[types.Part(text=query)])final_response_text = "代理未生成最终响应。"  # 默认值# 关键概念:run_async执行代理逻辑并生成事件。# 遍历事件以找到最终答案。async for event in runner.run_async(user_id=user_id, session_id=session_id, new_message=content):# 您可以取消下面一行的注释以在执行期间查看*所有*事件print(f"  [Event] 作者: {event.author}, 类型: {type(event).__name__}, 最终: {event.is_final_response()}, 内容: {event.content}")# 关键概念:is_final_response()标记该回合的结束消息。if event.is_final_response():if event.content and event.content.parts:# 假设文本响应在第一部分中final_response_text = event.content.parts.textelif event.actions and event.actions.escalate:  # 处理潜在的错误/升级final_response_text = f"代理已升级: {event.error_message or '没有具体消息。'}"# 如果需要可以添加更多检查(例如特定错误代码)break  # 一旦找到最终响应就停止处理事件print(f"<<< Agent Response: {final_response_text}")

这段代码定义call_agent_async 异步函数,用来:

  1. 接收用户的查询(query
  2. 调用 Agent 执行推理
  3. 获取并返回最终的 Agent 回复

其核心运行流程是:

  • 将用户查询转换为 ADK 需要的格式
  • 通过 runner.run_async() 运行 Agent
  • 通过 事件驱动机制 获取和处理每一轮的消息、工具调用、回复
  • 最终响应 到达时,停止循环并返回 Agent 的最终回答。

注意:

  • 为什么要定义这个辅助函数?在这段代码中,我们通过 call_agent_async 这个辅助函数来实现与 Agent 的交互。它的作用不仅是简单地给用户回复答案,而是通过 事件驱动 机制,来处理与 Agent 的复杂交互和状态管理。
  • 为什么不直接调用 runner.run_async?其实是为了能够更方便地处理和监控整个过程,尤其是在多轮对话或复杂交互中。将这些复杂逻辑封装到一个函数里,使得代码更加清晰、可维护,并且容易扩展。
  • 也就是说,可以把call_agent_async 想象成一个管控器,它负责管理这个异步对话的过程,并确保每一部分顺利完成。这个过程很复杂,因为:
    • 它不是一次性任务,可能涉及多步推理外部工具调用错误处理等环节。
    • 需要逐步监控每一个事件(可能有很多中间状态、工具调用等)。
    • 只有当所有步骤完成,最终的模型回复才算“最终回应”。
>>> User Query: 你好,我叫陈明,好久不见![Event] 作者: simple_agent, 类型: Event, 最终: True, 内容: parts=[Part(text='陈明先生您好!很高兴认识您!虽然我们可能是初次对话,但很乐意为您提供帮助。请问今天有什么问题需要解答,或是有什么我可以为您做的吗?😊'
)] role='model'
<<< Agent Response: 陈明先生您好!很高兴认识您!虽然我们可能是初次对话,但很乐意为您提供帮助。请问今天有什么问题需要解答,或是有什么我可以为您做的吗?😊

  • Authorsimple_agent — 这个事件是由 simple_agent 发出的,表示当前响应来自于我们定义的Agent
  • TypeEvent — 表明这是一个事件对象,表示某个状态发生。
  • FinalTrueTrue 表示这是最终的响应,模型已经完成任务并准备返回最终结果。
  • Contentcontent.parts=[Part(...)] — 这里包含了模型回复的实际内容。它是一个 Part 对象,其中 text 字段就是最终的文本回答:
    '你好!我是你的智能助手,专门用来回答你的问题、提供帮助或陪你聊天。我可以帮你查询信息、解答疑问、提供建议,或者只是随便聊聊。有什么我可以帮你的吗? 😊'
    
  • role'model' — 角色是 模型,意味着这条消息是从模型生成的,不是用户输入。

在这里插入图片描述

http://www.dtcms.com/a/324262.html

相关文章:

  • 智慧交通-道路积雪识别分割数据集labelme格式1985张2类别
  • python Flask简单图书管理 API
  • 【Linux知识】Linux grep 命令全面使用指南
  • 祝融号无线电工作频段
  • C++入门自学Day8-- 初识Vector
  • leetcode2379:得到K个黑块的最少涂色次数(定长滑动窗口)
  • 2.变量和常量
  • Go 工具链环境变量实战:从“command not found”到工具全局可用的全流程复盘
  • 【数据结构入门】栈和队列的OJ题
  • 二维前缀和问题
  • MySQL面试题及详细答案 155道(041-060)
  • 构建第三方软件仓库
  • 数据类型取值范围
  • String AOP、事务、缓存
  • 【18】OpenCV C++实战篇——【项目实战】OpenCV C++ 精准定位“十字刻度尺”中心坐标,过滤图片中的干扰,精准获取十字交点坐标
  • 力扣559:N叉树的最大深度
  • XGBoost算法在机器学习中的实现
  • C语言:指针(2)
  • Gin vs Beego vs Echo:三大主流 Go Web 框架深度对比
  • 前端开发中的常见问题与实战解决方案​
  • JS数组排序算法
  • scanpy单细胞转录组python教程(三):单样本数据分析之数据标准化、特征选择、细胞周期计算、回归等
  • 2025.8.10总结
  • 学生成绩管理系统的 SQL 表设计与多表查询实战
  • 部署一个免费开源的博客系统
  • 库的制作和原理
  • 双亲委派机制是什么?
  • 大模型工具集成四层架构:识别、协议、执行与实现
  • reinterpret_cast and static cast
  • Lua的数组、迭代器、table、模块