
AI 自动化任务如何支持断点续跑检查点、幂等与故障恢复实战大家好我是张大鹏大鹏 AI 教育创始人。一个 AI 自动化任务运行了 40 分钟在最后一步遇到网络超时。重启之后它应该从头再做一遍还是从失败处继续如果你的答案是“把上一次对话继续发给模型”这个系统还不具备真正的断点续跑能力。可靠恢复不是让模型记住自己说过什么而是让程序知道哪些事实已经成立、哪些外部动作已经发生、哪些证据仍然有效以及下一步是否可以安全执行。本文用一个通用任务处理器拆解检查点、现实侦察和幂等重试三个核心机制。知识与证据来源本文的知识主线来自 RuyiBookCourse《第三十一章 为长时间运行智能体设计 Harness》中的三个连续小节“检查点保存事实不保存幻想”“恢复前先侦察现实状态”“幂等性决定能否安全重试”。文章把这些原则改写为通用 Python 数据结构和恢复流程。文中的完成判断都要求绑定文件哈希、测试结果或外部对象状态不把模型自述当作事实证据。断点续跑不是继续聊天长任务通常会经过多个阶段接收任务 → 收集资料 → 生成产物 → 验证产物 → 执行外部动作 → 复核结果进程可能在任意阶段退出原因包括网络波动、机器重启、依赖服务故障、预算耗尽或者人工暂停。如果系统只保存一段模型总结例如“资料已经收集完成”恢复时就无法判断资料文件是否真的存在文件是否被其他程序修改验证命令是否运行过外部动作究竟成功、失败还是状态未知当前任务是否已经被另一个执行器接管。因此断点续跑的第一原则是检查点保存可验证事实不保存模型的自我判断。一个可靠检查点应该保存什么最小检查点至少包含以下字段fromdataclassesimportdataclass,fieldfromtypingimportLiteraldataclassclassCheckpoint:task_id:strrun_id:strstage:Literal[collect,generate,verify,deliver]step:strinput_hash:strartifact_path:str|NoneNoneartifact_hash:str|NoneNonecompleted_effects:list[str]field(default_factorylist)retry_count:int0budget_used:float0unresolved:list[str]field(default_factorylist)这里有三个容易忽略的设计点。第一task_id表示业务任务run_id表示某次执行。执行进程可以更换但业务任务不能因此失去身份。第二产物不仅要记录路径还要记录哈希。文件内容变化之后旧验证结果不能继续证明新文件。第三已经发生的外部副作用必须单独记录。发送消息、创建工单、扣减库存都不是普通计算不能因为进程重启就再次执行。检查点必须原子写入进程可能恰好在写检查点时崩溃。如果直接覆盖原文件磁盘上可能只剩半段 JSON。文件型检查点可以采用“临时文件 原子替换”importjsonimportosfrompathlibimportPathdefsave_checkpoint(path:Path,data:dict)-None:temporarypath.with_suffix(.tmp)temporary.write_text(json.dumps(data,ensure_asciiFalse,indent2),encodingutf-8,)withtemporary.open(rb)asstream:os.fsync(stream.fileno())os.replace(temporary,path)如果使用数据库则让状态更新、外部动作意图和结果记录进入受事务保护的写入过程。核心目标不是选择某一种存储而是保证系统看到的检查点只有两种状态完整的旧版本或者完整的新版本。恢复前必须侦察现实读取检查点之后不能立即执行下一步。恢复器应先重新检查现实状态definspect_reality(checkpoint:Checkpoint)-list[str]:differences[]ifsha256_of_current_input()!checkpoint.input_hash:differences.append(输入已经变化)ifcheckpoint.artifact_path:ifnotartifact_exists(checkpoint.artifact_path):differences.append(产物不存在)elifsha256_of_artifact()!checkpoint.artifact_hash:differences.append(产物哈希不一致)iflease_owner(checkpoint.task_id)!checkpoint.run_id:differences.append(执行租约已经转移)returndifferences只有现实状态与检查点一致任务才可以从下一步继续。如果发现差异正确动作不是强行恢复而是进入blocked状态输出差异和建议决策。这样可以避免在过期输入上继续生成或者让两个执行器同时修改同一对象。幂等性决定能否安全重试只读查询通常可以重试写操作则不一定。假设外部服务已经创建了工单但响应在返回途中丢失。客户端看到的是超时。如果它直接再次调用“创建工单”用户就会得到两个工单。解决方法是为同一次业务意图生成稳定的幂等键fromhashlibimportsha256defidempotency_key(task_id:str,artifact_hash:str,action:str)-str:intentf{task_id}:{artifact_hash}:{action}returnsha256(intent.encode(utf-8)).hexdigest()写工具应接受这个键并保证同一个键只产生一个最终对象resultticket_service.create(title数据处理异常,idempotency_keyidempotency_key(task_idcheckpoint.task_id,artifact_hashcheckpoint.artifact_hash,actioncreate-ticket,),)幂等键不能加入随机重试次数因为它代表的是业务意图而不是某一次网络请求。外部动作要先记录意图再记录结果一个安全的副作用执行过程可以分成四步写入“准备执行”的意图记录携带幂等键调用外部服务保存外部对象 ID 和最终状态回读外部对象并复核结果。如果在第二步之后超时恢复器应先按幂等键或业务标识查询结果而不是马上重新创建。当外部系统不支持幂等、又无法确认上一次调用是否成功时继续自动重试可能扩大损失。此时应暂停任务把已有证据交给人工判断。最小恢复循环把上面的原则组合起来可以得到一个最小运行循环defresume_task(task_id:str)-str:checkpointload_checkpoint(task_id)differencesinspect_reality(checkpoint)ifdifferences:mark_blocked(task_id,differences)returnblockedwhilecheckpoint.stage!done:resultrun_current_step(checkpoint)checkpointapply_result(checkpoint,result)save_checkpoint(CHECKPOINT_PATH,checkpoint.__dict__)returncompleted生产系统还需要补上租约、分层超时、取消传播、预算限制和可观测日志但这个骨架已经建立了正确顺序读取检查点 → 侦察现实 → 判断能否继续 → 执行一步 → 验证结果 → 原子保存怎样测试恢复能力不要只测试正常完成要主动注入故障在产物写到一半时终止进程确认旧检查点仍然完整在外部写入成功但响应返回前断网确认恢复后不会重复创建修改已验证产物确认旧证据立即失效同时启动两个执行器确认只有租约持有者可以继续让幂等能力不可用且状态未知确认任务转为人工处理。恢复测试通过的标准不是“任务最后完成了”而是任务在各种中断点都没有重复副作用、没有使用过期证据也没有跳过必要步骤。常见误区误区一保存完整对话就等于保存状态对话是上下文不是业务事实。恢复依据必须是结构化、可验证的状态。误区二所有失败都自动重试暂时性读取失败可以退避重试产生外部副作用的写操作必须先确认状态和幂等能力。误区三检查点越频繁越好检查点应位于明确的阶段边界。保存一半完成、无法验证的中间状态反而会增加恢复歧义。误区四模型说完成就算完成完成声明必须绑定真实证据例如文件哈希、测试退出码和外部对象状态。总结AI 自动化任务能否断点续跑取决于系统工程而不是模型记忆。一套可靠的恢复机制至少包含用显式状态机描述任务阶段用原子检查点保存可验证事实恢复前重新侦察现实状态用稳定幂等键保护外部写操作状态不明时暂停并转人工通过故障注入验证没有重复副作用。当执行进程可以随时被替换而任务仍能根据事实安全继续系统才真正具备了长任务能力。