2

多轮对话与工具:previous_interaction_id + google_search

用 previous_interaction_id 做服务端多轮;挂 Google Search 工具并读 citations;附官方 function calling 最小循环骨架。

图文22 分钟Gemini 官方文档 ↗

课程目录2 / 2

学习位置仅保存在当前浏览器,有效期 180 天。

01 / 图文教材

图文讲义

来源:Google AI · Getting started — Multi-turn / Tools / Function callingInteractions overview。本讲义为中文跟做整理,非原文搬运。

你将得到什么

  • previous_interaction_id 完成一轮「服务端记历史」的多轮对话(官方推荐的 stateful 方式)
  • 给 Interaction 挂上 tools=[{"type": "google_search"}],读出带 URL citation 的回答
  • 看懂官方 function calling 最小循环骨架(声明函数 → 模型 function_call → 本地执行 → function_result 回传)

本课默认你已完成上一课:环境里有 GEMINI_API_KEY,且 from google import genai 可用。

步骤 1:服务端多轮(stateful,推荐)

官方说明:Interactions API 支持两种多轮方式——

方式做法适用
Stateful(推荐)下一请求带 previous_interaction_id聊天、Agent;服务端管历史与缓存
Stateless每次自带完整 history,并设 store=False你要自己管存储 / 合规落盘时

先跑官方推荐的 stateful 示例。新建 multi_turn.py

from google import genai

client = genai.Client()

interaction1 = client.interactions.create(
    model="gemini-3.8-flash",
    input="I have 2 dogs in my house.",
)
print("Response 1:", interaction1.output_text)
print("id1=", interaction1.id)

interaction2 = client.interactions.create(
    model="gemini-3.8-flash",
    input="How many paws are in my house?",
    previous_interaction_id=interaction1.id,
)
print("Response 2:", interaction2.output_text)
print("status2=", interaction2.status)

运行:

python multi_turn.py

对照结果:

期望
Response 1确认或复述「家里有 2 只狗」类回复(措辞可变)
id1非空;复制给第二请求
Response 2应推出 8 只爪子(2×4);若答成「不知道」或无关数字,检查是否漏传 previous_interaction_id
status2completed

等价 curl(与官方 REST 一致;需 jq):

RESPONSE1=$(curl -sS -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash",
    "input": "I have 2 dogs in my house."
  }')

INTERACTION_ID=$(echo "$RESPONSE1" | jq -r '.id')
echo "Interaction 1 ID: $INTERACTION_ID"

curl -sS -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"model\": \"gemini-3.8-flash\",
    \"input\": \"How many paws are in my house?\",
    \"previous_interaction_id\": \"$INTERACTION_ID\"
  }" | jq -r '.status, (.steps[] | select(.type=="model_output") | .content[]? | select(.type=="text") | .text)'

对照结果:先打印非空 Interaction 1 ID;第二段应出现 completed 与包含 8 的文本。

何时用 Stateless?

若你必须在客户端持有完整历史:设 store=False,并把上一轮返回的 全部 steps(含 thoughtfunction_call 等)原样塞回下一轮 input。官方警告:漏步骤或改写模型步骤会导致上下文错误。本课验收以 stateful 为准即可;完整 Stateless 示例见官方 Getting Started「Stateless」小节。

步骤 2:Google Search 工具(grounding)

官方:把 Google Search 作为内置工具传入,API 会自行搜索、合成答案,并在文本上带 url_citation 注解。

新建 search_tool.py

from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="Who won the euro 2024?",
    tools=[{"type": "google_search"}],
)

print(interaction.output_text)

print("\nCitations:")
for step in interaction.steps:
    if step.type == "model_output":
        for content_block in step.content:
            if getattr(content_block, "type", None) == "text" and getattr(
                content_block, "annotations", None
            ):
                for annotation in content_block.annotations:
                    if getattr(annotation, "type", None) == "url_citation":
                        title = getattr(annotation, "title", "")
                        url = getattr(annotation, "url", "")
                        print(f"  [{title}]({url})")

运行:

python search_tool.py

对照结果:

期望
正文应提到 Spain / 西班牙 夺冠(Euro 2024;措辞可变)
stepsREST/SDK 中可能出现 google_search_call / google_search_result 等中间步(有则属正常)
Citations至少 0~多条 URL;有则打印为 [title](url)。若暂时无 annotation,只要正文事实正确也算本步通过;可换更时效的问题再试

curl 版:

curl -sS -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash",
    "input": "Who won the euro 2024?",
    "tools": [{"type": "google_search"}]
  }' | tee /tmp/gemini-search.json | jq -r '.status, (.steps[]? | select(.type=="model_output") | .content[]? | select(.type=="text") | .text)'

对照结果:statuscompleted,正文含西班牙夺冠信息。

其它官方内置工具(本课不逐一跟做,入口在同一 Getting Started):Code execution、URL context、File search、Google Maps 等。

步骤 3:Function calling 最小循环(跟做骨架)

目标:让模型决定调用你声明的本地函数,你执行后再把结果送回,拿到最终自然语言答案。官方示例函数名:get_current_temperature

新建 function_call_loop.py

import json
from google import genai

client = genai.Client()

weather_tool = {
    "type": "function",
    "name": "get_current_temperature",
    "description": "Gets the current temperature for a given location.",
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The city name, e.g. San Francisco",
            },
        },
        "required": ["location"],
    },
}

available_functions = {
    "get_current_temperature": lambda location: {
        "location": location,
        "temperature": "22",
        "unit": "celsius",
    },
}

user_input = "What is the temperature in London?"
previous_id = None

while True:
    interaction = client.interactions.create(
        model="gemini-3.8-flash",
        input=user_input,
        tools=[weather_tool],
        previous_interaction_id=previous_id,
    )

    function_results = []
    for step in interaction.steps:
        if step.type == "function_call":
            result = available_functions[step.name](**step.arguments)
            print(f"Called {step.name}({step.arguments}) → {result}")
            function_results.append(
                {
                    "type": "function_result",
                    "name": step.name,
                    "call_id": step.id,
                    "result": [{"type": "text", "text": json.dumps(result)}],
                }
            )

    if not function_results:
        break

    user_input = function_results
    previous_id = interaction.id

print(interaction.output_text)
print("final_status=", interaction.status)

运行:

python function_call_loop.py

对照结果:

  1. 第一轮循环通常打印类似:Called get_current_temperature({'location': 'London'}) → {...}(此时 interaction 在 REST 语义上可能是 requires_action)。
  2. 回传 function_result 后循环结束,最终 output_text 应提到 22°C / 22 摄氏度 与 London。
  3. final_statuscompleted

若模型没有发出 function_call:检查 tools 是否传入、描述是否清晰;可把问句改成更明确的 “Call the tool to get London temperature”。

步骤 4(了解即可):后台任务与托管 Agent

官方同一页还提供:

  • background=True:立即返回 in_progress,再用 client.interactions.get(id) 轮询到 completed / failed
  • Managed agent:传 agent=...environment="remote"(示例 agent 名以官方页当前值为准,如文档中的 preview agent),在远端沙箱跑代码与文件任务。

本课不强制跑通这两项;需要长任务或远端沙箱时,回到 Getting started 第 10–11 节按官方示例复制即可。

本课检查清单

  • stateful 多轮第二问能推出「8 只爪子」
  • google_search 对 Euro 2024 问句返回合理正文(最好带 citations)
  • function calling 循环至少完成一次本地函数调用并打印最终温度回答

延伸阅读(官方)

恭喜:你已用官方当前默认接口跑通 首调 → 多轮 → 搜索工具 → 函数调用骨架。把 GEMINI_API_KEY 继续留在环境变量或密钥管理里,不要写进代码仓库。

本课资料

适用环境

  • 网页
  • iOS
  • Android
  • API

官方文档

Gemini