Skip to content
预计 1 分钟右侧目录可快速定位

哪些信息能用于恢复:Memory、RAG、Event Log 与 Crash Recovery ​

前置:一条 Memory 还能不能信:Provenance、Freshness、Conflict 与 Isolation
核心问题:Crash 之后恢复 Run 时,哪些事实能从 Memory/RAG 找,哪些必须来自 Event Log 或 Runtime durable state?

服务 crash 前已经成功发送一封邮件,但聊天摘要没有记录;Memory 里存着过去用户的偏好,RAG 又检索到邮件模板。恢复时只有 execution record/event log 能回答“邮件是否已经发送”,Memory/RAG 都不能作为强一致事实源。

Mental Model ​

text
                 ┌─ Memory Store ── learned cross-run guidance ─┐
                 │                                              │
Model Context ◀──┼─ Retriever ───── external knowledge evidence ┤
                 │                                              │
                 └──────────────────────────────────────────────┘

Runtime Decision ◀─ RunState / Checkpoint / Event / Execution Record
                         │
                         └─ authoritative execution facts

把三类数据源放到不同的信任平面最容易理解:

Memory/RAG 主要提高模型“知道什么”;State/Checkpoint/Execution Record 决定程序“已经做了什么”。 前两者可以影响下一步语义决策,但不能替代后者证明副作用是否发生。

Memory vs RAG ​

Memory 通常来自系统在过去交互中学到、并经过写入策略筛选的跨 Run 信息:

text
user correction
prior run outcome
project-specific learned procedure
agent experience consolidation

RAG knowledge base 通常来自独立的外部知识源,例如文档、代码仓库、规范、工单或其他经过 ingestion/index 的语料。两者都可能参与下一轮 Context,但 provenance、更新方式和权限边界不同。

Event Log 与 State Reconstruction ​

Event Log 记录不可变的执行事实,例如:

text
RUN_STARTED
PLAN_COMPILED
NODE_STARTED
TOOL_CALL_COMMITTED
NODE_SUCCEEDED
APPROVAL_REQUESTED
RUN_RESUMED

Reducer 可以按顺序 fold 这些事件重建派生状态;snapshot/checkpoint 用来减少从头重放的成本,但不能改变事件已经提交的事实。

Crash Recovery ​

真正问题是:

crash 发生时,外部世界可能已经变化,但本地状态可能尚未完成下一次提交。

text
1. call payment API
2. payment succeeds remotely
3. process crashes
4. local DB hasn't recorded success
5. resume
6. call payment API again

🔍 源码对照:恢复正确性依赖 Checkpoint;Memory 维护失败不能改变 Turn 结果 ​

精确定位

ts
async function runTurnMemory(store, progress, session, ctx, ts, exchange) {
  await runMemoryExtraction(store, session, ctx, exchange)
  if (!progress) return

  try {
    progress.recordEpisodeTurn({ ts, ...exchange })
    if (progress.pending().length < episodeInterval()) return
    await summarizeAndPersistEpisode(progress, store, session, ctx)
  } catch {
    // maintenance must not fail the user-visible turn
  }
}

对照理解

  • Memory extraction / episode summarization 属于 maintenance path,不是 Turn settlement 的强一致步骤。
  • 源码故意吞掉这条维护路径的异常:记忆失败不能把已经完成的用户 Turn 反向判成失败。
  • 因此 Memory、Checkpoint、Conversation State 必须分开:Checkpoint 决定能否恢复,Memory 只增强未来决策。

源码说明

把 turn-memory、transcript-mirror、storage 三条路径并排阅读,可以形成本文最重要的边界:Memory 回答“未来推理可能记住什么”,Transcript 回答“交互发生过什么”,Durable State 回答“程序恢复时哪些执行事实仍成立”。RAG 则是从外部知识源检索证据,四者不能互相顶替。

工程边界

这个仓库并不是 RAG 参考实现,因此这里只用它帮助划清 Memory/Transcript/State;Retrieval quality、embedding 和 rerank 不从此案例推导。

Shadow Harness 对照

  • Crash recovery 只读取 durable authoritative state + versioned event/execution records。
  • Memory/RAG 可补充 Context,但不得把“模型记得曾执行”升级为“副作用已提交”。

验证

让 Memory 中存在“邮件已经发送”的文本,但 ExecutionRecord 显示 outcome unknown;resume 必须服从 execution fact,而不是 memory narrative。

Memory 不应参与强一致恢复 ​

错误:

text
模型从 Memory 记得:"邮件应该已经发过了"
→ Runtime 因此跳过发送

RAG 也不能证明 Runtime State ​

同样,RAG 找到一份文档写着“deployment completed”不能替代真实 execution record。RAG 提供知识证据,不是当前执行事务日志。

因此恢复时的 authority 顺序应当是 execution record / checkpoint / event-derived state → Runtime;执行状态确定之后,再由 Memory / RAG 补充模型下一轮需要的认知信息。

最小实现 / 数据结构 ​

接口层面要避免这种无边界的总管对象:

python
KnowledgeMemoryStateManager

这种名字通常意味着 execution state、learned memory 和 retrieval evidence 已经混成一种责任。更清晰的逻辑拆分是:

text
StateStore
├── current Run/Task state
└── optimistic version

CheckpointStore
├── state snapshot
└── next/pending metadata

EventStore
└── immutable runtime events

ExecutionRecordStore
├── tool/node attempts
├── idempotency keys
└── external side-effect commit status

MemoryStore
└── learned cross-run information

Retriever
└── external knowledge evidence

在 Shadow Harness 中怎么落地 ​

Shadow Harness 应把恢复依赖拆成 StateStore、CheckpointStore、EventStore、ExecutionRecordStore,把认知信息拆成 MemoryStore 与 Retriever。Runtime resume 只能以执行事实层为 authority;Memory/RAG 由 ContextManager 在恢复状态确定之后按需加载。

Failure Modes ​

Vector DB = Memory = RAG ​

症状: 因为都可能使用 embedding/vector store,就用一个 search_everything() 处理 Memory、RAG 和运行状态。

为什么危险: 存储技术相同不代表语义相同:Memory 有 write/freshness/scope,RAG 有 provenance/ranking,Runtime State 要求强一致恢复。

处理: 拆分 MemoryStore、Retriever、StateStore/CheckpointStore;可共享基础设施但不共享 domain contract。

Crash recovery 依赖 transcript ​

症状: 恢复时读取聊天记录/summary,让模型判断哪些动作已经做过。

为什么危险: Transcript 不是外部副作用 commit log,模型无法证明邮件、支付、PR 是否真正提交。

处理: 恢复从 checkpoint/event/execution record 开始;conversation 只用于后续 Context。

Replay 真实生产副作用 ​

症状: time travel/debug 从旧 checkpoint 重跑时直接调用真实邮件、支付、部署 Tool。

为什么危险: Replay 不天然具备 exactly-once;重新执行真实外部动作会复制副作用。

处理: Replay 默认 stub/mock/sandbox,或要求 Tool replay-safe;明确区分 replay 与 resume。

Event Log 没有 version/schema ​

症状: 事件 payload 随代码变化却没有 schema_version/event_version。

为什么危险: 旧事件在新 reducer 中可能被错误解释,state reconstruction 静默出错。

处理: 事件 schema 版本化,提供 upcaster/migration 或明确拒绝不兼容版本。

如何验证 ​

Case断言
Vector DB = Memory = RAG同一数据库下运行 contract tests,三类接口必须执行不同 scope/consistency 规则。
Crash recovery 依赖 transcript副作用成功但 transcript 未追加时 crash,resume 仍能识别已完成动作。
Replay 真实生产副作用对含 send_email 的历史 Run 做 replay,真实 provider 调用次数不得增加。
Event Log 没有 version/schema旧 event fixture 在新代码中要么迁移成功,要么明确报 unsupported。

关联源码 ​

自测 ​

  1. 恢复 Run 时,为什么 RAG 文档和 Long-term Memory 不能替代 Event Log / Runtime State?它们分别属于什么证据类型?
  2. 一条“任务已完成”的 Memory 与最新 execution record 冲突时,哪一个应拥有恢复 authority?

Sources ​

AI Engineering · Agent · Harness · Backend Systems