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中定义错误,如用随机错误测试我的应用中所述。 在您的 429 响应中,将 Retry-After 设为 @dynamic。 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。