Agent 中途失败后怎么办:检查点、重试与幂等执行

1929 字
10 分钟
Agent 中途失败后怎么办:检查点、重试与幂等执行

一个 Agent 依次读取信息、生成方案、调用工具并检查结果。如果它在第三步超时,再次运行时应该从哪里开始?这比“失败后重试三次”复杂,因为超时只意味着调用方没有及时得到结果,并不意味着外部操作没有发生。

假设工具已经创建了一条业务记录,但响应在返回途中丢失。Agent 若从头再次调用,可能创建重复记录;如果直接标记完成,又可能把一次真正失败的调用当成成功。

我在LangGraph 工作流笔记中讨论过显式状态的价值。这篇把关注点缩小到一个问题:流程如何在结果不确定时恢复,而不是盲目继续。

1. 先分清流程状态与业务状态#

检查点记录的是工作流已经推进到哪里,例如已完成规划、生成了候选参数、下一步准备执行什么节点。它可以帮助进程重启后恢复上下文,但并不天然知道外部系统到底发生了什么。

状态来源能回答的问题不能单独证明的事情
工作流检查点哪些节点及状态已持久化外部 API 是否产生副作用
工具调用日志发出了什么请求、收到什么响应响应丢失时对方是否已执行
业务系统记录目标对象是否存在、当前状态是什么它是否一定属于本次操作

因此,恢复时往往需要把检查点、操作标识和业务查询结果结合起来。状态快照越完整,也不意味着外部副作用就能自动获得“恰好一次”的保证。

2. 最危险的窗口在执行之后、记录之前#

可以把一次工具调用简化为以下顺序:

准备参数 → 记录执行意图 → 调用外部工具 → 保存结果 → 推进工作流

如果进程在工具执行前崩溃,通常可以重新尝试。如果在保存结果后崩溃,可以从记录恢复。真正棘手的是:外部动作已经生效,进程却在保存结果前退出。

为了表达这种情况,调用状态不宜只有“成功”和“失败”,还应允许“结果未知”。恢复后先核验,再决定复用结果、重试或交给人工处理。

一个用于讨论的状态转换是:

prepared → running → succeeded
→ failed
→ unknown → 核验外部结果

这里的 unknown 不是可以无限重试的错误分类,而是要求补充证据的状态。

3. 操作标识要绑定业务意图#

如果外部服务支持幂等键,同一次逻辑操作的所有重试应复用同一个键。每次重试都生成新的随机键,只能标记不同请求,不能防止重复副作用。

下面是一个简化的调用记录示例:

{
"operation_id": "task-demo:write-report:1",
"tool": "create_report",
"input_hash": "sha256:...",
"status": "unknown",
"external_resource_id": null,
"attempt": 2
}

operation_id 在发起外部动作前生成并持久化;重试沿用它,同时核对输入摘要。相同标识对应不同参数时应拒绝复用,而不是返回旧结果。业务意图发生变化,则应该创建新的操作,并重新判断所需授权。

如果自己实现幂等记录,还要考虑并发占用、唯一约束、结果保存与有效期。仅在内存里缓存成功结果,无法处理进程重启;仅给数据库表增加唯一键,也不能自动把另一个系统的操作纳入同一事务。

4. 重试策略取决于错误语义#

情况更合适的处理
参数不合法修正输入,保留校验错误供规划节点使用
身份或权限不足停止执行,补齐授权条件
限流或暂时不可用在工具语义允许时,按预算退避重试
请求超时且可能已经产生副作用先通过操作标识查询结果
操作不可逆且无法确认结果保留证据,交给人工核验

退避通常需要最大尝试次数、总时长上限和抖动;服务端给出 Retry-After 时应考虑它。取消状态也要参与判断,用户已经停止任务后,不应让后台重试继续执行写操作。

模型重新生成参数与程序重发同一请求也应区分。前者可能改变业务含义,不能自动当作同一次幂等重试。

5. 在 LangGraph 中划清恢复边界#

使用持久化 checkpointer,可以按线程保存图的状态,并从已有进度恢复。但它不是外部 API 的事务管理器。流程恢复时,部分执行逻辑可能重放,节点内部的副作用仍然需要独立设计。

我会优先让节点职责清楚:读取证据、生成计划、校验参数、执行动作和核验结果分别承担明确工作。具有外部副作用的部分通过任务封装、稳定操作标识和业务结果查询来保护,具体方式要以当前框架版本支持的恢复语义为准。

人工确认也需要与操作绑定。确认的是某个目标、某份参数和某个动作范围;恢复时如果这些内容发生变化,应重新校验授权,而不是因为线程里存在一个“已确认”布尔值就继续执行。

6. 补偿不是万能回滚#

创建的草稿可以删除,更新的配置可能恢复旧值,但已经发出的消息无法真正撤回接收者的阅读,已经触发的外部流程也未必能够完全逆转。

补偿动作本身也会失败,需要记录执行结果,并尽可能具备幂等性。设计时应明确哪些步骤可逆、哪些只能做业务补救、哪些必须人工处理,不要把“有一个撤销接口”当成事务回滚保证。

人工接管记录至少应包含:任务目标、操作标识、已确认完成的步骤、结果未知的步骤、最后一次错误,以及可用于核验的外部资源标识。接管者应该能据此判断下一步,而不是重新猜测整个任务发生了什么。

7. 把恢复能力做成可以验证的行为#

最有价值的测试位置,是故障窗口附近:

  • 工具执行前退出,恢复后确认操作可以继续。
  • 外部操作成功后、结果落库前退出,恢复后确认先核验而非直接重复执行。
  • 相同操作同时被两个执行器领取,确认并发约束有效。
  • 同一个幂等键携带不同参数,确认冲突被拒绝。
  • 用户确认后修改目标参数,确认旧授权不会被复用。
  • 重试期间取消任务,确认不会再发起新的副作用操作。

验证不只看工作流最终是不是绿色,还要看外部记录是否重复、取消后是否还有写操作、未知状态是否留下了可核验信息。Agent 的恢复能力,应当同时说明“下一步从哪里继续”和“已经做过的事情如何确认”。

参考与延伸#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Agent 中途失败后怎么办:检查点、重试与幂等执行
https://blog.miansu.eu.cc/posts/agent-checkpoint-idempotency/
作者
叶立恒
发布于
2026-08-26
许可协议
CC BY-NC-SA 4.0