AI はなぜ JSON Schema が必要か?Structured Output、Function Calling の完全整理
2024 年から製品ページは JSON Schema、Function Calling、Structured Output を同一機能のように書く。違う。Schema は契約言語、Function Calling は「ホストよ実行せよ」、Structured Output は「モデルはこの形を出せ」。三語を分けたうえで、確率モデルが「JSON で返して」という一文ではなく、検証可能な Schema の後ろに座る理由を書く。
先に要点
| 概念 | 一言 | どこに置るか |
|---|---|---|
| JSON Schema | フィールド・型・必須・列挙の契約。モデル機能ではない | git の .json、CI の validator |
| Function Calling | モデルが呼び出しを提案し、ホストが実行する。副作用はここ | tools[] / arguments |
| Structured Output | 最終返信がこの形でなければならない。副作用は通常ない | json_schema / output_type |
分担を先に覚える。Schema は口径、Function Calling は手を伸ばすこと、Structured Output はオブジェクトを返すこと。三つを「モデルに JSON を出させる」に潰すと、次ホップは散文を parse する。
三語はなぜいつも混ざるのか
文書も SDK 例も投稿も、一文に重ねたがる。Schema を渡せば合法 JSON が出る、と。デモは成功しやすい。事故は「もう構造化できている」と思ったあとに起きる。
混同は三つの別仕事を隠す:
- Function Calling の
argumentsは、まだ文字列であることが多い。 ホストは再JSON.parseする。型も enum も余剰フィールドも、まだ止まっていない。 - Structured Output は最終返信だけを縛る。 注文照会も送金も DB 書き込みもしない。副作用は Function Calling のまま。
- prompt の中だけの Schema は CI で落とせない。 「JSON で返して」は失敗しない。git の Schema は失敗できる。
問いは「AI は JSON ができるか」ではない。誰が、どの瞬間に、どの契約で、不正オブジェクトを止めるかだ。三語は三人の誰かを指す。
JSON Schema とは何か(モデル機能ではない)
JSON Schema は JSON の形を書く文書だ。どのキー、どの型、何が必須、enum の値、余分なフィールドを許すか。「JSON に見える」より厳しく、TypeScript 型や protobuf よりモデル API に引用されやすい。
Agent / Structured Output が実際に使うキーワードは、だいたいこれだけだ:
type/properties:オブジェクトの形。required:欠けたら失敗するキー。enum/pattern/ 数値の上下限:「だいたい」を有限集合にする。additionalProperties: false:余剰キーは失敗。prompt injection で持ち込まれたフィールドも止める。
構文は JSON Schema 教程。ここではSchema はまず validator とテストのためだと覚える。description はツール選択を助けるが、enum と required の代わりにはならない。
{
"$id": "https://example.com/schemas/order.json",
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^A-[0-9]{4,}$" },
"amount": { "type": "number", "exclusiveMinimum": 0 },
"status": { "type": "string", "enum": ["paid", "refunded", "pending"] }
},
"required": ["order_id", "amount", "status"],
"additionalProperties": false
}
上の注文契約は Function Calling の parameters、Structured Output の json_schema、ホストの ajv に同時に渡せる。フィールド変更は一箇所。
Function Calling とは何か
Function Calling(広い Tool Calling)は「モデルが関数を実行する」ことではない。モデルは名前と引数を出すだけだ。ホストが parse・検証・実行し、結果を会話へ戻す。在庫照会、返金、チケット——副作用はここにある。
ベンダーはツールを tools[] と書く。parameters は Schema の部分集合だ:
{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Look up an order by ID",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"pattern": "^A-[0-9]{4,}$"
}
},
"required": ["order_id"],
"additionalProperties": false
},
"strict": true
}
}
AI Agent 完全ガイド はこのホップをループの中に描く。MCP Tool Schema vs Function Calling は MCP の inputSchema とベンダーの parameters が、同じ辞書の二つの綴りだと示す。
もう構造化されているように見える。隙間は:arguments が文字列のままであること、ツール結果に Schema がないことが多いこと、strict がモデル側だけを縛ること。ホスト検証がなければ、amount が数か文字列かは、今日のスナップショット次第だ。
Structured Output とは何か
Structured Output(JSON mode の厳しい形)はモデル自身の最終メッセージを縛る。分類、抽出、要約オブジェクト、Agent の handoff——外部副作用はないが、次ホップは固定の形を要する。
フィールド名は違う。response_format、text.format.json_schema、output_type。核は同じ:Schema をデコーダに渡し、不正な token 経路を切る。
{
"type": "json_schema",
"json_schema": {
"name": "order",
"strict": true,
"schema": {
"$id": "https://example.com/schemas/order.json",
"type": "object",
"properties": {
"order_id": { "type": "string" },
"amount": { "type": "number" },
"status": {
"type": "string",
"enum": ["paid", "refunded", "pending"]
}
},
"required": ["order_id", "amount", "status"],
"additionalProperties": false
}
}
}
DevDay 2026 の予測 はこの層と Function Calling と Agent ランタイムを一本の JSON 管として書いた。口径は依然 Schema だ。先に直径を決め、それからプロトコルを付ける。
strict: true を付けると、欠けたフィールド、誤った enum、余剰キーはモデル側で止まりやすい。それは「JSON で答えて」という prompt の代わりになる。ホストの再検証の代わりにはならず、Function Calling の代わりにもならない。
三つはどう重なるか
「モデルに JSON を出させる」に潰すと、役割が消える。分けると:
- JSON Schema は共有の口径:フィールド辞書、必須、enum。呼び出さず、生成もしない。「合法」の見た目だけを書く。
- Function Calling は外へ手を伸ばすこと。モデルは副作用を頼む。引数は Schema を通らねばならず、結果も通るべきだ。
- Structured Output はオブジェクトを返すこと。ホップの終わりに、返信そのものがその形でなければならない。
同義語にしないための対照:
| 層 | モデルがしていること | Schema が無いと |
|---|---|---|
| Function Calling | 呼び出しを提案し、ホストを待つ | 引数が散文になる。余剰キーが課金系に入りうる |
| Structured Output | 最終オブジェクトを直接出す | 下流が段落からフィールドを掻き出す |
| JSON Schema | 何もしない。物差しだけ | prompt の中の物差しは CI で測れない |
多段 Agent は両方使う。Structured Output でトリアージ、Function Calling で照会と返金。AI Agent と JSON Schema ワークフロー は門の並べ方だ。本稿は三つのブロックを名指すだけだ。
AI はなぜ JSON Schema を省略できないか
モデルとプログラムは同じ種類のものではない。モデルは確率で token を続け、プログラムは規則でオブジェクトを読む。つなぎが「今日は JSON に見えた」だけなら、欠けたフィールド、文字列になった数、"Paid" と書かれた enum、余分な note は、次ホップの事実になりうる。
2024 年以前の鎖は短かった。一度のチャット、一つの関数、失敗は人が見る。2026 年は長い。分類 → 照会 → 返金か有人へ → 別の Agent にオブジェクトを渡す。どのホップも「JSON っぽい」だけなら、後段は誤りを固める。
同じ注文でも、モデルはいつでもこうした「合法に見える」オブジェクトを出しうる:
{
"order_id": "A-1042",
"amount": "99.00",
"status": "Paid",
"note": "please hurry"
}
amount は文字列、status の大小が違い、note が増えている。Schema が無ければ、下流は 99.00 を文字列のまま SQL に繋ぎ、Paid を未知状態として再試行しうる。デバッグでは先にローカルで 整形 し、先週通ったオブジェクトと JSON Diff する。ユーザーデータを含む応答を公開 JSON サイトへ貼らない。
Schema の価値は「モデルに話し方を教える」ことではない。不正オブジェクトをホストの門で止めることだ。呼び出し前に一度、返信後に一度、評価でもう一度。窓が広く、段が多いほど、散文の誤りはシステム内の事実になりやすい。
一つの Schema、二つの投影
Function Calling 用と Structured Output 用に「だいたい同じ」定義を手で書かない。形は一つのソース、二つのエクスポートだ:
- リポジトリに
schemas/order.jsonを置き、安定した$idと版を付ける。 - Function Calling へ出す:
function.parametersに裁ち、strictを付ける。照会ツールは多くの場合order_idだけで足りる。注文全体を引数に詰め込まない。 - Structured Output へ出す:同じオブジェクトを
json_schema/output_typeとして、抽出・トリアージ・最終返信に使う。
部分集合に注意。ベンダーの strict は全 property を required に入れさせ、oneOf / $ref の一部を禁ずることが多い。ソースは厚くてよい。エクスポータが対象ごとに裁つ。CI は「ソース vs 投影」を構造 Diff し、片側の手編集を防ぐ。
ホスト側の検証はまだ必要だ
strict: true はモデルの復号だけを縛る。スナップショットの交代、strict の切断、arguments の再パース、開放オブジェクトを返すツール——いずれもモデル側を迂回しうる。同じ Schema をホストの三箇所で走らせる:
- ツール実行前。 parse → validate → execute。失敗なら構造化エラーを返す。生文字列を次へ渡さない。
- モデルの最終オブジェクトを受けたあと。 Structured Output の成功は、上限・通貨・権限といった業務規則の成功ではない。
- 状態や eval 用 fixture を書くとき。 checkpoint と eval は合法 JSON でなければならない。チャットログから進捗を推測しない。
モデル側の制約とホスト側の検証は別の仕事だ。strict を切るか API を変えたあと、prompt の中だけの Schema は消える。
2026 年の実装(先にファイル、それから prompt)
schemas/tools/、schemas/extract/、schemas/state/を置く。各ファイルに$idと版。- 「JSON で返して」より先に Schema を書く。prompt の一文は CI で落ちない。
- 副作用(照会、送金、メール)は Function Calling。分類、抽出、handoff は Structured Output。
- 新しいオブジェクトは既定で
additionalProperties: falseと明示的なenum。拡張が要るなら別のmetadataを足し、根は緩めない。 - ツールが十を超えたら、先に検索してから呼ぶ。カタログ全体を一リクエストに入れない。
- 秘密とユーザーフィールドはブラウザだけで見る。整形、JSON Diff、アップロードなし。
ディレクトリは薄くてよい。大切なのはファイルが prompt より先であることだ。モデルは変わり、プロトコルは増える。口径を先に安定させる。
よくある誤り
- Structured Output を Function Calling だと思う。 前者はコードを実行しない。照会と返金にはツール層が要る。
- prompt にだけ「JSON で返して」と書く。 git に Schema が無ければ、失敗できるテストも無い。
- ツール引数だけ検証し、最終オブジェクトを見ない。 抽出とトリアージの事故は、「もう JSON に見える」返信で起きる。
- プロトコルごとに「だいたい同じ」Schema を手で書く。 三週で分岐する。コピーせず、エクスポートする。
- 広い
type: objectで設計を逃げる。 開放オブジェクトは門ではない。版を付けるか、明示的なmetadataを足す。
FAQ
Structured Output は Function Calling を置き換えられるか?
できない。Structured Output は最終返信の形を縛る。Function Calling はホストに副作用を頼む。注文フィールドの抽出は前者、在庫照会や返金は後者。同じ Schema を参照すべきであり、互いを置き換えてはいけない。
Function Calling にはすでに parameters がある。別ファイルは要るか?
要る。parameters は投影であり、源ではない。別ファイルなら Structured Output、MCP、評価、ホストの ajv に同時に渡せる。tools[] の中だけ直すと、三週後に抽出 Schema とずれる。
Agent は無く、抽出が一度だけだ。Schema は要るか?
むしろ要る。結果がそのまま DB や表に入るなら、「もう一度理解する」次ホップは無い。Structured Output とホスト検証が最小の完結セットだ。
strict: true を付けた。ホスト検証はまだ要るか?
要る。strict は復号を縛る。ホストは業務規則、再パース、ベンダーが strict を切ったあとの退化を縛る。門は安く二つある。一つ落とすと、モデル交換で露出する。
拒まれた JSON をローカルでどう見るか?
整形して形を見、Schema で欠けた required や誤った enum を探し、前回通った版と Diff する。JSONSort はブラウザローカルで行い、アップロードしない。秘密を含む応答を公開サイトへ貼らない。
まとめ
AI が JSON Schema を要するのは、モデルが自然言語を読めなくなったからではない。確率的な出力を、確定的な門に接続しなければならないからだ。Function Calling は「せよ」と言い、Structured Output は「このオブジェクトを返せ」と言い、Schema は両者が共有する口径だ。
今日から schemas/extract_order.json を書き、それからどの API を呼ぶかを決める。モデルは変わり、プロトコルは移る。直径を先に安定させる。
続きを読む
- AI Agent が JSON Schema を必要とし始めた理由 Tool Calling から構造化ワークフローへの門
- AI Agent とは?Tool Calling と JSON ランタイム、ツール呼び出し、JSON 契約
- MCP Tool Schema vs Function Calling ツール JSON のプロトコル境界
- JSON Schema とは required、enum、additionalProperties
- JSONSort のローカル道具箱 整形、検証、Diff
- すべての記事 JSON と AI 開発のメモ
更新記録: 初回公開