← ブログに戻る

OpenAI Structured Outputs完全ガイド:GPTにJSON Schema準拠のJSONを安定出力させる方法?

OpenAI Structured Outputs完全ガイド:GPTにJSON Schema準拠のJSONを安定出力させる方法?

GPTの出力をデータベース、API、キュー、Agent実行器へ接続する開発者向けの記事です。Structured Outputsとstrict modeの使い分け、Schema設計、拒否・途中終了の処理、業務ルール検証、回帰テストまでを用途別に整理します。

OpenAIの2024年8月6日の発表では、gpt-4o-2024-08-06のStructured Outputs評価が複雑なSchema追従テストで100%、比較対象のgpt-4-0613は40%未満でした。ただし、これは当時の特定モデルと評価条件の結果であり、現在のすべてのモデルにその数値を適用できる意味ではありません。(openai.com)

したがって、OpenAI Structured Outputs完全ガイドの結論は、普通のJSON指示やJSON modeだけに頼らず、対応範囲を確認したJSON Schemaとstrict modeを使い、拒否・途中終了・業務上の意味まで別々に検証することです。 構造の正しさは高められますが、値の真実性や業務ルールへの適合までは自動保証されません。

この内容は、GPT APIの結果を安定してパースしたいバックエンド開発者、出力をデータベースやキューへ流したいデータエンジニア、最終回答とツール引数を同時に制約したいAgent開発者に向いています。

まずStructured Outputsの役割を分けて理解する

GPTの出力を外部システムへ渡す場合、問題は「JSONとして読めるか」だけではありません。次の制約が同時に関係します。

  • 指定したフィールドが欠落していないか。
  • 文字列、数値、配列、オブジェクトの型が一致しているか。
  • 想定外のキーが混入していないか。
  • モデルが安全上の理由で拒否していないか。
  • 出力が上限に達して途中で切れていないか。
  • 値がデータベースの状態や権限条件と一致しているか。

OpenAIの公式説明では、Structured Outputsはresponse_formatjson_schema、またはFunction Callingのツール定義にstrict: trueを指定して利用します。前者は最終回答や抽出結果、後者は外部関数へ渡す引数の制約に向いています。(openai.com)

用途 設定の中心 検証後に追加すべき確認
文書からのデータ抽出 response_formatjson_schema 値の根拠、重複、欠損
分類・ルーティング enumを含むSchema 未確定状態、信頼度、人手確認
Agentのツール引数 Function Callingとstrict: true 権限、対象リソース、状態遷移
画面表示用データ 構造化されたレスポンス 日付、ID、金額、表示安全性
バッチ処理・データ連携 Schemaバージョンとログ 再実行、互換性、監査履歴

抽出処理では小さく閉じたSchemaから始める

請求書や議事録から項目を抽出する場合、最初から巨大なSchemaを作ると、項目の意味が曖昧になり、変更時の影響範囲も広がります。まずは必要なフィールドだけを持つオブジェクトにし、配列の要素、必須項目、追加キーの扱いを明示します。

{
  "type": "object",
  "properties": {
    "customer_name": {
      "type": "string",
      "description": "請求先の正式名称。不明な場合は空文字ではなく確認状態を返す"
    },
    "invoice_number": {
      "type": "string",
      "description": "請求書番号"
    },
    "total_amount": {
      "type": "number",
      "description": "請求総額。通貨単位は入力文書に従う"
    }
  },
  "required": [
    "customer_name",
    "invoice_number",
    "total_amount"
  ],
  "additionalProperties": false
}

additionalProperties: falseは、下流処理が知らないキーを受け取らないための境界になります。反対に、後から追加する可能性がある項目を必須にすると、Schema更新時に旧データとの互換性を壊しやすくなります。

プロンプトで「JSON形式で返してください」と指示するだけでは、キー名の揺れ、説明文の混入、不要なフィールドの追加が起こり得ます。JSON modeはJSON生成のための旧来の形式であり、対応モデルではjson_schemaの利用が推奨されています。(platform.openai.com)

分類処理ではenumに未知状態を用意する

カテゴリ分類や処理ルートの振り分けでは、自由記述のcategoryを許すと、同じ意味でも異なる文字列が返り、集計や分岐が不安定になります。業務で利用する値をenumへ限定し、判断できない場合の選択肢もSchemaに含めます。

{
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": [
        "billing",
        "technical",
        "account",
        "unknown"
      ],
      "description": "入力だけで確定できない場合はunknownを選ぶ"
    },
    "needs_human_review": {
      "type": "boolean",
      "description": "担当者による確認が必要か"
    }
  },
  "required": [
    "category",
    "needs_human_review"
  ],
  "additionalProperties": false
}

重要なのは、モデルに無理な断定をさせないことです。unknownneeds_human_reviewを用意すれば、分類不能な入力を合法的なJSONとして受け止めながら、別の審査ルートへ送れます。正解らしいカテゴリを必ず選ばせる設計は、構造エラーを減らしても誤ルーティングを増やします。

ツール引数と最終回答を別の契約として設計する

Agentでは、ツールを呼び出すための引数と、利用者へ返す最終回答を同じSchemaで管理しない方が安全です。たとえば注文検索ツールの引数にはcustomer_idや期間を定義し、最終回答には検索結果、説明、追加確認の要否を定義します。

Function Callingでstrict: trueを指定すると、生成される関数引数を定義済みSchemaへ合わせることができます。ただし、引数の型が正しくても、そのIDを実行者が利用できるとは限りません。OpenAIのFunction Calling案内も、Structured Outputsまたは検証ライブラリを使い、アプリケーション側で処理することを説明しています。(help.openai.com)

実行前には、少なくとも次を確認します。

  • 呼び出し元ユーザーに対象リソースへの権限があるか。
  • 指定されたIDが存在し、現在の状態で操作可能か。
  • 金額、数量、対象期間が業務上許容される範囲か。
  • 同じ操作を再実行しても二重登録や二重請求にならないか。
  • parallel_tool_callsを許可する設計が本当に安全か。

特に書き込み系ツールでは、Schema検証を認可処理の代わりにしてはいけません。Schemaは「形」を制約する契約であり、権限や在庫、承認状態を判定する機能ではありません。

注意:Structured Outputsを有効にしても、モデルが返す日付、識別子、金額、関連付けが事実と一致するとは限りません。Schema検証を通過したデータを、そのまま本番の書き込み処理へ渡さない設計が必要です。

画面表示と下流APIでは意味の検証を追加する

画面表示用のレスポンスでは、文字列や数値の型が合っているだけでは不十分です。日付がISO形式でも存在しない日付や前後逆転した期間は残り、金額が数値でも通貨単位が欠ければ誤表示になります。

そのため、検証は次の三層に分けます。

  1. Schema検証:必須項目、型、配列、列挙値、追加キーを確認します。
  2. 意味検証:日付の前後、関連IDの一致、金額の範囲、状態遷移を確認します。
  3. 永続化検証:データベースの外部キー、ユニーク制約、権限、トランザクション条件を確認します。

たとえばstart_dateend_dateがどちらも正しい文字列でも、開始日が終了日より後なら業務上は不正です。JSON Schemaだけで表現しにくい条件は、アプリケーションのバリデーターやデータベース制約へ移します。

OpenAIの公式発表でも、Structured OutputsはSchemaに合わせる一方、JSON内部の値についてモデルが誤る可能性を排除しないと説明されています。(openai.com)

拒否と途中終了は再試行前に分類する

構造化出力の失敗をすべて「JSONパースエラー」として扱うと、原因を見失います。少なくとも、次の三つを分けて保存します。

  • refusalがある:安全上の理由などで、通常のSchema本文ではなく拒否が返った状態です。
  • finish_reasonやレスポンス状態が途中終了:出力上限や停止条件により、JSONが完成していない可能性があります。
  • Schemaや実装の不一致:対応していない記法、必須項目の設計、SDK設定の誤りなどです。

OpenAIの資料では、拒否の場合にrefusalを検出でき、途中で生成が停止した場合もSchemaどおりにならない可能性があるとされています。(openai.com)

拒否に対して同じ入力を無条件に再送すると、同じ結果を繰り返すだけです。途中終了なら入力を分割する、出力項目を減らす、出力上限を見直すといった対策が候補になります。どのケースでも、元のレスポンス、エラー種別、モデル識別子、Schemaバージョンを保存しておくと再現調査が可能になります。

FAQで実装判断を確認する

OpenAIはJSON Schemaに合う出力をどのように保証しますか?

Structured Outputsでstrict: trueを有効にすると、対応するJSON Schemaの範囲内で出力を制約できます。ただし、拒否や途中終了は別の状態として返るため、まずレスポンス状態を判定し、その後にJSONパースとSchema検証を行います。(openai.com)

Structured OutputsとJSON modeは何が違いますか?

JSON modeはJSONとして読める形式を目指しますが、指定したSchemaへの一致を保証する機能ではありません。Structured Outputsはjson_schemastrict modeを使って、対応するSchemaへの一致を目的にするため、データベースやAPI連携ではこちらを優先します。(platform.openai.com)

GPTの構造化出力が解析に失敗する理由は何ですか?

拒否、出力上限による途中終了、未対応のSchema記法、必須項目や追加キー設定の不整合が代表的です。解析前にレスポンスの終了状態を確認し、失敗時は元データとSchemaバージョンを保存します。無条件の再試行だけでは、設計上の不具合を解消できません。

Structured Outputsでrefusalが返った場合はどう処理しますか?

refusalを通常のJSON本文としてパースせず、拒否専用の分岐へ送ります。利用者へ代替入力を案内する、担当者確認へ回す、監査ログへ保存するなどの処理を行い、拒否文を無理にSchemaへ詰め込まないことが重要です。(openai.com)

JSON Schemaの検証後も業務チェックは必要ですか?

必要です。Schemaは型や必須項目を確認しますが、日付の前後関係、金額の妥当性、IDの存在、権限、在庫、承認状態までは保証しません。Schema検証、業務ルール、データベース制約、人手確認を段階的に組み合わせます。

本番データパイプラインを回帰テストで守る

本番投入前には、正常系だけでなく、境界値、空入力、長文、悪意のある指示、未知カテゴリ、拒否対象、途中終了を含むテストケースを用意します。Schemaを変更する場合は、フィールド追加や列挙値変更をバージョンとして記録し、旧データを再処理できる状態にします。

次のチェック項目をリリース前の受け入れ条件にすると、単純なパース成功だけでは見えない不具合を拾えます。

  • [ ] strict: trueを指定し、利用モデルが対象機能に対応していることを確認した。
  • [ ] Schemaの必須項目とadditionalPropertiesを明示した。
  • [ ] 未知、該当なし、人手確認の状態を用意した。
  • [ ] refusalと途中終了を通常レスポンスから分離した。
  • [ ] Schema検証後に日付、金額、ID、権限を検証した。
  • [ ] 元のレスポンス、モデル、Schemaバージョン、エラー種別を保存した。
  • [ ] 正常、境界、悪意、拒否、Schema更新の回帰ケースを実行した。
  • [ ] 書き込み系ツールで二重実行を防ぐ仕組みを確認した。

連続バッチやApple向け開発パイプラインを長時間動かす場合は、実行場所の選定も運用条件になります。短期の検証やリリース前の回帰テストなら、必要な期間だけ使える日本リージョンのMac環境を比較対象にできます。海外向けの依存関係や検証が必要な場合は、米国西部のMac環境を候補にし、SDK、モデル、Schemaの組み合わせを固定して確認します。

現行環境とMac環境を運用条件で比較する

既存のWindowsやLinux環境、共有サーバー、短期のCI実行器は、初期検証には便利です。一方で、Apple向けの署名、Xcode依存のビルド、特定のmacOS環境を含む回帰テストでは、OS差分、権限設定、物理Macの空き時間、実行環境の再現性が負担になる場合があります。

その場合、必要な期間だけnuvcloudのMac環境を使う方法は、常駐設備を増やさずに検証環境を分離する選択肢になります。ただし、長期にわたる安定した高負荷処理、物理ポート、専用周辺機器、社内規定上の完全な物理占有が必要なら、自社購入や常設環境の方が適しています。構造化データの検証を短期導入するチームは、まず上のチェック項目を受け入れ条件にし、タスクの周期と実行時間を測ってから一時利用か常駐構成かを決めると、判断を誤りにくくなります。

Structured Outputsの検証環境を、nuvcloudで安定運用へ

nuvcloudなら、専有Mac mini M4を使ってJSON生成処理や業務ルール検証の実行環境をすぐに用意できます。

SSHとVNCに対応しているため、自動テストやCI処理からデスクトップ操作まで、用途に応じて柔軟に接続できます。

関連記事

期間限定オファー →