構造化出力:JSON / Function Calling

AI Navigate Original / 2026/5/16

共有:

要点

  • アプリは自由文でなく機械処理可能な構造化出力が必須
  • スキーマ JSON か Function Calling、実行は自前
  • スキーマ検証・余計な文禁止・列挙固定・引数検証
  • 検証+再試行、Function Calling は意図受領で実行ではない

アプリにAIを組み込むとき、本当に欲しいのは「読み物としての文章」ではなく、そのままプログラムが処理できるデータです。`{"name":"…","amount":1200}` のような決まった形で返ってくれば、画面に表示したり、DBに保存したり、次の処理へ渡したりできます。これを実現するのが構造化出力(Structured Output)Function / Tool Calling。本稿では、2026年時点の仕組みと、実務で壊れない設計の勘所を整理します。

自由文の回答 スキーマ で型を固定 { "name": "田中",   "amount": 1200 } 機械処理できるデータ

FIG.1 スキーマ(型の設計図)を渡すと、出力の「形」を固定できる

01「自由文」と「構造化出力」は別物

チャット画面で人間が読む答えは、文章として自然であれば十分です。ところがアプリの中でAIを使うときは、答えの一部を確実に取り出せることが必要になります。たとえば領収書の写真から「店名」「金額」「日付」を抜き出して経費精算フォームに入れる場面では、AIが「だいたい1,200円くらいでした」と書いてくれても困ります。プログラムが読むのは "amount": 1200 のような決まった形です。

そこで使うのが、出力の型(スキーマ)をあらかじめ定義し、その形で返させる仕組みです。何を必須にするか、各項目は文字列か数値か、選べる値は何か——これを設計図として渡します。

022つの代表的な手段

構造化を実現する道具は、大きく次の2つに整理できます。役割が違うので、目的で選びます。

JSON 構造化出力Function / Tool Calling
欲しいのは「整ったデータ」欲しいのは「どの操作を・どんな引数で呼ぶか」の意図
抽出・分類・要約をJSONで受け取る外部API・DB・社内関数を呼ぶ前段に使う
例:領収書→{店名, 金額, 日付}例:天気を聞かれたら get_weather(city="東京") を提案
返ってくるのはデータそのもの返ってくるのは「呼び出しの提案」。実行は自前のコード

大事なのは、Function Calling はAIが関数を実行するわけではないという点です。モデルは「この関数を、この引数で呼ぶとよさそう」という意図を返すだけ。実際に呼ぶかどうか、その引数が安全かは、受け取ったあなたのコードが判断します。

モデル 意図を出す call: refund(order=A12) =「呼びたい」という提案 引数を検証 承認 / 実行 実行の主導権は自分のコード側

FIG.2 モデルは「呼びたい」と言うだけ。検証して実行するのは人/コード

032026年の現在地:形は「ほぼ保証」できる

かつては「JSONで返して」とお願いしても、前置きの文章が混じったり、途中で壊れたJSONになったりして、後処理が大変でした。2026年現在、状況は大きく変わっています。主要なAPIがスキーマで生成を拘束する機能を正式提供しているからです。

  • OpenAI:関数定義や応答フォーマットに strict: true + JSON Schema を指定すると、文法(CFG)でトークン生成を制約し、スキーマに違反する出力をそもそも作れなくする。旧来の「JSON モード」はレガシー扱い。
  • Anthropic(Claude):Structured Outputs が Claude Opus 4.5 / Sonnet 4.5 / Haiku 4.5 で一般提供。スキーマを文法にコンパイルして生成を制約し、「JSON 出力」と、ツール引数を厳密に一致させる「strict tool use」の2パターンを使える。

つまり出力の「形」は、かなり確実に守らせられる時代になりました。「壊れたJSONを直すコード」を主役にする必要は薄れています。

スキーマで保証できるのは「形」であって、「中身の正しさ」ではない。

04形が正しくても、中身は嘘をつく

ここが最重要です。スキーマ拘束は「数値の項目に文字列が来る」「必須項目が欠ける」といった構造の崩れを防ぎます。しかし、その数値が事実として正しいかは保証しません。

たとえば入力に答えが含まれないとき、モデルは「分からない」と言う代わりに、もっともらしい嘘を正しい形で埋めてきます。"price": -500(負の価格)や、存在しない注文ID、根拠のない "confidence": 0.97 のように。JSONとしては完璧でも、業務としてはゴミです。

{ "price": -500 } 構文はOK 意味の検証 価格は0以上か? 却下 再試行 / 人へ

FIG.3 構文(形)と意味(中身)は別レイヤー。両方を検証する

だからスキーマ拘束があっても、受け取った後の意味の検証(業務ルール)は省けません。価格は0以上か、注文IDは実在するか、日付は妥当な範囲か——これらは自分のコードでチェックします。

05壊れにくくする設計の勘所

「形はAPIが守る/中身は自分で守る」を前提に、成功率を上げる具体策を挙げます。

01

選べる値は enum で固定する

ステータスのように候補が決まっている項目は、自由記述にせず enum: ["active","inactive","pending"] と列挙する。型を string にするより圧倒的に安定し、表記ゆれも消える。

02

「不明」を表現できる形にする

答えが入力に無いときに嘘で埋めさせないため、null 許容や "unknown" といった逃げ道をスキーマに用意し、根拠が無ければそれを選ぶよう指示する。

03

受け取ったら業務ルールで検証

範囲・整合性・実在性をコードでチェック。失敗したらリトライフォールバック(既定値・人手確認)へ。Pydantic(Python)や Zod(TypeScript)が定番。

04

関数の引数は実行前に必ず検証

Function Calling では、モデルの提案を信用せず引数を検査。返金・送信・削除のような重要操作は承認を挟む・権限を最小化する。

06知っておくべきトレードオフ

便利な反面、運用上の注意点もあります。誇張せず正しく押さえておきます。

  • 遅延とコスト:スキーマは入力トークンを消費し、生成中も妥当なトークンを追跡するためレイテンシが増えることがある。特に深いネスト・長い説明文・巨大な enum で顕著。スキーマは必要十分にとどめる。
  • 複雑なスキーマは失敗しやすい:拘束は厳密になる一方、過度に複雑な構造では生成が破綻する場合がある。まずシンプルな形から始める。
  • 拒否(refusal)への対応:安全方針に反する要求では、モデルがスキーマに沿った出力ではなく拒否を返すことがある。OpenAI は refusal を判別できる仕組みを持つので、拒否時の分岐も実装する。
  • 提供状況は変わる:対応モデルや料金・パラメータ名は更新が早い(例:Claude の output_formatoutput_config.format への移行)。実装前に必ず公式ドキュメントで最新仕様を確認する。

07勘所

構造化出力と Function Calling は、LLMをプログラムに組み込むための接着剤です。2026年現在、出力の「形」はAPIのスキーマ拘束でほぼ保証できます。残る仕事は中身の正しさ——形はAPIに、意味は自分のコードに守らせる、という役割分担が安定運用の前提です。enumで選択肢を縛り、「不明」を表現でき、業務ルールで検証してから実行する。この型を押さえれば、AIをアプリの一部として安心して動かせます。