1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gemini 3 Thought Signatures完全ガイド — 関数呼び出し400エラーを防ぐAPI実装

1
Last updated at Posted at 2026-03-09

Gemini 3 Thought Signaturesが推論チェーンをターン間で引き継ぐフロー図

はじめに

Gemini 3シリーズを使ってツール呼び出し(関数呼び出し)を実装したとき、突然 400 Bad Request が返ってきた経験はありませんか?

InvalidArgument: 400 Function call `tool_name` in the `1.` content block is missing a `thought_signature`.

このエラーはGemini 3から導入された Thought Signatures(思考シグネチャ) を正しく処理していないために発生します。LangChain、Google ADK、n8n、Windmill、Pipecatなど多数のフレームワークでも同様のIssueが報告されており、Gemini 3を使う開発者が共通して直面する問題です。

本記事では、Thought Signaturesの仕組みと実装方法を、公式ドキュメントと公開情報をもとに解説します。

この記事で学べること

  • Thought Signaturesとは何か、なぜGemini 3で必要になったか
  • 400エラーが発生するパターンと回避方法
  • Python公式SDKを使ったときの自動処理と、手動実装の方法
  • 逐次・並列関数呼び出しでのシグネチャの扱い方
  • thinking_level との組み合わせ時の注意点

対象読者

  • Gemini 3(Flash / 3.1 Pro等)のAPIで関数呼び出しを実装している開発者
  • 既存のGemini 2.xコードをGemini 3に移行しようとしているエンジニア
  • LangChain等のフレームワーク経由でGemini 3を使っている方

TL;DR

  • Gemini 3では、関数呼び出しの応答に thoughtSignature フィールドが付与される
  • 次のターンで会話履歴を送るとき、この署名を含めないと 400エラー
  • 公式PythonSDK(google-genai)の chat 機能を使えば自動処理される
  • 手動で会話履歴を管理する場合は、thought_signature を必ずそのまま引き継ぐこと
  • thinking_level: minimal に設定しても Thought Signatures の送付は必須

Thought Signaturesとは

Thought SignaturesがAPI呼び出し間で推論チェーンを引き継ぐ仕組み

Thought Signatures(思考シグネチャ)は、モデルの内部的な思考プロセスを 暗号化された表現 として保持し、マルチターンの会話で推論の文脈を維持するための仕組みです。

Gemini 2.xまでは、関数呼び出しの会話履歴は単純に functionCallfunctionResponse のやり取りでした。Gemini 3では、モデルが関数を呼び出す前に内部で行う推論過程(思考)を「シグネチャ」として返し、次の呼び出しでそれを受け取ることで、モデルが前の推論を引き継いだ状態 で処理を継続できます。

なぜGemini 3で必要になったのか

Gemini 3は「Dynamic Thinking(動的思考)」がモデルに組み込まれており、関数呼び出しを含むすべての応答で内部推論が動作しています。このとき思考の文脈(シグネチャ)を次のターンに渡さないと、モデルは「途中から文脈なしで作業を再開する」状態になり、整合性が崩れます。

Googleはこの整合性の問題を防ぐため、APIレベルでシグネチャの検証を 強制 することにしました。関数呼び出しの場合、シグネチャ欠落は即座に400エラーになります。


400エラーの発生パターン

SDK自動処理 vs 手動実装 — Thought Signaturesの実装パターン比較

Googleの公式ドキュメントによると、バリデーションの厳密さはコンテンツの種類によって異なります。

コンテンツ種別 シグネチャ欠落時の挙動
関数呼び出し(functionCall) 400エラー(厳密に強制
テキスト生成・チャット エラーなし(ただし推論品質が低下)
画像生成・編集 400エラー(厳密に強制

つまり、関数呼び出しを使う場合は必ずシグネチャを引き継ぐ 必要があります。

よくある誤実装パターン

# NG: functionCallをそのまま辞書に変換して再構成すると thoughtSignature が失われる
history.append({
    "role": "model",
    "parts": [{
        "functionCall": {
            "name": response.candidates[0].content.parts[0].function_call.name,
            "args": dict(response.candidates[0].content.parts[0].function_call.args)
        }
        # ← thoughtSignature が含まれていない!
    }]
})

この実装では thoughtSignature フィールドが手動で除外されてしまうため、次のターンで400エラーになります。


Python実装

方法1: 公式SDKの chat 機能を使う(推奨)

google-genai パッケージの chat セッションを使うと、Thought Signaturesは 自動的に管理 されます。

from google import genai
from google.genai import types

client = genai.Client(api_key="YOUR_GEMINI_API_KEY")

# ツール定義
def get_weather(city: str) -> str:
    """指定した都市の天気情報を取得する"""
    # 実際の実装ではAPIを呼び出す
    return f"{city}の現在の天気: 晴れ、気温 22℃"

tools = [get_weather]

# chatセッション作成 — Thought Signaturesは自動処理
chat = client.chats.create(
    model="gemini-3.1-pro-preview",
    config=types.GenerateContentConfig(
        tools=tools,
        thinking_config=types.ThinkingConfig(
            thinking_level="medium"
        )
    )
)

# 1ターン目: モデルがget_weatherを呼び出す
response = chat.send_message("東京の天気を教えて")

# chatセッションが自動で:
# 1. functionCallに付いたthoughtSignatureを保持
# 2. functionResponseを送るとき自動で引き継ぐ
# 3. 最終回答を返す

print(response.text)

公式SDKの chat.send_message() を使う場合、Thought Signaturesの管理は完全自動です。手動で何か対処する必要はありません。

方法2: 手動で会話履歴を管理する

generate_content() を直接呼び出して会話履歴を自分で管理する場合は、モデルの応答をそのままの形で履歴に追加 することが重要です。

from google import genai
from google.genai import types

client = genai.Client(api_key="YOUR_GEMINI_API_KEY")

def get_weather(city: str) -> str:
    return f"{city}の天気: 晴れ、22℃"

# 会話履歴
messages = []

# ユーザーの質問を追加
messages.append(
    types.Content(role="user", parts=[types.Part(text="東京の天気を教えて")])
)

# 1回目のAPI呼び出し
response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents=messages,
    config=types.GenerateContentConfig(
        tools=[get_weather],
        thinking_config=types.ThinkingConfig(thinking_level="medium")
    )
)

# ⭐ポイント: モデルの応答をそのままの形で履歴に追加する
# response.candidates[0].contentには thoughtSignature が含まれている
messages.append(response.candidates[0].content)

# 関数呼び出しがある場合は実行
for part in response.candidates[0].content.parts:
    if part.function_call:
        fn_name = part.function_call.name
        fn_args = dict(part.function_call.args)

        # 関数を実行
        result = get_weather(**fn_args)

        # 関数の結果を会話に追加
        messages.append(
            types.Content(
                role="user",
                parts=[types.Part(
                    function_response=types.FunctionResponse(
                        name=fn_name,
                        response={"result": result}
                    )
                )]
            )
        )

# 2回目のAPI呼び出し(thoughtSignatureは messages に含まれている)
final_response = client.models.generate_content(
    model="gemini-3.1-pro-preview",
    contents=messages,
    config=types.GenerateContentConfig(
        tools=[get_weather],
        thinking_config=types.ThinkingConfig(thinking_level="medium")
    )
)

print(final_response.text)

response.candidates[0].content をそのまま使わずに、functionCall のフィールドだけを取り出して辞書を再構成すると thoughtSignature が失われます。必ず元の content オブジェクトを履歴に追加してください。


逐次・並列関数呼び出し時のルール

Googleの公式ドキュメントでは、Thought Signaturesの取り扱いについて以下のルールが定められています。

逐次関数呼び出し(Sequential)

モデルが複数の関数を 順番に 呼び出す場合、各ステップの最初の functionCall パーツにシグネチャを含める 必要があります。

ターン1: ユーザー質問
ターン2(モデル): functionCall_A(thoughtSignature_A付き)
ターン3(ユーザー): functionResponse_A
ターン4(モデル): functionCall_B(thoughtSignature_B付き)  ← 各ステップに必要
ターン5(ユーザー): functionResponse_B
ターン6(モデル): 最終回答

並列関数呼び出し(Parallel)

モデルが複数の関数を 同時に 呼び出す場合、最初の functionCall パーツのみにシグネチャを含める だけで十分です。

ターン2(モデル):
  functionCall_A(thoughtSignature付き)  ← シグネチャはここだけ
  functionCall_B(シグネチャなし)         ← 2番目以降は不要

SDKの chat 機能を使えばこの違いも自動的に処理されます。


thinking_level との組み合わせ

thinking_level を設定してもThought Signaturesの送付が省略できるわけではありません。

thinking_level Thought Signaturesの送付
high(デフォルト) 必須
medium 必須
low 必須
minimal 必須(注意点)

minimal でもThought Signaturesは必須です。
公式ドキュメントには「Circulation of thought signatures is required even when thinking level is set to minimal for Gemini 3 Flash.」と明記されています。thinking_levelthought_signature は独立した概念であり、前者はモデルの推論の深さ、後者は文脈の引き継ぎを管理します。

また、旧来の thinking_budget パラメータはGemini 2.5系のパラメータです。Gemini 3では thinking_level を使うよう移行してください。公式ドキュメントによると、Gemini 3で thinking_budget を使うと予期しない動作になる可能性があります。

# Gemini 2.5系(旧): thinking_budget を使用
config = types.GenerateContentConfig(
    thinking_config=types.ThinkingConfig(
        thinking_budget=10000
    )
)

# Gemini 3系(新): thinking_level を使用
config = types.GenerateContentConfig(
    thinking_config=types.ThinkingConfig(
        thinking_level="high"  # minimal / low / medium / high
    )
)

よくあるエラーと対処法

エラー1: missing a thought_signature

InvalidArgument: 400 Function call `fn_name` in the `1.` content block is missing a `thought_signature`.

原因: 会話履歴を手動で構築する際に、functionCall から thoughtSignature フィールドを除外してしまっている
対処: response.candidates[0].content をそのまま履歴に追加する(辞書への変換を避ける)

エラー2: thinking_budget の挙動変化

Gemini 2.5系で使っていた thinking_budget パラメータをGemini 3モデルに対して使い続けると、予期しない動作が発生する可能性があります。エラーにはならない場合もありますが、推論品質が低下したりレスポンスが不安定になることがあります。

対処: thinking_budget を削除し、Gemini 3では thinking_levelminimal / low / medium / high)に移行する

エラー3: フレームワーク統合での問題

LangChain、n8n、Pipecat等のフレームワーク経由でGemini 3を使っている場合、フレームワーク側がThought Signaturesに対応していないことで400エラーが発生することがあります。

確認事項:

  1. 使用しているフレームワークの最新バージョンへアップデート
  2. リリースノートやIssueでGemini 3対応の記載を確認
  3. 対応していない場合、公式SDK直接使用を検討する

Gemini 3 Proからの移行(本日3/9が移行期限)

Gemini 3 Pro Preview(gemini-3-pro-preview)は 2026年3月9日 にシャットダウンされます。現在このモデルを使っている場合は、gemini-3.1-pro-preview への移行が必要です。

# Before: Gemini 3 Pro Preview(本日シャットダウン)
model = "gemini-3-pro-preview"

# After: Gemini 3.1 Pro Preview(現行推奨モデル)
model = "gemini-3.1-pro-preview"

移行時にThought Signaturesの実装も見直す良い機会です。SDKの chat 機能への切り替えを検討してみてください。


まとめ

  • Gemini 3の関数呼び出しではThought Signaturesが必須。含めないと400エラーになる
  • 最も簡単な解決策は公式SDKの chat セッションを使うこと。自動管理されるため実装コストがゼロ
  • 手動実装する場合は response.candidates[0].content をそのまま履歴に追加し、辞書への変換で削ぎ落とさないようにする
  • thinking_level: minimal でもThought Signaturesの送付は必須
  • Gemini 3では thinking_budget(Gemini 2.5系)ではなく thinking_level を使うこと

フレームワーク経由でGemini 3を使っている場合は、フレームワーク側の対応状況を確認し、未対応であれば公式SDKへの移行を検討してください。

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?