AI 開発

AI はなぜ JSON Schema が必要か?Structured Output、Function Calling の完全整理

約 14 分

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 を出させる」に潰すと、役割が消える。分けると:

  1. JSON Schema は共有の口径:フィールド辞書、必須、enum。呼び出さず、生成もしない。「合法」の見た目だけを書く。
  2. Function Calling は外へ手を伸ばすこと。モデルは副作用を頼む。引数は Schema を通らねばならず、結果も通るべきだ。
  3. 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 用に「だいたい同じ」定義を手で書かない。形は一つのソース、二つのエクスポートだ:

  1. リポジトリに schemas/order.json を置き、安定した $id と版を付ける。
  2. Function Calling へ出す:function.parameters に裁ち、strict を付ける。照会ツールは多くの場合 order_id だけで足りる。注文全体を引数に詰め込まない。
  3. 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 を呼ぶかを決める。モデルは変わり、プロトコルは移る。直径を先に安定させる。

続きを読む

更新記録: 初回公開