Agent 工具调用失败怎么办?从错误分类、超时接管到幂等重试的工程指南

Agent 调用工具失败后,不能只给它加一句“失败就重试三次”。查资料时多试一次,可能只是多花几秒;发邮件、创建订单、执行部署时多试一次,却可能真的做两遍。

更可靠的处理顺序是:先判断哪里失败、操作是否已经发生,再决定等待重试、修改参数、查询状态,还是停止并交给人处理。

OpenAI 和 Anthropic 的官方指南都要求为 Agent 设置退出条件、失败边界和人工接管机制。具体到退避、进程清理和防重复执行,还需要沿用分布式系统的工程方法。[1][2]

一、先分清:模型请求失败,还是工具执行失败?

一次工具调用通常有几个环节:应用请求模型,模型给出工具名和参数,应用执行工具,再把结果交回模型。

因此,“Agent 报错”至少可能发生在这些位置:

失败位置 常见表现 首先检查什么
模型 API 限流、余额不足、请求过大、服务异常 API 错误码、请求 ID、额度与请求大小
工具调用格式 工具不存在、缺少字段、类型不符 工具定义、参数校验、协议格式
工具运行环境 网络断开、命令卡住、依赖不可用 连接状态、进程状态、执行日志
业务操作 库存不足、订单状态不允许、无权限 业务规则和实际状态
结果回传 执行完成,但响应丢失或会话中断 执行记录、任务 ID、业务对象是否已创建

OpenAI 的 Function calling 文档明确把工具执行放在应用侧。模型提出调用,并不等于模型 API 替应用完成了业务操作。[3]

这一区分直接影响恢复方式:重新请求模型,不能代替检查上一次订单是否已经创建;工具参数错误,也不应该靠反复请求同一个外部服务解决。

二、错误类型和操作风险,要分开判断

“网络错误”“参数错误”“超时”描述的是失败情况;“是否会扣款、是否会修改数据”描述的是操作属性。它们不是互斥的四种错误。

同样一次网络超时,读取天气和创建付款的处理方式就不同。

建议按下面的表确定第一步。实际允许哪些错误自动恢复,应由工具实现和服务接口约定决定,而不是只看 HTTP 状态码。[4][5]

情况 默认处理 不应该做什么
临时限流、短暂服务不可用 在确认可以安全重复后,有限退避重试 立即连续发送相同请求
缺字段、参数非法 返回具体错误,让模型修正后重新提交 原参数原样重放
余额不足、权限不足 停止相关操作,提示需要外部处理 让模型反复尝试绕过限制
超时或响应丢失 先确认执行状态 直接认定“没有执行”
写入操作且结果未知 查询状态,或在已有幂等保障下恢复 换一个新请求标识再试
超出恢复预算 停止、降级或人工接管 一直循环到“成功”为止

一个容易误判的例子是 429。OpenAI 的错误文档区分了请求速率受限和额度、账单限制;后者需要先调整额度或账单条件,等待几秒并不会恢复访问。[4]

三、瞬时错误可以重试,但需要边界

对于接口明确允许安全重复的请求,临时故障适合退避重试。AWS 的工程资料建议使用指数退避、随机抖动,并限制重试次数或累计时间,避免服务已经过载时再增加压力。[5]

一套可落地的配置应包含:

  • 哪些错误允许重试,哪些必须立即停止。
  • 单次调用的超时。
  • 最大尝试次数,以及整个任务的截止时间。
  • 等待间隔的上限和随机化规则。
  • 服务端给出的等待提示如何处理。
  • 重试预算耗尽后,返回什么状态、交给谁处理。

例如,可以把等待时间设计为 random(0, min(cap, base × 2^n))。这是实现选择,不是所有工具必须采用的统一公式。服务端返回有效的 Retry-After 时,应结合接口约定和剩余任务时间安排等待;如果需要等待的时间超过任务预算,就应结束本轮或安排稍后恢复,而不是继续占着执行槽位。

还要检查 SDK 是否已经自动重试。OpenAI 官方 Python SDK 文档说明,部分连接错误、408、409、429 和服务端错误默认有自动重试行为。它针对的是模型 API 请求,不能据此推断自己的付款工具也能安全重试。[6]

如果 SDK、工具封装和 Agent 外层各自都允许最多三次尝试,三层嵌套最坏可能形成 27 次底层请求。这个数字是配置示例,不是某个框架的默认行为。AWS 明确提醒不要在多个层级叠加重试,建议选择合适的一层统一控制。[5]

四、参数错了,应该让模型改;权限错了,应该停

确定性错误的共同点是:在条件不变的情况下,原样再试通常不会变好。

但“回传给模型”不等于“模型都能修好”。

缺少日期、传错枚举值,可以给出字段要求,让模型修正。余额不足、账号无权限、缺少用户授权,则需要停止相关操作或请求用户处理。模型不应该为了完成任务,自行改账号、扩大权限或绕过审批。

Anthropic 建议把工具错误写成可操作的反馈,指出具体问题和允许的下一步,而不是只返回一个 failed 或大段堆栈。[7]

例如,创建日程失败后,可以返回:“结束时间早于开始时间;本次未创建日程。请检查两个时间字段。”这比“参数错误”更容易帮助模型恢复。

对于输入格式,OpenAI 推荐使用严格模式约束工具参数,使调用符合声明的结构。但符合结构不代表符合业务:一个金额可以类型正确,却超过允许的上限;一个订单 ID 可以格式正确,却属于其他用户。应用仍然需要验证业务条件和权限。[3]

错误标记也不是跨平台统一的:Claude 的客户端工具结果可以使用 is_error: true,MCP 的工具执行错误使用 isError: true;OpenAI 的函数结果则按其 API 格式回传。这些字段不能直接互换。[8][9][3]

五、超时后,先确认执行状态

超时只说明等待方没有按时拿到结果,不说明操作没有发生。 AWS 的重试资料特别提醒,调用超时或失败时,副作用可能已经发生。[10]

对本地命令和远端接口,需要分别处理。

本地命令:取消等待,不一定会结束进程

以 Python 为例,Popen.communicate(timeout=...) 超时后不会自动杀死子进程;官方文档要求应用在异常后清理进程并完成输出收集。另一种接口 subprocess.run(timeout=...) 的行为不同,不能把某个接口的行为推广到全部执行器。[11]

对短命令,工程上可以采用明确的终止流程:请求正常退出,超过宽限期后再强制结束,并回收输出和执行状态。涉及 shell、子进程或进程树时,还需要执行器按操作系统实现相应的清理。

但终止进程也不等于撤销已完成的修改。命令可能已经写了一半文件,或者向远端发出部署请求。恢复前仍要检查实际状态。[10]

长任务:从启动时就交给可查询的任务系统

构建、批量测试、数据导出等耗时任务,可以从启动时就由任务管理器托管,返回任务 ID,再查询状态、日志和结果。

推荐至少区分“已受理”“运行中”“成功”“失败”“已取消”;无法确认最终结果时,保留“结果未知”,不要伪装成失败或成功。这能让应用知道自己下一步能安全做什么。

所谓后台接管,也不是发生超时后再随手补一个 &。执行环境必须提前支持任务持久化、状态查询、取消和资源回收。否则只是让用户看不到进程,并没有解决任务管理。

Anthropic 在多 Agent 研究系统的工程总结中提到,长时间运行的系统需要保存状态并支持从故障中恢复,而不是每次故障都从头重启。[12]

远端操作:优先查询业务状态

创建订单、发邮件、提交部署等接口超时后,应先用已有的订单号、任务 ID 或业务请求标识查询状态。查询暂时没有结果,也未必就能证明原请求没有到达;如果接口没有防重复执行的约定,结果未知时应暂停并核对。[13]

六、有副作用的工具,幂等保障必须在第一次执行前准备好

发送邮件、创建工单、退款、发布帖子,和付款一样,都可能因重试而重复执行。

同一个业务操作的重试,需要复用同一个幂等键;新的业务操作才使用新键。 AWS 关于幂等 API 的资料说明,请求标识应在重试过程中保持一致,服务端也需要识别相同标识对应的请求。[13]

如果模型超时后重新发起调用,而应用每次都生成新 key,服务端就可能把它们当作两个不同操作。

以创建订单为例,推荐的恢复过程是:

  1. 应用先建立本次业务操作记录,保存操作标识和稳定的请求参数。
  2. 第一次提交时,把该标识用于服务端支持的幂等机制。
  3. 发生超时后,把状态记为“结果未知”,保留原标识。
  4. 通过业务状态查询核对;需要重发时,按服务端约定复用原标识和原参数。
  5. 只有收到明确结果,或完成核对后,才更新本地状态。

操作记录和幂等保障需要由应用实现,不能只靠提示词或模型自行记忆。

还有几个不能省略的限制:

  • 服务端必须真正支持幂等;给任意接口添加一个同名 HTTP 头不会自动生效。
  • 相同 key 对应的参数通常需要保持一致。改变金额或收件人,不能继续假装是原请求的重试。
  • 服务端必须处理并发重复请求,不能只有“先查缓存、再执行”的松散逻辑。
  • key 的保留时间、接口范围和失败结果处理方式,都要按具体服务约定确认。

Stripe 提供了具体例子:它会保存某个幂等键首次进入执行后的状态码和响应体,后续同键请求可返回相同结果,包括 500;记录达到其保留条件后可能被清理。因此,幂等机制不是“重试一定成功”,也不是永久有效的去重凭证。[14]

如果底层服务不支持幂等,只在 Agent 这一侧加缓存,并不能完整覆盖“远端成功、本地还没来得及记录就崩溃”的窗口。需要结合可查询的业务标识和核对机制;无法确认时,停止比再次提交更安全。[13]

七、模型负责调整计划,执行层负责守住边界

根据 OpenAI、Anthropic 的指南,可以把职责整理为下面的工程分工,而不是把所有恢复逻辑都塞进提示词。[1][2][7]

执行层应强制保证 模型可以决定
输入和权限校验 根据明确错误修正参数
超时、取消、重试预算 选择允许使用的替代工具
幂等键和业务状态保存 缩小查询范围、拆分任务
高风险操作的确认机制 解释阻塞原因、向用户补问
操作日志与结果查询 根据已验证的状态调整后续计划

应用可以告诉模型“最多尝试两次”,但也应在执行层真的拦住第三次。尤其是换个工具名、换个会话、换个子 Agent 后,不能重新获得一份无限预算。

OpenAI 的 Agent 指南把超出失败阈值和高风险操作列为人工介入的典型触发条件;Anthropic 的指南则要求 Agent 持续从工具结果获得实际反馈,并设置最大迭代次数等停止条件。[1][2]

八、研究如何评估工具调用的可靠性?

对 Agent 可靠性,独立研究 τ-bench 提供了更直接的评估思路:它模拟用户与工具 Agent 的多轮交互,通过对比最终数据库状态与目标状态判断任务是否完成,还考察同一任务多次执行的一致性。[15]

论文在 2024 年所测试的配置中发现,工具 Agent 的完成率和重复执行的一致性仍有明显不足。这是当时特定模型、提示和任务的实验结果,不是今天所有模型的能力上限。

Anthropic 的 “think” tool 实验则研究了 Claude 在复杂工具使用中增加中间思考步骤的效果。在其 Claude 3.7 Sonnet 航空领域配置里,优化提示后的单次通过指标从 0.370 提高到 0.570,属于该实验条件下的结果。[16]

这项实验说明,模型处理工具结果和业务规则的方式会影响完成率;它没有验证幂等协议,也不能证明让模型多想一会儿就能安全处理重复写入。

实际评估不应该只看 Agent 最后有没有说“完成”,还应检查最终数据是否正确、有没有多发邮件或重复创建对象、是否在预算内停止。[15][7]

九、上线前,至少测试这些故障

上线前,可以按下面的清单做故障注入测试:

测试情境 应检查的结果
临时限流后恢复 等待后有限重试,没有请求风暴
额度耗尽或权限不足 停止调用,没有反复原样提交
缺字段、字段值非法 错误能帮助模型修正,未发生写入
本地命令一直运行 按执行器策略结束或托管,资源可回收
远端写入成功,但响应丢失 核对后确认成功,没有创建第二份对象
同一业务操作被两个 Agent 同时提交 服务端仍满足约定的防重复要求
应用执行到一半崩溃 恢复时保留业务标识,不盲目重新提交
用户中途取消 停止新增动作,报告已发生和尚未发生的操作

日志至少应能关联任务、工具调用、业务操作标识、耗时、错误类型、重试次数和最终确认状态。记录时还要处理密钥和个人信息,不能为了排障把完整凭据写进日志。

Anthropic 建议同时收集任务准确率、调用耗时、工具调用次数、token 消耗和工具错误;MCP 规范也要求考虑输入校验、敏感操作确认、超时和审计记录。[7][9]

最后,一套实用的失败处理流程可以压缩为:

先确认有没有发生操作;可以安全重复的临时错误,有限退避重试;参数错误,给模型具体反馈;权限和额度问题,停止并交由外部处理;结果未知的写操作,查询或在已有幂等保障下恢复;超过预算,明确退出。

参考资料

  1. OpenAI:A practical guide to building agents:失败阈值、高风险操作与人工接管。
  2. Anthropic:Building effective agents:环境反馈、停止条件与 Agent 设计。
  3. OpenAI:Function calling:应用执行工具、严格参数模式。
  4. OpenAI:Error codes:限流与额度、账单错误。
  5. AWS:Control and limit retry calls:重试上限、退避、抖动和多层重试。
  6. OpenAI 官方 Python SDK:自动重试与超时配置。
  7. Anthropic:Writing effective tools for agents:工具设计、可操作的错误反馈和评估指标。
  8. Claude:Handle tool calls:工具结果及 is_error。
  9. MCP 工具规范,2025-06-18 版本:协议错误、执行错误与安全要求。
  10. AWS:Timeouts, retries, and backoff with jitter:超时不代表副作用没有发生。
  11. Python:subprocess:不同执行接口的超时和进程清理行为。
  12. Anthropic:How we built our multi-agent research system:生产系统的故障恢复与状态保存。
  13. AWS:Making retries safe with idempotent APIs:请求标识、参数一致性与核对。
  14. Stripe:Idempotent requests:幂等键的具体服务约定。
  15. τ-bench 论文,Shunyu Yao 等,2024;后发表于 ICLR 2025:最终状态验证与重复执行可靠性。
  16. Anthropic:The “think” tool:Claude 3.7 Sonnet 在复杂工具任务中的实验。

补充:术语、错误字段与结果未知时的返回示例

1. 工具调用与工具执行

工具调用是模型提出“使用哪个工具、传入什么参数”;工具执行是应用真正访问接口、运行命令或修改数据。模型生成了调用,并不代表操作已经成功。OpenAI 的 Function calling 文档将这两个阶段明确分开。

2. 瞬时错误与确定性错误

瞬时错误可能随着时间过去而消失,比如短暂网络故障;确定性错误在相关条件不变时不会自行消失,比如缺少必填字段。分类是为了决定恢复方式,不能只凭一条“调用失败”的提示下判断。

3. 指数退避与随机抖动

指数退避是逐步拉长重试间隔。随机抖动是在间隔里加入随机性,避免大量客户端同时再次访问服务。

正文中的 random(0, min(cap, base × 2^n)) 是一种常见的全抖动写法:base 是初始等待尺度,cap 是等待上限,n 是重试序号。次数和累计耗时还需要单独限制。

4. Retry-After

服务端提示客户端应等待多久再发送后续请求的 HTTP 响应头。其值可能是等待秒数,也可能是 HTTP 日期。它提供等待提示,不保证到时服务一定恢复,更不能代替写操作的防重复保障。

5. 副作用与幂等

副作用是操作改变了外部状态,例如发出邮件、创建订单、扣减库存。

幂等是同一个操作重复执行时,预期效果与执行一次一致。它不要求每次响应文字完全相同。例如第一次删除资源可能返回成功,第二次返回不存在,但资源最终都处于已删除状态。

6. Idempotency-Key

用于标识同一个业务操作的请求键。第一次请求前生成并保存;该操作发生重试时复用,而不是每次网络请求都重新生成。

Stripe 的约定是一个具体实现:同键请求可以返回首次保存的结果,包括 500;同键参数改变会报错,记录清理后再使用原键可能形成新请求。其他服务必须查看自己的接口约定。

7. “结果未知”与“失败”

“失败”通常表示已经得到明确失败结果;“结果未知”表示客户端无法确认最终状态。

付款请求超时后,钱可能已经扣了。把它直接写成失败,再创建一笔新付款,可能导致重复操作。结果未知是需要保留的业务状态,不是一个应该被掩盖的异常。

8. 超时、取消与回滚

超时是等待超过限制;取消是请求停止继续执行;回滚是撤销已经发生的修改。三者不同。

停止等待不会自动撤销远端订单,杀死进程也不会自动恢复已写入的文件。某些操作只能通过补偿动作处理,例如取消订单;补偿本身同样可能失败,需要确认结果。

Python 的 Popen.communicate(timeout=...) 超时不会自动杀死子进程,而 subprocess.run(timeout=...) 有不同的处理行为。使用执行器前,应确认具体接口的取消和清理约定。

9. 严格模式与业务校验

严格模式约束模型输出的参数结构,例如字段是否齐全、类型是否正确。它不替应用验证库存、金额上限、对象归属或用户权限。结构合法的请求,仍然可能违反业务规则。

10. is_error 与 isError

这是不同协议的字段,不能混用。

Claude 客户端工具结果的示例:

{
  "type": "tool_result",
  "tool_use_id": "toolu_example",
  "is_error": true,
  "content": "结束时间早于开始时间;本次未创建日程。请检查时间字段。"
}

MCP 工具执行错误的结果示例:

{
  "content": [
    {
      "type": "text",
      "text": "结束时间早于开始时间;本次未创建日程。"
    }
  ],
  "isError": true
}

以上只展示结果对象,不是完整 HTTP 请求。MCP 的工具执行错误与 JSON-RPC 协议错误也要区分:工具运行后报告业务错误,与请求无法按协议处理,并不是同一层问题。

11. 推荐给应用内部使用的错误信息

下面是自定义业务结果示例,不是 OpenAI、Claude 或 MCP 的统一标准:

{
  "operation_id": "op_example_001",
  "status": "unknown",
  "error_code": "RESPONSE_TIMEOUT",
  "execution_confirmed": false,
  "retry_allowed": false,
  "next_action": "query_operation_status",
  "message": "提交后未收到响应,尚未确认是否执行。请先查询已有操作状态,不要创建新操作。"
}

retry_allowed 和 next_action 应由执行层根据接口约定计算。模型可以利用这些信息调整计划,但不能靠修改字段给自己授予重试权限。

12. τ-bench 与 pass^k

τ-bench 是研究工具 Agent 在业务规则下与用户交互、执行任务的评估环境。评估会检查最终数据库状态,而不只检查模型是否声称完成。

论文中的 pass^k 考察同一任务在多次独立执行中都成功的可靠性;不要与“尝试 k 次,有一次成功就算通过”的 pass@k 混淆。

正文引用的 “think” tool 数字来自 Claude 3.7 Sonnet 的历史实验。Anthropic 当前已在该文章顶部说明,多数情况下推荐使用 extended thinking,而不是专门增加一个 think 工具。引用该实验是说明中间推理会影响任务完成率,不是推荐照搬旧模型配置。

对应资料