マガジン

構造化出力をOpenAI・Claude・Geminiで比べる:JSONスキーマ指定の違いと選び方

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

三つの仕切り箱に小片を分類する手元
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

3社とも、JSONスキーマを渡して出力の形を縛れます。違いが出るのは「スキーマをどこに書くか」と「スキーマのどの記法まで使えるか」の2点です。さらに、縛れるのは形だけで、中身の正しさは保証されません。 まず選び方の結論です。 • 複数社を切り替える可能性があるなら、全項目必須・additionalProperties: false・文字数や数値範囲の制約なしという最小公倍数のスキーマにします。 • 範囲や件数をスキーマ側で強制したいなら、記法が広いGeminiが向きます。ただし文字数制約は無視されます。 • ツール呼び出しの引数も厳密にしたいなら、Claudeのstrict: trueが使えます。ただし複雑さの上限があります。 この記事は、2026年10月27日に読んだ各社の公式ページに基づきます。各社の仕様は変わるため、実装前に必ず原典で再確認してください。サンプルコードやスキーマは説明用の例で、実際には実行していません。

この記事の目次
  1. 3社の比較表
  2. 指定方法の違い
  3. 記法の制約を読み比べる
  4. 3社で動かしやすい共通スキーマの作り方
  5. 判断表
  6. 導入前に確認すること
  7. 実装を依頼するときの文面

3社の比較表

  • 指定場所、OpenAI:text.formatにtype: "json_schema"とstrict: true、schemaを置く、Claude:output_config.formatにtype: "json_schema"とschemaを置く、Gemini:Interactions APIではresponse_formatにtype: "text"、mime_type: "application/json"、schemaを置く
  • ツール引数の厳密化、OpenAI:今回読んだ範囲では未確認、Claude:ツール定義にstrict: trueを付ける、Gemini:構造化出力とツールの併用はGemini 3系のプレビュー(引数の厳密化とは別機能)
  • 必須項目、OpenAI:全項目をrequiredに入れる、Claude:requiredを使える、Gemini:requiredを使える
  • additionalProperties、OpenAI:falseにする、Claude:falseのみ可、Gemini:キーワードとして利用可
  • 任意項目の表現、OpenAI:nullとの合併型(例:stringまたはnull)、Claude:任意項目は数に上限あり、Gemini:requiredから外せる
  • 数値の範囲、OpenAI:今回確認できず、Claude:minimum/maximumは不可、Gemini:minimum/maximumを利用可
  • 文字数、OpenAI:今回確認できず、Claude:minLength/maxLengthは不可、Gemini:無視される
  • 配列の件数、OpenAI:今回確認できず、Claude:minItemsは0か1のみ、Gemini:minItems/maxItemsは強制される
  • 再帰スキーマ、OpenAI:今回確認できず、Claude:不可、Gemini:可
  • 拒否・途中終了、OpenAI:refusalフィールドとstatusで判別、Claude:stop_reasonがrefusal/max_tokensになる、Gemini:400エラー(複雑すぎる場合)を確認
  • 初回の遅延、OpenAI:スキーマごとに初回のみ増える、Claude:初回は文法のコンパイルで遅れ、24時間キャッシュ、Gemini:今回確認できず

「今回確認できず」は、私が開いたページの範囲では数値や可否を読み取れなかったという意味です。「使えない」という意味ではありません。

指定方法の違い

OpenAI

OpenAIの構造化出力ガイドでは、text: { format: { type: "json_schema", strict: true, schema: ... } }の形で指定します。JSONモードは「有効なJSON」までしか保証しません。構造化出力は、スキーマへの適合まで保証します。ガイドも、可能なら構造化出力を使うよう勧めています。

上のコードは、読んだページで確認できたキーだけを抜き出したものです。実際のリクエストにはスキーマ名など追加の項目が要る場合があります。必ず原典のサンプルと照らしてください。

Claude

Claudeの構造化出力ガイドでは、output_config.formatにtype: "json_schema"を指定します。ガイドには、旧パラメータのoutput_formatは非推奨で、output_config.formatへ移行するよう書かれています。古い記事のコードをそのまま使うと動かない恐れがあります。

もう一つの機能が、ツール定義へのstrict: trueです。出力全体の形を縛る機能と、ツール呼び出しの引数を縛る機能は別物で、同じリクエストで併用できます。

Gemini

Geminiの構造化出力ガイドの現行サンプルでは、response_formatにtype: "text"、mime_type: "application/json"、schemaを置いています。サンプルはInteractions APIの形式でした。既存コードで別の呼び出し形式を使っている場合、パラメータ名が違う可能性があります。この記事ではその対応関係までは確認していません。

記法の制約を読み比べる

Claudeは「許可リスト」が狭い

公式ガイドによると、Claudeで使えない主なものは次のとおりです。

  • 再帰スキーマ
  • minimum、maximum、multipleOf
  • minLength、maxLength
  • additionalPropertiesをfalse以外にすること
  • 外部の$ref

enum、const、anyOf、allOf(制限あり)、社内定義の$ref、date-timeやemail、uuidなどのformatは使えます。

また、複雑さにも上限があります。1リクエストあたり、strictなツールは20個、任意パラメータは合計24個、anyOfなどの合併型を使うパラメータは16個までです。超えると「Schema is too complex for compilation」のようなエラーになります。

SDKのヘルパーを使うと、未対応の制約はスキーマから外されてdescriptionに書き足され、受け取った結果は元のスキーマで検証されます。たとえばminimum: 100は、API側には単なる整数として届きます。モデルへの縛りは弱くなるが、アプリ側の検証は残るという動きです。

Geminiは範囲指定に強く、文字数には効かない

Geminiはminimum/maximum、minItems/maxItems、prefixItems、再帰スキーマに対応しています。反対に、minLength、maxLength、minProperties、maxPropertiesなどは強制されません。

ここで混乱しやすいのは、エラーにならずに無視される点です。文字数の上限を書いたつもりでも効きません。

加えて、大きすぎるmaxItemsや、非常に長いプロパティ名・enum名が原因で、400 INVALID_ARGUMENTになることがあります。

OpenAIは「全項目必須」が出発点

OpenAIのガイドでは、すべてのプロパティをrequiredに入れ、additionalProperties: falseを指定します。任意項目は、型をnullとの合併にして表します。ガイドは、深さやプロパティ数に上限があること、一部のキーワードが非対応であることも述べています。ただし具体的な数値と一覧は、私が読めた範囲には含まれていませんでした。実装前に、同ガイドの「Supported schemas」節で確認してください。

3社で動かしやすい共通スキーマの作り方

上の制約を重ね合わせると、設計ルールが見えてきます。以下は読み比べからの編集上の提案です。

  1. ルートはobjectにする。
  2. 全プロパティをrequiredにし、additionalProperties: falseを付ける。
  3. 任意項目は省略せず、["string", "null"]のようにnullを許す。ただしClaudeは合併型の数に上限があるため、多用しない。
  4. 文字数、数値の範囲、件数の制約はスキーマに頼らない。説明文に書き、アプリ側で検証する。
  5. 分類はenumで固定する。
  6. 深い入れ子や再帰は避け、必要なら分割して複数回呼ぶ。

説明用の例として、問い合わせメールを分類するスキーマを示します。

json
{
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": ["billing", "bug", "feature_request", "other"]
    },
    "summary": {
      "type": "string",
      "description": "要点を日本語で。80字以内を目安にする"
    },
    "order_id": {
      "type": ["string", "null"],
      "description": "メールに記載がなければnull"
    }
  },
  "required": ["category", "summary", "order_id"],
  "additionalProperties": false
}

このschemaの部分を、各社の指定場所に差し替えます。

  • OpenAI:text.format.schema
  • Claude:output_config.format.schema
  • Gemini:response_format.schema

「80字以内」はスキーマで強制されないので、descriptionに目安を書き、受け取ったあとで文字数を数えます。

判断表

  • 3社を切り替える・比較する、向く選択:共通スキーマ(全項目必須、制約なし)を作り、検証はアプリ側に集約する
  • 数値の範囲や件数をAPI側で強制したい、向く選択:Geminiのminimum/maximum、minItems/maxItemsを検討する
  • ツール呼び出しの引数も厳密にしたい、向く選択:Claudeのstrict: trueを検討する。strictツールは20個まで
  • スキーマが大きく入れ子が深い、向く選択:先に分割する。Claudeは複雑さの上限、Geminiは400エラーに注意する
  • 再帰構造(ツリー)を出したい、向く選択:Geminiの再帰対応を検討する。Claudeは非対応

導入前に確認すること

導入前の確認は、次の順で進めます。

  1. 共通スキーマで3社に同じ入力を送り、パースできるか確認する。テスト入力は、個人情報を含まない説明用のデータにしてください。
  2. 拒否や途中終了を必ずテストする。
  • OpenAIはrefusalフィールドとstatusを見ます。
  • Claudeはstop_reasonのrefusalとmax_tokensを見ます。ガイドによると、拒否の場合は出力がスキーマに合わないことがあります。max_tokensの場合は途中で切れるので、上限を上げて再試行します。
  1. 値の正しさをアプリ側で検証する。Geminiの公式資料も、構文は正しくても内容が正確とは限らないので、値を検証するよう述べています。形が正しいことと、中身が正しいことは別です。
  2. スキーマを変えたときの影響を確認する。Claudeでは、スキーマ構造の変更で文法キャッシュが、output_config.formatの変更でプロンプトキャッシュが無効になります。

Claudeにはもう一つ注意点があります。enumの文字列が、大文字小文字だけスキーマと違って返ることがあると書かれています。比較は大文字小文字を区別しない形にしておくと安全です。

実装を依頼するときの文面

コード生成AIに実装を頼むなら、次のように渡します。説明用のひな形です。

次のJSONスキーマを、OpenAI(text.format)、Claude(output_config.format)、
Gemini(response_format)の各APIで使う3つのリクエスト本文に変換してください。
条件:
- 各社の公式ドキュメントのURLを私が貼るので、その記述にあるキー名だけを使う
- 公式に書かれていないキーは推測せず「要確認」と書く
- スキーマに文字数・数値範囲の制約を足さない
- 拒否・途中終了を検出する分岐を各社ぶん入れる

生成されたコードは、人が公式サンプルと突き合わせてから動かしてください。キー名を推測で補われると、この記事で触れたような旧パラメータの混入が起きやすくなります。

出典・参考資料