如何測試當你的 AI 代理的工具失效時會做什麼

你的 AI 代理會呼叫工具:HTTP API、MCP 伺服器及其他服務。 這些工具會超時、達到速率限制、回傳錯誤,還會以你意想不到的格式傳送資料。 模型會根據你的程式碼傳回來的內容來決定下一步該怎麼做。 如果你的程式碼回傳例外、空字串,或長時間等待後什麼都沒有,代理程式的行為會和收到明顯錯誤時不同。

工具故障如何出錯

  • 代理程式當機。 沒有逾時的工具呼叫會讓使用者等待。
  • 代理程式進入迴圈。 模型會一再呼叫失敗的工具,消耗代幣和工具的速率上限。
  • 特工把它掩蓋起來。 你的程式碼吞下錯誤,模型則像工具成功一樣回應。
  • 代理程式當機了。 未處理的例外會結束整個對話。

如何處理工具故障

  1. 每次工具呼叫都設定暫停時間,並設定整回合的預算。 MCP 規範指出客戶端應為工具呼叫實施逾時。
  2. 重試程式碼中的臨時錯誤。 在工具代碼中處理 429 和 503 的回應,尊重 Retry-After並限制嘗試次數,這樣模型就不用決定何時重試。
  3. 將失敗結果以明確結果回傳給模型。 MCP 將協定錯誤(如未知工具或無效參數)與工具執行錯誤(如 API 失敗)區分開來。 它會在工具結果中以 isError: true 回報執行錯誤,讓模型能看到哪裡出錯。 說出什麼失敗了,以及是否值得再試一次。
  4. 限制每回合工具呼叫次數。 在一定次數失敗後,停止並告訴使用者。
  5. 在交給模型之前,先驗證工具的結果。 MCP 規範說客戶端應該這麼做,並且當工具有輸出結構時,應該用結構化結果來驗證。
  6. 告訴使用者哪裡出了問題。 一個基於失敗工具呼叫的答案應該明確說明工具呼叫失敗。

如何在你的代理程式中測試工具失效處理

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。

下一步

也請參閱