Agent Systems

持久化执行:让长任务真正“断点续跑”

Mason10 MIN

一个 Agent 可能运行数小时,等待人工审批数天,也可能在调用外部工具后瞬间崩溃。如何让它从正确的位置继续,而不是从头来过或重复执行?这篇文章从状态、检查点和确定性重放讲起,最后处理最棘手的副作用崩溃窗口。

先说结论

要理解持久化执行,第一步是区分运行状态(state)和长期记忆(memory)。运行状态记录的是这一次任务的现场:它执行到哪里、哪些工具已经调用、当前在等待什么。长期记忆则是跨任务仍然有价值的知识,例如用户偏好、历史经验和长期事实。两者都需要保存,却服务于完全不同的目标。

因此,持久化执行并不等于把聊天记录存进数据库。真正需要保存的,是已经完成的步骤、模型当时作出的决定、工具返回的结果和等待条件。系统在故障后通过事件重放恢复这些信息,再从中断处接上后续工作。模型调用和外部工具调用都具有非确定性,恢复时应复用已有结果,而不是重新请求模型或让工具再执行一次。

工具调用通常是最值得设置检查点的边界,但检查点并不能自动解决所有问题。例如,一笔转账已经在外部系统成功,Agent 却在记录结果前崩溃;简单重试就可能造成重复扣款。持久化解决的是“已经完成的工作不丢失”,并不等同于高可用、低延迟或永不宕机。要可靠地处理外部副作用,还需要幂等性和更谨慎的恢复协议。

问题从哪里开始

一个会调用工具的 Agent,通常都在重复下面这个循环:

读取当前状态 → 模型决定下一步 → 调用工具 → 接收结果 → 更新状态 → 继续

在演示环境里,这些变量往往只存在于一个 Python 或 Node.js 进程中。这个前提在任务只需几秒钟时看似无害;一旦任务跨越了容器重启、Serverless 请求超时、部署替换实例,或者等待三天的人工审批,内存里的进度就会消失。此时,即使 Agent 已经正确完成前半段工作,也只能从头开始,甚至无法判断前面是否已经做过关键动作。

持久化执行(durable execution)在模型与计算资源之间增加了一层运行时:它将关键步骤的输入、输出和完成状态写入外部存储。于是,计算进程可以随时消失,任务的身份和进度却不会丢失。下一个进程接手时,不需要猜测任务此前发生过什么,只需读取这份执行记录,再继续完成尚未结束的部分。

数据类型保存什么主要用途
run state计划、步骤位置、结果、待审批动作恢复本次任务
memory用户偏好、长期事实、历史经验跨任务复用
trace执行过程与诊断信号观察和调试
stream cache已发送给前端的文本片段刷新与断线续传

MongoDB 的工程文章把这条边界说得很清楚:Agent 回答错误,可能是上下文或模型的问题;已经完成五步却无法从第五步继续,则是状态持久化的问题。阅读 MongoDB 的状态与持久化分析

Mastra 的实现还提醒我们:浏览器刷新后的流续传,与后端崩溃后的执行恢复,是两种不同的保证。阅读 Mastra Durable Agents

如何实现恢复

事件日志与确定性重放

成熟的运行时不会在每行代码后都保存整块内存。它记录的是一串足以恢复任务的事件:

run_started
llm_step_completed(result=A)
tool_call_prepared(operation_id=42)
tool_call_completed(result=B)
approval_waiting
approval_received

恢复时,工作流代码可能会从头解释,但完成过的步骤会直接返回事件日志中的结果。因此,“代码从头重放”不等于“业务动作从头再做”。对开发者而言,执行函数仍然像普通代码一样从上往下书写;对运行时而言,每个已记录的步骤都是可以跳过的历史。这种分层让普通的控制流代码,也能获得接近工作流引擎的恢复能力。

否则,同一个 checkpoint 恢复后,模型可能生成不同的参数、工具顺序或幂等键,让执行路径发生语义分叉。Inngest Durable Agents 文档

检查点粒度

检查点的划分没有唯一答案。设置得太粗,恢复时可能需要重做昂贵操作;设置得太细,又会带来更多持久化写入、延迟和协调成本。实践中可以把连续的纯计算和小型只读操作合并为一个步骤,因为即使重做,它们的成本通常可控。

相反,LLM 调用通常应该单独记录,避免恢复时重复消耗 token,也避免拿到不同的回答。任何会改变外部世界的工具调用,例如发送邮件、创建工单或写入数据,同样应是独立步骤。子 Agent 委派也值得单独保存,否则恢复时可能重复创建 worker。至于人工审批,正确的做法是在进入等待前持久化完整的待审批状态,然后释放计算资源;审批到达后,系统再从记录的位置继续。

版本与凭据也是恢复状态的一部分

Agent 挂起期间,代码、提示词、模型和工具 schema 都可能发生变化。因此,运行记录至少应包含:

workflow_version
state_schema_version
prompt_version
model_config_version
tool_schema_version

对于长任务,最好固定其代码、提示词与模型配置的运行 bundle。需要升级时,使用显式的状态迁移。凭据则不应跟随 checkpoint 长期保存;恢复时应重新授权并签发短期凭据。

关键模式:Side-effect Sandwich

前面的机制可以保存进度,但外部副作用仍然存在一个危险窗口:外部系统已经执行成功,但 Agent 还没来得及保存“成功”的结果就崩溃了。例如,CRM 已经创建了客户,支付系统已经扣款,部署平台已经开始发布;从 Agent 的记录看,这一步却仍然“未完成”。如果恢复逻辑只会盲目重试,结果就是重复操作。

  1. 01 / PREPARE

    持久化规范化请求、operation_id 和稳定幂等键。

  2. 02 / EXECUTE

    使用同一个 operation_id 调用外部工具。

  3. 03 / COMMIT

    持久化返回值、外部资源 ID 和完成状态。

在调用前写入的 PREPARED 记录至少应包含:

{
  "operation_id": "run-83:create-customer:4",
  "tool": "crm.create_customer",
  "canonical_request": {
    "email": "user@example.com"
  },
  "idempotency_key": "run-83:create-customer:4",
  "status": "PREPARED"
}

恢复时不能把“没有 COMMITTED”直接理解为“尚未执行”。如果记录已经是 COMMITTED,系统直接重放保存的结果即可。如果它仍然停留在 PREPARED,则应先凭 operation_id 或业务唯一键向外部系统查询。

如果动作实际已经发生,就补写 COMMITTED,而不是再次执行;只有确认动作尚未发生时,才使用完全相同的请求和幂等键重试。对于无法查询、工具又不支持幂等性且动作不可逆的场景,自动恢复并不安全,应将任务转入人工复核。这就是 Side-effect Sandwich 的核心:先记录意图,再执行副作用,最后提交结果。

这个模式适用于支付、邮件发送、工单创建、代码合并、部署、文件删除和外部 Agent 委派。最常见的错误,是在恢复时让模型重新生成请求和幂等键;这样看似恢复了流程,实际上已经把一次确定的操作变成了另一次全新的尝试。

哪些是事实,哪些是判断

事实:Inngest 支持持久化步骤结果、重试、挂起等待事件和子 Agent 调用;Mastra 区分了可续传的流缓存与抵御后端崩溃的工作流执行。

事实:在 Trigger.dev 6 月 30 日的事故中,列表、日志和 trace 出现故障,但 PostgreSQL 与 Redis 的执行路径未受影响,任务仍在运行。查看事故复盘

作者观点:MongoDB 的文章认为工具调用边界正成为常见的检查点粒度,并主张将模型、代码与提示词作为统一的版本 bundle。这是一项架构建议,不是行业标准。

我的推断:Agent 的持久化执行层会逐渐接近“数据库事务 + 工作流引擎”的组合:模型提出下一步,运行时负责记录决策、恢复进度并控制副作用。

延伸阅读

  1. State & Persistence: The Problem of Agent ReliabilityMongoDB · 2026.07.06

    系统梳理 state、memory、checkpoint、版本固定与恢复成本,适合作为入门主线。

  2. Introducing Durable AgentsMastra · 2026.06.26

    借助框架实现,理解流续传、后台执行和客户端观察的区别。

  3. Experiments: safely test code changesInngest · 2026.06.23

    解释为什么运行中的实验分支同样需要被持久化。

  4. Runs list and logs degradedTrigger.dev · 2026.06.30

    一个执行平面、状态真源与分析副本相互隔离的真实案例。

  5. Incident report on June 22, 2026Trigger.dev · 2026.06.24

    说明“可恢复”“可用”与“及时完成”是三项不同的能力。

这篇文章补上了什么

长期记忆回答“Agent 知道什么”,权限系统规定“Agent 可以做什么”,可观测性帮助我们理解“Agent 做过什么”。持久化执行关注的是另一个常被忽略的问题:当任务在任意时刻中断,系统如何确信自己知道该从哪里继续,以及哪些动作绝不能重复。

如果只记住一个原则,可以是:将执行过程视为可恢复的历史,而不是一次不可重来的内存计算。状态不等于记忆,流续传不等于执行恢复,检查点也不等于 exactly-once;面对外部副作用,还必须用类似 Side-effect Sandwich 的协议缩小最危险的崩溃窗口。