ADK Python 示例注入指南用 ExampleTool 为 Agent 构建动态 Few-shot 学习【免费下载链接】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-pythonADK Python 的Example、BaseExampleProvider与ExampleTool三件套用于把「输入-输出」示例以系统指令文本的形式注入到每个回合的 LLM 请求中让模型在真实调用前先掌握正确的回答形态。本文以 Example and ExampleTool 官方指南 为主线结合源码与仓库示例讲解静态示例列表、按查询动态选取示例、与上下文缓存的相互作用以及 YAML 配置、A2A Agent 卡片发布等进阶用法。为什么需要独立的示例注入机制如果示例只是一小段固定文本直接拼进instruction字符串就足够了。ADK 专门提供这套包是为了覆盖两种固定字符串解决不了的场景示例是结构化数据而非散文示例中要包含工具调用function call和工具响应function response。这些内容需要 ADK 按目标模型期望的格式渲染手工拼字符串容易出错且难以跨模型复用。示例取决于当前回合的用户提问合适的示例必须根据「这一轮用户问了什么」动态查询而不是构建 Agent 时一次性写死。整套机制由三个部件组成定义见 src/google/adk/examples/ 与 src/google/adk/tools/example_tool.pyExample一个 Pydantic 模型只有两个字段——input: types.Content一轮用户输入和output: list[types.Content]应当紧随其后的模型回合。定义见 example.py。BaseExampleProvider一个单方法抽象接口get_examples(query: str) - list[Example]负责按查询取回示例。ADK 自带一个实现VertexAiExampleStore。定义见 base_example_provider.py 与 vertex_ai_example_store.py。ExampleTool把以上两者接到请求管线上的「接线员」。它是一个不向模型声明任何 function 的BaseTool唯一职责是在请求发出前改写请求。关键事实LlmAgent没有examples参数在 ADK Python 中LlmAgent不存在examples字段。示例要到达 Agent唯一途径是把ExampleTool放进它的tools列表。如果你正在找一个字段却找不到原因就在这里。这一点可以从源码得到印证example_tool.py 中ExampleTool继承自BaseTool而Agent的tools参数接受BaseTool实例。与上下文缓存context cache的相互作用添加ExampleTool会改变系统指令而系统指令正是上下文缓存命中的关键依据。该工具在每个回合都会把渲染好的示例块追加到系统指令末尾因此固定列表每个回合渲染出的字符串完全一致缓存前缀始终匹配缓存持续生效。编辑列表下一次运行会生成新的系统指令缓存失效重新计费。Provider 动态选取这是最需要警惕的情况——Provider 根据当前用户查询重建示例块一旦选中的示例与构建缓存时不同系统指令就与缓存不匹配该回合需要为整个前缀支付全价而不是缓存价。缓存的开关通过App.context_cache_config配置详见 App 指南。快速开始在代码中构建示例最基本的用法是在代码里构建示例列表传给tools中的ExampleToolfrom google.adk.agents import Agent from google.adk.examples import Example from google.adk.tools import ExampleTool from google.genai import types example_tool ExampleTool([ Example( inputtypes.UserContent(parts[types.Part(textWhere is order 4417?)]), output[ types.ModelContent( parts[types.Part.from_function_call( namecheck_order_status, args{order_id: 4417} )] ), types.ModelContent( parts[types.Part(textOrder 4417 shipped on Tuesday and arrives Friday.)] ), ], ), Example( inputtypes.UserContent(parts[types.Part(textI want a refund.)]), output[ types.ModelContent( parts[types.Part(textSure — which order number is that for?)] ) ], ), ]) agent Agent( namesupport_agent, instructionHelp the user with their order., tools[check_order_status, issue_refund, example_tool], )注意这些示例不是模型可以调用的工具。它们以系统指令文本的形式在每一回合与你的instruction一起送达模型。字典简写形式当示例全是纯文本时ExampleTool也接受普通字典并通过TypeAdapter(list[Example])校验转换为Example对象见 example_tool.py 的validate_python调用。代码更短example_tool ExampleTool([ { input: {role: user, parts: [{text: Is 7 a prime number?}]}, output: [{role: model, parts: [{text: Yes, 7 is a prime number.}]}], }, ])推荐从代码内列表开始建议优先使用代码内静态列表。这是仓库中所有示例采用的路线也是 A2A Agent 卡片唯一能发布的路线并且运行时零开销。只有当下述情况成立时才考虑 Provider示例必须按查询逐个挑选——意味着存储规模达数千条或示例内容需要在不重新部署的情况下变更。工作原理每个回合发生了什么ExampleTool的全部工作发生在一个每回合都会执行的钩子里唯一的区别只是示例来自你构建的列表还是每次询问的 Provider。它实现了process_llm_request——这是BaseTool提供的、在请求构建完成后、发送之前运行的钩子源码见 example_tool.py。每个回合它会读取tool_context.user_content.parts[0].text即当前用户消息的文本。如果没有 parts或第一个 part 不是文本直接返回、不追加任何内容。解析示例列表原样使用BaseExampleProvider则用这段文本调用get_examples(query)。把示例渲染成一个字符串追加到请求的系统指令中。渲染后的块带有明确的分隔标记和自描述文本模型可以区分示例与你的指令EXAMPLES Begin few-shot The following are examples of user queries and model responses using the available tools. EXAMPLE 1: Begin example [user] Where is order 4417? [model] check_order_status(order_id4417) Order 4417 shipped on Tuesday and arrives Friday. End example End few-shot EXAMPLES渲染细节与模型分支渲染逻辑实现在 example_util.py 的convert_examples_to_text中函数调用渲染为 Python 风格调用语法字符串参数加引号其余按字面量函数响应渲染为 dict 形式源码中实际是part.function_response.__dict__的字符串化结果example_util.py。代码围栏fence取决于请求中的模型名模型名包含gemini-2或没有模型名使用普通的三反引号围栏其他任何模型名使用tool_code与tool_outputs围栏。这个判定是 Gemini 1.5 到 2.0 过渡时期写的之后未更新——Gemini 3 模型会走 pre-2.0 分支example_util.py 中的gemini2 model is None or gemini-2 in model。从工具角度看ExampleTool不声明任何 function因此它永远不会出现在模型的工具列表中、永不可被调用、也永远不会产生 function response——它只是在tools中占一个槽位别无他用。Provider 路由BaseExampleProvider在异步请求路径内部每回合同步调用一次以用户文本作为查询。get_examples里的任何耗时操作都会阻塞本次调用而且没有缓存、没有超时、没有错误处理——异常会直接向上传播导致该回合失败。VertexAiExampleStore是对 Vertex AI Example Store 的实现。构造时传入 store 资源名每次调用对该查询文本做相似度检索丢弃相似度低于0.5的结果把剩余结果转换为Example对象。top_k10与 0.5 阈值都是硬编码常量见 vertex_ai_example_store.py 中的请求构造与过滤逻辑example_tool ExampleTool( VertexAiExampleStore( projects/my-project/locations/us-central1/exampleStores/my-store ) )该类在未安装任何 Vertex AI 包时也能正常 import——它的依赖在get_examples内部才 importvertex_ai_example_store.py因此缺失安装会在第一个回合以ModuleNotFoundError形式暴露而不是在构造时。配置参数ExampleTool只接受一个参数位置传参或examples关键字均可OptionTypeDefaultDescriptionexampleslist[Example] \| BaseExampleProviderrequired示例列表或按查询取示例的 Provider。列表通过TypeAdapter(list[Example])校验形状正确的字典会被接受并转换Provider 实例原样存储每回合被查询工具的name与description被固定为example_tool与example toolexample_tool.py因为它们永远不会被发送给模型工具本身不向模型声明。Example恰好只有两个字段OptionTypeDefaultDescriptioninputtypes.Contentrequired示例演示的用户回合。outputlist[types.Content]required应当紧随其后的回合。output是列表因为一次完整交互往往需要多个回合先是一次函数调用再是使用其结果的回答。请给每个Content都带上role因为渲染器根据它切换[user]/[model]前缀types.UserContent与types.ModelContent已经替你设好了 role。进阶应用代码内列表已经覆盖大多数 Agent。以下小节分别处理它覆盖不到的场景。不用 Vertex Store 也能按查询选示例当示例按意图分组成几十条时值得做筛选——每回合全量发送会消耗上下文并稀释真正匹配那几条示例的信号。实现你自己的BaseExampleProvider即可。该方法同步执行且只收到原始用户文本请保持为内存内选择不要做网络调用class IntentExampleProvider(BaseExampleProvider): def __init__(self, examples_by_intent: dict[str, list[Example]]): self._examples_by_intent examples_by_intent def get_examples(self, query: str) - list[Example]: for intent, examples in self._examples_by_intent.items(): if intent in query.lower(): return examples return []返回空列表是安全的。块仍然会被追加——只含头部和尾部、中间没有示例——模型会看到一段略显奇怪但无害的前缀。在 Agent 配置文件YAML中声明示例用 YAML 而非 Python 定义的 Agent 同样能获得示例。ExampleTool.from_configexample_tool.py接受两种形式内联示例列表直接在配置中写list[Example]Provider 全限定名一个字符串指向你代码中定义的BaseExampleProvider实例。校验规则名字无法解析时抛出ValueError解析成功但对象不是BaseExampleProvider时抛出ToolExecutionError错误类型为BAD_REQUEST见 example_tool.py。在 A2A Agent 卡片上发布示例远程调用方在调用前往往想知道你的 Agent 接受什么样的输入而示例是表达这一点最清晰的方式且无需额外配置Agent 卡片构建器会在 Agent 的工具列表中查找ExampleTool把它的示例复制进卡片的 skill examples。只有列表形式会被发布Provider 会被跳过并打一条 debug 日志因为构建器没有查询可用来调用它见 agent_card_builder.py其中_convert_example_tool_examples明确跳过动态 Provider。限制与注意事项非文本回合下工具静默无效音频、图片或空的用户内容意味着第一个 part 没有textprocess_llm_request直接返回、不追加任何内容也不记录任何警告。在语音或多模态 Agent 中示例可能实际上永远不会生效。Gemini 3 上的围栏启发式判断失效渲染器只检测模型名中是否含gemini-2因此 Gemini 3 模型会收到本为 Gemini 1.5 设计的tool_code格式。渲染出的函数响应包含空字段响应 part 被逐字段字符串化未设置的 genai 字段会以{will_continue: None, scheduling: None, parts: None, id: None, name: ..., response: ...}形式出现在提示词中模型需要略过这些噪音。Provider 每个回合都被调用同步、无缓存。成本按回合计而非按会话计且因为它们渲染的块进入系统指令返回不同示例的 Provider 也会使该回合的上下文缓存失效。VertexAiExampleStore不可配置10 条结果上限与 0.5 相似度下限是源码中的常量。示例是追加而非合并一个 Agent 添加两个ExampleTool会产生两个独立的EXAMPLES块而不是合并成一组。无法从 Agent 侧查看渲染后的块要检查模型实际收到什么请直接调用google.adk.examples.example_util.convert_examples_to_text(examples, model)该函数的完整实现与常量前缀见 example_util.py。仓库中的相关示例hello_world_ma 的 agent.py多 Agent 架构示例根 Agent 携带一个由Example对象UserContentModelContent构建的ExampleTool演示掷骰子与素数判断两个子 Agent 的委派流程。a2a_basic 的 agent.py同样的示例换成字典形式Agent 通过 A2A 对外提供服务因此这些示例最终也会出现在 Agent 卡片上。相关指南BaseTool覆盖了ExampleTool所依赖的process_llm_request钩子以及如何编写另一个只改写请求的工具。AgentCardBuilder列表形式示例如何在 A2A Agent 卡片中呈现对应实现见 agent_card_builder.py。App 指南上下文缓存配置App.context_cache_config与示例注入的联动。【免费下载链接】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),仅供参考