跳到主要内容

长任务 Agent:检查点、恢复与幂等

一个 Agent 连续工作几个小时,最难处理的通常不是“怎样让模型一直说下去”,而是进程重启、工具超时或上下文被压缩之后,如何分辨哪些事情已经发生。扩大上下文和增加循环次数,不能替代对任务状态的记录。

把任务状态与聊天记录分开​

聊天记录保存讨论过什么;可恢复状态还必须说明目标、约束、待执行动作、已经确认的结果、失败原因、剩余预算和停止条件。模型写一句“已经完成”不是完成证据:应有可重新读取的产物、工具结果或验证结论。

检查点是某一时刻可恢复的状态快照。LangGraph 的持久化文档区分单个执行线程的状态快照与跨线程的长期存储,也明确内存中的检查点会随进程退出丢失。聊天摘要可以帮助下一次模型调用理解进度,但不应是外部动作是否发生的唯一记录。

例如,一个虚构的资料整理任务包含读取文档、生成草稿、写入文件和通知用户。状态可以记录草稿文件的版本、写入动作的标识、通知是否得到服务端确认。恢复时就不必要求模型从几千行对话猜测最后一步有没有成功。

最危险的是“已经执行,但没来得及记下”​

考虑通知动作:外部服务已经接收请求,客户端却在收到响应前超时。如果 Agent 因为本地没有成功记录就重新发送,用户可能收到两次通知。反过来,先把动作标记为完成再发请求,进程又可能在真正发送前崩溃,造成永久漏发。

本地快照不能和任意远端服务天然组成一个原子事务。Temporal 的活动执行模型将可能失败、重试的外部工作与工作流推进分开;具体应用仍要设计重复执行的语义。不能仅凭使用了持久化框架,就宣称所有外部副作用“恰好一次”。

幂等键标识逻辑动作,不标识尝试次数​

幂等操作重复执行不会额外改变结果。例如“把文件内容设为这一版本”比“在末尾再追加一段”更容易重试。对于支持幂等键的外部接口,同一个逻辑动作的每次重试都必须使用同一个键,而不是每试一次生成新 UUID。

可以把键与任务 ID、步骤 ID 和有效负载摘要关联。同一步改了接收方或正文,就需要新的逻辑动作;复用旧键可能返回旧结果。因此接收端应能检测“同键不同参数”,而不只是静默去重。

接收端要在同一个事务里先按唯一约束插入这个键,再做业务修改;先查键是否存在、最后才写键,两个并发请求会都看到“不存在”而各执行一次。为什么必须这样排、outbox 又怎样处理重复投递,见关系型数据、SQL 与事务。无法确认的动作应保留为“结果未知”,而不是自动等同于失败。

恢复不是无条件重放​

恢复时先读取最后确认的状态和外部产物,再决定下一步。对已经完成的生成调用,可以复用保存的结果;重新调用模型可能得到不同文本,进而改变后续动作。工作流代码、工具 schema 或任务输入发生变化时,也要明确旧检查点是否兼容。Temporal 的工作流执行文档介绍了用执行历史恢复工作流的机制;可重放计算与外部 I/O 的分离是理解这种设计的关键。

失败要按原因处理:暂时性网络错误可有限退避重试;参数错误应修正参数;权限不足不能靠更多重试解决;长期等待必须有截止时间。取消时怎样连同子进程一起停下,见有界 Agent 循环;长任务另外要记下取消前已经完成的副作用,不能把“停止继续工作”当成“过去什么都没发生”。

检查点与上下文压缩怎样配合​

状态快照保留机器可读的进度,摘要给模型提供继续推理所需的解释,两者可以一起更新。摘要该留下什么,见上下文工程;巨大的工具输出可留在持久存储,只把相关片段放回模型。

完成条件必须依附目标。例如“草稿已写入且引用检查通过”与“用户已收到通知”是两个不同结果。如果只完成了前者,就不能用聊天里的完成标记覆盖后者。预算耗尽、等待外部输入和目标达成也应是不同状态。

最有说服力的恢复测试,是在写入前、写入后但记录前、记录后分别中断,再检查最终产物是否正确、动作是否重复、未知结果能否被查清。测试先用本地文件和假的服务,不需要为了验证恢复机制反复发送真实消息。

编码 Agent 版本:用 git 提交当检查点​

让编码 Agent 跨好几个会话做完一个项目,上面的状态记录可以直接落在仓库里。Anthropic 在 2025 年 11 月的长任务 Harness 文章里给了一套做法:

  1. 第一个会话只搭环境。 用单独的提示让它写一个启动开发服务器的 init.sh、一个记录进度的 claude-progress.txt,并做第一次 git 提交。
  2. 把需求写成 JSON 功能清单,每项一开始都标为未通过。 后面的会话只能改每项的 passes 字段,提示里写明“删除或修改测试是不可接受的”。文章说,模型改坏 JSON 的情况比改坏 Markdown 少。
  3. 每个会话只做一项功能。 开头先运行 pwd,读进度文件和 git 日志,跑一次基本的端到端检查,确认上一个会话没把应用留在坏的状态。
  4. 结束前提交并更新进度。 每次提交写清做了什么,做坏了就能用 git 回到能用的版本。
  5. 按用户的方式验收。 只跑单元测试或 curl 时,Agent 常常没发现功能在端到端上不通;让它用浏览器自动化像用户一样操作,结果好得多。

这里 git 历史和进度文件就是检查点,功能清单就是完成条件,和前面讲的状态记录是同一回事。新会话从哪里接上,可以用 claude -c、codex resume --last 或 pi -c;各工具的恢复和无人值守命令汇总在 Harness 末尾的表里。

探索关联打开关联网络