<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>API迁移 on KnightLi的博客</title>
        <link>https://knightli.com/tags/api%E8%BF%81%E7%A7%BB/</link>
        <description>Recent content in API迁移 on KnightLi的博客</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Sun, 12 Jul 2026 10:33:00 +0800</lastBuildDate><atom:link href="https://knightli.com/tags/api%E8%BF%81%E7%A7%BB/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Gemini Interactions API 迁移指南：outputs 改为 steps 后怎么排错</title>
        <link>https://knightli.com/2026/07/12/gemini-interactions-api-outputs-steps-migration-troubleshooting/</link>
        <pubDate>Sun, 12 Jul 2026 10:33:00 +0800</pubDate>
        
        <guid>https://knightli.com/2026/07/12/gemini-interactions-api-outputs-steps-migration-troubleshooting/</guid>
        <description>&lt;p&gt;Gemini Interactions API 已成为新项目推荐的统一接口。它把一次生成、工具调用、思考过程、工具结果和最终回复都表示为可观察的执行步骤，适合 Agent、长任务和需要显示中间状态的应用。&lt;/p&gt;
&lt;p&gt;这也意味着旧代码不能再假定响应中有 &lt;code&gt;outputs&lt;/code&gt;。从 2026 年 5 月起，新 schema 开始成为默认；旧 schema 已在 6 月 8 日移除。若迁移后出现空回复、工具调用丢失、SSE 事件不触发或历史上下文断裂，通常不是模型问题，而是仍按旧结构读取数据。&lt;/p&gt;
&lt;h2 id=&#34;先确认你迁移的是哪一层&#34;&gt;先确认你迁移的是哪一层
&lt;/h2&gt;&lt;p&gt;排错前先把问题归类，避免只改一个字段：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;层级&lt;/th&gt;
          &lt;th&gt;旧做法&lt;/th&gt;
          &lt;th&gt;新做法&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;最终文本&lt;/td&gt;
          &lt;td&gt;遍历 &lt;code&gt;outputs&lt;/code&gt; 找文本&lt;/td&gt;
          &lt;td&gt;简单场景读 &lt;code&gt;interaction.output_text&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;完整响应&lt;/td&gt;
          &lt;td&gt;在 &lt;code&gt;outputs&lt;/code&gt; 中找内容、工具或搜索结果&lt;/td&gt;
          &lt;td&gt;遍历 &lt;code&gt;interaction.steps&lt;/code&gt;，按 &lt;code&gt;type&lt;/code&gt; 处理&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;工具调用&lt;/td&gt;
          &lt;td&gt;从旧 content 类型中解析&lt;/td&gt;
          &lt;td&gt;处理 &lt;code&gt;function_call&lt;/code&gt;、&lt;code&gt;function_result&lt;/code&gt; 等步骤&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;流式事件&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;content.start&lt;/code&gt;、&lt;code&gt;content.delta&lt;/code&gt;、&lt;code&gt;content.stop&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;step.start&lt;/code&gt;、&lt;code&gt;step.delta&lt;/code&gt;、&lt;code&gt;step.stop&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;多轮历史&lt;/td&gt;
          &lt;td&gt;回传旧 &lt;code&gt;outputs&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;服务器端用 &lt;code&gt;previous_interaction_id&lt;/code&gt;，或客户端回传 &lt;code&gt;steps&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果 SDK 仍是 Python 1.x 或 JavaScript 1.x，先确认版本。官方迁移说明要求使用 Python ≥2.0.0 或 JavaScript ≥2.0.0 来自动采用新 schema；但升级 SDK 不会自动修复你自己写的 &lt;code&gt;outputs&lt;/code&gt; 解析器、SSE 处理器和前端状态机。&lt;/p&gt;
&lt;h2 id=&#34;最简单的修复用-output_text-读取最终文本&#34;&gt;最简单的修复：用 &lt;code&gt;output_text&lt;/code&gt; 读取最终文本
&lt;/h2&gt;&lt;p&gt;只处理纯文本问答时，不必手动从 &lt;code&gt;steps&lt;/code&gt; 中找最后一段文字。新版 SDK 提供 &lt;code&gt;output_text&lt;/code&gt;，会提取并拼接响应末尾连续的文本块：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;google&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;genai&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;genai&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;interaction&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interactions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;gemini-3.5-flash&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;用三句话解释什么是 prompt caching。&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interaction&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;output_text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果你迁移后把 &lt;code&gt;interaction.outputs[-1].text&lt;/code&gt; 原样保留，常见结果是属性不存在、索引失败，或错误地把对象序列化成空字符串。先替换成 &lt;code&gt;interaction.output_text&lt;/code&gt;，再补充复杂场景的步骤解析。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;output_text&lt;/code&gt; 不适合所有响应：当文本被 thought、图片、音频或工具调用隔开时，它不会替你还原所有交错内容。需要展示完整执行过程时，应遍历 &lt;code&gt;steps&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;如何正确遍历-steps&#34;&gt;如何正确遍历 &lt;code&gt;steps&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;新 schema 将过程表示为有类型的步骤。至少要识别 &lt;code&gt;user_input&lt;/code&gt;、&lt;code&gt;model_output&lt;/code&gt;、&lt;code&gt;function_call&lt;/code&gt; 和 &lt;code&gt;function_result&lt;/code&gt;；如果使用服务端工具，还会看到 &lt;code&gt;google_search_call&lt;/code&gt;、&lt;code&gt;google_search_result&lt;/code&gt; 或其他工具特定步骤。&lt;/p&gt;
&lt;p&gt;下面示例只收集最终模型输出中的文本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;collect_model_text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;chunks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;step&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;interaction&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;steps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;model_output&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;item&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;chunks&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chunks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;collect_model_text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;真实项目中不要假设每个步骤都有 &lt;code&gt;content&lt;/code&gt;，也不要把 &lt;code&gt;thought&lt;/code&gt; 当成最终答案。先根据 &lt;code&gt;step.type&lt;/code&gt; 分支，再读取该类型允许的字段。把未知步骤记录为类型、ID 和状态，保留向前兼容空间；不要因为出现新的工具步骤就让整个请求失败。&lt;/p&gt;
&lt;h2 id=&#34;工具调用为什么消失了&#34;&gt;工具调用为什么“消失”了
&lt;/h2&gt;&lt;p&gt;旧 schema 常把服务端工具操作包在 &lt;code&gt;outputs&lt;/code&gt; 的特定内容类型里。新 schema 将它们拆为独立步骤，因此只扫描 &lt;code&gt;model_output&lt;/code&gt; 会看不到搜索、函数调用和函数结果。&lt;/p&gt;
&lt;p&gt;例如，函数调用应这样读取：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;step&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;interaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;steps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;function_call&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`Calling &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;arguments&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;服务端 Google Search 也应分别处理调用和结果步骤，而不是从最终文本中猜测有没有执行搜索。对于客户端函数工具，收到 &lt;code&gt;requires_action&lt;/code&gt; 后，提交对应 &lt;code&gt;function_result&lt;/code&gt;，并继续使用该 interaction 的状态完成后续流程。&lt;/p&gt;
&lt;h2 id=&#34;流式-sse-事件要一起迁移&#34;&gt;流式 SSE 事件要一起迁移
&lt;/h2&gt;&lt;p&gt;只改 REST 响应解析、不改流式处理器，前端通常会表现为“请求成功但页面不更新”。新版事件名称如下：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;旧事件&lt;/th&gt;
          &lt;th&gt;新事件&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;interaction.start&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;interaction.created&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;interaction.complete&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;interaction.completed&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;content.start&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;step.start&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;content.delta&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;step.delta&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;content.stop&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;step.stop&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;interaction.status_update&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;interaction.in_progress&lt;/code&gt;、&lt;code&gt;interaction.requires_action&lt;/code&gt; 等状态事件&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;函数调用的参数也不再保证一次性完整到达。流中 &lt;code&gt;step.start&lt;/code&gt; 会先给出函数名，后续多个 &lt;code&gt;step.delta&lt;/code&gt; 事件以部分 JSON 参数逐段传递。客户端必须累积参数，在 &lt;code&gt;step.stop&lt;/code&gt; 或需要动作的状态后再解析完整 JSON；不要对每一个 delta 都直接 &lt;code&gt;JSON.parse()&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;rawArguments&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;step.delta&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;delta&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;arguments&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;rawArguments&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;delta&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;partial_arguments&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;step.stop&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 只在对应 function_call 步骤完成后解析 rawArguments。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;多轮对话别再回传-outputs&#34;&gt;多轮对话别再回传 &lt;code&gt;outputs&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;旧的无状态实现常把上一轮的 &lt;code&gt;outputs&lt;/code&gt; 收集后塞回下一轮 &lt;code&gt;input&lt;/code&gt;。迁移后有两种更清晰的选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用默认服务器端状态，通过 &lt;code&gt;previous_interaction_id&lt;/code&gt; 延续同一会话；&lt;/li&gt;
&lt;li&gt;必须自行管理历史时，回传上一轮的 &lt;code&gt;steps&lt;/code&gt;，再追加新的 &lt;code&gt;user_input&lt;/code&gt; 步骤。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务器端状态更适合普通多轮对话；需要严格控制保存内容、跨系统迁移或离线回放时，再使用客户端状态。无论选择哪种，都不要同时拼接旧 &lt;code&gt;outputs&lt;/code&gt; 和新 &lt;code&gt;steps&lt;/code&gt;，否则容易产生重复上下文、工具结果不匹配或 token 激增。&lt;/p&gt;
&lt;h2 id=&#34;response_format-也可能是报错来源&#34;&gt;&lt;code&gt;response_format&lt;/code&gt; 也可能是报错来源
&lt;/h2&gt;&lt;p&gt;这次迁移不只改了输出数组。结构化输出和多模态配置也统一到顶层 &lt;code&gt;response_format&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原先的 &lt;code&gt;response_mime_type&lt;/code&gt; 已移除；在 &lt;code&gt;response_format&lt;/code&gt; 条目中指定 &lt;code&gt;mime_type&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;JSON schema 需要放入带有 &lt;code&gt;type: &amp;quot;text&amp;quot;&lt;/code&gt; 的格式对象。&lt;/li&gt;
&lt;li&gt;图片配置从 &lt;code&gt;generation_config&lt;/code&gt; 移到 &lt;code&gt;response_format&lt;/code&gt; 中的 &lt;code&gt;type: &amp;quot;image&amp;quot;&lt;/code&gt; 条目。&lt;/li&gt;
&lt;li&gt;多模态输出需要使用格式条目数组。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果接口返回 400，除了检查 &lt;code&gt;steps&lt;/code&gt;，也搜索代码中的 &lt;code&gt;response_mime_type&lt;/code&gt;、&lt;code&gt;generation_config.image_config&lt;/code&gt; 和旧版单对象 &lt;code&gt;response_format&lt;/code&gt;。这些旧字段与 &lt;code&gt;outputs&lt;/code&gt; 问题常在同一次升级后一起出现。&lt;/p&gt;
&lt;h2 id=&#34;一份实用排错顺序&#34;&gt;一份实用排错顺序
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;升级 Google GenAI SDK，并记录实际版本。&lt;/li&gt;
&lt;li&gt;用一个无工具、非流式的最小请求验证 &lt;code&gt;interaction.output_text&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;打印 &lt;code&gt;interaction.steps&lt;/code&gt; 的类型和状态，确认程序收到的是新 schema。&lt;/li&gt;
&lt;li&gt;分别迁移函数调用、服务端搜索和工具结果的解析逻辑。&lt;/li&gt;
&lt;li&gt;修改 SSE 事件订阅和参数累积逻辑。&lt;/li&gt;
&lt;li&gt;检查多轮历史是否改为 &lt;code&gt;previous_interaction_id&lt;/code&gt; 或 &lt;code&gt;steps&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;搜索并替换旧的 &lt;code&gt;response_format&lt;/code&gt; 相关字段。&lt;/li&gt;
&lt;li&gt;用文本、工具调用、流式输出和失败重试各跑一次回归测试。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不要为了临时恢复旧代码去依赖过去的 &lt;code&gt;Api-Revision&lt;/code&gt; 头。旧 schema 的过渡期已经结束；现在应把迁移作为正式兼容性修复，而不是继续保留两套不一致的解析器。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;outputs&lt;/code&gt; 改为 &lt;code&gt;steps&lt;/code&gt; 的本质是：Interactions API 不再把所有过程塞进一个输出列表，而是显式暴露输入、思考、工具、结果和最终输出。纯文本场景优先使用 &lt;code&gt;interaction.output_text&lt;/code&gt;；Agent、工具、流式和多模态场景按 &lt;code&gt;step.type&lt;/code&gt; 建立明确分支；多轮会话改用 &lt;code&gt;previous_interaction_id&lt;/code&gt; 或 &lt;code&gt;steps&lt;/code&gt;。按这三个原则迁移，绝大多数“无输出”“工具丢失”和“SSE 不刷新”问题都能定位。&lt;/p&gt;
&lt;p&gt;官方资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://ai.google.dev/gemini-api/docs/interactions-breaking-changes-may-2026&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://ai.google.dev/gemini-api/docs/interactions-breaking-changes-may-2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://ai.google.dev/gemini-api/docs/migrate-to-interactions&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://ai.google.dev/gemini-api/docs/migrate-to-interactions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://ai.google.dev/gemini-api/docs/changelog&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://ai.google.dev/gemini-api/docs/changelog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
