GEMINI LABEN
PRO35 — 報道が目標日としていた7月17日を過ぎましたが、Gemini 3.5 Proの公式発表もモデルカードも本日時点で確認できていません。予備日として7月24日が挙げられていますNB2LITE — Nano Banana 2 Lite(Gemini 3.1 Flash-Lite Image)が登場しました。約4秒で画像を生成し、1,000枚あたり0.034ドルという水準ですOMNI — Gemini Omni Flashが公開プレビューに入りました。最長10秒の動画を生成でき、価格は出力1秒あたり0.10ドルですEDIT — Omni Flashは会話による編集を軸に設計されています。登場人物の差し替え、ライティングの変更、アングルの調整を自然文で指示でき、元の音声と映像のトラックは保持されますSYNTHID — 新しい2モデルにはSynthIDの電子透かしが組み込まれており、生成物の来歴をGeminiアプリ側から確認できますSHUTDOWN — 旧来の画像生成モデルは非推奨となり、8月17日に停止されます。移行の期限をご確認いただければと思いますPRO35 — 報道が目標日としていた7月17日を過ぎましたが、Gemini 3.5 Proの公式発表もモデルカードも本日時点で確認できていません。予備日として7月24日が挙げられていますNB2LITE — Nano Banana 2 Lite(Gemini 3.1 Flash-Lite Image)が登場しました。約4秒で画像を生成し、1,000枚あたり0.034ドルという水準ですOMNI — Gemini Omni Flashが公開プレビューに入りました。最長10秒の動画を生成でき、価格は出力1秒あたり0.10ドルですEDIT — Omni Flashは会話による編集を軸に設計されています。登場人物の差し替え、ライティングの変更、アングルの調整を自然文で指示でき、元の音声と映像のトラックは保持されますSYNTHID — 新しい2モデルにはSynthIDの電子透かしが組み込まれており、生成物の来歴をGeminiアプリ側から確認できますSHUTDOWN — 旧来の画像生成モデルは非推奨となり、8月17日に停止されます。移行の期限をご確認いただければと思います
記事一覧/API / SDK
API / SDK/2026-06-18上級

Gemini の構造化出力で入力種別ごとに型を変える — anyOf 判別ユニオンの実運用メモ

種類の違う入力を1つのエンドポイントで分類すると、フラットなスキーマは null だらけになります。anyOf 判別ユニオンで種別ごとに型を切り替え、Pydantic / Zod で安全に受け取る実装をまとめました。

gemini-api278structured-output20anyofdiscriminated-unionindie-development4

プレミアム記事

きっかけは、個人開発で回しているレビュー集約の小さなバッチでした。App Store と Google Play のレビュー、サポート問い合わせメール、そして稀に届く返金依頼を、ひとつの分類エンドポイントにまとめて流していたのですが、出力が安定しないのです。レビューには rating が、返金依頼には order_id が必要なのに、全部を1枚のフラットなスキーマで受けていたため、フィールドの大半が optional になり、Gemini が「埋められそうなところを埋める」挙動で order_id にレビュー本文の一部を入れてくる、ということが起きていました。

問題はモデルの賢さではなく、こちらの渡したスキーマが「どの種別なのか」をモデルに決めさせる構造になっていなかったことでした。種別を先に確定させ、その種別に応じてフィールドを切り替える——つまり判別可能なユニオン(discriminated union)を anyOf で表現すれば、この曖昧さはかなり消えます。今回はその設計と、Pydantic / Zod で安全に受け取るところまでの実装メモです。モデルは本日 GA となった gemini-3.5-flash に固定して検証しています。

フラットな1枚スキーマが null だらけになる理由

最初に組んでいたスキーマは、考えうる全フィールドを並べただけのものでした。

{
  "type": "object",
  "properties": {
    "category": { "type": "string" },
    "rating": { "type": "integer" },
    "summary": { "type": "string" },
    "order_id": { "type": "string" },
    "reason": { "type": "string" },
    "urgency": { "type": "string" }
  }
}

この形は一見すると無難ですが、運用に乗せると次の問題が出ます。種別ごとに必要なフィールドが違うのに、required を厳しくできません。レビューに order_id は不要で、返金依頼に rating は無意味です。すべてを optional にすると、今度はモデルが「空欄を嫌って」無関係なフィールドを埋め始めます。私の手元では、返金依頼として処理すべき入力のうち約 15% で rating に推測値が入り、order_id が空のまま流れてくるケースが目立ちました。

下流のコードはこの曖昧さを吸収するために if category == "refund" and order_id is None のような分岐だらけになり、しかもその分岐は「モデルが正しく category を入れてくれた」前提に乗っています。category 自体が信用できないのに、です。

フラット型と判別ユニオン型の違いを整理すると、次のようになります。

観点フラット1枚スキーマanyOf 判別ユニオン
必須フィールド種別差を表現できず全部 optional になりがち種別ごとに required を厳密に指定できる
誤入力無関係なフィールドを埋めやすいその種別に無いフィールドは構造上存在しない
下流の分岐category を信用した手書き if が増える判別子で型が確定し網羅性チェックが効く
検証部分的にしか効かないPydantic / Zod の判別ユニオンがそのまま使える

anyOf 判別ユニオンという考え方

判別ユニオンは、各バリアントに「種別を表す1つのフィールド(判別子)」を持たせ、その値で型を一意に決められるようにしたものです。OpenAPI / JSON Schema では anyOf でバリアントを並べ、各バリアントの判別子フィールドを「単一値だけを許す enum」にします。kind: ["app_review"] のように許容値を1つに絞ると、モデルはそのバリアントを選んだ瞬間に kind の値が確定し、こちらは kind を見るだけで型を切り分けられます。

Gemini の responseSchema は OpenAPI のサブセットをサポートしており、anyOfenumrequiredproperty_ordering あたりは実用範囲で使えます。ここで効いてくるのが property_ordering です。生成は前から順に進むため、判別子を先頭に置くと、モデルは「まず種別を決めてから、その種別のフィールドを埋める」順序になります。私の検証では、判別子を末尾に置いた場合と先頭に置いた場合で、無関係フィールドの混入率が体感で大きく変わりました。判別子は必ず required かつ property_ordering の先頭に置く、というのが実運用での結論です。

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

この記事の続きを読む

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

この記事で得られること
responseSchema を anyOf で書くときの実際に通るサブセットと、判別子(discriminator)をモデルに必ず先頭で確定させる property_ordering の指定
Python(Pydantic 判別ユニオン)と TypeScript(Zod discriminatedUnion)で受け取り、検証失敗時に1回だけ修復する実装コード
未知種別を握りつぶさず DLQ に流す設計と、判別ユニオンが 3.5 Flash でトークンとレイテンシに与えた実測の差
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

API / SDK2026-05-20
Gemini API 構造化出力スキーマを本番アプリで安全に進化させる設計記録
個人開発のアプリ事業でGemini APIのJSON出力スキーマを変えるとき、何を契約として守り、何を段階的に切り替えたか。Dual-EmitパターンとSunsetプロトコルの実装記録です。
API / SDK2026-07-13
responseSchema で $ref が使えず詰まったら — responseJsonSchema で再帰スキーマを本番で扱う
Gemini の responseSchema は OpenAPI サブセットで $ref/$defs が使えず、共有定義も再帰も表現できません。responseJsonSchema へ移行し、多言語フィールドの再利用とカテゴリ木の再帰を本番で扱う実装をまとめました。
API / SDK2026-07-05
使っているモデルの廃止予告だけを拾う — url-context に公式チェンジログを読ませる仕組み
画像モデルの停止を公開3日前に知って肝を冷やしました。url-context に公式チェンジログを直接読ませ、自分が実際に使っているモデルの廃止予告だけを構造化して差分通知する仕組みを、そのまま動く Python と運用で削った過検知の調整まで含めて組み立てます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →