本阶段的核心命题 阶段 6 讲的是 Harness 内部长什么样,本阶段讲的是它作为一个产品怎么活下去:能安装、能启动、能恢复、能升级、能回滚。
这一层最容易被产品经理跳过,也最容易在上线后集中爆发——因为它的问题不出现在 Demo 里,只出现在"用了三个月之后"。
一次 LLM 请求是秒级的,一个 Agent 任务可能是分钟级、小时级甚至跨天的。中间会发生什么?
没有 Runtime 的 Agent,遇到以上任何一件事都会从零开始。 这就是"持久执行(Durable Execution)"要解决的问题。
| 形态 | 代表 | 机制 |
|---|---|---|
| 显式工作流 + 检查点 | LangGraph、Temporal 类 | 把执行建模成图/工作流,每一步存快照,可从任意点恢复 |
| 事件溯源 | Codex 的 rollout、dsh 的会话投影 | 把发生过的事件全部记下来,状态由事件重放推导 |
两者不互斥。共同点是:状态不在内存里,在存储里。
LangGraph 把持久化明确切成两层,这个切分很干净:
| 层 | 概念 | 作用域 | 用途 |
|---|---|---|---|
| Checkpointer | 检查点 | 线程内(一次会话) | 会话连续性、人工介入、时间旅行调试、故障恢复 |
| Store | 存储 | 跨线程 | 用户偏好、事实、共享知识 |
这正是阶段 3 与阶段 8 分工的工程对应物 Checkpointer ≈ 会话状态(本阶段);Store ≈ 长期记忆(阶段 8)。两者用不同的存储、不同的生命周期、不同的清理策略。把它们混在一张表里,是很多 Agent 产品后期最难拆的技术债。
它还提供三档持久化时机(从快到稳):退出时写、异步写、同步写。这是一个典型的性能与一致性权衡,产品经理要参与决策:
| 档位 | 快 | 风险 |
|---|---|---|
| 退出时持久化 | 最快 | 崩溃时丢整段 |
| 异步持久化 | 快 | 崩溃时可能丢最后几步 |
| 同步持久化 | 慢 | 基本不丢 |
判据:这个 Agent 的一步操作有没有副作用?有副作用(下单、扣款、发消息)就必须同步持久化,否则恢复时会重复执行。
| 能力 | 产品价值 | 实现难点 |
|---|---|---|
| 存储 | 关掉还能回来 | 存什么粒度:原始消息?事件?还是投影后的状态? |
| 恢复 | 断点续跑 | 恢复后上下文要不要重建?工具的外部状态还对得上吗? |
| 分叉 | "从这一步换个方向试试" | 分叉后的副作用怎么算 |
| 重放 | 审计历史、重建界面、复现输入条件 | 重新调用模型无法保证走同一路径;事件回放则可重建已发生轨迹 |
区分“历史回放”与“重新运行” 保存原始 Transcript、Tool Call、Tool Result 和环境快照,可以审计历史轨迹,事件投影也可以确定性重建 UI;但用相同输入重新调用模型,无法保证复现同一行为。问题复现通常需要固定环境并重复采样,而不是把“重放”一概说成不可能。
三类会话实现的对照读法:
Claude Code 的 Resume / Fork 类能力适合说明这个边界:
| 能力 | 恢复什么 | 不保证恢复什么 |
|---|---|---|
| Resume / Continue | Transcript、上下文和会话身份 | 已退出的 Shell 子进程、浏览器状态、远端事务 |
| Fork / Branch | 从某个历史状态派生新会话 | 两个分支的外部副作用隔离 |
| Durable Execution | 任务状态、检查点、等待条件和恢复策略 | 仍需业务侧设计幂等、补偿和 exactly-once 边界 |
恢复 Transcript 后先校验外部世界 订单、文件、远端任务可能已被其他人或其他进程修改。恢复后不能直接沿用旧判断,应重新查询外部状态,再决定继续、补偿或停止。
一个 Agent 任务的完整生命周期,产品都要定义:

每个转换都要回答三个问题:
| 转换 | 谁能触发 | 用户看到什么 | 中间产物怎么办 |
|---|---|---|---|
| 运行 → 挂起 | 权限规则 / 资源不足 | ||
| 运行 → 中断 | 用户 | ||
| 中断 → 恢复 | 用户 | ||
| 运行 → 取消 | 用户 / 超预算 | ||
| 运行 → 失败 | 系统 |
"中间产物怎么办"这一列是产品经理最容易漏的 Agent 跑到一半被打断,它已经做的事(创建的文件、占的座、发的请求)不会自动消失。方案里必须写清楚:哪些要回滚、哪些保留、用户怎么知道当前处于什么状态。
判别:任务预期时长 > 用户愿意等待的时间,就是长任务。这时产品形态必须改变——从"等结果"变成"提交任务 + 通知"。
四件必须做的事:
Anthropic 在 Effective harnesses for long-running agents 里给出的方案很值得记:
关键在最后半句:跨会话的连续性不靠"记住",靠"留下东西"。这是阶段 3 四动作里 Write 的极致应用——把状态写到上下文之外的文件里,下一次读回来。
这一节是"Packaging Layer",也是 Pi 桌面端这类产品的全部价值所在。
| # | 事项 | 做不好的后果 |
|---|---|---|
| 1 | 安装:一键、无依赖 | 用户在第一步流失 |
| 2 | 首次启动自检:环境、凭据、连通性 | 报错信息看不懂 |
| 3 | 配置分层:默认 / 用户 / 项目 / 会话 | 改一处影响全局 |
| 4 | 能力发现:这台机器上有什么可用 | 承诺了做不到的能力 |
| 5 | 运行时更新:热更 vs 整包更新 | 更新即事故 |
| 6 | 版本兼容:配置/会话/扩展的跨版本可读性 | 升级后老会话打不开 |
| 7 | 回滚:出问题能退回去 | 只能等修复 |
| 8 | 数据迁移:会话、记忆、配置 | 升级丢数据 |
| 9 | 崩溃与诊断:日志、上报、复现包 | 无法支持用户 |
一、升级链路一旦脱离进程管理器,故障是静默的 本机运维记录里有一个典型案例:某服务升级后脱离了 systemd 管理,表现为"静默掉线"——进程没了,但没有任何告警,因为管理器根本不知道它存在过。
产品含义:升级流程必须验证"升级后仍然被管理",而不只是"新版本能跑起来"。自检要包含"我是被谁拉起来的"。
二、跨平台打包的隐形杀手是编码与换行 热更打包时的 CRLF/LF 差异、中文路径下的 JSON 转义、无 BOM 的 .ps1 被按 GBK 解码——这几类问题的共同特征是静默失效:脚本不报错,就是不生效。
产品含义:Windows 支持不是"多编译一个二进制",是一整套编码与路径规范。排期时按平台单独估。
三、版本回滚要连数据版本一起回 应用版本回滚容易,数据库/会话格式的迁移版本回滚不容易。回滚方案必须写清"退到哪个版本 + 对应的数据 revision",否则回滚后会遇到"新数据老代码"的更糟状态。
配置分层的标准做法(从低到高优先级):

产品要定义的是:每一层允许覆盖什么。全都允许覆盖会导致行为不可预期;全都不允许会导致不可用。常见的切法是:能力开关允许各层覆盖,安全边界只允许向更严格的方向覆盖。
能力发现:Agent 启动时要知道这台机器上有什么(网络、沙箱支持、已安装工具、可用凭据)。发现结果要:
| 误区 | 纠正 |
|---|---|
| "会话存下来就行了" | 存什么粒度决定了能不能恢复、能不能分叉、能不能投出不同界面 |
| "重放能复现问题" | 历史事件可回放;重新调用模型只能复现输入条件,不能保证复现行为 |
| "会话能 Resume 就是持久执行" | Resume 恢复上下文,不自动恢复进程、事务和外部副作用 |
| "长任务就是加个进度条" | 是产品形态改变:提交 + 通知,不是等待 |
| "更新出问题再回滚" | 回滚要连数据版本一起设计,否则退不回去 |
| "打包是研发的事" | 首次启动体验、能力发现、失败提示全是产品定义 |
| "热更新更快更好" | 热更的失败模式更隐蔽(编码、换行、部分更新),要有校验与回退 |
| "跨平台就是多编译一份" | Windows 的沙箱与编码成本是数量级差异 |
| 资料 | 出处 | 读它拿什么 |
|---|---|---|
| LangGraph Persistence | LangChain 文档 | Checkpointer / Store 两层切分 |
| LangGraph Checkpointers | LangChain 文档 | 三档持久化时机与线程模型 |
| Effective harnesses for long-running agents | Anthropic,2025-11-26 | 跨上下文窗口的长任务模式 |
| A Harness For Every Task: Dynamic Workflows 对应本仓译文 | 本仓已收录 | 动态工作流与 harness 的关系 |
本仓已有资料: