3行でいうと
- 3社とも、決めた形(JSONスキーマ)に沿った文字列を返す機能があります。ただし保証されるのは形で、値の意味の正しさは別です。
- 拒否(安全上の理由)や、出力が上限で途中切れしたときは、形に合わない出力が返ることがあります。必ず状態を見てから読みます。
- Anthropicはスキーマの複雑さに数値の上限(厳密な道具20個など)を公開しています。OpenAIとGoogleは、読んだ文書に数値が見つかりませんでした。
この記事は、実際に使って確かめた記録ではありません。この記事は公式の文書を読んでまとめたものです。情報は2026年10月22日に確認しました。変わることがあります。
先に結論
- 構造化出力は、AIの返事を「機械が読める、決まった形」にする仕組みです。人間向けの文章ではなく、プログラムに渡すデータが欲しいときに使います。
- 3社とも、JSONスキーマ(データの形を書く決まった書式)を渡して使います。OpenAIとAnthropicには、「形に合うことを保証する」という趣旨の厳密なモードがあります。GoogleのGeminiは、文書が保証しているのは「文法的に正しいJSON」までで、値が意味として正しいかは確認しなさい、と書いています。
- 実運用では、形の保証とは別に、次の3つを必ず処理します。拒否(refusal)、途中切れ(max tokensなど)、値の検証。
前提:何の話か
APIは、アプリの中からAIを呼び出す開発者向けの窓口です。通常、AIの返事は自由な文章なので、そこから必要な値を取り出すのは面倒で、形が崩れることもあります。
JSONは、{"name": "田中", "age": 30}のような、名前と値の組でデータを表す書式です。JSONスキーマは、そのJSONがどんな形であるべきか(どの項目があり、文字か数字か、必須か)を書く決まった書式です。構造化出力は、このスキーマを渡して、返事がそれに合うようにする機能です。
似たものに「JSONモード」があります。OpenAIの文書によると、JSONモードは有効なJSONを返すところまでで、スキーマへの一致は保証しません。構造化出力はその進化形とされ、スキーマに合うことが保証される、と書かれています。
3社の比較
| OpenAI | Anthropic(Claude) | Google(Gemini) | |
|---|---|---|---|
| 返事の形を固定 | text.formatにjson_schemaとstrict: true(Responses API)。Chat Completionsはresponse_format |
output_config.formatにjson_schema |
生成設定のresponse_formatにMIMEタイプapplication/jsonとスキーマ |
| 道具の引数を固定 | 関数定義にstrict: true |
道具の定義にstrict: true |
道具との併用はプレビュー(Gemini 4系と3系のみ) |
| 対応モデル | GPT-4o以降。新規にはgpt-6-astraを推奨 | Fable 5/5.1、Mythos、Opus 4.5〜5.5、Sonnet 4.5〜5.5、Haiku 4.5/5.5 | 文書に一覧あり(Gemini 4 Argon、3.8 Flash、3.1 Pro Preview、2.5系など) |
| 拒否の検出 | 応答にrefusalの項目 |
stop_reason: "refusal"(HTTP 200で返る) |
文書に記載なし |
| 途中切れ | statusがincomplete、理由はmax_output_tokens |
stop_reason: "max_tokens" |
文書に記載なし |
| スキーマの初回の遅れ | あり(初回のみ) | あり(文法のコンパイル。24時間キャッシュ) | 文書に記載なし |
| バッチとの併用 | 構造化出力はBatch APIでも使える | 使える(50%割引) | 読んだ文書では確認できていません |
| SDKの補助 | Pydantic(Python)、Zod(JavaScript)など | messages.parse()にPydanticモデルを渡す |
Pydantic、Zod(z.fromJSONSchema()) |
各社の中身
OpenAI
公式のStructured Outputsの文書によると、次の通りです。
- 有効にする:Responses APIでは
text: { format: { type: "json_schema", "strict": true, "schema": ... } }。Chat Completions APIではresponse_format: { type: "json_schema", json_schema: {"strict": true, "schema": ...} }。JSONモードはjson_objectという別の指定です。 - 使いわけ:道具や関数、データに繋ぐときは関数呼び出し(function calling)、ユーザーへの返事の形を決めたいときは
json_schemaの返事形式。 - 使える型:文字列、数値、真偽値、整数、オブジェクト、配列、列挙(enum)、
anyOf。文字列にはpattern(正規表現)とformat(date-time、date、email、uuidなど)、数値にはminimum、maximum、multipleOfなど、配列にはminItems、maxItemsが使えると書かれています。 - 例の書き方:例のスキーマはすべて
"additionalProperties": falseで、全項目をrequiredに入れています。ただし、読んだ範囲では、これを正式な決まりとして書いた箇所は見つかりませんでした。 - 拒否:安全上の拒否は、プログラムで検出できる、と書かれています。拒否は必ずしもスキーマに合わないので、応答に別の
refusalの項目が入ります。読む前に確認する、とあります。 - 途中切れ:出力が上限に達すると、
statusがincomplete、incomplete_details.reasonがmax_output_tokensになります。例では、この2つを確認してから解析しています。ほかに、コンテンツフィルターで中断される場合もあり、その扱いが例に出ています。 - 初回の遅れ:「どんなスキーマでも、最初のリクエストはスキーマを処理するぶん遅れる。同じスキーマの2回目以降は遅れない」と書かれています。
Anthropic
公式のStructured outputsの文書によると、次の通りです。
- 2つの機能:JSON出力(
output_config.format。返事全体を固定)と、厳密な道具の使用(strict: true。道具の名前と引数を固定)。別々にも、同時にも使えます。 - 対応:Fable 5/5.1、Mythos 5/5.1/Preview、Opus 4.5〜4.8/5/5.5、Sonnet 4.5/4.6/5/5.5、Haiku 4.5/5.5。対応の場所として、Claude API、Claude Platform on AWS、Amazon Bedrock、Google Cloud、Microsoft Foundryが挙げられています。Bedrockについては、10月8日に読んだ版に「旧来の統合(Opus 4.6以前)のみの対応」という趣旨の脚注がありました。10月22日に取り直した版では、その脚注が見つからず、サイドバーに「Opus 4.7 and later」「Opus 4.6 and earlier」の2ページがあるだけでした。どちらで使えるかは、確認できていません。
- 拒否:
stop_reason: "refusal"で、HTTPは200、生成されたトークンには課金されます。拒否の文言が優先されるので、出力がスキーマに合わないことがあります。モデルの思考を欄に書かせようとすると、reasoning_extractionの拒否になることがあるので、短い説明を求めるように、と書かれています。 - 途中切れ:
stop_reason: "max_tokens"のとき、出力が不完全でスキーマに合わない場合があります。max_tokensを上げて再試行します。 - 大文字小文字:
enumとconstの文字列は、大文字小文字が変わることがあります(空白のあとの語頭など)。特別なstop_reasonは出ません。比べるときは大文字小文字を無視します。 - 文法の準備:最初のリクエストでは、スキーマの文法のコンパイルのために遅れが出ます。コンパイル結果は、最後の使用から24時間キャッシュされます。スキーマの構造や道具の組を変えるとキャッシュは無効になりますが、
nameとdescriptionだけの変更なら無効になりません。 - 項目の順序:必須項目がスキーマの順に先に来て、そのあとに任意項目がスキーマの順で来ます。順序が重要なら、全項目を必須にします。
- 追加のコスト:出力の形を説明するシステム用の文が追加され、入力トークンが増えます。
output_config.formatを変えると、その会話のプロンプトキャッシュ(同じ前置きを安く読み直す仕組み)が無効になります。 - 併用できない:引用機能(citations)を有効にして
output_config.formatを使うと400エラー。メッセージの先頭書き込み(prefilling)とも併用できません。 - 併用できる:バッチ(50%割引)、トークン数の計算、ストリーミング。
- SDK:Pythonでは
client.messages.parse()にPydanticモデルを渡し、検証済みの結果をparsed_outputで受け取れます。以前のベータ用のoutput_format引数は非推奨で、output_config.formatを使います。
公式文書の例の一部です(この記事では実行していません)。
output_config={
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {"name": {"type": "string"},
"demo_requested": {"type": "boolean"}},
"required": ["name", "demo_requested"],
"additionalProperties": False,
},
}
},
Google(Gemini)
Geminiの構造化出力の文書(generateContent版とInteractions版)によると、次の通りです。
- 有効にする:Interactions版の文書では、
response_formatを指定し、MIMEタイプをapplication/jsonにして、スキーマを渡します。generateContent版の文書では、生成設定にresponse_mime_type(application/json)とスキーマ(response_json_schema)を渡す書き方で、出力の項目はスキーマの順に並ぶ、とあります。スキーマは有効なJSONスキーマであること、と書かれています。 - 使える型とキーワード:
string、number、integer、boolean、object、array、null(型の配列で表す。例:["string", "null"])。オブジェクトはproperties、required、additionalProperties。文字列はenumとformat(date-time、date、time)。数値はenum、minimum、maximum。配列はitems、prefixItems、minItems、maxItems。再帰(自分自身を参照)の例もあります。 - 制約の書き方:JSONスキーマの一部だけの対応で、非対応の項目はモデルに無視される、と書かれています。非常に大きい、または深くネストしたスキーマは拒否されることがあるが、数値の上限は書かれていません。
- 対応:generateContentの文書には、Gemini 4 Argon、3.8 Flash、3.6 Flash、3.1 Pro Preview、2.5系、2.0系などが並んでいます(2.0系は
propertyOrderingの指定が要る、とあります)。道具との併用はプレビューで、generateContent版の文書では、Gemini 4系と3系のみ、とあります(Interactions版の文書は「Gemini 3系のみ」)。 - ストリーミング:出力は「連結すれば完全なJSONになる、部分的なJSON文字列」で届きます。
- 失敗:文書は、特定のエラーの返り方を書いていません。文法的に正しいJSONは保証されるが、値が意味として正しいとは限らないので、アプリ側で検証するように、と書かれています。
OpenAIの関数呼び出しの`strict`と、道具の呼び出しの流れ
OpenAIの関数呼び出しの文書によると、strictは「関数呼び出しを厳密モードにするか」を示す項目で、例では"strict": trueと、"additionalProperties": false、全項目をrequiredに入れる書き方が使われています。ただし、これらを必須条件として明記した文はありませんでした。
呼び出しの流れは、次の5段階です。
- 呼べる道具の一覧を付けてモデルに送る。
- 応答の
outputにfunction_callが入る。中身はcall_id、name、JSON文字列のarguments。 - 自分のプログラムで関数を実行する。
- 道具の出力を、
call_idで元の呼び出しに結びつけて、2回目のリクエストで返す。 - 最終の応答、または次の道具の呼び出しを受け取る。
応答は、道具の呼び出しがゼロ、1つ、複数のどれにもなりうるので、複数ある前提で書くのがよい、と文書にあります。一度に使える道具の数に厳密な上限は書かれておらず、「ターンの開始時に20個未満が目安」という弱い提案があります。
道具の呼び出しの仕組みそのものは、別記事「ツール呼び出し」で扱います。
選び方・判断の基準
見立てです。次の考え方が無難だと思います。
- 返事をそのままプログラムに渡す(分類、情報抽出、フォームの自動入力):構造化出力を使います。自由な文章の返事から正規表現で抜き出すより、壊れにくいはずです。
- 道具(関数)の引数を、必ず決まった形にしたい:OpenAIとAnthropicの
strictが合います。ただしAnthropicは数の上限があるので、必要な道具だけを厳密にします。 - 値の正しさが重要な処理(金額、日付、人の名前):形が合うことと、値が正しいことは別です。アプリ側で、範囲や整合性を検証します。
- 小さな形から始める:公式文書がそろって、複雑で深いスキーマは通らないことがある、と書いています。まず平らで小さな形で試し、必要に応じて広げるのが無難です。
よくある失敗・つまずき
- 拒否を見ずに解析する。拒否のときは形に合わない文字が返ることがあります。OpenAIは
refusalの項目、Anthropicはstop_reasonを先に確認します。 - 出力の上限が小さくて途中で切れ、不完全なJSONになる。OpenAIは
incomplete、Anthropicはmax_tokensで気づけます。 enumの大文字小文字がずれる(Anthropicの文書が明記)。- スキーマが複雑すぎる。Anthropicでは400エラー「Schema is too complex for compilation」になります。
- 引用機能や先頭書き込みと一緒に使う(Anthropicでは併用不可)。
- スキーマを頻繁に変える。初回は文法の準備で遅れ、Anthropicではキャッシュも切れます。
Anthropicのスキーマの複雑さの上限(公式の数値)
Anthropicの文書によると、output_config.formatまたはstrict: trueを使うリクエストには、次の上限があります。
| 項目 | 上限 |
|---|---|
| 1リクエストの厳密な道具 | 20個 |
| 任意の(必須でない)パラメータ(全スキーマの合計) | 24個 |
共用体型(anyOfや型の配列)を持つパラメータ |
16個 |
| コンパイルのタイムアウト | 180秒 |
上限を超えると、400エラー「Schema is too complex for compilation」が返ります。対策として、本当に必要な道具だけを厳密にする、パラメータを必須にする、ネストを平らにする、道具をリクエストやサブエージェントに分ける、が挙げられています。
また、SDKの補助機能は、minimum、maximum、minLength、maxLengthなどの非対応の制約をスキーマから外して、項目の説明文に移す、と書かれています。SDKが検証するときには、元の制約で確認します。
OpenAIとGoogleの文書では、これに相当する数値の上限は、読んだ範囲に見つかりませんでした。
気をつけること
- この記事は、実際に使って確かめた記録ではありません。内容は公式文書の記載です。
- OpenAIの文書は、長いため、読んだ範囲で見つからなかった項目があります。スキーマの「根はオブジェクトでなければならない」「プロパティ数の上限」「ネストの深さの上限」などは、確認できていません。
- Googleの文書は、拒否や途中切れ、エラーの返り方を書いていません。「ない」とは断定できません。
- OpenAIの対応モデルは、文書に「GPT-4o以降」とあり、新規にはgpt-6-astraを勧めています。実際に自分の使うモデルで使えるか、確認してください。
- Anthropicの文書の「Not supported」の節は、10月8日には中身を取り出せませんでしたが、10月22日の取り直しで読めました。再帰的なスキーマ、外部
$ref、minimum・maximum・multipleOf、minLength・maxLength、minItemsが0か1以外の配列、false以外のadditionalProperties、一部の正規表現(後方参照、先読み・後読みなど)が挙げられています。要約を通して読んだので、使う前に、公式ページの「Supported features」と「Not supported」を直接確認してください。 - OpenAIの構造化出力の文書は、10月22日に取り直した版では、使えるスキーマの一覧が「see supported schemas」と参照されるだけで、中身は要約に出てきませんでした。
incompleteの扱いや、初回の遅れの記述も、今回の取り直しでは見つかっていません。この記事のそれらの記述は、10月8日に読んだ内容のままで、10月22日には再確認できていません。 - 「保証」の範囲は、会社ごとに言葉が違います。値の意味の正しさ、拒否、途中切れは、保証の外にあります。
- データの扱い:Anthropicの文書では、スキーマは最後の使用から最大24時間キャッシュされ、医療情報(PHI)はスキーマの定義(項目名、
enum、const、pattern)に入れてはいけない、と書かれています。個別の判断は専門家に相談してください。 - 仕様、対応モデル、上限は変わることがあります。
出典
- Structured model outputs(OpenAI API、OpenAI、2026年10月22日確認)
- Function calling(OpenAI API、OpenAI、2026年10月22日確認)
- Structured outputs(Claude Platform Docs、Anthropic、2026年10月22日確認)
- Structured output(Gemini API、Google AI for Developers、Google、2026年10月22日確認)
- Structured output(generateContent、Google AI for Developers、Google、2026年10月22日確認)
更新履歴
-
2026年10月25日 書き方を直しました。
- 前:運営者が使っていないと読める書き方 → いま:「この記事は、実際に使って確かめた記録ではありません」。公式の資料を読んでまとめた記事で、使い心地は書いていない、という意味に直した
-
2026年10月22日 公式の資料を読み直して、次の点を直しました。
- 前:Geminiで道具と併用できるのはGemini 3系のみ(プレビュー) → いま:generateContent版はGemini 4系と3系、Interactions版は3系のみ
- 前:Gemini対応モデルは3.1 Pro Preview、3.5 Flash、2.5系など → いま:Gemini 4 Argon、3.8 Flash、3.6 Flash、3.1 Pro Preview、2.5系、2.0系など
- 前:Bedrockは旧来の統合(Opus 4.6以前)のみ対応 → いま:その脚注が見つからず、どちらで使えるか確認できていません
- 前:Anthropicの「Not supported」の中身は取り出せなかった → いま:読めた。再帰的なスキーマ、外部の$refなどが挙げられています
- 前:Geminiはresponse_formatで指定 → いま:generateContent版はresponse_mime_typeとresponse_json_schemaを渡す書き方
- 前:OpenAIのincompleteの扱いなどを記載 → いま:取り直した版では見つからず、10月8日の内容のままです
一部の出典は読めなかったため、その部分は前のままです。
