GEMINI LABEN
SHEETS — Fill with Geminiが28言語に拡大しました。中国語・トルコ語ほか各言語のまま自然文で表を組めますALPHAEVOLVE — Gemini Enterpriseに、コードをAIが自律的に最適化するAlphaEvolveが一般提供されましたSPARK — macOS向けの個人AIエージェントGemini Sparkが、フォルダ整理やWorkspace横断の作業を代行しますOMNI — Gemini Omniがテキスト・写真・動画を掛け合わせた高品質な動画作成と、自分に似たAIアバターに対応しますGEMINI35 — Gemini 3.5 Proがアーキテクチャ刷新のため7月17日へ延期。200万トークンとDeep Thinkを導入予定ですDEEPTHINK — 3.5 Proは数学的推論・SVGシーン生成・画像品質の改善を狙って再設計されていますSHEETS — Fill with Geminiが28言語に拡大しました。中国語・トルコ語ほか各言語のまま自然文で表を組めますALPHAEVOLVE — Gemini Enterpriseに、コードをAIが自律的に最適化するAlphaEvolveが一般提供されましたSPARK — macOS向けの個人AIエージェントGemini Sparkが、フォルダ整理やWorkspace横断の作業を代行しますOMNI — Gemini Omniがテキスト・写真・動画を掛け合わせた高品質な動画作成と、自分に似たAIアバターに対応しますGEMINI35 — Gemini 3.5 Proがアーキテクチャ刷新のため7月17日へ延期。200万トークンとDeep Thinkを導入予定ですDEEPTHINK — 3.5 Proは数学的推論・SVGシーン生成・画像品質の改善を狙って再設計されています
記事一覧/API / SDK
API / SDK/2026-07-13上級

responseSchema で $ref が使えず詰まったら — responseJsonSchema で再帰スキーマを本番で扱う

Gemini の responseSchema は OpenAPI サブセットで $ref/$defs が使えず、共有定義も再帰も表現できません。responseJsonSchema へ移行し、多言語フィールドの再利用とカテゴリ木の再帰を本番で扱う実装をまとめました。

gemini101gemini-api274structured-output20json-schema2python100

プレミアム記事

壁紙アプリのカテゴリ分類を Gemini にやらせようとして、最初に壁にぶつかったのは「カテゴリの木構造をスキーマで表現できない」という一点でした。自然(風景 → 山 → 雪山)のように、親カテゴリの下に子があり、その下にさらに孫がある。深さは画像によって変わります。ところが responseSchema に自己参照を書こうとしても $ref を受け付けてくれません。仕方なく3階層まで手でインライン展開し、4階層目が来たら諦める、という妥協をしていました。

この妥協を解いてくれたのが responseJsonSchema です。responseSchema とは別のフィールドで、JSON Schema の $ref$defs を解釈します。共有定義を1回書いて使い回せますし、自己参照で再帰も宣言できます。App Store と Google Play で配信している壁紙アプリのために、多言語かつ入れ子の構造化出力を個人開発で扱うなら、この差は運用のしやすさに直結します。両者の違いと移行手順、そして実際に踏んだ落とし穴を、順に整理していきます。

responseSchema が表現できないもの

responseSchema が受け取るのは OpenAPI 3.0 スキーマオブジェクトのサブセットです。typepropertiesitemsenumnullablepropertyOrdering・後から追加された anyOf あたりは使えます。しかし JSON Schema の中核である $ref(他の定義への参照)と $defs(再利用可能な定義の置き場)は解釈しません。

これが効いてくるのは、次の2つのケースです。

第一に、同じ形のオブジェクトを複数の場所で使い回したいとき。私の場合は「日本語と英語のペア」を表す LocalizedText を、カテゴリ名・説明文・タグの3か所で使いたい。responseSchema ではこれを3回インラインで書くしかなく、スキーマ本体が縦に伸び、後から ja/en の必須指定を直すたびに3か所を漏れなく直す必要が出ます。

第二に、再帰構造。カテゴリ木のように「自分自身を子に持つ」形は、参照がないと表現できません。固定深さまで展開する回避策はありますが、深さが可変のデータでは必ずどこかで破綻します。

観点responseSchemaresponseJsonSchema
スキーマ方言OpenAPI 3.0 のサブセットJSON Schema($ref/$defs 対応)
共有定義の再利用不可(インライン展開)$defs + $ref で可能
再帰・自己参照不可可能
propertyOrdering指定できる指定の概念がない
併用同時指定は不可(どちらか一方のみ)

$defs で多言語オブジェクトを1回だけ定義する

まず、共有定義の再利用から見ていきます。google-genai(新しい Python SDK)を使い、LocalizedText$defs に1回だけ書いて、複数の場所から $ref で参照します。

from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_API_KEY")
 
# LocalizedText を一度だけ定義し、複数箇所から参照する
schema = {
    "type": "object",
    "$defs": {
        "LocalizedText": {
            "type": "object",
            "properties": {
                "ja": {"type": "string"},
                "en": {"type": "string"},
            },
            "required": ["ja", "en"],
        }
    },
    "properties": {
        "name": {"$ref": "#/$defs/LocalizedText"},
        "description": {"$ref": "#/$defs/LocalizedText"},
        "tags": {
            "type": "array",
            "items": {"$ref": "#/$defs/LocalizedText"},
        },
    },
    "required": ["name", "description", "tags"],
}
 
resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="雪をかぶった山の壁紙にカテゴリ名・説明・タグを日英で付けてください。",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_json_schema=schema,
    ),
)
print(resp.text)

期待する出力(整形済み)は次のようになります。

{
  "name": {"ja": "雪山", "en": "Snowy Mountain"},
  "description": {"ja": "雪をかぶった山の風景", "en": "A mountain landscape covered in snow"},
  "tags": [
    {"ja": "自然", "en": "Nature"},
    {"ja": "冬", "en": "Winter"}
  ]
}

LocalizedText の定義は1か所だけです。後から「ja/en に加えて zh も必須にする」と決めても、直すのは $defs の中の1ブロックだけで済みます。responseSchema でインライン展開していた頃は、同じ変更を3か所に手で反映していました。定義が増えるほど、この差は効いてきます。実際、LocalizedText を3か所にインライン展開していたスキーマは約60行ありましたが、$defs に切り出して参照へ置き換えると約35行、およそ40%短くなりました。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
responseSchema で $ref が使えず、多言語オブジェクトを何度もインライン展開して肥大化していた人が、$defs で1回定義して使い回せるようになる
固定深さでしか書けなかったカテゴリ木を、$ref の自己参照で任意の深さの再帰スキーマとして宣言し、動くコードで受け取れるようになる
responseSchema と responseJsonSchema のどちらを選ぶかを、機能差と落とし穴を踏まえて自分のタスクごとに判断できるようになる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

API / SDK2026-03-20
Gemini API × Python で AI データ分析エージェントを構築する — Code Execution・Function Calling・Structured Output 統合ガイド
Gemini API の Code Execution、Function Calling、Structured Output を組み合わせ、CSV/Excel を自動解析し可視化・レポート生成まで行う AI データ分析エージェントを Python で構築する実践ガイド。
API / SDK2026-06-17
Gemini CLI 終了前に、自動化スクリプトを API へ載せ替えた記録
6/18 に Gemini CLI のホスト応答が停止します。シェルから gemini を呼んでいた自動化スクリプトを、google-genai SDK へ安全に載せ替える手順を、構造化出力・リトライ・コスト計測まで含めて実装ベースでまとめました。
API / SDK2026-05-18
Gemini Vision で壁紙アプリの自動カテゴリ分類を実装した話
個人開発の壁紙アプリで Gemini Vision API を使い、画像の自動カテゴリ分類を実装した実体験です。精度改善のプロセスと、公式ドキュメントには載っていない落とし穴、GPT-4o Vision とのコスト比較までまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →