Gemini Interactions API(测试版)
ADK-Rust 为 Google 的 Interactions API 提供了专用客户端,这是 Google 为 Gemini API 探索的新方向。它以围绕类型化步骤时间线、服务器端历史记录和原生代理工作流构建的有状态 Interaction 资源,取代了 generateContent 请求/响应结构。
Interactions API 处于测试版。Google 建议在稳定的生产工作负载中使用 generateContent,并且可能会对 Interactions 架构进行不兼容更改。ADK-Rust 固定了 Api-Revision: 2026-05-20(步骤架构)契约。
概述
┌─────────────────────────────────────────────────────────────────────┐
│ Gemini Interactions API Client │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Endpoint: POST /v1beta/interactions │
│ Builder: Gemini::create_interaction() │
│ Feature: interactions (adk-gemini) │
│ gemini-interactions (adk-model / adk-rust) │
│ │
│ Capabilities: │
│ • Single-turn and streaming (step.delta events) │
│ • Server-side history via previous_interaction_id │
│ • Typed step timeline (thought, function_call, model_output, …) │
│ • Multimodal input (text, image, audio, document, video) │
│ • Structured output (response_format JSON schema) │
│ • Client-side function calling + built-in server tools │
│ • Background / long-running tasks (background = true) │
│ • Lifecycle: get / delete / cancel a stored interaction │
│ │
│ vs generateContent (GeminiModel): │
│ • Stateful conversations (server stores history) │
│ • Observable execution steps for agentic UIs │
│ • New models & tools launch here first │
│ │
└─────────────────────────────────────────────────────────────────────┘
何时使用哪个 API
| 方面 | generateContent(GeminiModel) | 交互 API(create_interaction) |
|---|---|---|
| 端点 | POST /v1beta/models/{model}:generateContent | POST /v1beta/interactions |
| 稳定性 | 稳定,推荐用于生产环境 | Beta,架构可能会更改 |
| 历史记录 | 客户端重新发送完整记录 | 服务端通过 previous_interaction_id |
| 响应形态 | candidates + parts | steps 时间线 |
智能体运行时(Llm trait) | ✅ 默认传输 | ✅ 通过 use_interactions_api 启用 |
| 新模型 / 工具 | — | 从这里优先发布 |
ADK agent 运行时(Llm trait、工具循环和 Runner)默认使用 generateContent。你也可以通过在 GeminiModel 上启用 use_interactions_api(true),使用同一运行时驱动 Interactions API——请参阅下文的将 Interactions 用作运行时传输。直接客户端(文档首先介绍)仍然可用,适用于希望使用服务器端历史记录、可观测步骤或仅限 beta 的模型,且不涉及 agent 的调用方。
启用
# Direct client (adk-gemini)
adk-gemini = { version = "2.1.0", features = ["interactions"] }
# Through the model facade / umbrella
adk-model = { version = "2.1.0", features = ["gemini-interactions"] }
adk-rust = { version = "2.1.0", features = ["gemini-interactions"] }
此功能不会新增依赖项,并且完全兼容现有的 generateContent API。
快速开始
use adk_gemini::{Gemini, Model, ThinkingLevel};
let gemini = Gemini::new(std::env::var("GEMINI_API_KEY")?)?;
let interaction = gemini
.create_interaction()
.model(Model::Gemini35Flash)
.system_instruction("You are concise.")
.input_text("What is the capital of France?")
.thinking_level(ThinkingLevel::Low)
.send()
.await?;
println!("{}", interaction.output_text().unwrap_or_default());
流式传输
进行流式传输时,API 会发出面向步骤的 SSE 事件模型。最常见的
方式是从 step.delta 事件中累积文本片段:
use futures::StreamExt;
let mut stream = gemini
.create_interaction()
.model(Model::Gemini35Flash)
.input_text("Write a haiku about Rust.")
.stream()
.await?;
while let Some(event) = stream.next().await {
if let Some(fragment) = event?.text_delta() {
print!("{fragment}");
}
}
事件类型包括:interaction.created、step.start、step.delta、step.stop、
interaction.status_update、interaction.completed 和 error。未知的
未来事件会反序列化为 InteractionSseEvent::Other,而不会导致
流失败。
服务器端多轮对话
传入之前交互的 id,即可在不重新发送
历史记录的情况下继续对话。请注意,tools、system_instruction 和 generation_config
都属于交互级别,必须在每一轮重新指定:
let first = gemini.create_interaction()
.model(Model::Gemini35Flash)
.input_text("My favorite color is teal.")
.send().await?;
let second = gemini.create_interaction()
.model(Model::Gemini35Flash)
.previous_interaction_id(&first.id)
.input_text("What is my favorite color?")
.send().await?;
函数调用
Interactions API 将客户端工具调用作为带有 requires_action 状态的 function_call 步骤
提供。请在后续轮次中提交结果:
use serde_json::json;
let interaction = gemini.create_interaction()
.model(Model::Gemini35Flash)
.function("get_weather", "Get the weather",
json!({"type": "object", "properties": {"location": {"type": "string"}}}))
.input_text("Weather in Boston?")
.send().await?;
if interaction.status.requires_action() {
let follow_up = gemini.create_interaction()
.model(Model::Gemini35Flash)
.previous_interaction_id(&interaction.id);
let mut follow_up = follow_up;
for (call_id, name, _args) in interaction.pending_function_calls() {
follow_up = follow_up.function_result(call_id, name, json!({"temperature": "72F"}));
}
let final_interaction = follow_up.send().await?;
println!("{}", final_interaction.output_text().unwrap_or_default());
}
结构化输出
use serde_json::json;
let interaction = gemini.create_interaction()
.model(Model::Gemini35Flash)
.input_text("Summarize this article: ...")
.json_schema(json!({
"type": "object",
"properties": { "summary": { "type": "string" } },
"required": ["summary"]
}))
.send().await?;
生命周期
已存储的交互(服务器默认行为)可以被检索、删除或取消:
let fetched = gemini.get_interaction(&interaction.id, /* include_input */ true).await?;
gemini.cancel_interaction(&interaction.id).await?; // background tasks only
gemini.delete_interaction(&interaction.id).await?;
状态值
InteractionStatus 与 API 生命周期保持一致:InProgress、RequiresAction、
Completed、Failed、Cancelled、Incomplete、BudgetExceeded。使用
is_terminal() 和 requires_action() 进行控制流处理。
限制
Interactions API 尚不支持 Batch API 或显式缓存
(服务器端隐式缓存可通过 previous_interaction_id 使用)。ADK agent runtime 默认使用
generateContent;Interactions API 既可作为上文所述的独立客户端使用,也可作为选择加入的
runtime transport 使用(见下文)。
将 Interactions 作为 runtime transport(agents + runner)
上文介绍的是直接 wire client(adk_gemini::interactions)
——一种需要手动调用的独立功能。本节介绍构建于其之上的
runtime transport:GeminiModel 上的一个开关,使普通的
LlmAgent、Runner、tool loop 和 sessions 能够驱动 Interactions API,
而无需更改任何 agent 代码。
这与 ADK-Python 的设计一致,其中 Gemini(model=..., use_interactions_api=True)
保留相同的 Agent、runner 和 tools。agent 与 transport 无关:
切换模型与后端通信的方式不应要求创建新的 agent 类型。
generateContent 仍是默认方式
generateContent 仍是稳定生产工作负载的默认且推荐 transport。Interactions API 处于 beta 阶段,其 schema 可能会发生变化。
请针对每个 model 有意选择启用 transport。如果不调用
use_interactions_api(true),GeminiModel 的行为将与之前完全一致——
generateContent 路径不会发生任何行为变化。
启用 transport
该 transport 由 gemini-interactions feature 控制(从
adk-rust → adk-model → adk-gemini/interactions 传递):
adk-model = { version = "2.1.0", features = ["gemini-interactions"] }
adk-rust = { version = "2.1.0", features = ["gemini-interactions"] }
在 model 上启用该开关,并将其包装在普通的 LlmAgent 和 Runner 中——
agent 设置的其他部分无需更改:
use adk_agent::LlmAgentBuilder;
use adk_core::{Content, Part, SessionId, UserId};
use adk_model::GeminiModel;
use adk_runner::Runner;
use adk_session::{CreateRequest, InMemorySessionService, SessionService};
use futures::StreamExt;
use std::collections::HashMap;
use std::sync::Arc;
// 1. Build a Gemini model and toggle the Interactions transport.
// `use_interactions_api` validates the model id against the allowlist and
// returns `Result<Self>`, so it is fallible (`?`).
let model = GeminiModel::new(std::env::var("GEMINI_API_KEY")?, "gemini-3.7-flash")?
.use_interactions_api(true)?;
// 2. Wrap it in a normal LlmAgent — unchanged agent API.
let agent = Arc::new(
LlmAgentBuilder::new("assistant")
.instruction("You are concise.")
.model(Arc::new(model))
.build()?,
);
// 3. Drive it through the standard Runner.
let sessions: Arc<dyn SessionService> = Arc::new(InMemorySessionService::new());
sessions
.create(CreateRequest {
app_name: "assistant".into(),
user_id: "user".into(),
session_id: Some("session-1".into()),
state: HashMap::new(),
})
.await?;
let runner = Runner::builder()
.app_name("assistant")
.agent(agent)
.session_service(sessions)
.build()?;
let mut stream = runner
.run(
UserId::new("user")?,
SessionId::new("session-1")?,
Content::new("user").with_text("What is the capital of France?"),
)
.await?;
while let Some(event) = stream.next().await {
let event = event?;
// The server-assigned interaction id is a first-class field on every event.
if let Some(id) = event.interaction_id() {
println!("interaction_id = {id}");
}
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
print!("{text}");
}
}
}
}
保持一致的默认值
传输层默认采用 API的预期姿态,通过 InteractionOptions 配置(从 adk_model::gemini 重新导出):
| 选项 | 默认值 | 含义 |
|---|---|---|
store | true | 交互存储在服务器端,因此开箱即用地支持有状态的延续和可观测性。 |
stateful | true | 多轮对话通过 previous_interaction_id 继续;进行串联时仅发送当前轮次的内容。 |
background | BackgroundMode::AgentTargetsOnly | background=true 用于代理目标(深度研究、长时间运行);false 用于模型目标,以便聊天轮次保持低延迟。 |
poll_interval | 1s | 后台交互在终止前的轮询频率。 |
将以下任意内容替换为 interaction_options:
use adk_model::gemini::{BackgroundMode, InteractionOptions};
use std::time::Duration;
let model = GeminiModel::new(api_key, "gemini-3.7-flash")?
.use_interactions_api(true)?
.interaction_options(InteractionOptions {
store: true,
stateful: true,
background: BackgroundMode::AgentTargetsOnly,
poll_interval: Duration::from_millis(500),
});
BackgroundMode 有三种变体:AgentTargetsOnly(默认)、Always 和
Never。
当
store为false时,API 的不兼容规则会禁用有状态的 继续执行和后台执行;随后传输会发送 transcript 输入,行为与 generateContent 完全相同。
支持的目标(允许列表)
Interactions API 支持一组固定的目标。use_interactions_api(true)
会在配置时验证模型 ID;如果该 ID 不在允许列表中,则返回类别为
InvalidInput 的 AdkError(其中列出受支持的目标),而不是将错误延迟为
不透明的服务器拒绝。
模型目标设置请求的 model 字段;代理目标设置
agent 字段。
模型目标:
gemini-3.7-flashgemini-3.6-flashgemini-3.5-flashgemini-3.5-flash-litegemini-3.1-flash-litegemini-3.1-pro-previewgemini-3-flash-previewgemini-2.5-progemini-2.5-flashgemini-2.5-flash-litelyria-3-clip-previewlyria-3-pro-preview
这是传输层的兼容性允许列表,而不是推荐列表。
新应用应从 gemini-3.7-flash 开始;由于 Interactions 端点仍然接受较旧的 ID 和预览版 ID,
因此它们仍列在此处。
代理目标:
deep-research-pro-preview-12-2025deep-research-preview-04-2026deep-research-max-preview-04-2026
// Unsupported targets fail fast at configuration time:
let result = GeminiModel::new(api_key, "gpt-4")?.use_interactions_api(true);
assert!(result.is_err()); // AdkError { category: InvalidInput, .. }
InteractionTarget 枚举(也从 adk_model::gemini 重新导出)
表示经过验证的目标;如果需要直接检查分类,可以使用它。
混合使用内置工具和自定义工具(bypass_multi_tools_limit)
Interactions API 禁止在单个请求中混合使用内置(服务器端)工具和自定义
函数工具。例如,如果要同时使用 Google Search 和自己的函数工具,请将内置工具
转换为函数调用工具,使整个工具集保持统一。这与 ADK-Python 的
bypass_multi_tools_limit=True 相似。
转换逻辑位于 BypassMultiToolsLimit trait 上,由内置工具包装器(GoogleSearchTool、UrlContextTool、GeminiFileSearchTool)实现。with_bypass_multi_tools_limit(agent) 接收一个内部的单轮 grounded-search agent——一个配置了内置工具和 Gemini 模型的普通 LlmAgent——并返回一个 Arc<dyn Tool>,用于报告 is_builtin() == false,同时在内部运行内置行为并返回普通的函数响应。
use adk_agent::LlmAgentBuilder;
use adk_tool::{BypassMultiToolsLimit, FunctionTool, GoogleSearchTool};
use adk_model::GeminiModel;
use std::sync::Arc;
// The grounded-search agent the bypass tool delegates to: a normal LlmAgent
// with the built-in GoogleSearchTool + a Gemini model.
let search_agent = Arc::new(
LlmAgentBuilder::new("grounded-search")
.instruction("Answer the query using Google Search. Be factual and concise.")
.model(Arc::new(GeminiModel::new(&api_key, "gemini-3.7-flash")?))
.tool(Arc::new(GoogleSearchTool::new()))
.build()?,
);
// Convert the built-in search tool into a function tool (is_builtin() == false).
let search_tool = GoogleSearchTool::new().with_bypass_multi_tools_limit(search_agent);
// A custom function tool to mix alongside it.
let weather_tool: Arc<dyn adk_core::Tool> = Arc::new(/* your FunctionTool */);
// Now the tool set is uniform (all function tools) and the Interactions
// transport accepts it.
let model = GeminiModel::new(&api_key, "gemini-3.7-flash")?.use_interactions_api(true)?;
let agent = Arc::new(
LlmAgentBuilder::new("assistant")
.model(Arc::new(model))
.tool(search_tool)
.tool(weather_tool)
.build()?,
);
如果在 Interactions transport 下将内置工具与函数工具混用时,让内置工具保持未绕过状态,则请求构建会返回一个 AdkError,其类别为 InvalidInput,并指向 with_bypass_multi_tools_limit。函数调用 id 会在工具循环中原样往返传递,与 generateContent 完全相同。
有状态的连续性与保留回退机制
interaction_id 是一个一等字段,而不是旁路通道。每个 LlmResponse 都携带 interaction_id: Option<String>(由 Interactions transport 填充,否则为 None),而 Event 通过 event.interaction_id() 访问器提供该字段——与 ADK-Python 的 event.interaction_id 相对应。
连续性与提供商无关。LlmRequest 携带一个附加的 previous_response_id: Option<String> 字段,该字段由 LlmAgent 根据最近事件的 interaction_id 填充。Interactions transport 会将其映射到请求的 previous_interaction_id,并且仅发送当前轮次的内容(而不是完整记录)。adk-agent 中不存在 Gemini 专用的粘合逻辑;对于 generateContent 和其他提供商,该字段未被使用(即无操作)。
Turn 1: request (transcript) → interaction v1_abc → event.interaction_id() == "v1_abc"
Turn 2: request previous_response_id = "v1_abc"
→ previous_interaction_id = "v1_abc", sends only the new turn
→ interaction v1_def → event.interaction_id() == "v1_def"
保留窗口回退。 存储的交互会过期。如果提供的
previous_interaction_id 已失效或过期,服务器会返回 NotFound。传输层会透明地处理这一情况:它会回退到发送完整的会话记录,并开始一次新的交互——不会向 agent 或 runner 暴露错误。多轮对话可以跨越保留边界持续工作,无需在代码中进行特殊处理。
重新导出的类型
在启用 gemini-interactions 特性后,以下内容可从
adk_model::gemini 获取:
GeminiTransport—GenerateContent(默认)或Interactions。InteractionOptions—store、stateful、background、poll_interval。BackgroundMode—AgentTargetsOnly(默认)、Always、Never。InteractionTarget— 经过验证的模型/agent 目标。
绕过接口位于 adk-tool 中(可通过 adk_tool 或 umbrella 访问):
- 带有
with_bypass_multi_tools_limit(agent)的BypassMultiToolsLimittrait。 - 由
GoogleSearchTool、UrlContextTool、GeminiFileSearchTool实现。
附加的 LlmResponse.interaction_id 和 LlmRequest.previous_response_id
核心字段始终存在(不受特性门控),因此无论启用了哪些 provider,
event.interaction_id() 访问器都能编译。