)
ADK 函数工具实战把普通 Python 函数变成 Agent 可调用的工具function_tools 示例详解【免费下载链接】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本文以 ADKAgent Development Kit官方示例contributing/samples/tools/function_tools为主体完整还原两个纯 Python 函数如何被注册为 Agent 工具的全过程从函数定义、类型注解与 docstring 规范到tools[...]注册方式、测试事件文件中的完整调用链再到 ADK 源码层面FunctionTool如何从函数签名自动推导工具声明FunctionDeclaration、如何注入框架上下文。读完本文你可以照此模式将任意本地 Python 方法转化为 Agent 能力并理解 ADK 底层参数解析与声明缓存的实现原理。一、示例定位最小可用的 Function Tools Agent该示例README的目标非常聚焦演示如何用ADK框架构造一个配备了内置 Python 函数工具的 Agent。它定义了一个Agent包裹了两个工具函数generate_random_number和is_even——LLM 会根据用户提示词自动调用这两个底层 Python 函数展示把原始 Python 方法变成 Agent 可执行能力有多简单。示例目录结构contributing/samples/tools/function_tools/ ├── README.md # 本文主体文档 ├── __init__.py # 将 agent 模块暴露为 ADK agent 包入口 ├── agent.py # 工具函数 root_agent 定义 └── tests/ ├── a_random_number.json # 场景1单次工具调用 ├── a_random_number_and_check_even.json # 场景2两步串行调用 └── random_number_and_is_5_even.json # 场景3单步并行调用init.py 仅一行from . import agent这正是 ADK 标准 agent 包的约定目录名即 agent 目录agent.py中必须导出名为root_agent的 Agent 实例。README 中给出的调用关系图如下二、完整实现agent.py 逐行解析示例的全部业务代码就是 agent.py去掉 License 头后如下import os import random from google.adk.agents import Agent _counter 0 def generate_random_number(max_value: int 100) - int: Generates a random integer between 0 and max_value (inclusive). Args: max_value: The upper limit for the random number. Returns: A random integer between 0 and max_value. # Return a growing value in tests to ensure determinism while allowing # multiple calls. if PYTEST_CURRENT_TEST in os.environ: global _counter _counter 1 return _counter return random.randint(0, max_value) def is_even(number: int) - bool: Checks if a given number is even. Args: number: The number to check. Returns: True if the number is even, False otherwise. return number % 2 0 root_agent Agent( namefunction_tools, tools[generate_random_number, is_even], )对照 README 的 How To这里有三个关键写法要点标准 Python 函数 类型注解 精确 docstring。README 明确要求Define standard Python functions with type hints and precise docstrings。这不是风格建议而是框架硬需求——ADK 依赖inspect.signature提取参数类型与默认值来生成工具声明见第四节源码分析。Google 风格 docstring 的Args/Returns段会成为 LLM 理解该工具何时该调用、参数语义为何的主要依据。函数默认值决定可选参数。max_value: int 100有默认值因此在生成的声明中它是可选参数模型完全可以像测试文件里那样以空args: {}发起调用。注册即传入直接把函数对象放进Agent的tools列表。注意这里传的是未调用的函数引用而不是FunctionTool(...)实例——ADK 会在内部自动包装源码佐证见下文。值得注意的细节generate_random_number在 pytest 环境下检测到PYTEST_CURRENT_TEST环境变量改为返回自增计数器1、2、3……。源码注释写明这是ensure determinism while allowing multiple calls——让集成测试可重复断言同时支持同一函数被多次调用。这也解释了为什么三个测试 JSON 中该函数第一次调用的结果恒为1。三、三条示例输入与对应的真实事件流README 的 Sample Inputs 给出三条典型提示词与tests/下三个事件快照文件一一对应是理解函数工具调用协议的最佳材料示例输入事件文件行为特征Give me a random number.a_random_number.json单工具单步调用Give me a random number up to 50, and tell me if its even.a_random_number_and_check_even.json两次工具调用串行跨步结果依赖Give me a random number and is 44 even?random_number_and_is_5_even.json同一模型事件内并行发起两个工具调用场景 1单工具调用a_random_number.json 中一次交互产生 4 个事件完整呈现了 ADK 的 function-call 协议闭环用户事件author: usera random number模型 functionCallauthor: function_tools{functionCall: {args: {}, id: fc-1, name: generate_random_number}}——注意args为空即模型省略了有默认值的max_valueid: fc-1是后续响应配对用的调用标识框架 functionResponse{functionResponse: {id: fc-1, name: generate_random_number, response: {result: 1}}}——通过id与第 2 步的调用配对结果包裹在result键下模型文本事件Here is a random number: 1\nfinishReason: STOP交互结束。每个事件还携带nodeInfo.path如function_tools11表示第 1 次调用与invocationId多 Agent 场景下用于区分事件归属于哪个节点的第几轮执行。场景 2串行依赖调用a_random_number_and_check_even.json 有 6 个事件模型先调用generate_random_number拿到1在下一个模型轮次中才基于该结果调用is_even(number1)得到false最终回复The random number is 1. It is not an even number.。这展示了工具间存在数据依赖时ADK 会逐轮回传结果由 LLM 决定下一步调用哪个工具、传什么参数。场景 3单步并行工具调用random_number_and_is_5_even.json 是 README 特别标注的场景This will cause parallel tools being called in a single step同一个模型事件的parts里同时携带两个 functionCallgenerate_random_number与is_even(number5)随后框架在一个 functionResponse 事件中并行返回两个结果模型再一次性汇总作答。这证明 ADK 对模型单轮发起的多个工具调用做了并发执行与批量回传无需模型往返两轮。四、源码深挖一个函数引用如何变成工具示例里tools[generate_random_number, is_even]传的是裸函数但 ADK 的工具体系里真正干活的是FunctionTool。整条链路可以拆成包装 → 声明生成 → 参数注入 → 执行四步。4.1 自动包装LlmAgent 解析 tools 列表在 llm_agent.py 的工具解析逻辑中对tools列表中的每一项做了类型分派if isinstance(tool_union, BaseTool): return [tool_union] if callable(tool_union): return [FunctionTool(functool_union)]也就是说BaseTool子类直接采用普通可调用对象会被自动包一层FunctionToolBaseToolset如 MCP 工具集则展开为其下属工具BaseAgent/BaseNode走另一分支子 Agent 不能作为工具。这就是示例中裸函数直接进 tools 列表能工作的根本原因。4.2 名称与描述来自函数名和 docstringFunctionTool 构造函数 中工具name取自函数名经_function_tool_declarations.get_callable_name解析保证以注册名声明工具description直接取self._spec.doc——即函数 docstring 全文。这解释了为何示例 docstring 写得如此完整它一字不差地出现在发给模型的 FunctionDeclaration 里是模型决定何时调用该工具的唯一文本依据。4.3 声明生成从签名到 FunctionDeclarationFunctionTool._get_declaration 调用build_function_declaration定义于 _automatic_function_calling_util.py。核心机制用inspect.signature遍历形参仅接受位置/关键字参数*args/**kwargs不支持按类型注解映射出 JSON Schema 属性str→STRING、int→INTEGER、float→NUMBER、bool→BOOLEAN、list/tuple→ARRAY、dict→OBJECT等见模块内_py_type_2_schema_type映射表无默认值且不可空的参数进入required有默认值的如max_value为可选——与场景 1 中args: {}的行为严格对应使用 Pydantic 临时建模create_modelmodel_json_schema再清洗为平台 Schema对 Vertex AI 变体还会依据返回类型注解附加responseSchema_get_return_typeL210-L217因此写全- int这类返回注解对 Vertex AI 通道有价值结果经_build_declaration_cached以lru_cache(1024)缓存因为pydantic 建模 JSON Schema 生成开销较大而结果只取决于静态输入否则每次 LLM 调用每个工具都要重算源码注释原话。4.4 框架上下文注入模型看不见的参数FunctionTool初始化时L121-L123会把tool_context以及 live 流式模式的input_stream列入_ignore_params——这些参数从声明中剔除模型永远看不到。实际调用时_prepare_invocation_args会做两件事把 Pydantic 模型字典参数反序列化回实例_preprocess_args再把tool_context实例注入到函数签名中声明了该参数的位置并过滤掉签名之外的多余键。由此得到一个实战技巧若你的工具函数需要读写会话状态、追加事件只需在签名里加一个tool_context: ToolContext参数例如def is_even(number: int, tool_context: ToolContext) - bool框架自动完成注入LLM 侧的声明不受影响。此外FunctionTool(func, require_confirmation...)还支持布尔或可调用的确认条件用于高危操作的 Human-in-the-Loop 拦截L100-L114——本示例的随机数/奇偶判断属于纯计算、无副作用故未启用。五、运行与验证方式本仓库为只读参考以下均为查看/运行说明。前提已安装google-adkpip install google-adk并配置好模型凭据如环境变量GOOGLE_API_KEYAgent未显式指定model时使用框架默认值具体默认模型以你安装的 ADK 版本为准。命令行交互运行agent 目录须包含__init__.py与agent.py本示例已满足adk run contributing/samples/tools/function_toolsWeb 界面运行传入示例所在父目录即可在浏览器中挑选该 agentadk web contributing/samples/tools随后输入 README 中的三条提示词观察事件流即可复现tests/目录下三个 JSON 快照所示的行为单次调用、串行依赖调用与单步并行调用。若要在自动化测试中验证可复用PYTEST_CURRENT_TEST分支带来的确定性返回1、2、3……对工具结果做精确断言——这正是示例自带三份事件快照的用途。六、要点回顾写法契约普通 Python 函数 完整类型注解 Google 风格 docstring 有意义的默认值是零装饰器注册工具的全部前提注册方式函数引用直接放入Agent(tools[...])ADK 在 llm_agent.py 中自动包装为FunctionTool协议闭环模型发出带id的functionCall→ 框架执行后以functionResponse按id配对回传 → 模型继续推理多个调用可在同一轮并行执行框架级注入tool_context/input_stream参数对模型不可见、由框架注入是工具访问会话状态与流式数据的标准通道声明性能FunctionDeclaration 生成昂贵但静态ADK 用 LRU 缓存避免每次 LLM 调用重复计算。按这一模式任何确定性的本地 Python 方法查询、计算、格式化等都可以按同样步骤接入 ADK Agent需要访问外部服务或复杂权限时再考虑BaseTool子类或BaseToolset如 MCP 工具集等更重的形式。【免费下载链接】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),仅供参考