上一篇《AI Agent 為什麼開始使用 JSON Schema、Function Calling 與 MCP》講的是為什麼會出現這三層。本文換一個視角:盯住一次真實呼叫裡流動的位元組——幾乎全是 JSON。
使用者看到的是自然語言;Agent 真正「辦事」靠的是:把意圖編碼成 JSON 引數、把工具結果編碼成 JSON 訊息、把跨程式協議也編碼成 JSON-RPC。JSON 不是點綴,而是模型、宿主程式、MCP Server 之間唯一能互相校驗的公共語言。
三個名字,同一份 JSON
檔案裡常把三個詞混用,資料流上它們處在不同層,但載荷形狀高度同構:
| 名稱 | 發生在哪兩端 | JSON 扮演的角色 |
|---|---|---|
| Function Calling | 模型 API ↔ 宿主 | tools 定義 + tool_calls.arguments |
| Tool Calling | 同上(更通用的叫法) | 同一套 messages / tools JSON |
| MCP | 宿主 ↔ 工具程式 | JSON-RPC 方法 + inputSchema |
可以記成一句話:模型側用 JSON 選工具、填引數;MCP 側用 JSON 發現工具、執行工具。 宿主是翻譯器:把 MCP 的 tools/list 對映成模型的 tools 陣列,把模型的 tool_calls 對映成 tools/call。
為什麼必須是 JSON
Agent 要同時滿足三方:
- 模型:訓練語料裡 JSON 極多,生成合法物件比生成 protobuf 二進位制容易得多
- 程式:有成熟的解析、Schema 校驗、Diff 與 JSONPath 生態
- 協議:OpenAPI、JSON-RPC、MCP inputSchema 已經綁在同一套型別描述上
純自然語言無法 fail-fast:括號、引號、多語言混寫都會讓正則解析崩潰。YAML 對縮排敏感,模型更容易寫壞。二進位制協議對人類與 LLM 都不友好。於是 JSON 成為「可審計、可校驗、可版本化」的預設導線格式——這也是本站工具全部圍繞 JSON 的原因:你除錯的就是這條導線。
第一跳:工具定義裡的 Schema
資料流從「告訴模型有哪些工具」開始。無論走 OpenAI 風格的 tools,還是 MCP 的 tools/list,核心都是一份 JSON Schema(或其子集):
{
"name": "get_weather",
"description": "查詢指定城市當前天氣,只讀",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名,如上海" },
"unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
},
"required": ["city"]
}
}
MCP 裡同一份約束寫在 inputSchema 欄位。Schema 同時進兩路:校驗器攔截非法引數;模型上下文靠 description 決定何時呼叫。欄位說明寫得越像業務檔案,誤呼叫越少。
第二跳:Function Calling / Tool Calling
宿主把工具列表隨 messages 發給模型後,模型不執行程式碼,只返回結構化呼叫。典型形態(各廠商欄位名略有差異):
{
"role": "assistant",
"tool_calls": [
{
"id": "call_01",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"上海\",\"unit\":\"celsius\"}"
}
}
]
}
注意 arguments 常常是字串化的 JSON:要先 JSON.parse,再按 Schema 校驗,最後才執行。執行結果再以 tool 角色訊息迴流:
{
"role": "tool",
"tool_call_id": "call_01",
"content": "{\"city\":\"上海\",\"temp_c\":31,\"condition\":\"晴\"}"
}
這一跳解決的是「模型如何伸手」。並行多工具時,陣列裡會出現多個 tool_calls,宿主可併發執行,再按 id 把結果對號入座。
第三跳:MCP JSON-RPC
若工具不在宿主程式內,而是獨立 MCP Server(檔案系統、GitHub、內部訂單服務),宿主與 Server 之間走 JSON-RPC 2.0。一次只讀查詢大致三步:
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"host","version":"1.0"}}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_weather","arguments":{"city":"上海"}}}
Server 的成功響應同樣是 JSON:content 陣列裡常見 type: "text",文字內容又是一段 JSON 字串。於是出現「JSON 套 JSON」——外層是協議信封,內層是業務載荷。除錯 MCP 時先分清這兩層,再用 Schema 校驗內層。
傳輸可以是 stdio 或 Streamable HTTP,但載荷仍是 JSON 行或 JSON 體。關於 2026 傳輸與 SDK 是否要改程式碼,見《MCP 2026 遷移指南》。
一次完整呼叫的資料流追蹤
使用者說:「上海今天多少度?」端到端如下:
- Host → MCP Server:
tools/list得到帶inputSchema的工具清單(JSON) - Host → 模型 API:對映為
tools[].parameters(仍是 JSON Schema) - 模型 → Host:
tool_calls,arguments為{"city":"上海"} - Host 校驗:對照 Schema,缺欄位或型別錯誤則拒絕執行,把錯誤 JSON 回喂模型
- Host → MCP:
tools/call,params.arguments為物件(不是字串) - MCP → Host:天氣結果 JSON
- Host → 模型:
role: tool的 content 字串 - 模型 → 使用者:自然語言;若下游系統只要結構,再用輸出 Schema 約束最終 JSON
使用者自然語言
│
▼
Host 編排 ──JSON Schema──► LLM Tool Calling
│ │
│ ▼
│ arguments JSON
│ │
▼ ▼
MCP JSON-RPC ◄──────── 校驗透過才執行
│
▼
結果 JSON ──► tool message ──► 模型最終答覆
小型指令碼可能跳過 MCP,直接在宿主裡調本機函式;企業 Agent 則幾乎總是「Tool Calling + MCP」疊在一起。選型與生態見《2026 MCP Server 排名》。
校驗失敗時資料如何迴流
JSON 能成為 Agent 的「型別系統」,是因為失敗也可以結構化。建議至少兩道閘:
| 閘門 | 校驗物件 | 失敗後怎麼迴流 |
|---|---|---|
| 執行前 | 模型 arguments | 不呼叫真實工具;把 Schema 錯誤寫成 tool 結果或系統提示,讓模型重填 |
| 回寫前 | MCP / 函式返回值 | 截斷、脫敏或標錯;避免把堆疊原文灌進下一輪上下文 |
開發階段把 Schema 與 2~3 組正/反例 payload 存進倉庫,用 JSON 工具箱本機校驗——這和測 REST 契約同一思路,只是消費者換成了模型。
常見問題 FAQ
Tool Calling 和 Function Calling 是一回事嗎?
對開發者幾乎是同一套資料流:宿主把工具 Schema 發給模型,模型返回帶 JSON 引數的呼叫,宿主執行後再把 JSON 結果塞回對話。Function Calling 是早期 OpenAI 命名;Tool Calling / Tools API 是後續更通用的叫法。
MCP 報文為什麼也是 JSON?
MCP 基於 JSON-RPC 2.0:initialize、tools/list、tools/call 的請求與響應都是 JSON 物件。工具的 inputSchema 本身又是 JSON Schema,因此 Host 可以把 MCP 工具一對一對映成模型 API 的 tools 陣列。
模型輸出的 arguments 是字串還是物件?
多數 Chat Completions 風格的 API 把 arguments 做成 JSON 字串,需要宿主 JSON.parse 後再按 Schema 校驗。部分新介面直接給物件。無論哪種,落地前都應用同一份 Schema 校驗。
為什麼不能用 YAML 或 protobuf 替代 JSON?
可以在工具實現內部用任意格式,但模型上下文與跨廠商協議層已把 JSON 當作事實標準。YAML 縮排易錯,protobuf 對模型不友好。常見做法是邊界用 JSON,內部再轉換。
資料流裡哪一層最該做 Schema 校驗?
至少兩處:模型返回 tool_calls 之後、真正執行工具之前;以及 MCP Server 返回結果之後、寫回模型之前。前者防幻覺引數,後者防髒資料汙染下一輪推理。
如何本機驗證這條鏈路上的 JSON?
把 inputSchema、樣例 arguments、工具返回樣例儲存成 JSON 檔案,用 JSON 工具箱在瀏覽器本機校驗 Schema 與資料是否匹配,資料不上傳伺服器。
總結
AI Agent 離不開 JSON,是因為每一跳都要機器可讀:Schema 描述工具,Tool Calling 傳遞呼叫,MCP 用 JSON-RPC 把呼叫送出程式。自然語言只出現在兩端的使用者介面;中間全是可校驗的物件。
建議你從一次真實工具開始:寫出 Schema → 列印模型返回的 arguments 字串並解析 → 若工具在 MCP Server 上,再抓一條 tools/call。三份 JSON 對得上,這條 Agent 才算真正跑通。演進背景見《技術演進全解析》;Schema 樣例可在 JSON 工具箱本機校驗後再上線。