AI AgentのTool CallingはなぜJSON Schemaに依存するか:引数エラー・型エラーと検証方法

Tool Calling、Structured OutputからMCP inputSchemaまで。JSON Schemaがクロスベンダー統一契約になるか、OpenAPI・Protobufとの役割分担。

このシリーズの以前の投稿では、舞台を設定しました。JSON スキーマ、関数呼び出し、およびMCP の進化により、それらが存在する理由が説明されています。 Tool Calling から MCP への JSON データ フローは、バイトが移動する場所をトレースします。 JSON スキーマ が標準の エージェント 契約でエコシステムの収束をカバーしているかどうか。この記事は、なぜ Tool Calling がほぼ必然的に JSON Schema に依存するのか、およびパラメーターと型のエラーを分類および検証する方法という実用的な質問に焦点を当てています。

モデルがツールを選択してパラメータを入力するとき、ホストは「運を信頼」できません。実行前に同じスキーマに対して fail-fast する必要があります。幻覚の議論が 1 つ発生すると、データが削除されたり、間違ったメールが送信されたり、次のターンに悪影響を及ぼしたりする可能性があります。結論: JSON スキーマ は、モデル API、MCP、およびホスト ランタイムによって同様に理解される唯一のパラメーター コントラクトです。解析後実行前に検証し、再試行のために構造化エラーをフィードバックします。

ツール呼び出し が JSON スキーマ に依存する理由

ツール呼び出し (関数呼び出し と同じデータ フロー) は、モデルがツールを選択し、コントラクトに一致する JSON 引数 を出力することを意味します。三者は次のことに同意する必要があります。

  • Model APIs: OpenAI, Gemini, and Anthropic Tools APIs describe parameters with JSON Schema; some vendors also constrain decoding with Schema.
  • MCP: each Tool’s inputSchema is JSON Schema; Hosts often pass it through or trim to a subset when mapping to model APIs.
  • ホスト プログラム: 機械可読、バージョン管理可能、CI チェック可能なコントラクトが必要 — ajv、Python jsonschema などは、「プロンプト内の JSON 形式」よりも桁違いに優れています。

Without Schema, hosts regex-parse or prompt-parse arguments—that breaks at Agent scale. Schema gives shape (which fields), types, and constraints (enum, minimum, pattern)—everything you need syntactically before calling HTTP/DB/MCP. Business rules (“does priority=high violate SLA?”) still need code; Schema blocks most hallucinations at the syntax layer.

User intent → model reads JSON Schema in tools[]
           → outputs tool_calls[].function.arguments (JSON string)
           → host JSON.parse + Schema validate
           → only then call MCP / HTTP / DB

スキーマが呼び出しチェーン上の 3 つの場所に存在する

ステージスキーマの役割典型的な失敗
ツール登録(ツール/MCPリスト)どのようなツールが存在し、どのような引数が必要なのかをモデルに伝えます。無効なスキーマ、ドラフトの不一致、誤解を招く説明
モデル出力 (tool_calls.arguments)生成されたパラメータ JSON を制約します必須フィールドの欠落、間違ったタイプ、作成されたフィールド
ツールの結果 (メッセージ)オプション: コンテキストの前に結果の形状を制約します非 JSON 応答、フィールド ドリフト

Vs. 構造化された出力: Structured Output constrains the final user-facing JSON reply; Tool Calling Schema constrains execution parameters. You can share one Schema source (Pydantic / Zod), but validate Tool arguments on every tool_calls before execute.

パラメータエラー: 欠落、余分、間違った名前、構文

パラメーター エラーは、JSON は解析できる (または解析前に失敗する) が、スキーマ キーと必要なルールに違反していることを意味します。

エラー例スキーマキーワード緩和
必須がありませんSchema needs title, args only have priorityrequiredエラーをフィードバックします。説明で必要なことを明確にする
追加フィールドModel invents urgent: trueadditionalProperties: falseOpenAI はしばしば厳格に適用されます。それ以外の場合は剥がすか拒否します
キーのスペルが間違っていますtitel vs titleproperties keys一貫した命名。強力な説明
JSON 構文末尾のカンマ、一重引用符(解析層)最初にJSON.parse; 構造化された出力 により構文エラーが削減されます
空の引数{} but Schema has requiredrequired, minPropertiesZero-arg tools: explicit properties: {}
// Schema fragment
{
  "type": "object",
  "properties": {
    "ticket_id": { "type": "string", "description": "Ticket ID" },
    "note": { "type": "string" }
  },
  "required": ["ticket_id"],
  "additionalProperties": false
}

// Model output (missing ticket_id) → validation fails
{ "note": "Please handle ASAP" }

型エラー: 不一致、enum、ネスト、強制

型エラー: フィールドは存在しますが、値の JSON 型または形式がスキーマに違反しています:

エラー例よくある原因
プリミティブ型limit: "10" should be numberモデルは数値を文字列化することがよくあります
列挙 違反priority: "urgent", enum is low/medium/high説明に許可される値がリストされていませんでした
ネストされた配列/オブジェクトExpected tags: [], got stringモデルのサブセットに対してスキーマが複雑すぎる
フォーマット文字列email fails format: email幻覚を起こした電子メールまたは日付の形式
いずれか/いずれかポリモーフィック arg はブランチに一致しませんターゲット API の複雑すぎるスキーマ

Coercion: some validators coerce "10" to 10. In production Agents, prefer coercion off—silent fixes hide systematic drift. If you must coerce, document it and lock behavior in CI samples.

// Type error example
Schema: { "limit": { "type": "integer", "minimum": 1, "maximum": 100 } }
Model:  { "limit": " fifty " }  // string, not numeric → fail

検証: 構文、引数、厳密モード

1. スキーマ自体を検証する

Before registering tools, meta-validate parameters / inputSchema (draft 2020-12, etc.). JSON Toolbox in the browser works locally—don’t ship invalid Schema to model APIs.

2. 引数 をスキーマに対して検証します

After JSON.parse(arguments), validate with the same Schema used at registration:

  • JavaScript / TypeScript: ajv (mind draft and strict options)
  • Python: jsonschema, Pydantic (model_validate after JSON parse)
  • Codegen: Zod / Pydantic → JSON Schema シングルソース

3. ベンダー 厳密モード

OpenAI strict: true requires a stricter subset (e.g. all objects with additionalProperties: false). That reduces model-side errors but does not replace host validation—dialects differ by vendor; see the 契約条項.

4. サンプル主導型 CI

ツールごと: 有効な引数サンプル + CI での意図的な失敗。スキーマの変更は API の破壊的な変更であり、バージョンを変更します。

エンドツーエンドのパイプラインとエラーのフィードバック

最小限のパイプライン (データフローの記事を拡張):

1. tools/list or static register → validate each inputSchema syntax
2. On tool_calls → JSON.parse(arguments)
   ├─ parse fail → tool message "JSON syntax error: …" → model retry
   └─ parse ok → ajv/jsonschema validate
        ├─ fail → structured errors (missing, type, enum) → feed back
        └─ ok → execute + optional business rules
3. Tool result → optional result Schema before append to messages
4. Log: schema version, raw arguments, error codes (no secrets)

Error feedback must be machine-readable: “ticket_id is required” beats “bad params, retry”. Many frameworks format validation errors as JSON in the tool role for self-correction.

実行には依然として認証と冪等性が必要です。スキーマは「この ticket_id がユーザーに属する」のではなく、形状を保証します。

実践的な推奨事項

  • 単一のスキーマ ソース: Pydantic / Zod → MCP inputSchema + OpenAI ツール。
  • 説明はプロンプトです。説明は、enum と必要なコンプライアンスを推進し、API コードなどのスキーマを確認します。
  • シンプルなスキーマ、厳密な検証: oneOf/$ref の深さをターゲット API サブセットにトリミングします。すぐに失敗し、サイレント修正はありません。
  • 2 つの必須チェックポイント: tool_calls の後、実行前。 MCP の後、コンテキストの前に戻ります (結果がモデルにフィードされる場合)。
  • まずローカルで検証します。運用前に、スキーマ + サンプル arguments を JSON Toolbox に貼り付けます。
  • 構造化出力 とは別に: ユーザー応答スキーマとツール スキーマ — マージしないでください。

よくある質問

ツール呼び出し で JSON スキーマ をスキップし、パラメーターに自然言語を使用できますか?

プロトタイプはあります。製造番号自然言語は「フェイルファスト」や CI バージョンを使用できません。モデルではフィールドとドリフト タイプが省略されます。メインストリーム API と MCP のデフォルトはスキーマです。

arguments は文字列ですか、それともオブジェクトですか?

ほとんどのチャット完了 API は JSON 文字列を使用し、JSON.parse をホストして検証します。一部の新しい API はオブジェクトを返します。いずれの場合も、同じスキーマを使用して検証します。

検証失敗時の再試行回数は何回ですか?

多くの場合、1 ~ 3 で構造化されたエラーのフィードバックがあり、その後明確にするかエスカレーションします。無限に再試行するとトークンが消費され、幻覚がループする可能性があります。

ajv vs ピダンティック?

ノード/TS ホスト: JSON スキーマ 上の ajv を直接実行します。 Pydantic モデルを使用した Python: 実行時にスキーマ + model_validate を生成します。モデル側のスキーマと同じソース。

strict モード をオンにしても、ホスト上で検証しますか?

はい。厳密にはモデルエラーを削減します。汚い MCP の結果、スキーマ/コードのドリフト、またはビジネス ルール違反は止まりません。

スキーマと 引数 をローカルで検証するにはどうすればよいですか?

スキーマとサンプル JSON を JSON ツールボックス に貼り付けます — ブラウザーローカル検証、何もアップロードされません。

まとめと次のステップ

ツール呼び出し は、JSON スキーマ に依存します。これは、モデル、MCP、およびホストの共有の検証可能なパラメーター コントラクトであるためです。パラメータエラー (欠落、余分、間違った名前、構文) と型エラー (型、enum、ネスト) を分類します。実行前にインターセプトし、自己修正のために構造化エラーをフィードします。

次に、実際のツール (チケット作成など) を 1 つ選択し、スキーマと有効/無効なサンプルを作成し、JSON ツールボックス でローカルに検証してから、エージェント を接続します。シリーズの順序: 進化 → データ フロー → 契約 → この記事 (検証)。