← 学习路线
AI 学习 · 实践复盘

工具失败以后:分类、超时与有限重试

通过可控故障练习,分清哪些错误应该修正输入,哪些才值得在安全条件下重试。

康雨 · 发布 · 约 5 分钟

阅读基础:输入输出契约、try/except、async/await

读完可以:说明重试次数、退避、取消与副作用的边界,并运行失败测试。

本文目录

先知道失败发生在哪里

这篇继续使用工具契约练习。测试会注入连接异常、慢协程和错误返回值,不需要真的让外部服务出故障。

错误类别本练习的处理理由
unknown_tool直接失败当前注册表不允许这个工具
input_validation直接失败相同错误参数再执行没有帮助
output_validation直接失败工具返回值违背接口约定
business直接失败业务条件不满足,应检查业务原因
timeout / connection仅对允许重复执行的工具有限重试暂时故障可能恢复,但重复动作也可能有风险
internal返回固定失败类别,不重试未知异常不能默认可恢复

这个分类是教学实现的选择。真实 SDK 往往使用自己的异常类型,接入时需要明确映射;不能只捕获 Python 内置 ConnectionError 就声称处理了所有网络错误。

把次数与等待都限制住

配套程序的 max_attempts 包含第一次调用,默认最多尝试三次。第一次成功就结束;连续失败时,只在两次尝试之间等待。它没有无限 while 重试。

python
delay = min(cap_delay, base_delay * (2 ** (attempt - 1))) * rng()
await sleep(delay)

这段使用带上限的指数退避与随机抖动。本例 rng 默认取 0 到 1 的随机数;测试把它固定为 0.5,并替换 sleep 为记录函数,所以能检查等待值,而无需真的等待退避时长。

在默认 base_delay=0.05、cap_delay=0.5 下,测试中两次等待分别为 0.025 与 0.05 秒。这些数值用来演示机制,不是推荐给生产系统的参数。AWS 重试指南强调限制重试、退避与抖动,避免故障时进一步放大压力。

超时不等于动作没发生

程序用 asyncio.wait_for 对每次协程调用设置超时。根据 Python 协程文档,它会尝试取消被等待任务,并等待取消完成。因此它不是强制终止任意代码的硬开关,实际等待时间可能超过设置值。

同步阻塞、吞掉取消异常的协程,以及已经发送到远端的请求,都需要额外考虑。本练习只使用能响应取消的异步工具;调用方主动取消时,CancelledError 会继续向上传递,不伪装成普通业务失败。

如果以后接入写数据库、发邮件或支付工具,超时可能只意味着“没有收到结果”。再次执行可能重复产生副作用。retry_safe 在这里是由程序作者登记的元数据,不能让模型自行决定;设置为 True 也不会自动赋予幂等性。AWS 幂等 API 说明可作为进一步阅读。

用故障测试检查分支

测试情景预期
前两次连接失败,第三次返回 42共调用三次,有两次等待
一直连接失败达到次数上限后返回 connection
不允许重复执行的工具连接失败只尝试一次,无退避
工具返回错误类型output_validation,不重试
慢协程超过时限返回 timeout,清理分支执行
调用方取消运行取消向上传递,不自动重试

这些测试在配套程序中已经通过。测试的是可控离线场景,不包含真实限流响应、服务端副作用或数据库事务。HTTP 429、Retry-After、SDK 自带重试与全局时间预算,在真实接入时还要单独设计。

还有哪些没有覆盖

每次调用有超时,不代表整个 Agent 有截止时间;多个工具与多轮推理叠加后,仍可能耗时很长。生产设计需要统一预算和取消路径,也要避免 SDK 与外层重复重试。

工具轮次上限、调用超时、总运行预算分别限制不同维度。先把这几条规则说清楚,再决定在何处加限制。后续可在日志专题中检查每次尝试留下的记录。

来源

承接个人学习摘要中的错误分类、timeout、retry 与 backoff;技术边界核对自上方 Python 与 AWS 官方资料。故障场景由配套测试注入。核对日期:2026-09-21。

试着做一个小练习

把测试工具的 retry_safe 改为 False,检查连接错误是否只调用一次。