长任务 Agent:检查点、恢复与幂等
一个 Agent 连续工作几个小时,最难处理的通常不是“怎样让模型一直说下去”,而是进程重启、工具超时或上下文被压缩之后,如何分辨哪些事情已经发生。扩大上下文和增加循环次数,不能替代对任务状态的记录。
把任务状态与聊天记录分开
聊天记录保存讨论过什么;可恢复状态还必须说明目标、约束、待执行动作、已经确认的结果、失败原因、剩余预算和停止条件。模型写一句“已经完成”不是完成证据:应有可重新读取的产物、工具结果或验证结论。
检查点是某一时刻可恢复的状态快照。LangGraph 的持久化文档区分单个执行线程的状态快照与跨线程的长期存储,也明确内存中的检查点会随进程退出丢失。聊天摘要可以帮助下一次模型调用理解进度,但不应是外部动作是否发生的唯一记录。
例如,一个虚构的资料整理任务包含读取文档、生成草稿、写入文件和通知用户。状态可以记录草稿文件的版本、写入动作的标识、通知是否得到服务端确认。恢复时就不必要求模型从几千行对话猜测最后一步有没有成功。
最危险的是“已经执行,但没来得及记下”
考虑通知动作:外部服务已经接收请求,客户端却在收到响应前超时。如果 Agent 因为本地没有成功记录就重新发送,用户可能收到两次通知。反过来,先把动作标记为完成再发请求,进程又可能在真正发送前崩溃,造成永久漏发。
本地快照不能和任意远端服务天然组成一个原子事务。Temporal 的活动执行模型将可能失败、重试的外部工作与工作流推进分开;具体应用仍要设计重复执行的语义。不能仅凭使用了持久化框架,就宣称所有外部副作用“恰好一次”。
幂等键标识逻辑动作,不标识尝试次数
幂等操作重复执行不会额外改变结果。例如“把文件内容设为这一版本”比“在末尾再追加一段”更容易重试。对于支持幂等键的外部接口,同一个逻辑动作的每次重试都必须使用同一个键,而不是每试一次生成新 UUID。
可以把键与任务 ID、步骤 ID 和有效负载摘要关联。同一步改了接收方或正文,就需要新的逻辑动作;复用旧键可能返回旧结果。因此接收端应能检测“同键不同参数”,而不只是静默去重。
接收端要在同一个事务里先按唯一约束插入这个键,再做业务修改;先查键是否存在、最后才写键,两个并发请求会都看到“不存在”而各执行一次。为什么必须这样排、outbox 又怎样处理重复投递,见关系型数据、SQL 与事务。无法确认的动作应保留为“结果未知”,而不是自动等同于失败。
恢复不是无条件重放
恢复时先读取最后确认的状态和外部产物,再决定下一步。对已经完成的生成调用,可以复用保存的结果;重新调用模型可能得到不同文本,进而改变后续动作。工作流代码、工具 schema 或任务输入发生变化时,也要明确旧检查点是否兼容。Temporal 的工作流执行文档介绍了用执行历史恢复工作流的机制;可重放计算与外部 I/O 的分离是理解这种设计的关键。
失败要按原因处理:暂时性网络错误可有限退避重试;参数错误应修正参数;权限不足不能靠更多重试解决;长期等待必须有截止时间。取消时怎样连同子进程一起停下,见有界 Agent 循环;长任务另外要记下取消前已经完成的副作用,不能把“停止继续工作”当成“过去什么都没发生”。
检查点与上下文压缩怎样配合
状态快照保留机器可读的进度,摘要给模型提供继续推理所需的解释,两者可以一起更新。摘要该留下什么,见上下文工程;巨大的工具输出可留在持久存储,只把相关片段放回模型。
完成条件必须依附目标。例如“草稿已写入且引用检查通过”与“用户已收到通知”是两个不同结果。如果只完成了前者,就不能用聊天里的完成标记覆盖后者。预算耗尽、等待外部输入和目标达成也应是不同状态。
最有说服力的恢复测试,是在写入前、写入后但记录前、记录后分别中断,再检查最终产物是否正确、动作是否重复、未知结果能否被查清。测试先用本地文件和假的服务,不需要为了验证恢复机制反复发送真实消息。
编码 Agent 版本:用 git 提交当检查点
让编码 Agent 跨好几个会话做完一个项目,上面的状态记录可以直接落在仓库里。Anthropic 在 2025 年 11 月的长任务 Harness 文章里给了一套做法:
- 第一个会话只搭环境。 用单独的提示让它写一个启动开发服务器的
init.sh、一个记录进度的claude-progress.txt,并做第一次 git 提交。 - 把需求写成 JSON 功能清单,每项一开始都标为未通过。 后面的会话只能改每项的
passes字段,提示里写明“删除或修改测试是不可接受的”。文章说,模型改坏 JSON 的情况比改坏 Markdown 少。 - 每个会话只做一项功能。 开头先运行
pwd,读进度文件和 git 日志,跑一次基本的端到端检查,确认上一个会话没把应用留在坏的状态。 - 结束前提交并更新进度。 每次提交写清做了什么,做坏了就能用 git 回到能用的版本。
- 按用户的方式验收。 只跑单元测试或
curl时,Agent 常常没发现功能在端到端上不通;让它用浏览器自动化像用户一样操作,结果好得多。
这里 git 历史和进度文件就是检查点,功能清单就是完成条件,和前面讲的状态记录是同一回事。新会话从哪里接上,可以用 claude -c、codex resume --last 或 pi -c;各工具的恢复和无人值守命令汇总在 Harness 末尾的表里。