症狀:JSON 明明可以解析,Agent 卻仍然選錯工具、API 被拒絕,或拿到 MCP 結果後無法繼續。
最快解法:把問題拆成五層,依序驗證 JSON 語法、Schema、工具選擇與權限、呼叫關聯、結果消費,不要只檢查「是不是合法 JSON」。
這篇適合三類讀者:
Agent 開發者需要理解呼叫鏈中 JSON 的實際角色;排障工程師需要定位參數、狀態與結果錯誤;平台架構師則需要設計統一事件、日誌和 Schema 版本。
JSON 不是推理引擎,而是可驗證的資料邊界
AI Agent 並不是靠 JSON 完成推理,而是靠 JSON 及 Schema 在模型、編排器、工具和 API 之間傳遞機器資料。模型負責理解任務和提出工具呼叫,應用程式負責驗證、授權與執行,協定負責傳輸,業務系統則負責最後的狀態判定。
以「替客戶建立工單」為例,一次完整鏈路通常是:
- 使用者提出自然語言需求。
- 模型根據工具名稱、描述與輸入 Schema 產生工具呼叫。
- 編排器解析工具名稱和參數,執行本地函式或遠端 API。
- 執行器回傳成功或結構化錯誤。
- 編排器以原始呼叫 ID 將結果放回對話狀態。
- 模型讀取工具結果,產生下一個動作或最終回答。
- 業務層驗證工單是否真的建立,而不是只相信模型文字。
OpenAI 的工具呼叫資料通常包含工具名稱、JSON 格式的 arguments 和 tool call ID;Google 的 Function Calling 流程則明確要求由你的應用程式執行函式,再把結果送回模型。你可以參考 OpenAI Function Calling API 參考 與 Google Gemini Function Calling 官方文件 對照各自欄位,不要把不同平台的訊息格式直接混用。(platform.openai.com)
先分清楚四個責任層
- 模型生成層:產生工具名稱、參數和下一步意圖。
- 應用執行層:驗證參數、認證、授權、呼叫 API。
- 協定傳輸層:保存訊息順序、呼叫 ID、結果格式。
- 業務驗證層:確認資源真的建立、更新或刪除。
只要你把這四層混在同一個 agent_error 欄位裡,日誌就只能告訴你「失敗」,不能告訴你到底是誰的責任。
「能解析」仍然不代表呼叫成功
第一層:JSON 合法,但 Schema 不合規
以下資料在語法上是合法 JSON:
{
"ticket_id": 123,
"priority": "urgent"
}
但如果 Schema 要求 ticket_id 是字串、priority 只能是 low、normal 或 high,這個請求就會在結構驗證階段失敗。常見問題包括:
- 必填欄位遺失;
- 字串、數字、布林值型別錯誤;
- 陣列元素格式不一致;
- 出現執行器未預期的額外欄位;
- Schema 版本更新後,舊工具仍送出舊欄位。
因此,驗證順序應是「先 JSON parser,再 JSON Schema validator」。不要使用 json.loads() 成功作為放行條件。不同模型平台也只支援各自文件定義的 Schema 子集;即使名稱都叫 JSON Schema,嚴格模式可接受的關鍵字未必相同。OpenAI 官方文件也提醒,嚴格工具呼叫只支援部分 JSON Schema,且應在你的程式中再次驗證 arguments。(platform.openai.com)
第二層:Schema 合規,但工具選錯
假設你同時提供:
create_ticketupdate_ticketsearch_ticket
三個工具,而模型選了 update_ticket。即使參數完全符合 Schema,執行結果仍可能錯誤,因為模型的「工具語意判斷」出錯。
這時繼續收緊欄位型別通常沒有幫助。你應該檢查:
- 工具名稱是否直接描述動作,不要使用過度相似的名稱;
- 描述是否寫明「何時使用」及「何時不要使用」;
- 候選工具範圍是否過大;
- 使用者目前是查詢、建立還是修改;
- 工具是否明確標示唯讀、破壞性或需要確認。
這也是 Tool Calling 的核心邊界:Schema 管理「參數長什麼樣」,工具描述和上下文管理「應該呼叫哪一個」。
第三層:參數正確,但 API 執行被拒絕
API 拒絕不一定是模型錯。至少要分開記錄:
- 認證失敗,例如 API Key 過期;
- 授權不足,例如帳戶沒有修改資源的權限;
- 資源狀態不允許,例如工單已關閉;
- 網路、DNS、逾時或上游服務不可用;
- 業務規則不符合,例如重複訂單或超過限額。
執行器不能只回傳「request failed」。應該產生模型和人都能讀懂的結構,例如:
{
"ok": false,
"error": {
"code": "RESOURCE_STATE_INVALID",
"retryable": false,
"message": "ticket is already closed"
}
}
其中 code 用於程式分支,retryable 用於決定是否重試,message 才是提供模型理解的補充說明。這比讓模型從 HTTP 狀態碼或一段堆疊追蹤中猜原因可靠得多。
五層故障分流表
下面這張表可用來建立你的第一版排障分流規則:
| 檢查層 | 典型症狀 | 應保存的欄位 | 修正方向 |
|---|---|---|---|
| JSON 語法 | 解析器直接報錯 | 原始 arguments、解析錯誤位置 | 修正序列化或串流拼接 |
| Schema | 缺欄位、型別錯誤 | Schema 版本、驗證差異 | 更新工具定義或參數映射 |
| 工具選擇 | 呼叫了不相關工具 | 候選工具、描述、上下文 | 縮小工具範圍、重寫描述 |
| 執行與權限 | API 401、403 或業務拒絕 | 權限決策、資源狀態、錯誤碼 | 在執行器處理,不交給模型猜 |
| 狀態與結果 | 重複執行、結果錯配 | interaction ID、call ID、結果版本 | 修復歷史順序與關聯鍵 |
這個分法的價值在於,你可以先回答「失敗發生在哪一層」,再決定要改提示詞、Schema、執行器,還是狀態儲存。不要一看到工具失敗就降低模型溫度或無限重試。
呼叫 ID 遺失會破壞長任務狀態
在單一工具的簡單流程中,呼叫 ID 遺失可能只造成一次回傳錯誤;但在並行工具或長任務中,後果會嚴重得多。
例如模型同時呼叫:
[
{"id": "call_a", "name": "get_user", "arguments": {"id": "u1"}},
{"id": "call_b", "name": "get_orders", "arguments": {"user_id": "u1"}}
]
如果執行器只保存工具名稱,沒有保存 call_a 和 call_b,兩個結果回來後就可能互相配錯。常見結果是:
- 模型把訂單清單當成使用者資料;
- 同一個工具因為「沒有收到結果」而再次執行;
- 編排器無法判定哪些工具已完成;
- 長任務在中途停止,重試後又重複修改資源。
Google 的新式互動流程要求在回傳 function result 時帶回對應的 call_id;OpenAI 的工具訊息也使用 tool_call_id 關聯結果。Anthropic 的工具使用則要求 tool_result 緊接在原本的 tool_use 之後,並以 tool_use_id 配對。這些名稱不同,但責任相同:結果必須可追溯到唯一一次呼叫。(ai.google.dev)
第二步:保存完整狀態,而不是只保存最後一句話
若你採用無狀態模式,每次後續請求都要由客戶端保留完整歷史,包括使用者輸入、模型產生的工具呼叫,以及工具結果。Google 官方文件特別列出這個要求;缺少其中一段,模型就可能看不到先前的呼叫上下文。(ai.google.dev)
建議至少保存以下欄位:
{
"trace_id": "trace-...",
"interaction_id": "interaction-...",
"tool_call_id": "call-...",
"tool_name": "get_orders",
"schema_version": "orders.v3",
"status": "executed",
"result_hash": "sha256:..."
}
不要只記錄最終回答。真正能幫你重現問題的,是每一個模型輸出、執行決策、權限結果和工具回傳。
MCP 結果返回後仍要做下游驗證
Model Context Protocol 對工具結果提供兩種重要路徑:
content:可包含文字、圖片、資源連結等內容;structuredContent:供程式和客戶端消費的結構化 JSON;outputSchema:描述結構化結果應符合的格式。
MCP 規範指出,如果工具提供 outputSchema,伺服器必須提供符合該 Schema 的結構化結果;客戶端則應進行驗證。為了相容較舊的客戶端,工具在提供結構化內容時,也應保留序列化後的文字內容。(modelcontextprotocol.io)
所以,不要假設收到 structuredContent 就代表下游一定能用。你還要檢查:
- 客戶端是否真的支援該欄位;
structuredContent是否符合當前outputSchema;- 文字
content是否能作為相容降級; - 結果是否包含
isError或等效錯誤狀態; - Schema 版本是否和消費端一致。
MCP 版本與提案可能持續調整,尤其是 outputSchema 對 JSON Schema 子集的支援範圍。部署前應以 MCP Tools 規範 和 MCP Schema Reference 作為實作依據,不要把某個 SDK 的型別定義當成所有客戶端的共同標準。(modelcontextprotocol.io)
FAQ:排查 JSON 資料流時最容易混淆的問題
AI Agent 為什麼普遍使用 JSON?
JSON 能讓欄位、陣列和巢狀物件保持明確邊界,方便模型輸出後由程式驗證,也方便日誌系統保存和重播。但 JSON 只解決「怎樣表示資料」,並不解決工具選擇、權限、資源狀態或業務正確性。
Function Calling 的 JSON 是模型直接執行的嗎?
不是。模型只產生函式名稱和參數,實際執行者是你的編排器或應用程式。執行前必須驗證 Schema、檢查認證與授權,執行後再把結果連同原始呼叫 ID 傳回模型。
MCP 工具結果如何讓模型繼續工作?
MCP 伺服器回傳工具結果後,客戶端會將結果放入後續模型互動。結構化資料可放在 structuredContent,人類可讀內容則放在 content;兩者都應保留,讓不同客戶端有降級處理空間。
JSON 已經合法,Agent 為什麼仍會失敗?
合法 JSON 不等於符合 Schema,也不等於工具選擇正確。你還要檢查必填欄位、型別、列舉值、工具描述、認證、授權、資源狀態和業務規則,並把每一層的錯誤分開記錄。
呼叫 ID 不見了,怎樣判斷是否已經重複執行?
先比對 trace ID、工具名稱、參數雜湊和執行器的冪等鍵。如果只有模型訊息沒有執行事件,不能直接判定已成功;對有副作用的工具,應在執行器保存唯一請求鍵,避免重試造成重複建立或修改。
第三步:建立可重播的統一事件日誌
你可以把所有平台轉成內部統一事件,但不要抹掉原始欄位。推薦事件至少分成:
model_tool_proposed:模型提出工具名稱、原始參數和模型回應 ID;schema_validated:使用哪個 Schema 版本、驗證成功或失敗;permission_decided:使用者、服務帳戶、資源和授權結果;tool_executed:開始時間、結束時間、重試次數和執行結果;protocol_returned:原始 call ID、MCP 結果欄位和訊息順序;business_verified:資源最終狀態,以及是否真的完成任務。
可勾選的驗收清單
- [ ] 每次工具呼叫都有唯一
trace_id和tool_call_id。 - [ ] 原始 arguments 與解析後物件分開保存。
- [ ] 每次驗證都記錄 Schema 名稱與版本。
- [ ] 工具選擇錯誤和參數驗證錯誤分成不同錯誤碼。
- [ ] API 401、403、逾時和業務拒絕不共用同一個失敗狀態。
- [ ] 並行工具結果回傳前,已用呼叫 ID 完成配對。
- [ ] MCP 結果同時保留
content、structuredContent和錯誤狀態。 - [ ] 具副作用的工具具備冪等鍵或去重策略。
- [ ] 日誌可依 trace ID 重播完整對話與執行鏈。
- [ ] 涉及 macOS 工具時,同時記錄遠端環境、權限提示和依賴版本。
如果你正在建立驗收規則,可以先閱讀 Kvmzen 繁體中文幫助中心,把權限、遠端連線與環境重現條件一起納入平台作業文件。
你應該採用的六步落地流程
第一步,先固定一個可重現任務,例如查詢資料、建立資源或執行 macOS 指令,不要一開始就用多工具複合流程。
第二步,故意注入四類故障:Schema 缺欄位、權限拒絕、呼叫 ID 遺失、MCP 結果與 outputSchema 不匹配。
第三步,確認每類故障是否落到不同事件和錯誤碼,而不是全部變成「Agent failed」。
第四步,加入並行工具測試,檢查結果順序改變時,編排器是否仍能用 ID 正確配對。
第五步,測試重試與中斷恢復。特別是建立、刪除、付款或修改檔案等有副作用操作,必須確認重試不會重複執行。
第六步,將平台原始訊息保存在冷資料區,內部統一事件則提供查詢介面。這樣既能跨平台分析,也不會因欄位正規化而失去原始證據。
當前環境與 Mac 方案,差異在可重現性
如果你的 Agent 依賴 macOS 指令、Xcode、AppleScript、iOS 模擬器或本機權限,目前環境常見的缺點是:開發者各自使用不同版本、權限狀態難以複製、錯誤日誌分散在本機,而且排障時還要等待同事釋放設備。Windows 或 Linux 雲端主機雖然適合一般 API 編排,但遇到 macOS 專屬工具時,往往需要額外轉接層,增加權限和狀態差異。
若你要持續重現跨層呼叫故障,租用 Kvmzen 的 Mac 環境會更適合短期測試、隔離依賴和遠端協作;你可以先從 Mac 雲端租用方案確認環境,再把固定的 Schema、事件日誌與測試案例部署上去。若團隊需要比較自購設備與遠端環境,也可先參考 Mac mini 價格與方案資訊,再按任務週期、硬體介面需求與長期負載作決定。
如果你的工作是全年穩定重負載、必須接實體 USB 或特殊周邊,自購 Mac 仍可能更合理;但若目標是隔離環境、臨時重現問題或驗證一條 MCP 與 Function Calling 呼叫鏈,遠端 Mac 通常能讓你更快建立一致的測試條件。
