Google GenAI SDK のストリーミングでマルチターン画像編集🍌が不安定になる問題と対処法

Google GenAI SDK のストリーミングでマルチターン画像編集🍌が不安定になる問題と対処法

こんにちは!

Gemini 3 Pro Image (Nano banana Pro)を使ったマルチターン画像編集機能を実装していたところ、動いたり動かなかったりするという厄介な問題に遭遇しました。

本記事では、この問題の現象、原因調査の過程、そして解決策を共有します。


問題の現象

実行環境

Google GenAI SDKライブラリ(pip): google-genai 1.56.0

期待する動作

  1. ユーザー: 「かわいい子猫の画像を生成して」
  2. Gemini: 子猫の画像を生成
  3. ユーザー: 「この子にメガネをかけて」
  4. Gemini: 同じ子猫にメガネをかけた画像を生成

実際に起きた現象

  1. ユーザー: 「かわいい子猫の画像を生成して」
  2. Gemini: 茶色の子猫の画像を生成
  3. ユーザー: 「この子にメガネをかけて」
  4. Gemini: メガネをかけた女の子の画像を生成
あれれ、メガネをかけた子猫になるはずが、メガネをかけた女の子の画像が生成されてしまった

つまり、前回生成した画像を「覚えていない」状態になっていました。

厄介だったのは「再現性のなさ」

この問題が特に厄介だったのは、動いたり動かなかったりするという点でした。

  • 同じコードなのに、タイミングによって成功したり失敗したり、と挙動が変わる
  • サーバー再起動したら、タイミングからは長時間動作しなくなる
  • 開発環境では動いたが、ステージングでは動かない

同一コードで急に動かなくなると、「いったん再起動しよう」などとりあえずやってしまうと、環境の固定が崩れてしまい、問題の切り分け難しくなり「さっきまで動いてたのに...」という状況が発生し、原因特定に時間がかかりました。


原因調査

thought_signature の仕組み

Gemini 3 Pro Image のマルチターン画像編集は、thought_signature という仕組みに依存しています。

  • 画像生成時に、モデルは thought_signature を返す
  • これは生成した画像の情報(構図、色、内容など)を保持する約2MBのデータ
  • 次のターンでこれを渡すことで、前回の画像を「覚えている」状態になる

Google の公式ドキュメントによると

If you use the official Google Gen AI SDKs and use the chat feature, thought signatures are handled automatically.

ということで、つまり、SDK のチャット機能を使えば自動管理されるはず...でした。
この thought_signature という仕組みをつかえば、テキストチャットで行う毎回それまでのすべての履歴を送信する、ということを避けることができます。

SDK のチャットセッション

私たちのアプローチでは Google GenAI SDK の client.aio.chats.create() でチャットセッションを作成し、chat.send_message_stream() でメッセージを送信していました。

# チャットセッション作成
chat = client.aio.chats.create(model="gemini-3-pro-preview", config=config)

# メッセージ送信(ストリーミング)
response_stream = await chat.send_message_stream(content_parts)
async for response in response_stream:
    # レスポンス処理
    ...

ドキュメント通りなら、これで thought_signature は自動管理されるはず。しかし実際には動作しませんでした。

GitHub Issue #1791 の発見

調査を進める中で、GitHub で関連する issue を発見しました。

[Bug] ChatSession history fragmentation when using send_message_stream with Thinking (Gemini 3 Pro)
https://github.com/googleapis/python-genai/issues/1791

当該issue

この issue によると

When using Gemini 3 Pro Preview with thinking_config enabled, the ChatSession history becomes fragmented when using send_message_stream. Instead of appending a single model turn with the complete response, the SDK appends multiple model turns corresponding to the streaming chunks.

つまり、send_message_stream() を使うと、チャット履歴が断片化されてしまうというバグが報告されていました。

期待値

[User, Model]  # 2エントリ

実際

[User, Model, Model, Model, Model, ...]  # 複数のModelエントリ

ストリーミングのチャンクごとに履歴エントリが追加されてしまい、会話構造が壊れるとのこと。

「動いたり動かなかったり」の理由

この issue を読んで、「動いたり動かなかったり」の理由が推測できました。

  1. 同じサーバーインスタンス内で連続してリクエストすると、セッションがメモリ上に残っているため動くことがある
  2. サーバー再起動新しいセッションでは、壊れた履歴から再開しようとして動かない
  3. タイミングやネットワーク状況によって、履歴の断片化の程度が変わる

これが再現性のない挙動の原因でした。


解決策

非ストリーミング版を使う

issue #1791 を参考に、send_message_stream() の代わりに send_message() を使うことにしました。

# 修正前(ストリーミング)
response_stream = await chat.send_message_stream(content_parts)
async for response in response_stream:
    # 処理
    ...

# 修正後(非ストリーミング)
response = await chat.send_message(content_parts)
# 処理
...

結果

非ストリーミング版に変更したところ、マルチターン画像編集が安定して動作するようになりました。

  • 子猫を生成 → 同じ子猫にメガネを追加
今度は、ちゃんと、元の子猫にメガネが装着されました
  • 何度試しても同じように​
  • サーバー再起動後も動作

まとめ

問題

Google GenAI SDK の send_message_stream() を使うと、チャット履歴が断片化され、thought_signature が正しく管理されない。

影響

Gemini 3 Pro Image のマルチターン画像編集が不安定になる(動いたり動かなかったりする)。

解決策

send_message_stream() の代わりに send_message() を使う。

副作用

  • リアルタイムのストリーミング表示ができなくなる(文章+SVG出力などでの逐次表示に影響)
  • 画像生成完了まで結果が返ってこない
  • ただし、進捗表示(「処理中です...」など)のサブメッセージを別途実装すれば UX への影響は最小限で済む

今後

  • SDK のバグ修正を待つ
  • issue #1791 の進捗を監視
  • 修正されたらストリーミング版に戻すことを検討

参考リンク


最後に

同一コードで「動いたり動かなかったりする」バグは、原因特定が非常に難しいですね。今回のケースでは、SDK の内部動作を疑うまでに時間がかかりました。

同じ問題で困っている方の参考になれば幸いです。

それでは、次回またお会いしましょう!

Read more

PyCharmで npm start 実行時にIDEがサイレントクラッシュした事例と切り分け

PyCharmで npm start 実行時にIDEがサイレントクラッシュした事例と切り分け

こんにちは!Qualitegプロダクト開発部です! PyCharmの内蔵npmツールで npm start を実行した瞬間、何のエラーメッセージもなくIDEが消える。 再起動してもう一度試すとまた落ちる。ログを見ても手がかりがない——。 今回はこの「サイレントクラッシュ」に遭遇し、原因の絞り込みから回避策の確立まで至った過程を書き残しておきます。同じ現象で困っている方の参考になれば幸いです。 環境 項目 内容 OS Windows 10/11 PyCharm 2026.1(2023.1.6時代から連綿とUpdateをした状態) Python 3.11.4(venv使用) Node.js v25.2.1 プロジェクト Python + Node.js 混合構成 上記のとおり、PyCharmは執筆時点の最新版(2026.1)となります。 確認できたこと・推測していること まず最初に、

By Qualiteg プロダクト開発部
大企業のAIセキュリティを支える基盤技術 - 今こそ理解するActive Directory 第6回 よくある問題と解決方法

大企業のAIセキュリティを支える基盤技術 - 今こそ理解するActive Directory 第6回 よくある問題と解決方法

こんにちは、今回はシリーズ第6回トラブルシューティング - よくある問題と解決方法 について解説いたします! さて、前回(第5回)は、統合Windows認証がブラウザでどのように動作するかを解説しました。 「イントラネットゾーン」という概念を理解することで、同じサーバーでもURLの書き方(NetBIOS名、FQDN、IPアドレス)によって認証動作が変わる理由が明確になったかと思います。また、Chrome/Firefoxではデフォルトで統合認証が無効になっている理由と、グループポリシーによる一括設定方法も学びました。 しかし、設定が完璧なはずなのに「なぜかうまく動かない」という場面は、実際の現場では必ず訪れます。 「最近、ファイルサーバーへのアクセスが遅い」「金曜日は使えたのに、月曜日の朝にログインできない」「特定のサービスだけKerberosが失敗する」——これらはヘルプデスクに日々寄せられる典型的な問い合わせです。 原因はKerberosの失敗、時刻のずれ、SPNの設定ミス、DNS関連の問題など多岐にわたりますが、体系的にトラブルシューティングすることで必ず解決できます。

By Qualiteg コンサルティング, Qualiteg AIセキュリティチーム
AIエージェントを"事業に載せる"ために【第2回】AIエージェントの責任分解はなぜ難しいのか

AIエージェントを"事業に載せる"ために【第2回】AIエージェントの責任分解はなぜ難しいのか

— AI導入を"事業に載せる"ために、いま設計すべきこと(全3回) こんにちは!Qualitegコンサルティングチームです! 前回(第1回)では、Replit/Lemkin事件とDeloitte豪州政府報告書問題を通じて、AIエージェント導入の課題がモデル性能ではなく「権限・監査・責任の設計不在」にあることを見ました。 では、実際に事故が起きたとき、責任は誰が負うのでしょうか。第2回となる本記事では、法務・契約・組織の3つの観点から、AIエージェントの責任分解がなぜ難しいのかを構造的に整理します。 結論を先に言えば、法務だけでも契約だけでも組織論だけでも足りません。この3つを接続して設計しなければ、AIエージェントの責任分解は実務上機能しません。 1. 法的フレームワーク:複数の法理論が並走している AIエージェントが損害を出したとき、どの法理論で責任が問われるかについて、現時点でグローバルなコンセンサスは形成されていません。 Clifford Chanceの論考は、この状況の根本的な難しさを整理しています。法律は歴史的に、有害な行為がいつどのように発生したかを特定でき

By Qualiteg コンサルティング
AIエージェントを"事業に載せる"ために【第1回】

AIエージェントを"事業に載せる"ために【第1回】

AI導入事故は何を示しているのか — AI導入を"事業に載せる"ために、いま設計すべきこと(全3回) こんにちは!Qualitegコンサルティングチームです! AIエージェントを導入する企業が増える一方で、 「試してみる」段階から「事業に載せる」段階へ進める難しさ が、はっきり見え始めています。 本シリーズでは、AIエージェント導入を技術論だけでなく、責任分解・監査可能性・契約・運用統制を含む業務設計の問題として整理します。 全3回を通じて、「AIが賢いかどうか」ではなく、「AIを業務に載せるために何を設計するか」を考えていきます。 第1回となる本記事では、2025年に起きた2つの事例を出発点に、なぜいま「責任設計」が問題になっているのかを見ていきます。 上図は、本シリーズ全体で扱う論点の全体像です。 AIエージェントの導入は、技術的なモデル選定だけでは完結せず、権限設計、契約、監査、品質監視、保険、異常時対応まで含めた設計が必要になります。 第1回ではまず、なぜこうした設計が求められるようになったのかを、実際の事例から見ていきたいとおもいます なお、本シリー

By Qualiteg コンサルティング