For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
メインナビゲーション

モデルの構造化出力

モデルのテキスト応答を、定義した JSON スキーマに準拠させます。

JSON は、アプリケーション間のデータ交換に世界で最も広く使われている形式のひとつです。

構造化出力は、指定した JSON Schema にモデルの応答が常に準拠することを保証する機能です。必須キーの欠落や、ハルシネーションによる無効な列挙値の生成を心配する必要がなくなります。

構造化出力には、次のような利点があります。

  1. 確実な型安全性: 形式が正しくない応答の検証や再試行が不要
  2. 明示的な拒否: 安全上の理由によるモデルの拒否をプログラムで検出可能
  3. シンプルなプロンプト: 出力形式を統一するために、強い表現で指示するプロンプトが不要

REST API での JSON Schema のサポートに加え、OpenAI の Python および JavaScript ライブラリでは、それぞれ pydantic.BaseModelz.object を使ってオブジェクトのスキーマを定義できます。以下では、非構造化テキストから情報を抽出し、コードで定義したスキーマに沿った形式にする方法を紹介します。

Ruby SDK は、Sorbet の T::Struct で定義したスキーマをサポートし、型付きの解析結果を返します。

構造化されたレスポンスの取得
from openai import OpenAI
from pydantic import BaseModel

client = OpenAI()


class CalendarEvent(BaseModel):
    name: str
    date: str
    participants: list[str]


response = client.responses.parse(
    model="gpt-6-astra",
    input=[
        {"role": "system", "content": "Extract the event information."},
        {
            "role": "user",
            "content": "Alice and Bob are going to a science fair on Friday.",
        },
    ],
    text_format=CalendarEvent,
)

event = response.output_parsed

対応モデル

構造化出力は、GPT-4o 以降の最新の大規模言語モデルで利用できます。新しいプロジェクトでは、gpt-6-astra から始めてください。gpt-4-turbo やそれ以前の古いモデルでは、代わりに JSON モードを利用できます。

構造化出力における Function Calling と text.format の使い分け

OpenAI API では、次の 2 つの方法で構造化出力を利用できます。

  1. Function Calling を使用する場合
  2. json_schema 応答形式を使用する場合

Function Calling は、モデルとアプリケーションの機能を連携させるアプリケーションを構築するときに役立ちます。

たとえば、データベースにクエリを実行する関数をモデルに使わせることで、ユーザーの注文をサポートする AI アシスタントを構築できます。また、UI を操作する関数をモデルに使わせることもできます。

一方、ツールの呼び出し時ではなく、ユーザーへの応答時にモデルが従うスキーマを指定したい場合は、response_format による構造化出力が適しています。

たとえば、数学の個別指導アプリケーションを構築している場合、モデルの出力の各部分をそれぞれ異なる方法で表示する UI を生成できるよう、特定の JSON Schema に従ってアシスタントに応答させたいことがあります。

実際の使い分けは次のとおりです。

  • システム内のツール、関数、データなどにモデルを接続する場合は、 Function Calling を使用してください。ユーザーへの応答時に モデルの出力を構造化したい場合は、構造化された text.format を使用してください。

このガイドの以降の内容では、Responses API で Function Calling を使わないユースケースを中心に説明します。構造化出力と Function Calling を組み合わせて使う方法については、

Function Calling

のガイドをご覧ください。

構造化出力と JSON モードの比較

構造化出力は、JSON モードを発展させた機能です。どちらも有効な JSON の生成を保証しますが、スキーマへの準拠を保証するのは構造化出力だけです。構造化出力と JSON モードは、どちらも Responses API、Chat Completions API、Assistants API、Fine-tuning API、Batch API でサポートされています。

可能な場合は、常に JSON モードの代わりに構造化出力を使用することをお勧めします。

ただし、response_format: {type: "json_schema", ...} を使った構造化出力に対応しているのは、gpt-4o-minigpt-4o-mini-2024-07-18gpt-4o-2024-08-06 およびそれ以降のモデルスナップショットのみです。

構造化出力JSON モード
有効な JSON の出力はいはい
スキーマへの準拠はい(対応スキーマを参照)いいえ
対応モデルgpt-4o-minigpt-4o-2024-08-06 およびそれ以降gpt-3.5-turbogpt-4-*gpt-4o-* および対応する GPT-5 モデル
有効化の方法text: { format: { type: "json_schema", "strict": true, "schema": ... } }text: { format: { type: "json_object" } }

思考の連鎖

ユーザーが解法を理解できるように、構造化された形式で段階的に回答を出力するようモデルに指示できます。

思考の連鎖を用いた数学指導のための構造化出力
from openai import OpenAI
from pydantic import BaseModel

client = OpenAI()


class Step(BaseModel):
    explanation: str
    output: str


class MathReasoning(BaseModel):
    steps: list[Step]
    final_answer: str


response = client.responses.parse(
    model="gpt-6-astra",
    input=[
        {
            "role": "system",
            "content": "You are a helpful math tutor. Guide the user through the solution step by step.",
        },
        {"role": "user", "content": "how can I solve 8x + 7 = -23"},
    ],
    text_format=MathReasoning,
)

math_reasoning = response.output_parsed

レスポンスの例

{
  "steps": [
    {
      "explanation": "Start with the equation 8x + 7 = -23.",
      "output": "8x + 7 = -23"
    },
    {
      "explanation": "Subtract 7 from both sides to isolate the term with the variable.",
      "output": "8x = -23 - 7"
    },
    {
      "explanation": "Simplify the right side of the equation.",
      "output": "8x = -30"
    },
    {
      "explanation": "Divide both sides by 8 to solve for x.",
      "output": "x = -30 / 8"
    },
    {
      "explanation": "Simplify the fraction.",
      "output": "x = -15 / 4"
    }
  ],
  "final_answer": "x = -15 / 4"
}

text.format による構造化出力の使い方

構造化出力での拒否

ユーザーが生成した入力に構造化出力を使用すると、OpenAI のモデルが安全上の理由でリクエストへの対応を拒否することがあります。拒否の応答は、response_format で指定したスキーマに必ずしも従わないため、API レスポンスには、モデルがリクエストへの対応を拒否したことを示す refusal という新しいフィールドが含まれます。

出力オブジェクトに refusal プロパティが含まれる場合は、拒否の内容を UI に表示したり、レスポンスを処理するコードに条件分岐を追加して、リクエストが拒否された場合に対応したりできます。

class Step(BaseModel):
    explanation: str
    output: str


class MathReasoning(BaseModel):
    steps: list[Step]
    final_answer: str


response = client.responses.parse(
    model="gpt-6-astra",
    input=[
        {
            "role": "system",
            "content": "You are a helpful math tutor. Guide the user through the solution step by step.",
        },
        {"role": "user", "content": "how can I solve 8x + 7 = -23"},
    ],
    text_format=MathReasoning,
)

for output in response.output:
    if output.type != "message":
        continue

    for item in output.content:
        if item.type == "refusal":
            # If the model refuses to respond, you will get a refusal message
            print(item.refusal)
            continue

        if not item.parsed:
            raise Exception("Could not parse response")

        print(item.parsed)

拒否された場合の API レスポンスは、次のようになります。

{
  "id": "resp_1234567890",
  "object": "response",
  "created_at": 1721596428,
  "status": "completed",
  "completed_at": 1721596429,
  "error": null,
  "incomplete_details": null,
  "input": [],
  "instructions": null,
  "max_output_tokens": null,
  "model": "gpt-4o-2024-08-06",
  "output": [{
    "id": "msg_1234567890",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "refusal",
        "refusal": "I'm sorry, I cannot assist with that request."
      }
    ]
  }],
  "usage": {
    "input_tokens": 81,
    "output_tokens": 11,
    "total_tokens": 92,
    "output_tokens_details": {
      "reasoning_tokens": 0,
    }
  },
}

ヒントとベストプラクティス

ユーザーが生成した入力の扱い

アプリケーションでユーザーが生成した入力を使用する場合は、その入力から有効な応答を生成できない状況への対処方法を、必ずプロンプトに含めてください。

モデルは常に指定されたスキーマに従おうとするため、入力がスキーマとまったく無関係な場合は、ハルシネーションが発生する可能性があります。

入力がタスクに適合しないとモデルが判断した場合は、空のパラメーターや特定の文を返すよう、プロンプトで指定できます。

誤りへの対処

構造化出力にも誤りが含まれることがあります。誤りが見つかった場合は、指示を調整する、システム指示に例を含める、タスクをより単純なサブタスクに分割するなどの方法を試してください。入力の調整方法について詳しくは、プロンプトエンジニアリングガイドを参照してください。

JSON スキーマの不整合の防止

JSON Schema とプログラミング言語側の対応する型との不整合を防ぐため、SDK に組み込まれたスキーマヘルパーが利用できる場合は、その使用を強く推奨します。

JSON スキーマを直接指定したい場合は、JSON スキーマまたは基となるデータオブジェクトのいずれかが編集されたことを検知する CI ルールを追加できます。または、型定義から JSON Schema を自動生成する CI ステップ(あるいはその逆を行うステップ)を追加する方法もあります。

ストリーミング

ストリーミングを使うと、モデルの応答や関数呼び出しの引数を生成中に処理し、構造化データとして解析できます。

これにより、応答全体の生成が完了するのを待たずに処理を始められます。 JSON フィールドを 1 つずつ表示したい場合や、関数呼び出しの引数が利用可能になり次第処理したい場合に特に便利です。

構造化出力でストリーミングを扱う際は、SDK の使用をお勧めします。

from openai import OpenAI
from pydantic import BaseModel


class EntitiesModel(BaseModel):
    attributes: list[str]
    colors: list[str]
    animals: list[str]


client = OpenAI()

with client.responses.stream(
    model="gpt-6-astra",
    input=[
        {"role": "system", "content": "Extract entities from the input text"},
        {
            "role": "user",
            "content": "The quick brown fox jumps over the lazy dog with piercing blue eyes",
        },
    ],
    text_format=EntitiesModel,
) as stream:
    for event in stream:
        if event.type == "response.refusal.delta":
            print(event.delta, end="")
        elif event.type == "response.output_text.delta":
            print(event.delta, end="")
        elif event.type == "response.error":
            print(event.error, end="")
        elif event.type == "response.completed":
            print("Completed")  # print(event.response.output)

    final_response = stream.get_final_response()
    print(final_response)

サポートされるスキーマ

構造化出力は、JSON Schema 言語のサブセットをサポートしています。

サポートされる型

構造化出力では、次の型をサポートしています。

  • 文字列
  • 数値
  • 真偽値
  • 整数
  • オブジェクト
  • 配列
  • 列挙型
  • anyOf

サポートされるプロパティ

プロパティの型に加えて、次のような制約を指定できます。

string でサポートされるプロパティ:

  • pattern:文字列が一致する必要のある正規表現
  • format:文字列の定義済み形式。現在サポートされている形式は次のとおりです。
    • date-time
    • time
    • date
    • duration
    • email
    • hostname
    • ipv4
    • ipv6
    • uuid

number でサポートされるプロパティ:

  • multipleOf:数値はこの値の倍数である必要があります。
  • maximum:数値はこの値以下である必要があります。
  • exclusiveMaximum:数値はこの値未満である必要があります。
  • minimum:数値はこの値以上である必要があります。
  • exclusiveMinimum:数値はこの値より大きい必要があります。

array でサポートされるプロパティ:

  • minItems:配列の要素数はこの値以上である必要があります。
  • maxItems:配列の要素数はこの値以下である必要があります。

これらの型の制約を使用する例を紹介します。

{
    "name": "user_data",
    "strict": true,
    "schema": {
        "type": "object",
        "properties": {
            "name": {
                "type": "string",
                "description": "The name of the user"
            },
            "username": {
                "type": "string",
                "description": "The username of the user. Must start with @",
                "pattern": "^@[a-zA-Z0-9_]+$"
            },
            "email": {
                "type": "string",
                "description": "The email of the user",
                "format": "email"
            }
        },
        "additionalProperties": false,
        "required": [
            "name", "username", "email"
        ]
    }
}

ルートはオブジェクトのみ(anyOf は不可)

スキーマのルートはオブジェクトである必要があり、anyOf は使用できません。たとえば Zod では、判別可能なユニオン型を使用するパターンがありますが、これにより最上位に anyOf が生成されます。そのため、次のようなコードは動作しません。

import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";

const BaseResponseSchema = z.object({
  /* ... */
});
const UnsuccessfulResponseSchema = z.object({
  /* ... */
});

const finalSchema = z.discriminatedUnion("status", [
  BaseResponseSchema,
  UnsuccessfulResponseSchema,
]);

// Invalid JSON Schema for Structured Outputs
const json = zodResponseFormat(finalSchema, "final_schema");

すべてのフィールドで required の指定が必須

構造化出力を使用するには、すべてのフィールドまたは関数パラメータを required として指定する必要があります。

{
    "name": "get_weather",
    "description": "Fetches the weather in the given location",
    "strict": true,
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The location to get the weather for"
            },
            "unit": {
                "type": "string",
                "description": "The unit to return the temperature in",
                "enum": ["F", "C"]
            }
        },
        "additionalProperties": false,
        "required": ["location", "unit"]
    }
}

すべてのフィールドを必須にする必要があり、モデルは各パラメータの値を返しますが、null を含むユニオン型を使用すれば、任意のパラメータに相当する動作を実現できます。

{
    "name": "get_weather",
    "description": "Fetches the weather in the given location",
    "strict": true,
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The location to get the weather for"
            },
            "unit": {
                "type": ["string", "null"],
                "description": "The unit to return the temperature in",
                "enum": ["F", "C"]
            }
        },
        "additionalProperties": false,
        "required": [
            "location", "unit"
        ]
    }
}

オブジェクトのネストの深さとサイズの制限

スキーマに含められるオブジェクトのプロパティは合計 5000 個まで、ネストの深さは 10 階層までです。

文字列の合計サイズの制限

スキーマ内のすべてのプロパティ名、定義名、enum 値、const 値の文字列長の合計は、120,000 文字を超えることはできません。

enum のサイズの制限

スキーマに含められる enum 値は、すべての enum プロパティを合わせて 1000 個までです。

文字列値を持つ単一の enum プロパティで、enum 値が 250 個を超える場合、すべての enum 値の文字列長の合計は 15,000 文字を超えることはできません。

オブジェクトでは常に additionalProperties: false の設定が必須

additionalProperties は、JSON Schema で定義されていない追加のキーと値をオブジェクトに含めることを許可するかどうかを制御します。

構造化出力では、指定されたキーと値の生成のみをサポートしています。そのため、構造化出力を利用するには、開発者が additionalProperties: false を設定する必要があります。

{
    "name": "get_weather",
    "description": "Fetches the weather in the given location",
    "strict": true,
    "schema": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The location to get the weather for"
            },
            "unit": {
                "type": "string",
                "description": "The unit to return the temperature in",
                "enum": ["F", "C"]
            }
        },
        "additionalProperties": false,
        "required": [
            "location", "unit"
        ]
    }
}

キーの順序

構造化出力を使用すると、スキーマ内のキーと同じ順序で出力が生成されます。

一部の型固有キーワードは未対応

  • 組み合わせ: allOfnotdependentRequireddependentSchemasifthenelse

ファインチューニング済みモデルでは、さらに次のキーワードもサポートされていません。

  • 文字列の場合: minLengthmaxLengthpatternformat
  • 数値の場合: minimummaximummultipleOf
  • オブジェクトの場合: patternProperties
  • 配列の場合: minItemsmaxItems

strict: true を指定して構造化出力を有効にし、サポートされていない JSON Schema で API を呼び出すと、エラーが返されます。

anyOf 内にネストできるのは、このサブセットに準拠した有効な JSON Schema のみ

サポートされている anyOf スキーマの例を以下に示します。

{
    "type": "object",
    "properties": {
        "item": {
            "anyOf": [
                {
                    "type": "object",
                    "description": "The user object to insert into the database",
                    "properties": {
                        "name": {
                            "type": "string",
                            "description": "The name of the user"
                        },
                        "age": {
                            "type": "number",
                            "description": "The age of the user"
                        }
                    },
                    "additionalProperties": false,
                    "required": [
                        "name",
                        "age"
                    ]
                },
                {
                    "type": "object",
                    "description": "The address object to insert into the database",
                    "properties": {
                        "number": {
                            "type": "string",
                            "description": "The number of the address. Eg. for 123 main st, this would be 123"
                        },
                        "street": {
                            "type": "string",
                            "description": "The street name. Eg. for 123 main st, this would be main st"
                        },
                        "city": {
                            "type": "string",
                            "description": "The city of the address"
                        }
                    },
                    "additionalProperties": false,
                    "required": [
                        "number",
                        "street",
                        "city"
                    ]
                }
            ]
        }
    },
    "additionalProperties": false,
    "required": [
        "item"
    ]
}

定義のサポート

定義を使うと、スキーマ内の各所から参照できるサブスキーマを定義できます。簡単な例を以下に示します。

{
    "type": "object",
    "properties": {
        "steps": {
            "type": "array",
            "items": {
                "$ref": "#/$defs/step"
            }
        },
        "final_answer": {
            "type": "string"
        }
    },
    "$defs": {
        "step": {
            "type": "object",
            "properties": {
                "explanation": {
                    "type": "string"
                },
                "output": {
                    "type": "string"
                }
            },
            "required": [
                "explanation",
                "output"
            ],
            "additionalProperties": false
        }
    },
    "required": [
        "steps",
        "final_answer"
    ],
    "additionalProperties": false
}

再帰スキーマのサポート

# でルートへの再帰を指定する再帰スキーマの例です。

{
    "name": "ui",
    "description": "Dynamically generated UI",
    "strict": true,
    "schema": {
        "type": "object",
        "properties": {
            "type": {
                "type": "string",
                "description": "The type of the UI component",
                "enum": ["div", "button", "header", "section", "field", "form"]
            },
            "label": {
                "type": "string",
                "description": "The label of the UI component, used for buttons or form fields"
            },
            "children": {
                "type": "array",
                "description": "Nested UI components",
                "items": {
                    "$ref": "#"
                }
            },
            "attributes": {
                "type": "array",
                "description": "Arbitrary attributes for the UI component, suitable for any element",
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {
                            "type": "string",
                            "description": "The name of the attribute, for example onClick or className"
                        },
                        "value": {
                            "type": "string",
                            "description": "The value of the attribute"
                        }
                    },
                    "additionalProperties": false,
                    "required": ["name", "value"]
                }
            }
        },
        "required": ["type", "label", "children", "attributes"],
        "additionalProperties": false
    }
}

明示的な再帰を使った再帰スキーマの例を以下に示します。

{
    "type": "object",
    "properties": {
        "linked_list": {
            "$ref": "#/$defs/linked_list_node"
        }
    },
    "$defs": {
        "linked_list_node": {
            "type": "object",
            "properties": {
                "value": {
                    "type": "number"
                },
                "next": {
                    "anyOf": [
                        {
                            "$ref": "#/$defs/linked_list_node"
                        },
                        {
                            "type": "null"
                        }
                    ]
                }
            },
            "additionalProperties": false,
            "required": [
                "next",
                "value"
            ]
        }
    },
    "additionalProperties": false,
    "required": [
        "linked_list"
    ]
}

JSON モード

JSON モードは、構造化出力よりも基本的な機能です。JSON モードはモデルの出力が有効な JSON であることを保証しますが、構造化出力は、モデルの出力を指定したスキーマに確実に準拠させます。ユースケースでサポートされている場合は、構造化出力の使用をおすすめします。

JSON モードを有効にすると、モデルの出力が有効な JSON であることが保証されます。ただし、一部の例外的なケースについては、検出して適切に処理する必要があります。

Responses API で JSON モードを有効にするには、text.format{ "type": "json_object" } に設定します。Function Calling を使用する場合、JSON モードは常に有効です。

重要な注意事項:

  • JSON モードを使用する場合は、システムメッセージなど、会話内のいずれかのメッセージで、JSON を生成するよう必ずモデルに指示してください。JSON を生成するという明示的な指示がないと、モデルが空白文字を出力し続け、トークン上限に達するまでリクエストの処理が続く可能性があります。この指示を忘れないよう、コンテキスト内のどこにも文字列「JSON」が含まれていない場合、API はエラーを返します。
  • JSON モードが保証するのは、出力が有効な JSON であり、エラーなくパースできることだけです。特定のスキーマへの準拠は保証しません。出力をスキーマに確実に準拠させるには、構造化出力を使用してください。使用できない場合は、検証ライブラリを利用し、必要に応じて再試行することで、出力が目的のスキーマに準拠していることを確認してください。
  • モデルの出力が完全な JSON オブジェクトにならない例外的なケースを、アプリケーションで検出して処理する必要があります(下記参照)。

リソース

構造化出力についてさらに詳しく知るには、次のリソースを参照してください。