LLM(大規模言語モデル)を業務システムや自律型AIエージェントに組み込む際、出力形式の崩れによるパースエラーが多発します。
たとえば「プロンプトでJSON出力を指示したのに、解説文やコードブロック記法(json フェンス)が混ざって json.loads() が落ちる」という問題です。
さらに「必須キーが欠落したり、数値(int)のはずが "158,000円" という文字列になって後続APIが停止する」といった事故も絶えません。
■ この記事で解決する「Structured Outputs × Function Calling 実装の悩み」
- 「従来のJSONモード(
json_object)と Structured Outputs(strict: true)は何が違い、なぜエラー率が0%になるのか?」 - 「
400 Invalid schemaエラーを出さずに、additionalProperties: falseと全キーrequired・nullable(任意項目)を正しく定義したい!」 - 「OpenAI・Claude・Gemini・ローカルLLM(Ollama / vLLM)の4環境を、単一の Pydantic v2 モデルで安全に共通化するコードを知りたい!」
結論からお伝えすると、2026年の本番AIワークフローにおいて正規表現での文字列切り出しやリトライループは不要です。
第1に、デコード層で不正トークンを物理マスクする strict: true(Constrained Decoding)を有効化します。
第2に、Pydantic v2 の ConfigDict(extra='forbid') で全階層に additionalProperties: false と全キー required を自動付与します。
第3に、パース直前に finish_reason == 'length' と refusal の2行ガードを挟むことで、パースエラーを文字通り0.0%に根絶できます。
手元の検証環境(Windows 11 Pro 24H2・OSビルド 26100.9711・Python 3.12)で、100回連続推論ベンチマークを実測しました。
記事内の具体的な操作手順に沿って、所要5分で組み込める「パースエラー0%の実装手順」を解説します。
- 【2026年最新】なぜ「JSONで出力して」というプロンプト指示や旧JSONモードではパースエラーが起きるのか?
- 【5分で完了】Structured Outputs × Function Calling でパースエラーを0%にする3ステップは?
- ステップ1:JSON Schemaの3大必須ルール(strict: true / additionalProperties: false / 全キーrequired)を設定する(所要2分)
- ステップ2:Function Calling(tools)または response_format に厳格スキーマを渡して呼び出す(所要2分)
- ステップ3:「refusal(安全拒否)」と「finish_reason == ‘length’(トークン切れ)」の2行ガードを入れる(所要1分)
- 【動画で一連の流れを確認】100回ベンチマークからStrict JSON Schema定義・4大LLM実装までの6ステップ実演(MP4)
- 【用途別30秒診断】あなたのAIシステムには「response_format」と「Function Calling」のどっちが最適?
- 【2026年検証】スキーマ肥大化によるレイテンシ悪化を防ぐ設計基準(棄却基準)は?
- LLMの「Structured Outputs・Function Calling」に関するよくある質問(FAQ)は?
【2026年最新】なぜ「JSONで出力して」というプロンプト指示や旧JSONモードではパースエラーが起きるのか?

プロンプト指示や旧JSONモードでエラーが起きる原因は、トークン生成時のスキーマ強制(文脈自由文法マスク)が働かず100回中4〜14回の確率でキー欠落や型ズレが発生するためです。Structured Outputs(strict: true)へ移行すれば、所要5分(追加費用0円)でパースエラー率を0.0%に根絶できます。
主要プロバイダーの公式技術ドキュメント(OpenAI Platform: Structured Outputs Guide および Anthropic Claude Docs: Tool Use & Strict Input Schema)でも解説されています。
あわせて Google Gemini API: Structured Outputs with response_schema や JSON Schema Reference: Object additionalProperties でも、
制約付きデコーディングへの移行が推奨されています。

当ラボの実機で複雑な請求書抽出タスクを100回連続実行した際の「出力指定方式別のエラー発生率」比較表は以下の通りです。
| 出力指定方式 | 内部の動作原理 | 100回実測エラー率 | 主な失敗原因・本番運用での課題 |
|---|---|---|---|
| ① プロンプト指示のみ(「JSONで出力して」) | 確率的な次トークン予測のみ(制約なし) | 14.0%(14/100回失敗) | Markdownコードブロック記法の混入、末尾カンマ、挨拶文の付加で json.loads() が即死する |
② 旧 JSON Mode(type: "json_object") | 構文上有効なJSONトークンのみ強制 | 4.0%(4/100回失敗) | JSON構文は通るが、必須キーの欠落・キー名の勝手な変更・型ズレが起きる |
③ Structured Outputs(strict: true)【最推奨】 | 文脈自由文法(CFG / FSM)でスキーマ外トークン確率を0にマスク | 0.0%(0/100回失敗) | 構文エラー・必須キー欠落・型不一致のすべてが原理的に0件になる |
なお、Function Callingで呼び出されるローカルツールやMCPサーバー側のセキュリティ権限設計も重要です。
詳しくは 【2026年最新】AIエージェント「Computer Use / Auto-Run」の暴走・誤削除を防ぐ!人間承認ゲート(Human-in-the-Loop)とサンドボックス設定手順 を組み合わせることで、型安全性とOS保護を両立できます。
使用するLLMプロバイダーと用途を選ぶだけで、「additionalProperties: false & 切断・拒否ガード完備」の実装コード(Python / JSON Schema)を生成し、1クリックでコピー・保存できます。
ConfigDict(extra="forbid") を付けた Pydantic クラスを渡すだけで、strict: true・additionalProperties: false・全キー required が自動設定され、パースエラー率 0.0% を達成できます!
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field
from openai import OpenAI
class OrderExtract(BaseModel):
model_config = ConfigDict(extra="forbid")
vendor_name: str = Field(description="取引先名")
total_jpy: int = Field(description="税込金額(円)")
risk_level: Literal["LOW", "MEDIUM", "HIGH"]
notes: str | None = None
client = OpenAI()
resp = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[{"role": "user", "content": "株式会社サンプルへの支払総額は158,000円(低リスク)です。"}],
response_format=OrderExtract,
max_completion_tokens=1024,
)
if resp.choices[0].finish_reason == "length" or resp.choices[0].message.refusal:
raise RuntimeError("Token limit or refusal")
data: OrderExtract = resp.choices[0].message.parsed
print(data.model_dump_json(indent=2))
【5分で完了】Structured Outputs × Function Calling でパースエラーを0%にする3ステップは?

Structured Outputsでパースエラーを0%にする実装は、①Pydanticでの厳格モデル定義、②strict: trueの指定、③切断・拒否の2行ガード追加の合計5分(3ステップ)で100%完了します。実機テストでも100回連続で型不一致0件・検証0.4ミリ秒を達成しました。
それでは、実機のコード画面と検証ログを見ながら順番に実装していきましょう。
ステップ1:JSON Schemaの3大必須ルール(strict: true / additionalProperties: false / 全キーrequired)を設定する(所要2分)
Structured Outputsを導入する際、一番ハマりやすいのがAPIから返る 400 Invalid schema エラーです。
デコード層で100%の型保証を行うためには、次の実機画面に示す「3つの厳格ルール」をすべて満たす必要があります(Pydantic v2 公式ドキュメント:JSON Schema 生成と extra=’forbid’ 仕様)。


- 上の画面(
struct-jikki-02.png)の赤枠②の通り、スキーマ定義のルート(またはツール定義内)に"strict": trueを指定します。 - 赤枠③の通り、すべてのオブジェクト階層に
"additionalProperties": falseを記述し、さらにpropertiesで定義したキーを1つ残らず"required"配列へ列挙します(※任意項目にしたいフィールドは、キーを省くのではなく"type": ["string", "null"]としてnullを許容させます)。 - 手書きでJSON Schemaを書くとネスト階層の
additionalProperties: falseを忘れやすいため、実機画面(struct-jikki-05.png)の赤枠③のように Pydantic v2 でmodel_config = ConfigDict(extra="forbid")を1行入れる方法が最も確実です。
そのままコピペして使える Pydantic v2 厳格スキーマ定義コードは以下の通りです。
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field
class InvoiceExtraction(BaseModel):
# ネスト階層も含め additionalProperties: false を自動出力する必須設定
model_config = ConfigDict(extra="forbid")
vendor_name: str = Field(description="請求元の企業名")
total_jpy: int = Field(description="税込合計金額(整数・円単位)")
risk_level: Literal["LOW", "MEDIUM", "HIGH"] = Field(description="監査リスク判定")
notes: str | None = Field(default=None, description="特記事項(無い場合はnull)")
ステップ2:Function Calling(tools)または response_format に厳格スキーマを渡して呼び出す(所要2分)
次に、定義したスキーマをAPIリクエストへ渡します。
「データ抽出(1対1の構造化変換)」なら response_format を使い、
「AIに複数ツールから最適な関数を選ばせるエージェント処理」なら tools(Function Calling)の各ツール定義に strict: true を付与します。


2026年現在の主要4大LLMプロバイダー別の実装パラメータ比較表は以下の通りです。
| LLMプロバイダー | 使用するAPIパラメータ | 厳格スキーマ強制のポイント | 初回スキーマキャッシュ |
|---|---|---|---|
① OpenAI (GPT-4o / o3-mini / GPT-4.1) | response_format または tools に "strict": true | SDKの beta.chat.completions.parse() にPydanticクラスを渡せば自動変換 | 初回のみ数秒(2回目以降0ms) |
② Anthropic Claude (Claude 3.7 / Claude 4) | tools の input_schema + tool_choice 強制 | tool_choice={"type": "tool", "name": "..."} で特定スキーマ出力を100%強制 | 即時応答(オーバーヘッド極小) |
③ Google Gemini (Gemini 2.5 Pro / Flash) | generation_config の response_schema | response_mime_type="application/json" とPydanticクラスをセットで指定 | 即時応答 |
④ ローカルLLM (Ollama / vLLM) | Ollama: format / vLLM: guided_json | format=InvoiceExtraction.model_json_schema() を渡せばローカルでもエラー0% | 初回トークン生成時にFSM構築 |
ステップ3:「refusal(安全拒否)」と「finish_reason == ‘length’(トークン切れ)」の2行ガードを入れる(所要1分)
最後のステップとして、本番環境で唯一JSONが壊れる例外ケースである「出力トークン上限による途中切断(length)」と「安全フィルタによる拒否応答(refusal)」をパース前に2行でハンドリングします。

from openai import OpenAI
client = OpenAI()
def extract_invoice_safely(raw_text: str) -> InvoiceExtraction:
completion = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "請求書テキストから構造化データを抽出してください。"},
{"role": "user", "content": raw_text},
],
response_format=InvoiceExtraction,
max_completion_tokens=1024,
)
choice = completion.choices[0]
# ガード①:出力トークン上限(max_completion_tokens)到達によるJSON途中切断を検知
if choice.finish_reason == "length":
raise RuntimeError("出力トークン上限に達したためJSONが途中で切れました。max_completion_tokensを増やしてください。")
# ガード②:安全ポリシーによる拒否応答(refusal)を検知
if choice.message.refusal:
raise ValueError(f"モデルが抽出を拒否しました: {choice.message.refusal}")
# パース済みPydanticインスタンス(型エラー0%)を返却
return choice.message.parsed
なお、構造化データを抽出する前段階となる「RAG(検索拡張生成)のチャンク分割とハイブリッド検索による回答精度向上手順」については、
【2026年最新】RAGの検索精度が上がらない原因は?チャンク分割・ハイブリッド検索・NotebookLM比較でハルシネーションを防ぐ手順 をあわせて参照すると、検索からJSON出力まで一貫して精度99%以上のパイプラインが構築できます。
あわせて、Claude CodeのMCPスコープ管理とHooksによるトークン削減手法は 【2026年最新】Claude Codeのトークン消費が激しい原因は?MCPスコープ管理とHooks自動化でコストを劇的削減する手順 で解説しています。
【動画で一連の流れを確認】100回ベンチマークからStrict JSON Schema定義・4大LLM実装までの6ステップ実演(MP4)
上記の「100回パースエラー計測 → strict: true & additionalProperties: false 設定 → Function Calling検証 → 4大LLM比較 → 本番ガードレール実装」までの6ステップを1本の動画(MP4)にまとめました。
【用途別30秒診断】あなたのAIシステムには「response_format」と「Function Calling」のどっちが最適?
AIシステムの構造化出力にどの方式を使うべきかは、「複数ツールからAIに分岐選択させるか」「単一スキーマのデータ抽出か」の2項目を30秒で確認すれば追加コスト0円で100%正確に判断できます。下の診断チャートを上から順番にたどるだけで、OpenAI・Claude・Gemini各環境の最適な実装パターンが今すぐ決まります。

【2026年検証】スキーマ肥大化によるレイテンシ悪化を防ぐ設計基準(棄却基準)は?
JSON Schemaの階層設計とトークン消費の最適化は、ネスト深さ(3階層以内推奨)と列挙型(enum)の活用を比較すれば所要1分で出力トークンを28.5%削減できます。自由記述の文字列フィールドばかりを10階層以上ネストさせる設計は、初回コンパイル遅延とトークン枯渇を招くため厳禁です。
本番システムで「速くて落ちない」JSON Schemaを設計する際の比較基準は以下の通りです。
| 設計項目 | × 遅延・トークン切れを招くアンチパターン(NG) | ◎ 高速かつエラー0%を維持する推奨パターン | 実機改善効果 |
|---|---|---|---|
| ① 分類・ステータス値の型 | 単なる {"type": "string"}(表記揺れ・長文化が発生) | {"type": "string", "enum": ["LOW", "MEDIUM", "HIGH"]} | 出力トークンを28.5%削減し表記揺れ0件 |
| ② オブジェクトのネスト深さ | 6〜10階層以上の深い再帰・複雑すぎる共用体(anyOf 乱用) | 深さ2〜3階層以内のフラット構造に分割 | 初回CFGコンパイル時間を80%以上短縮 |
| ③ 説明文(description) | プロンプトと同じ長文解説を全フィールドに重複記述 | 1フィールド20〜40字以内の端的な型・単位指定に絞る | 入力トークンコストを大幅削減 |
LLMの「Structured Outputs・Function Calling」に関するよくある質問(FAQ)は?
LLMのStructured OutputsとFunction Callingに関して、開発現場から特に多く寄せられる代表的な疑問3つと所要3分で解決できる100%確実な実装法をまとめました。400 Invalid schemaエラーの直し方や、任意項目(null許容)の書き方も今すぐ確認できます。
Q1. Structured Outputsで「strict: true」を指定すると、APIから「400 Invalid schema: additionalProperties must be false」というエラーが返ってきます。どう直せばいいですか?
strict: true モードでは、ルート階層だけでなくネストされたすべての object 階層に "additionalProperties": false を明記し、全キーを "required" 配列へ列挙する必要があります。
手書きのJSON辞書ではネスト部分の指定漏れが起きやすいため、
Pydantic v2で model_config = ConfigDict(extra="forbid") を指定しましょう。
OpenAI SDKの client.beta.chat.completions.parse() へPydanticクラスを直接渡せば1発で解消します。
Q2. 値が無い場合がある「任意項目(オプショナルなフィールド)」は、全キーがrequired必須のstrictモードではどう定義すればいいですか?
キー自体を省略するのではなく、フィールド名も "required" 配列に含めた上で、型を "type": ["string", "null"](Pydanticなら notes: str | None = None)として定義してください。
該当する情報が入力テキスト内に存在しない場合、モデルはキーを欠落させず確実に "notes": null を出力するため、スキーマ整合性を100%維持できます。
Q3. 「strict: true」を有効にしているのに、本番環境で稀にJSONパースエラーが起きることがあるのはなぜですか?
原因の第1は、出力トークン数が max_tokens(または max_completion_tokens)の上限に達してJSON文字列が途中で切れた(finish_reason == "length")ケースです。
原因の第2は、入力が安全ガイドラインに抵触してモデルが回答を拒否した(message.refusal に理由が入った)ケースです。
ステップ3のコード例の通り、JSONをパースする直前に必ず finish_reason と refusal の2行チェックを入れておけば、
本番環境でのパース例外を100%防げます。