<?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/zh-tw/tags/api%E9%81%B7%E7%A7%BB/</link>
        <description>Recent content in API遷移 on KnightLi的博客</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-tw</language>
        <lastBuildDate>Sun, 12 Jul 2026 10:33:00 +0800</lastBuildDate><atom:link href="https://knightli.com/zh-tw/tags/api%E9%81%B7%E7%A7%BB/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Gemini Interactions API 遷移指南：outputs 改為 steps 後怎麼排錯</title>
        <link>https://knightli.com/zh-tw/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/zh-tw/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>
