你的 AI 代理會呼叫工具:HTTP API、MCP 伺服器及其他服務。 這些工具會超時、達到速率限制、回傳錯誤,還會以你意想不到的格式傳送資料。 模型會根據你的程式碼傳回來的內容來決定下一步該怎麼做。 如果你的程式碼回傳例外、空字串,或長時間等待後什麼都沒有,代理程式的行為會和收到明顯錯誤時不同。
工具故障如何出錯
- 代理程式當機。 沒有逾時的工具呼叫會讓使用者等待。
- 代理程式進入迴圈。 模型會一再呼叫失敗的工具,消耗代幣和工具的速率上限。
- 特工把它掩蓋起來。 你的程式碼吞下錯誤,模型則像工具成功一樣回應。
- 代理程式當機了。 未處理的例外會結束整個對話。
如何處理工具故障
- 每次工具呼叫都設定暫停時間,並設定整回合的預算。 MCP 規範指出客戶端應為工具呼叫實施逾時。
- 重試程式碼中的臨時錯誤。 在工具代碼中處理 429 和 503 的回應,尊重
Retry-After並限制嘗試次數,這樣模型就不用決定何時重試。 - 將失敗結果以明確結果回傳給模型。 MCP 將協定錯誤(如未知工具或無效參數)與工具執行錯誤(如 API 失敗)區分開來。 它會在工具結果中以
isError: true回報執行錯誤,讓模型能看到哪裡出錯。 說出什麼失敗了,以及是否值得再試一次。 - 限制每回合工具呼叫次數。 在一定次數失敗後,停止並告訴使用者。
- 在交給模型之前,先驗證工具的結果。 MCP 規範說客戶端應該這麼做,並且當工具有輸出結構時,應該用結構化結果來驗證。
- 告訴使用者哪裡出了問題。 一個基於失敗工具呼叫的答案應該明確說明工具呼叫失敗。
如何在你的代理程式中測試工具失效處理
| Approach | 你發現的 | 你錯過的內容 |
|---|---|---|
| 用 stubbed 客戶端對你的工具包裝程式進行單元測試 | 你的程式碼如何對應你所寫的失敗案例 | 模型怎麼處理它,以及真正的工具如何失效 |
| 中斷真實環境,例如停止伺服器或撤銷金鑰 | 那種真正的失敗 | 速率限制、反應緩慢,以及資料錯誤,這些情況不是你能隨時刻意重現的 |
| 寫一個假的 API 或 MCP 伺服器 | 任何你編寫的回應 | 你必須讓你的代理程式指向假目標,而它會逐漸偏離真正的工具 |
| 攔截代理的真實工具流量並注入故障 | 執行中的代理和模型如何處理錯誤、延遲和來自真實工具的錯誤資料 | 單獨來看你的程式碼。 把單元測試留到那種情況再用。 |
模型輸出在不同執行中可能有所不同,因此每個失敗情境應執行多次。
在你的應用程式中試試看
Dev Proxy 位於你的代理程式與其工具之間,注入故障,且不會修改代理程式的程式碼。
對於呼叫 HTTP API 的工具,結合隨機錯誤、延遲,以及檢查代理是否依 API 要求的時間等待:
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
"plugins": [
{
"name": "RetryAfterPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
},
{
"name": "LatencyPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "latencyPlugin"
},
{
"name": "GenericRandomErrorPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "errorsContosoApi"
}
],
"urlsToWatch": [
"https://api.contoso.com/*"
],
"latencyPlugin": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/latencyplugin.schema.json",
"minMs": 2000,
"maxMs": 10000
},
"errorsContosoApi": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/genericrandomerrorplugin.schema.json",
"errorsFile": "errors-contoso-api.json",
"rate": 50
}
}
如 以隨機錯誤測試我的應用程式 所述,在 errors-contoso-api.json 中設定錯誤。 將 Retry-After 設為 @dynamic,在你的 429 回覆中。 RetryAfterPlugin 只檢查這些。
對於使用 STDIO 的 MCP 伺服器,請透過 devproxy stdio 啟動伺服器,並使用啟用 MockStdioResponsePlugin 的設定,如 stdio 設定範例所示。 儲存為 devproxyrc-stdio.json。 接著將此放入 stdio-mocks.json 中,讓每個 tools/call 請求都回傳一個工具執行錯誤:
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/mockstdioresponseplugin.mocksfile.schema.json",
"mocks": [
{
"request": {
"bodyFragment": "tools/call"
},
"response": {
"stdout": "{\"jsonrpc\":\"2.0\",\"id\":@stdin.body.id,\"result\":{\"content\":[{\"type\":\"text\",\"text\":\"Failed to fetch weather data: API rate limit exceeded\"}],\"isError\":true}}\n"
}
}
]
}
devproxy stdio --config-file devproxyrc-stdio.json npx -y @modelcontextprotocol/server-filesystem
要讓你的代理程式使用它,請在代理的 MCP 伺服器設定中更改指令,使其透過 devproxy stdio 啟動伺服器。 在 mock 物件上使用 nth 屬性,只讓特定呼叫失敗,並加入 LatencyPlugin 來減慢伺服器的回應速度。
為了測試你的代理在模型本身失敗時的反應,LanguageModelFailurePlugin 會讓模型產生幻覺、忽略指令,或用錯誤格式回答。 請參考 「使用語言模型失敗情境測試我的應用程式」。
要安裝 Dev Proxy,請參見 設定 Dev Proxy。