基于 adk-python 官方示例掌握 Interactions API:有状态对话链与工具调用实战指南
【免费下载链接】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
本文以 adk-python 仓库中的官方示例contributing/samples/models/interactions_api/为主体,系统讲解 Google ADK 对 Interactions API 的集成方式:如何用previous_interaction_id实现有状态的链式对话、如何在该模式下正确配置搜索与自定义函数工具,以及 ADK 底层如何从会话事件中提取 interaction 链并压缩每轮请求内容。读完本文,你可以独立运行该示例验证多轮状态保持,并理解use_interactions_api=True在请求链路中的实际作用与限制条件。
一、Interactions API 的核心概念
Interactions API 为模型调用提供了**有状态对话(stateful conversation)**能力。与传统generate_content每次都要把完整会话历史随请求发送不同,Interactions API 允许通过previous_interaction_id把多次交互"链接"起来:
- 每次响应会返回一个
interaction_id; - 下一轮请求只需携带上一次的
interaction_id作为previous_interaction_id,服务端即基于既有状态继续对话; - 因此链式调用时只需发送当前轮(current turn)的内容,无需重发全部历史,对长对话场景尤其友好;
- 与标准 API 不同,Interactions API不使用上下文缓存(context caching),因为其自身通过 interaction 链维护状态。
示例 README.md 中对两种模式的差异归纳如下,这里完整保留并补充说明:
| 维度 | Interactions API(use_interactions_api=True) | 标准 API(use_interactions_api=False) |
|---|---|---|
| 会话方式 | 通过previous_interaction_id做有状态链式调用 | 无状态的generate_content调用 |
| 每轮发送内容 | 链式调用时只发送当前轮内容 | 每次都发送完整会话历史 |
| 响应标识 | 响应返回interaction_id供下一轮链接 | 响应不含 interaction ID |
| 适用场景 | 轮次较多的长对话 | 通用场景 |
| 上下文缓存 | 不使用(状态由 interaction 链维护) | 可以使用 |
二、示例工程的文件组织
示例位于 contributing/samples/models/interactions_api/,当前仓库中的实际文件结构如下:
interactions_api/ ├── __init__.py # 包初始化 ├── agent.py # 启用 Interactions API 的 Agent 定义 ├── main.py # 测试运行入口(自动化测试 + 交互模式) ├── tests/ # 各测试用例的会话/期望内容 JSON │ ├── basic_text.json │ ├── google_search_france.json │ ├── google_search_1984.json │ ├── multi_turn.json │ └── custom_function_weather.json └── README.md # 本文的主体文档- agent.py:定义
root_agent,挂载 Gemini 模型(use_interactions_api=True)、Google Search 工具和一个模拟天气查询的自定义函数工具; - main.py:测试运行器,通过
InMemoryRunner创建会话并依次执行自动化断言测试,同时提供interactive手工调试模式; tests/目录下的 JSON 文件(如 multi_turn.json)为各测试场景的对话内容与期望结果的示例数据。
需要说明的是,README 的 "Code Structure" 一节中还列出了test_interactions_curl.sh与test_interactions_direct.py两个文件;从当前仓库的目录内容看,这两个文件已不在示例中,实际运行入口统一为main.py。
三、Agent 配置:开启 Interactions API 与工具兼容性处理
3.1 基本配置
README 给出的核心配置如下:
from google.adk.agents.llm_agent import Agent from google.adk.models.google_llm import Gemini from google.adk.tools.google_search_tool import GoogleSearchTool root_agent = Agent( model=Gemini( model="gemini-2.5-flash", use_interactions_api=True, # 启用 Interactions API ), name="interactions_test_agent", tools=[ GoogleSearchTool(bypass_multi_tools_limit=True), # 转换为函数调用工具 get_current_weather, # 自定义函数工具 ], )use_interactions_api是Gemini模型类上的布尔字段,默认为False。在 google_llm.py 的字段文档中明确写道:启用后,模型调用将走client.aio.interactions.create()而非传统的generate_contentAPI,且响应格式会被转换为既有的LlmResponse结构以保持兼容——这意味着上层 Runner、Session、回调等 ADK 机制无需感知底层 API 的切换。
从当前仓库 agent.py 的实际代码看,示例已演进为使用gemini-3.1-flash-lite模型,并直接以GoogleSearchTool()挂载(工具兼容处理见下一节的源码说明);README 中的配置保留了bypass_multi_tools_limit=True这一关键参数的示范用法,两者可互为参照。
3.2 关键限制:内置工具与自定义函数工具不能混用
README 中特别强调了Tool Compatibility(工具兼容性)这一重要限制:
Interactions API不支持在同一 Agent 中混用自定义函数调用工具与内置工具(如
google_search)。
规避方式是使用bypass_multi_tools_limit=True参数:
# 将 google_search 转换为函数调用工具,从而可与自定义函数工具共存 GoogleSearchTool(bypass_multi_tools_limit=True)该参数会触发GoogleSearchTool通过GoogleSearchAgentTool把内置google_search能力转换成一个普通的函数调用工具(function calling tool),从而与get_current_weather这类自定义函数工具在同一 Agent 下协同工作。这一参数在 google_search_tool.py 中定义,对应的转换实现在 google_search_agent_tool.py 的GoogleSearchAgentTool类中。
3.3 自定义函数工具:模拟天气查询
示例中的get_current_weather(city: str) -> dict是一个 mock 实现(见 agent.py):内置了 New York、London、Tokyo、Paris、Sydney 五个城市的温度/天气/湿度数据,未知城市返回默认值并附带note说明。测试断言正是围绕这些固定值编写的(例如 Tokyo 断言68或Partly Cloudy),这使得测试结果可复现、不依赖外部天气服务。
此外,agent.py与main.py的注释中记录了另一个实践结论:代码执行器(如UnsafeLocalCodeExecutor)与函数调用模式不兼容——模型会尝试调用run_code之类的函数,而不是按 code-executor 的预期在 markdown 中输出代码。因此示例未挂载代码执行工具。
四、运行示例:前置条件与命令
4.1 前置条件
按 README 的 "Prerequisites" 一节,在 adk-python 根目录执行:
# 从 adk-python 根目录执行 uv sync --all-extras source .venv/bin/activate # 配置认证(二选一): # 方式 1:Google Cloud 凭据 export GOOGLE_CLOUD_PROJECT=your-project-id # 方式 2:API Key export GOOGLE_API_KEY=your-api-key4.2 运行自动化测试
cd contributing/samples # 使用 Interactions API 运行自动化测试 python -m interactions_api.mainmain.py通过 argparse 提供了两个运行参数(见 main.py):
--mode test(默认):依次执行全部自动化断言测试,任一断言失败即退出码为 1;--mode interactive:进入手工交互模式,输入new创建新会话,quit退出;--debug:将 ADK 日志级别提升到 DEBUG,可观察完整的 Interactions API 请求/响应日志。
4.3 SDK 可用性检查
main.py在启动测试前会执行check_interactions_api_available()(main.py):构造google.genai.Client并检查client.aio上是否存在interactions属性。Interactions API 要求安装了支持该功能的 google-genai SDK 版本,若当前 SDK 不具备该能力,脚本会明确报错并终止,而不是抛出难以理解的运行时异常。这是运行示例时最常见的"门槛",需要优先确认。
五、测试覆盖范围与输出解读
README 的 "Features Tested" 列出了 4 项能力,main.py的实际测试函数扩展为 6 个(TEST 1~6):
- 基础文本生成(无工具):发送 "Hello! What can you help me with?",断言响应非空;
- Google Search 工具函数调用:"Search for the capital of France.",断言响应包含 "paris";
- 多轮有状态对话:三轮对话——先告知 "My favorite color is blue",再询问伦敦天气(触发
get_current_weather),最后询问 "What is my favorite color...",断言模型能回忆出 "blue",并打印id1 -> id2 -> id3的 interaction 链,验证上下文保持; - Google Search 补充覆盖:"who wrote the novel '1984'",断言出现 "orwell" 或 "george";
- 自定义函数工具:"What's the weather like in Tokyo?",断言出现 68/Partly Cloudy/Tokyo,验证
bypass_multi_tools_limit模式下函数工具可用; - PDF 摘要(
main.py新增,README 未列入):用 httpx 下载一份公开 PDF,以types.Part.from_bytes(..., mime_type="application/pdf")作为附加内容部件传入,验证多模态输入在 Interactions API 下可用。
README 给出的典型输出片段如下(节选),其中[Interaction ID: v1_xxx]行正是链式对话的凭证:
============================================================ TEST 3: Multi-Turn Conversation (Stateful) ============================================================ >> User: Remember the number 42. << Agent: I'll remember that number - 42. [Interaction ID: v1_ghi789...] >> User: What number did I ask you to remember? << Agent: You asked me to remember the number 42. [Interaction ID: v1_jkl012...] PASSED: Multi-turn conversation works with context retention ALL TESTS PASSED (Interactions API)main.py的call_agent_async()(main.py)展示了在 ADK 中读取这些信息的标准姿势:遍历runner.run_async()产生的Event流,从event.interaction_id收集最新 interaction ID,用event.get_function_calls()/event.get_function_responses()打印工具调用轨迹,并按author != "user"且非 partial 的事件聚合最终文本。
六、底层实现:ADK 如何驱动 Interactions API 链路
以下结论均来自当前仓库源码,用于印证 README 所述机制的落地细节。
6.1 模型层的分支切换
在 google_llm.py 的generate_content_async()中,use_interactions_api=True时请求被转发给_generate_content_via_interactions(),其内部调用 interactions_utils.py 的generate_content_via_interactions();否则走原有的generate_content/generate_content_stream路径。
同时可以注意到一个与 README 表格"Context caching can be used / not used"对应的实现:google_llm.py 中上下文缓存处理被条件if llm_request.cache_config and not self.use_interactions_api守卫——启用 Interactions API 时,GeminiContextCacheManager完全不会参与,与文档声明一致。
6.2 previous_interaction_id 从哪来
previous_interaction_id不需要用户手工维护。interactions_processor.py 中的InteractionsRequestProcessor是一个 LLM 请求处理器:
- 它先确认当前 Agent 的
canonical_model是Gemini且use_interactions_api为真,否则直接跳过; - 然后通过
_find_previous_interaction_state()从会话事件列表中逆序扫描,跳过不属于当前 branch 的事件,找到该 Agent 最近一条携带interaction_id的事件,取出(interaction_id, environment_id); - 最终把找到的 ID 写入
llm_request.previous_interaction_id。
这解释了示例中多轮对话"开箱即用"的原因:每一轮interaction_id已随Event落盘到会话历史,下一轮处理器自动完成链接。
6.3 每轮只发当前 turn 的实现
generate_content_via_interactions()(interactions_utils.py)中,当llm_request.previous_interaction_id存在时,会调用_get_latest_user_contents()压缩内容:
- 从
contents末尾向前收集连续的用户消息(当前轮输入); - 特殊处理:若前一条 model turn 的部件带有
thought_signature(思维签名),只把这些签名部件补回请求头部,其余历史视为已由服务端previous_interaction_id状态承载; - 其余全部历史不发送,这正是 README 中 "Only sends current turn contents when chaining interactions" 的代码级落地。
请求最终经_create_interactions()(interactions_utils.py)以model / input / system_instruction / tools / generation_config / previous_interaction_id组装 kwargs,调用api_client.aio.interactions.create();流式模式下逐条消费 SSE 事件(interaction.created、step.delta、interaction.completed等),由convert_interaction_event_to_llm_response()归一化为 ADK 的LlmResponse,并把interaction_id、environment_id透传到响应上,供下一轮处理器链使用。
6.4 参数透传的边界:采样参数
interactions_utils.py顶部(interactions_utils.py)定义了两类采样参数清单:
_UNDECLARED_SAMPLING_PARAMS(temperature、top_p、top_k):当前已安装的 google-genai 版本请求模型未声明这些字段,序列化时会被静默丢弃——设置它们与不设置效果相同;_UNSUPPORTED_SAMPLING_PARAMS(presence_penalty、frequency_penalty):Interactions API 本身会作为未知参数拒绝,调用方必须停止设置。
从源码结构看,ADK 对这两类参数会做降级/告警处理(每进程仅告警一次)。实践含义:在 Interactions API 模式下,不要依赖 temperature/top_p 等采样参数实际生效,这是与标准generate_content路径的显著行为差异。
6.5 内容处理的协同
在 contents.py 中,内容处理器同样会依据canonical_model.use_interactions_api决定过滤策略——即InteractionsRequestProcessor负责提取链式 ID,内容处理器负责保证只保留必要的最新用户消息,两者按处理器链顺序协作,这与interactions_processor.py模块 docstring 中"content filtering is done by the content request processor after this processor runs"的描述吻合。
七、实践要点与限制清单
结合 README 声明与源码印证,使用该模式时应注意:
- 工具类型一致性:自定义函数工具与内置工具(如原生
google_search)不能在同一 Agent 混用;确需搜索能力时优先用GoogleSearchTool(bypass_multi_tools_limit=True)将其转为函数调用工具。 - 上下文缓存不生效:启用 Interactions API 后
cache_config相关的上下文缓存逻辑被跳过,长上下文成本由 interaction 链机制自身承担,选型时需与标准 API 的成本模型区分开。 - SDK 版本依赖:Interactions API 需要包含
client.aio.interactions能力的 google-genai SDK;示例脚本会先行探测并在不可用时给出明确报错,自定义集成时建议做同样的能力探测。 - 代码执行器不兼容:如示例注释所述,
code_executor类工具在函数调用模式下行为异常,二者不要同时挂载。 - 采样参数受限:
presence_penalty/frequency_penalty会被 API 拒绝,temperature/top_p/top_k在部分 SDK 版本中不生效。 - 多模态输入可用:示例 TEST 6 验证了 PDF 以 bytes Part 形式附加在用户消息中同样能走通 Interactions API 链路。
八、延伸阅读
围绕本主题,仓库中可继续深入的入口:
- 示例本体:README.md、agent.py、main.py;
- 模型层实现:google_llm.py(
use_interactions_api字段与分支逻辑)、interactions_utils.py(类型转换、请求组装、流式事件归一化); - 请求处理链:interactions_processor.py(interaction 链 ID 提取);
- 工具层:google_search_tool.py 与 google_search_agent_tool.py(
bypass_multi_tools_limit的转换机制)。
Interactions API 模式的价值在于把"会话状态"从客户端请求体转移到服务端的 interaction 链上:ADK 通过请求处理器自动完成链式 ID 的提取与续接,开发者只需在模型上打开use_interactions_api,即可获得更轻量、可扩展的多轮对话,同时保留 ADK 原有的工具、会话与事件体系。
【免费下载链接】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),仅供参考