长任务 Agent:检查点、事件日志与故障恢复
为跨分钟、跨小时的 Agent 任务设计持久状态、检查点、幂等恢复和人工等待机制。
为什么长任务不能依赖一个进程
几秒钟完成的 Agent 请求可以跟随 HTTP 生命周期,跨分钟甚至跨小时的任务却会遇到部署重启、模型限流、工具超时、人工审批和用户取消。若所有状态只存在内存或一段对话中,任何中断都会迫使任务从头开始,并可能重复产生外部副作用。
长任务需要持久化工作流。核心不是让进程永远不死,而是让进程随时可以死,任务仍能从明确状态继续。
把运行建模为事件和状态
每次 Agent 运行拥有稳定 runId,其状态可以由一系列事件构成:
RunCreated
PlanAccepted
ToolCallRequested
ToolCallSucceeded
CheckpointSaved
ApprovalRequested
ApprovalGranted
RunCompleted
事件记录发生过什么,当前状态则是事件归约后的快照。只保存快照读取快,但难以审计;只保存事件可追溯,却会增加恢复成本。实际系统通常同时保留事件日志和周期性检查点。
事件要包含版本、时间、前后关联和幂等标识。敏感工具参数只保存受控引用或脱敏摘要,不能因为需要恢复就把密钥写进事件库。
检查点保存真正需要恢复的信息
检查点不等于保存完整 Prompt。它至少包括当前计划版本、步骤状态、已经确认的事实、产物引用、未解决问题、工具幂等键、授权状态和剩余预算。
{
"runId": "run-42",
"version": 7,
"status": "waiting_approval",
"planVersion": 2,
"completedSteps": ["collect", "analyze"],
"artifacts": [{"id": "report-9", "checksum": "..."}],
"pendingAction": {"type": "publish_report", "approvalId": "apr-3"},
"budget": {"toolCallsLeft": 8, "tokensLeft": 12000}
}
大型工具结果存入对象存储,检查点只保存不可变引用、摘要和校验值。恢复时按需加载,避免每轮上下文不断膨胀。
恢复不是简单重放最后一步
任务恢复时,外部世界可能已经变化。网络超时并不代表工具没有执行;人工可能在 Agent 离线时完成了操作;审批可能已经过期。
恢复器应依次确认:任务是否被取消;权限和审批是否仍有效;外部资源版本是否变化;最后一个工具调用是否已有业务结果;当前计划的前提是否仍成立。
写工具必须支持幂等键。恢复时先按幂等键查询,已经成功则记录结果并继续,未执行才重试。无法查询状态的高风险工具不适合自动恢复,应转人工确认。
等待是状态,不是占用线程
等待用户补充信息、等待审批或等待外部批处理时,运行进入持久等待状态并释放计算资源。系统保存唤醒条件,例如审批事件、指定时间或外部回调。
被唤醒后重新加载最新检查点,而不是继续旧闭包。对事件做去重,避免同一个回调唤醒两次。等待也需要超时策略:审批超过期限后自动取消,或提醒用户重新确认,因为业务参数可能已经过期。
长任务的用户界面应展示它正在等待什么,而不是一直显示“处理中”。
并发、租约与取消
多个工作进程可能同时拿到同一运行。可以使用短期租约或乐观锁确保一个步骤只有一个执行者。每次状态更新带预期版本,版本不匹配时放弃写入并重新读取。
取消需要贯穿所有层。用户取消后写入 RunCancelled,队列停止派发新步骤,正在执行的工具收到取消信号。即使工具无法立即中断,结果返回时也必须检查运行状态,不能把已取消任务重新标成成功。
补偿动作要谨慎。并不是所有操作都能真正撤销。与其假设存在通用回滚,不如在设计工具时区分可逆、需人工补偿和不可逆动作,并在执行前设置不同审批。
重试策略属于业务语义
限流和短暂网络错误可以指数退避;无权限、参数错误和业务拒绝不应重试。每个步骤有独立重试上限,总运行也有失败预算。否则一个坏依赖会让大量任务无限占用队列。
重试事件要记录尝试号和错误分类。达到上限后进入 blocked 或 failed,并保留已完成产物。用户可能接受部分结果,不必把整个任务标成毫无价值。
版本升级与可重放测试
工作流代码、状态 Schema、工具契约和 Prompt 都应版本化。新部署不能假设旧任务按新计划创建。可以让运行固定在启动版本直至完成,或者为状态提供经过测试的迁移器。
事件日志允许离线重放。测试时替换真实模型和工具,用记录结果重建状态,检查同一事件序列是否得到预期快照。还应模拟进程在每个事件间崩溃,验证恢复不会遗漏或重复副作用。
小结
持久化工作流把“运行中的 Agent”从一个脆弱进程变成可恢复作业。事件记录事实,检查点加速恢复,幂等保护写入,等待释放资源,版本保证演进。做到这些,长任务才真正能够跨越故障、审批和部署继续工作。