AI 開発

AI Agent が JSON Schema を必要とし始めた理由:Tool Calling から構造化ワークフローへ

約 15 分

2024 年以前、多くの「Agent」は prompt に関数を二、三個足しただけでした。2026 年では通用しません。Function Calling は引数を記述し、MCP はツールを登録し、Structured Outputs は戻り値を拘束し、A2A は能力を交渉し、Agents SDK は handoff オブジェクトで経路を決めます。各層は独立に進みましたが、契約言語は同じ——JSON Schema に戻ります。本稿では、なぜ「ドキュメント上の検証文法」が Agent のランタイムになったのか、単発の Tool Calling から多段階ワークフローへ進むとき Schema をどこに置くべきかを整理します。

先に要点

段階 Schema がないとき Schema があるとき
単発の Tool Calling 引数は文字列、型は運任せ、余分なフィールドでも動く parameters / inputSchema が呼び出し前に止める
多段階 Agent 下流は散文の解析頼み、handoff は「billing と書いた」頼み handoff オブジェクトに output_type、経路はテスト可能
プロトコル横断の再利用 Function Calling、MCP、A2A を別々に書き、改修のたびにずれる Git に 1 つの Schema、3 種のアダプタへ書き出す

先に結論:JSON Schema は「モデル向けの文書」ではなく、Agent ホストが各ステップの実行前・引き渡し時・評価時に走らせる検証器です。

なぜ「必要になり始めた」のか——以前から必要だったわけではない

初期の Tool Calling が成立したのは、経路が短かったからです。モデルが関数名と引数を出し、ホストが実行し、結果を会話へ戻します。失敗したら再試行し、ユーザーにも見えます。Schema は README に書いてあれば十分で、「あればよい」程度でした。

2025–2026 年、経路は長くなりました。チケット Agent は分類し、注文を調べ、返金か有人へ回すかを決め、オブジェクトを別の Agent へ渡します。途中の一ステップが「JSON に見える」だけだと、後段はその誤りを事実として扱います。ここで Schema は文書からランタイムの門になります。通らなければ先へ進みません。

もう一つの圧力はプロトコル層です。MCP Tool Schema vs Function Calling で書いたとおり、ベンダー API は parameters、MCP は inputSchema を使います。A2A Extensions は能力を Agent Card に書きます。3 つのプロトコルはランタイムを共有しませんが、いずれも JSON Schema の部分集合を認めます。最初に Schema を決めなければ、3 箇所で「ほぼ同じ」定義を保守し、3 週目に order_id が string だったり number だったりする事態になります。

DevDay 2026 予測 は同じことをより直截に述べます。Structured Outputs、Function Calling、Agent ランタイムは1 本の JSON 管に収束しつつあります。Schema はその口径です。口径が決まらなければ、どのプロトコルを繋いでも漏れます。

Tool Calling にはすでに「構造」があるように見える。欠けはどこか

Function Calling の tools[] には、もともと Schema に似た parameters があります。多くのチームはこれで「すでに構造化した」と考えます。本番で本当に壊れるのは、たいてい次の 4 種です。

第一に、arguments は依然文字列です。モデルが返すのは次の形です。

{
  "tool_calls": [{
    "id": "call_8f2a",
    "type": "function",
    "function": {
      "name": "create_refund",
      "arguments": "{\"order_id\":\"A-1042\",\"amount\":\"99.00\",\"reason\":\"late\"}"
    }
  }]
}

ホストはもう一度 JSON.parse しなければなりません。amount が文字列か数値か、reason が列挙に入るか、余分な note を会計へ入れてよいか——parameters をホスト側で強制しなければ、すべては「今日のモデルの機嫌」次第です。Schema を書いただけで自動適用されるわけではありません。strict: true はモデル側だけを拘束し、ホストは自分で検証する必要があります。

第二に、ツール結果に Schema がないことです。role: tool はほとんど自由文字列です。次のステップのモデルは、この文をもう一度「理解」します。照会成功、在庫 0、権限不足——外形が違えば、多段階ワークフローは 3 ステップ目で誤った枝へ分かれます。

第三に、型が広すぎて選別力がないことです。type: string だけの priority なら、モデルは "urgent!!!" を出せます。enum、required、additionalProperties: false のない Schema は、注釈にすぎません。

第四に、単発の成功がワークフローの失敗を隠すことです。最初の lookup_order が余分な status: "ok" を返し、次の返金 Agent が status を注文状態と見なします。ローカルのハッピーパスでは見えず、回帰セットで爆発します。Schema の価値はここです。「このステップを次へ渡せるオブジェクト」を、会話履歴ではなく断言可能なテストにします。

こうした入れ子 JSON をデバッグするときは、まずローカルで 整形して構文を確認し、先週動いていた定義と Diff してください。ユーザーデータや秘密を含む tool 応答を、公開 JSON サイトへ貼らないでください。

JSON Schema は Agent のなかで 4 層の役割を持つ

Schema を「ツール引数の説明書」だけだと思うと、2026 年に本当に伸びている 3 層を見逃します。全体像は次のとおりです。

  1. ツール入力。 Function Calling の parameters、MCP の inputSchema。モデルが「何を要求できるか」を決めます。
  2. ツール出力。 照会、書き込み、外部 API の戻りオブジェクト。次のステップが「何を信じられるか」を決めます。いま最も欠けやすい層です。
  3. Agent の引き渡し(handoff)。 分類結果、意図、信頼度、誰へ渡すか。Agents SDK では経路の根拠であり、チャット要約ではありません。
  4. ワークフロー状態と評価。 チェックポイント、trace、eval fixture。長時間ジョブは会話履歴から進捗を推測するのではなく、JSON から復元できなければなりません。

入力 Schema の例(返金ツール):

{
  "$id": "https://example.com/schemas/tools/create_refund.json",
  "type": "object",
  "properties": {
    "order_id": { "type": "string", "pattern": "^A-[0-9]{4,}$" },
    "amount": { "type": "number", "exclusiveMinimum": 0 },
    "reason": { "type": "string", "enum": ["late", "damaged", "duplicate", "other"] }
  },
  "required": ["order_id", "amount", "reason"],
  "additionalProperties": false
}

handoff Schema の例(振り分け → 会計):

{
  "$id": "https://example.com/schemas/handoffs/triage_to_billing.json",
  "type": "object",
  "properties": {
    "intent": { "type": "string", "enum": ["refund", "exchange", "human"] },
    "order_id": { "type": "string" },
    "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
    "from": { "const": "triage" },
    "to": { "const": "billing_agent" }
  },
  "required": ["intent", "order_id", "confidence", "from", "to"],
  "additionalProperties": false
}

2 つのファイルは、違いより共通点の方が重要です。どちらもオブジェクトで、列挙があり、余分なフィールドを禁止し、Git に置け、ajv(または同等ライブラリ)で CI を回せます。モデルのスナップショットが変わっても、プロトコルが MCP でも Function Calling でも、検証器を書き直す必要はありません。キーワードの書き方は JSON Schema チュートリアル を見てください。

単発呼び出しから構造化ワークフローへ、Schema はどの門に立つか

単発の Tool Calling の門は 1 つだけです。引数が合法かどうか。構造化 Agent ワークフローには少なくとも 4 つあります。

門 1:ツールを選ぶ前。 カタログが 10 を超えると、Schema 全部を 1 リクエストに詰めるのは高く、誤選択も増えます。先に検索してから呼ぶなら、検索結果自体も Schema 付きの短リストであるべきで、モデルが生成したツール紹介文ではありません。

門 2:実行する前。 parse → validate → execute。validate が失敗したら、構造化エラー(欠落フィールド、型誤り、列挙外)を返します。生の文字列を次のステップへ投げないでください。この段は、prompt 注入による余分なキーも同時に止めます。

門 3:引き渡す前。 triage が handoff Schema に合うオブジェクトを出して初めて、billing が起動します。経路条件は intent === "refund" && confidence >= 0.8 と書き、「返信に返金の二字が出た」ではありません。

門 4:復元と評価。 長時間ジョブのチェックポイントは合法 JSON にします。

{
  "run_id": "run_20260903_014",
  "step": "await_refund_ack",
  "state": {
    "order_id": "A-1042",
    "intent": "refund",
    "amount": 99.0
  },
  "schema": "https://example.com/schemas/state/refund_flow.json"
}

評価セットも同じ種類のオブジェクトです。入力を与え、出力が Schema を通り、重要フィールドが等しいことを断言します。Agent が「鈍くなった」ときは、先に今週と先週の Schema と fixture を Diff し、それからモデルを疑ってください。事故の多くは required が一つ増えた、または enum 値が一つ欠けただけです。

1 つの Schema を Function Calling、MCP、A2A へどう渡すか

プロトコル層で別々に書かないでください。推奨は1 つの仕様ファイル、3 種の投影です。

プロトコル Schema の置き場 同一ファイルからの書き出し
Function Calling function.parameters type/properties/required をコピーし、strict をオン
MCP inputSchema 同じオブジェクトを tools/list の一部として出す
Structured Outputs text.format.json_schema handoff / 最終応答に同じオブジェクト定義を使う
A2A Agent Card / Extension metadata 対外能力の宣言が同じ $id を参照

投影では部分集合の差に注意してください。ベンダーの strict は、すべての property を required に入れ、oneOf / $ref の一部を禁じることが多いです。仕様ファイルはより完全でよく、エクスポータが対象に合わせて切り、CI で「仕様 vs 投影」の構造 Diff を一度走らせ、片側の手直しを防ぎます。

MCP はツール供給、Function Calling はモデルが呼び出し意図をどう表すか、A2A はAgent 同士の発見と交渉を担います。Schema はこの 3 層を置き換えません。3 層が共有するフィールド辞書です。前 2 本の結論と同じで、「辞書」を概念からリポジトリのファイルへ落としただけです。

実装:JSON Schema を単一の真実にする

発表会を待たず、今すぐできることがあります。

  • リポジトリに schemas/tools/、schemas/handoffs/、schemas/state/ を作る。各ファイルに安定した $id と版を付ける。
  • スクリプトで Function Calling / MCP / Structured Outputs の 3 種アダプタを書き出し、アダプタファイルでフィールドを手直ししない。
  • CI で ajv(または同等ライブラリ)により検証する。サンプル payload、過去の fixture、本番サンプリング(マスキング後)は現行 Schema を通ること。
  • 新規ツールは既定で additionalProperties: false と明示的な enum。開放拡張が必要なら、別途 metadata オブジェクトを開き、ルートを緩めない。
  • ツールが 10 を超えたら経路選択か検索を入れ、カタログ全体を 1 リクエストに載せない。
  • ホストは arguments を文字列でもオブジェクトでも受け、ベンダーが型を締めたあとにサイト全体が警報を出さないようにする。
  • 秘密やユーザーデータを含む payload はブラウザローカルだけ:整形、Diff、アップロードなし。

カタログは薄くて構いません。大切なのは先にファイルを置き、それから prompt を書くことです。prompt の「JSON を返してください」は CI で失敗できません。Schema ならできます。

よくある誤解

  • システムプロンプトに Schema を書けば終わりだと思う。 モデル側の拘束とホスト側の検証は別物です。ホスト検証がなければ、strict を切るかスナップショットを変えた瞬間に契約は消えます。
  • 入力だけ検証し、出力と handoff を見ない。 多段階 Agent の事故は、「前段が予期しない形を返した」ときに起きやすいです。
  • プロトコルごとに「だいたい同じ」Schema を手で書く。 3 週目には必ず分岐します。書き出してください。コピーしないでください。
  • 極端に広い type: object で設計を逃げる。 開放オブジェクトは門がないのと同じです。本当に拡張するなら、版番号か明示的な metadata を使います。
  • Schema をモデルの学習コーパスだと思う。 まず検証器とテストが走らせるものです。説明を明確にするとツール選択には役立ちますが、enum と required の代わりにはなりません。
  • 視覚的な編成でフィールドを変え、Git へ戻さない。 キャンバス上のノードは真実ではありません。先に Schema を書き出し、キャンバスにファイルを読ませてください。

FAQ

Schema なしで Tool Calling を本番に出せますか?

試作なら可能です。ツールが固定、手順が 3 未満、失敗を人が見られるなら、文字列引数で足りることが多いです。分岐、自動再試行、2 つ目の Agent が出た瞬間、Schema のない誤りは静かに伝播します。

JSON Schema は Structured Outputs や MCP に置き換わりますか?

なりません。それらは Schema を消費する層であり、別の型システムではありません。2026 年の流れは、新しいフィールド言語を発明するのではなく、より多くのプロトコルが同じ Schema を参照することです。

draft-07 と 2020-12 のどちらを使うべきですか?

検証ライブラリとベンダーの部分集合に合わせてください。Agent で本当に使うのは type、properties、required、enum、additionalProperties です。最新 draft を追うより、CI とモデル API のあいだで揃う部分集合を選ぶ方が大切です。

社内の非公開 API でも MCP と A2A が必要ですか?

必須ではありません。内部閉ループなら Function Calling + Schema で足ります。MCP / A2A を予約する価値は、同じ Schema をリポジトリへ置いたあと、プロトコル追加はエクスポータを足すだけで、フィールドを再発明しなくてよい点です。

失敗した tool / handoff JSON をどうデバッグしますか?

ブラウザローカルで整形し、Schema と照合して欠けた required を確認し、前版と Diff してください。JSONSort はデータをアップロードしません。秘密を含む応答を公開サイトへ貼らないでください。

結論

AI Agent が JSON Schema を「必要とし始めた」のは、モデルが突然自然言語を読めなくなったからではありません。ワークフローが長くなり、プロトコルが増え、誤りをホスト側で止めなければならなくなったからです。Tool Calling は呼び出し意図を出し、Structured Outputs は最終オブジェクトを出し、MCP と A2A は供給と交渉を出します。これらを貼り合わせるのが、リポジトリにある検証でき、Diff でき、書き出せる Schema ファイルです。

今日からは、より長い prompt を先に書くより、schemas/tools/create_refund.json を先に書いてください。モデルは入れ替わり、プロトコルは変わります。口径を先に安定させてください。

関連記事

更新履歴: 初稿公開