LLM Structured Output(エルエルエムストラクチャードアウトプット)
LLMの出力をJSON、XMLなど事前定義されたスキーマに厳密に準拠させる機能。OpenAI structured outputs、Anthropic tool_use、Google Gemini controlled generationなど各プロバイダが独自実装を提供し、アプリケーション統合の信頼性を飛躍的に向上させる。
LLM Structured Outputとは
LLM Structured Output(構造化出力)は、大規模言語モデルの応答を事前定義したスキーマ(JSONスキーマ、Pydanticモデルなど)に厳密に従わせる機能である。従来の「JSONで返してください」というプロンプト指示とは異なり、APIレベルでスキーマを指定し、モデルの出力がそのスキーマに100%準拠することを保証する。
主要プロバイダの実装比較
| プロバイダ | 機能名 | スキーマ形式 | 保証レベル | 対応モデル |
|---|---|---|---|---|
| OpenAI | Structured Outputs | JSON Schema | 100% | GPT-4o, GPT-4o-mini |
| Anthropic | Tool Use (forced) | JSON Schema | 100% | Claude 3.5/4 |
| Controlled Generation | JSON Schema | 高い | Gemini 1.5/2.0 | |
| Mistral | JSON Mode + Schema | JSON Schema | 高い | Mistral Large 2 |
| Ollama | format: json | JSON Schema | モデル依存 | Llama 3, Qwen 2.5 |
OpenAI Structured Outputs
2024年8月に正式導入。response_formatパラメータにJSON Schemaを指定すると、出力が100%スキーマ準拠することを保証する。内部的にはConstrained Decoding(制約付きデコード)を使用し、スキーマに違反するトークンの生成確率をゼロにする。
制約として、additionalProperties: falseが必須、$refによる再帰参照は深さ制限あり、oneOf/anyOfは限定的にサポートされる。
Anthropic Tool Use
Anthropicはtool_use機能を活用してStructured Outputを実現する。ツール定義にJSON Schemaを指定し、tool_choice: {"type": "tool", "name": "..."}でそのツールの呼び出しを強制すると、応答がスキーマ準拠のJSONとなる。
直接的なstructured outputパラメータではなくツール呼び出しの強制という間接的な方法だが、実質的に同等の機能を提供する。
ローカルモデルでの実現
llama.cppのGBNF文法、vLLMのGuided Decoding、OutlinesのFSM(有限状態機械)ベースの制約など、ローカルモデルでもStructured Outputが実現可能だ。OllamaもJSON Schema指定をサポートしているが、モデルによって精度にばらつきがある。
JSON Modeとの違い
| 項目 | JSON Mode | Structured Output |
|---|---|---|
| 出力形式 | 有効なJSON保証 | スキーマ準拠JSON保証 |
| フィールド名制御 | × | ○ |
| 型制御 | × | ○ |
| 必須フィールド保証 | × | ○ |
| enum制約 | × | ○ |
| ネスト構造 | 不定 | スキーマ通り |
JSON Modeは「構文的に正しいJSON」を保証するだけで、アプリケーションが期待するスキーマへの準拠は保証しない。Structured Outputはスキーマレベルの制約を強制する上位機能だ。
実装パターン
直接API利用
各プロバイダのSDKでスキーマを直接指定する。最もシンプルだがプロバイダロックインが発生する。
Instructor経由
InstructorライブラリはPydantic v2モデルをJSON Schemaに変換し、OpenAI/Anthropic/Gemini/Ollama等のAPIに統一的にStructured Outputを要求する。プロバイダ間の差異を吸収し、リトライやバリデーションも組み込まれている。
LangChain with_structured_output
LangChainの.with_structured_output()メソッドでPydanticモデルやJSON Schemaを指定すると、対応するプロバイダのStructured Output機能を自動選択して利用する。
設計上の考慮事項
- スキーマの複雑さ: ネストが深いスキーマほど生成品質が低下する。3階層以内が推奨
- optional vs required: 必須フィールドを最小限にし、モデルが答えられない可能性のあるフィールドはoptionalにする
- enum の活用: カテゴリ分類やステータスにはenumを使い、想定外の値を排除する
- description の充実: JSON Schemaのdescriptionフィールドに各フィールドの意味を記述すると、モデルの理解精度が向上する
よくある質問
Q: Structured Outputを使うとモデルの創造性が低下しますか?
A: スキーマに定義されたフィールドの値(文字列フィールドの内容など)についてはモデルの自由度が維持される。制約されるのは出力の構造(フィールド名、型、必須項目)であり、内容の品質や創造性への影響は最小限だ。ただしフィールドが極めて多い複雑なスキーマでは、各フィールドへの「注意力」が分散し品質が低下する傾向がある。
Q: すべてのLLM APIがStructured Outputに対応していますか?
A: 主要プロバイダ(OpenAI、Anthropic、Google、Mistral)は対応しているが、実装方法と保証レベルが異なる。OpenAIの保証は最も厳密で100%のスキーマ準拠を謳っている。対応していないプロバイダではInstructorやOutlinesで補完する。
Q: Structured OutputとFunction Callingの関係は?
A: Function Calling(Tool Use)はモデルが外部関数を呼び出すための仕組みで、引数がJSON Schemaに従う。Structured Outputはこの仕組みを「出力フォーマット制御」に転用したものと言える。OpenAIはStructured Outputを独立機能として実装し、AnthropicはTool Use経由で同等機能を提供している。