11.03概念更新于 2026年9月17日

任务状态与 Checkpoint

长任务如何记录进度、中间结果与已执行的动作。

11.03 · 课时讲解

任务状态与 Checkpoint

任务状态是长任务的施工日志,每个关键节点都要落盘。

1 / 12

一句话理解:任务状态是长任务的“施工日志”:计划了什么、每步做到哪、产物放在哪、对外做过哪些动作、在等谁;它必须是结构化的、每个关键节点都落盘,这样任何时候中断都能准确续上,而不是重做或漏做。

回到本模块的实践目标:让 Agent 支持“继续昨天那个任务”。上一课的会话能帮 Agent 想起“昨天聊过什么”,但对一个要诊断 200 个页面的批量 SEO 分析任务来说,这远远不够。Agent 需要准确知道:

  • 200 个页面里哪些处理完了、哪些失败了、哪些还没开始?
  • 第 87 个页面创建了工单,但通知是否发出去了?
  • 哪 3 个页面的改动在等主管审批?审批结果回来了吗?
  • 已经花了多少预算,还剩多少?

这些问题的答案如果只能从几百轮对话里“读出来”,就既慢又不可靠:历史可能已被压缩,模型也可能读错。这一课讲如何设计任务状态和检查点。

对话历史为什么不能当进度

维度 对话历史 结构化任务状态
可读者 主要给模型读 程序、模型、人都能读
查询“第 87 个页面是否已通知” 需要模型在长历史里找 直接查字段
被压缩后 细节可能丢失 不受影响
用于界面展示进度 困难 直接渲染
用于防止重复执行写操作 不可靠 可以做程序级校验

Anthropic 在关于长时间运行 Agent 的实践中给出了一个很好的例子:让 Agent 先生成一份 JSON 格式的功能清单,每项初始标为“未通过”,每完成并验证一项才修改状态,同时配合 Git 提交和进度文件。这本质上就是把任务状态从对话中剥离出来,存成结构化、可验证的外部记录。

任务状态里应该有什么

以「全站 SEO 批量诊断任务」为例,一份任务状态可以是这样(示例结构,不对应任何特定产品):

{
  "task_id": "task_20260917_0042",
  "goal": "诊断 9 月 16 日抓取的 200 个页面的 SEO 问题",
  "status": "running",
  "created_by": "user_ops_zhang",
  "created_at": "2026-09-17T09:00:00+08:00",
  "updated_at": "2026-09-17T10:42:13+08:00",
  "plan": [
    "逐页诊断 SEO 问题",
    "为需要修复的页面创建工单",
    "通知页面负责人",
    "影响范围超过阈值的改动提交主管审批"
  ],
  "progress": { "total": 200, "done": 86, "failed": 2, "waiting_approval": 3, "pending": 109 },
  "items": {
    "page_087": {
      "stage": "notify",
      "steps": {
        "diagnose":      { "status": "done", "result": "缺失 meta 描述", "checked_at": "2026-09-17T10:40:02+08:00" },
        "create_ticket": { "status": "done", "external_id": "T-8812", "idempotency_key": "task_20260917_0042:page_087:create_ticket" },
        "notify":        { "status": "started", "idempotency_key": "task_20260917_0042:page_087:notify" }
      }
    }
  },
  "approvals": [
    { "item": "page_033", "action": "批量改写 37 组重复标题", "requested_at": "2026-09-17T09:31:00+08:00", "decision": null }
  ],
  "artifacts": { "report_draft": "s3://reports/task_20260917_0042/draft.md" },
  "budget": { "limit_usd": 20, "spent_usd": 7.35 },
  "last_checkpoint": "page_087.notify.started"
}

逐项说明它们各自的作用:

字段 作用 缺了会怎样
goal、plan 恢复时让模型迅速进入状态 恢复后模型重新理解任务,结论可能偏移
progress 给人看进度,给程序判断是否完成 用户只能问“做完了吗”
items[].steps 精确到每个对象、每个步骤的状态 不知道从哪里续跑
external_id 记录外部系统返回的 ID 无法核对“工单到底建没建”
idempotency_key 保证重试不重复执行 重复工单、重复通知
status: started 标记“开始执行但结果未知” 崩溃后无法区分“没做”和“做了一半”
approvals 记录等待中的人工决定 审批回来后找不到对应的动作
artifacts 中间产物的位置(而非内容本身) 产物塞进状态,导致状态臃肿
budget 已花费与上限 续跑后预算重新计算,失去约束
时间戳 判断数据是否过期 用几小时前的诊断结论执行动作

两个原则:状态里存引用而不是大块内容(报告正文放对象存储,状态里只存路径);状态要能被人读懂(运营同学打开它,应该能看明白任务进展)。

Checkpoint:什么时候落盘

Checkpoint(检查点)就是把任务状态持久化保存的时刻。粒度的选择是一种权衡:

粒度 做法 优点 缺点
太粗 整个任务结束才保存 实现简单 中断就全部重来
适中 每个业务步骤、每个写操作前后保存 恢复精确,开销可控 需要设计步骤边界
很细 每次模型调用都保存完整上下文 可以精确回放 存储与性能开销大

把三种粒度放在同一条时间线上:

检查点粒度对比:太粗只在任务结束保存,适中在每个业务步骤和写操作前后保存,很细在每次模型调用都保存 一个任务的执行过程 → 太粗 中断就全部重来 适中 每个业务步骤、每个写操作前后:恢复精确,开销可控 很细 每次模型调用都存完整上下文:可精确回放,开销大
图 1 · 检查点粒度:点越密恢复越精确,开销也越大;推荐按业务步骤与写操作落盘

对含有写操作的任务,推荐的节奏是“意图 → 执行 → 结果”三次落盘:

写操作的三次落盘:先写入 started 意图并附幂等键,再携带幂等键调用通知服务,成功写入 done 与回执,失败写入 failed 或保持 started 检查点 1 · 记录意图 steps.notify = started 附幂等键 调用通知服务 携带幂等键 成功 · 检查点 2 写入 done 附回执 ID 失败或超时 · 检查点 2 写入 failed + 错误 结果未知则保持 started 恢复时重点检查 started 的步骤:按幂等键或外部 ID 查询真实结果
图 2 · “意图 → 执行 → 结果”:任何时刻崩溃,都能分清没做、做了一半和做完了

框架里也有现成的检查点机制,但语义各不相同:

  • LangGraph:Checkpointer 在图执行过程中保存线程状态的检查点,支持对话延续、人工介入、时间回溯和容错。需要注意,用 interrupt() 暂停的节点在恢复时会从头重新执行,暂停点之前的写操作必须幂等。
  • Claude Agent SDK:会话保存对话,另有文件检查点功能用于快照和回滚 Agent 对文件的修改。两者分别管“说了什么”和“改了什么文件”,业务系统里的写操作仍需你自己记录。
  • Claude API 的记忆工具:启用后,API 会自动在系统提示中加入一段协议,要求模型先查看记忆目录中的既有进度,并在工作中记录状态与进展,因为上下文窗口随时可能被重置。这是一种“由模型维护进度笔记”的轻量方案,适合开放式任务;对批量业务任务,仍建议由程序维护结构化状态。

恢复流程

“继续昨天那个任务”的标准恢复流程:

“继续昨天那个任务”的八步恢复流程:定位任务、校验归属、处理不确定项、刷新现实、检查审批、检查预算、装配上下文、继续执行 第 1 步 定位任务 按任务 ID 加载状态 第 2 步 校验归属 有权继续?被人接管? 第 3 步 处理不确定项 started 查真实结果 已生效补记 · 未生效重试 第 4 步 刷新现实 重查业务状态 页面可能已被修改 第 5 步 检查审批 推进已有决定的动作 第 6 步 检查预算 不够则请用户确认 第 7 步 装配上下文 给简报,不给整段旧对话 第 8 步 继续执行 从第一个未完成步骤开始
图 3 · 八步恢复流程:先把状态和现实对齐,最后才交给模型一份精炼简报

第 7 步是关键:恢复时给模型的是“一份精炼的简报”,而不是把昨天几百轮对话全部塞回去。这既省成本,也避免模型被旧对话中过时的推断误导。

常见误区

  • “有会话恢复就够了。” 会话恢复的是对话,长任务需要的是可查询、可校验的进度。
  • “状态里把所有中间结果都存进去,方便恢复。” 状态会迅速膨胀。大块内容存外部,状态只存引用和摘要。
  • “步骤标记为 done,就说明做完了。” 标记应该在验证之后,而不是调用之后。发送成功要看回执,创建成功要有外部 ID(见 各类动作的验证方式)。

设计要点

  • 任务状态结构化,包含目标、计划、逐项步骤状态、外部 ID、幂等键、审批、产物引用、预算与时间戳。
  • 写操作遵循“意图 → 执行 → 结果”三次落盘。
  • started 状态是恢复时的重点检查对象,必须能查询真实结果。
  • 恢复时先刷新业务状态,再给模型一份精炼简报。
  • 任务状态同时服务于界面进度展示,字段设计要考虑“人能看懂”。
  • 明确任务状态的保留期:任务结束后保留多久用于审计,何时清理。

练习

为「可以断点续跑的长任务 Agent」(第 8 周实践目标)完成设计,用时约 60 分钟:

  1. 选一个场景:全站 SEO 诊断,或批量处理客服工单。
  2. 写出任务状态的 JSON 结构,至少覆盖本课表格中的 8 个字段。
  3. 画出一个写操作的三次落盘流程。
  4. 模拟三个中断时刻(刚写完意图、外部调用超时、审批等待中),分别写出恢复时 Harness 应该执行的步骤。

延伸阅读

下一步

任务状态随任务结束而结束。下一课「长期记忆」讨论跨越任务和会话仍然需要记住的东西:写入什么、如何召回、如何纠错与遗忘。

试试:上下文、MCP、沙箱、Prompt 注入、外链