Gemini APIでPydanticの『再帰構造エラー』を回避して複雑なJSONを生成する方法

PythonでGemini APIのStructured Output(構造化出力)を実装中、Pydanticモデルで階層構造を定義したところ、400エラーでハマったので備忘録として残します。

この記事でわかること

  • Gemini APIで「400 Schema is invalid」が出る原因
  • Pydanticにおける再帰構造の制限
  • 階層構造データを安全に生成するための代替案

[現象] 実行時にスキーマエラーが発生する

ツリー構造やファイルディレクトリのような階層データを生成しようとして、以下のように自分自身をリストで持つPydanticモデルをresponse_schemaに指定すると、APIリクエスト時にエラーが発生します。

google.api_core.exceptions.InvalidArgument: 
400 Schema is invalid: recursive types are not supported. 
Please remove recursion from the schema.

[環境]

  • Language: Python 3.10+
  • Library: google-generativeai
  • Validation: Pydantic v2

[原因] Gemini APIのスキーマ制限

2026年現在の仕様において、Gemini APIのresponse_schema機能は自己参照(再帰的な構造)を持つJSONスキーマをサポートしていません。

Pydanticで children: list['Node'] と定義すると、生成されるJSON Schemaに $ref を用いた再帰が含まれます。Gemini APIはこの参照解決に対応していないため、「スキーマが無効です」としてリクエストが拒絶されます。

[解決策] dict型での定義と事後バリデーション

解決策は、APIに渡すモデルからは再帰を排除し、生成されたデータをPython側で再パースするという二段階構成にすることです。

修正前のコード(エラー)

class Node(BaseModel):
    name: str
    children: list["Node"] # ここでエラー

修正後のコード(正常動作)

API送信用のモデルでは list[dict] として定義し、APIからのレスポンスを本来の再帰モデルで読み込み直します。

import google.generativeai as genai
from pydantic import BaseModel
from typing import List

# 1. APIスキーマ用のモデル(再帰を避ける)
class GeminiNode(BaseModel):
    name: str
    children: List[dict] # APIにはdictのリストとして認識させる

# 2. アプリケーションで使いたい本来の再帰モデル
class FinalNode(BaseModel):
    name: str
    children: List["FinalNode"]

# APIリクエスト
model = genai.GenerativeModel("gemini-1.5-flash")
response = model.generate_content(
    "マインドマップの構造を生成して",
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=GeminiNode,
    )
)

# 3. 取得したJSONを本来の型でパースして安全性を確保
import json
raw_data = json.loads(response.text)
validated_node = FinalNode.model_validate(raw_data)
print(validated_node)

[まとめ]

Gemini APIのStructured Outputで階層構造を扱う際は、以下のポイントを押さえましょう。

  • 400 Schema is invalidが出たら再帰定義を疑う
  • API用スキーマでは list[dict]Any でお茶を濁す
  • 生成されたデータに対し、Python側で本来の再帰Pydanticモデルを使ってバリデーションをかける

この方法なら、APIの制限を回避しつつ、アプリケーション内部では型安全なデータを扱うことが可能です!

タイトルとURLをコピーしました