Ch17: OpenClaw 记忆——Pre-Compaction Flush 与 Dreaming
Part 4: 生产级 Coding Agent 记忆系统 前置章节:Ch16: Codex 记忆——AI 驱动的批量整合 后续章节:Ch18: 八大记忆设计模式——从 Flush 到 Rules-as-Memory
17.1 一句话定位
OpenClaw 是腾讯 tRPC-Agent-Go 的 Coding Agent 模式,其独家创新是 Pre-Compaction Memory Flush——在上下文压缩(compaction)之前,主动运行嵌入式 agent 将重要信息 flush 到日记文件,是唯一显式将记忆保存前置于上下文压缩的生产方案。
17.2 日常类比:值班交接本
想象你是一个 24 小时值班的运维工程师,三班倒:
- Claude Code 的做法:每处理一个工单就记一条笔记(实时写入),换班时把所有笔记交给下一班
- Codex 的做法:处理工单时不记笔记,下班后统一整理当天所有工单的要点(批量整合)
- OpenClaw 的做法:处理工单时正常工作,但换班前必须把重要事项写在交接本上(Pre-Compaction Flush)
第三种做法的独特之处:它不是”随时记”也不是”事后整理”,而是在一个关键的临界时刻——换班——做一次主动的信息保存。为什么这个时刻关键?因为换班意味着你的工作记忆会被清空(对应 AI 的上下文压缩),如果不在清空前保存,重要信息就永久丢失。
类比的深层含义
换班(compaction)不是普通的时刻,而是一个信息生存的分水岭:
- 换班前保存的信息 → 存活在交接本(日记文件)中,下一班能看到
- 换班前没保存的信息 → 随着工作记忆清空而永久丢失
其他两个方案都没有显式关注这个分水岭:
- Claude Code 的 extractMemories 和 compaction 独立运行——extractMemories 可能还没跑完 compaction 就已经发生了
- Codex 的 Phase1 完全不关心 compaction 时机——记忆提取在 session 启动时,和 compaction 无关
只有 OpenClaw 显式地把”保存记忆”排在”压缩上下文”之前,确保不因压缩而丢失重要信息。
类比的边界
| 值班交接类比 | 对应物 | 类比失效之处 |
|---|---|---|
| 值班工程师 | AI agent session | 工程师主动判断什么重要,agent 靠嵌入式 LLM 判断 |
| 交接本 | daily/YYYY-MM-DD.md | 交接本是给人看的,日记文件是给 agent 自己看的 |
| 换班 | compaction | 换班是确定时刻,compaction 由上下文窗口用量触发 |
| 重要事项 | flush 的内容 | 人的判断更可靠,LLM 可能误判重要性 |
17.3 三层文件布局
OpenClaw 的记忆文件按时间稳定性和用途分为三层:
17.3.1 第一层:MEMORY.md(长期层)
# Memory
## Preferences
- Editor: vim keybindings
- Language: TypeScript preferred
- Style: functional over OOP
## Stable Knowledge
- tRPC: always define procedures with input/output schemas
- Go: use errgroup for concurrent goroutine error handling
- Docker: multi-stage builds for production images
## Project Conventions
- Monorepo: pnpm workspaces
- CI: GitHub Actions with caching
| 属性 | 值 | 说明 |
|---|---|---|
| 预算 | 10000 字符 | 约束总大小,保证注入时不超上下文预算 |
| 内容类型 | 核心偏好 + 稳定知识 | 只存长期有效的信息 |
| 更新频率 | 低(由 Dreaming 晋升) | 不是实时写入,而是由日记层晋升 |
| 生命周期 | 长期 | 除非被 Dreaming 淘汰,否则永久保留 |
10000 字符的预算约等于 3000-4000 个中文字符或 200-300 行 markdown。比 Claude Code 的 MEMORY.md(25KB)和 Codex 的 memory_summary.md 都小,但 OpenClaw 的策略是”小而精”——只存真正核心的信息。
17.3.2 第二层:daily/YYYY-MM-DD.md(日记层)
# 2026-06-23
## 今日工作
- 修复了 login API 的认证 bug(token 过期未刷新)
- 给 user service 加了 retry 逻辑
## 学到的
- tRPC 的 middleware 执行顺序是洋葱模型:先入后出
- pnpm 的 hoist-pattern 配置影响 monorepo 依赖解析
## 遇到的问题
- Docker build 在 Apple Silicon 上需要 --platform linux/amd64
- GitHub Actions 的 cache key 需要包含 pnpm-lock.yaml 的 hash
## 待跟进
- [ ] login bug 的根因分析还没完成
- [ ] retry 逻辑需要加 exponential backoff
| 属性 | 值 | 说明 |
|---|---|---|
| 命名 | 按日期 | 一天一个文件,自然的时间分区 |
| 内容类型 | 工作 + 学习 + 问题 + 待办 | 当天的所有重要信息 |
| 更新频率 | 高(由 Pre-Compaction Flush 写入) | 每次 compaction 前都可能写入 |
| 生命周期 | 中期(由 Dreaming 晋升或由 Budget Compaction 删除) | 日记可能晋升到长期层,也可能被预算压缩删除 |
17.3.3 第三层:DREAMS.md(整合日志)
# Dreams Log
## 2026-06-22 Dream
- Consolidated 3 daily files (06-19, 06-20, 06-21)
- Promoted: "tRPC middleware onion model" → MEMORY.md
- Promoted: "pnpm hoist-pattern" → MEMORY.md
- Discarded: "临时 workaround for build error" (resolved)
- Memory budget: 8500/10000 chars (85%)
## 2026-06-15 Dream
- Consolidated 5 daily files (06-10 to 06-14)
- Promoted: "Docker multi-stage builds" → MEMORY.md
- Promoted: "GitHub Actions cache strategy" → MEMORY.md
- Discarded: "deprecated API endpoint" (no longer relevant)
- Memory budget: 7200/10000 chars (72%)
| 属性 | 值 | 说明 |
|---|---|---|
| 内容类型 | Dream 操作的审计日志 | 记录每次整合做了什么 |
| 作用 | 可追溯 + 可回滚 | 知道哪些信息被晋升/淘汰,出问题可回溯 |
| 更新频率 | 低(每次 Dreaming 后追加) | 和 Codex 的 Phase2 频率类似 |
17.3.4 三层的协作关系
日记层(daily/*.md)
│
│ Pre-Compaction Flush ──→ 写入当天日记
│
│ Dreaming ──→ 晋升重要内容到长期层
│ ──→ 淘汰过时内容
│ ──→ 记录操作到 DREAMS.md
│
└──→ 长期层(MEMORY.md)
│
│ Budget Compaction ──→ 超预算时删除最旧段落
│
└──→ 注入 agent 上下文
关键洞察:信息流动方向是单向的——从日记层到长期层(晋升),不会从长期层回到日记层(降级)。这保证了长期层的内容质量始终在提升(只晋升不降级),而日记层是”草稿”——可以粗糙、可以重复、可以过时。
17.4 Pre-Compaction Memory Flush——核心创新
这是 OpenClaw 最独特的设计,值得深入拆解。
17.4.1 问题背景:Compaction 导致的信息丢失
所有长对话的 AI agent 都面临上下文窗口不够的问题。当对话累积的 token 数接近上下文窗口上限时,需要压缩(compaction)——用一个摘要替换前面的对话历史。
压缩的本质是有损压缩:100 轮对话的细节被压缩成一段摘要,必然丢失信息。问题在于:
- 用户在早期说的重要偏好(如”不要用 any 类型”)可能不在摘要中
- agent 在早期发现的关键事实(如”这个项目的数据库是 PostgreSQL”)可能被压缩掉
- 问题的排查线索可能分散在多轮对话中,压缩后线索断裂
17.4.2 Flush 机制详解
OpenClaw 的解决方案:在 compaction 前主动运行一次记忆保存。
对话进行中,上下文逐渐增长
│
├─ token_count > compaction_threshold?
│ │
│ ├─ Yes → 触发 Pre-Compaction Flush
│ │ │
│ │ ├─ 1. 启动嵌入式 agent(比 forked agent 更轻量)
│ │ ├─ 2. 扫描当前上下文,识别"重要信息"
│ │ ├─ 3. 将重要信息写入 daily/YYYY-MM-DD.md
│ │ ├─ 4. 等待 flush 完成(阻塞式,不是 fire-and-forget)
│ │ │
│ │ └─ 5. 执行 compaction
│ │
│ └─ No → 继续对话
关键细节:
- Flush 是阻塞式的:必须等 flush 完成后才执行 compaction,确保信息已经安全写入文件
- 嵌入式 agent:和 Claude Code 的 forked agent 类似但有区别——嵌入式 agent 共享当前 session 的完整上下文,而不是从 prompt cache 恢复
- 重要性判断:由嵌入式 LLM 判断当前上下文中哪些信息值得保存
17.4.3 和 Claude Code extractMemories 的区别
| 维度 | Claude Code extractMemories | OpenClaw Pre-Compaction Flush |
|---|---|---|
| 触发时机 | 每轮无工具响应后 | compaction 前 |
| 和 compaction 的关系 | 独立运行,无时序保证 | 显式前置于 compaction |
| 执行模式 | fire-and-forget(异步) | 阻塞式(同步等待完成) |
| 上下文来源 | prompt cache(可能不完整) | 当前 session 完整上下文 |
| 信息安全保证 | 无(可能和 compaction 并发导致丢失) | 强(flush 完成后才 compaction) |
最核心的区别:Claude Code 的 extractMemories 和 compaction 是两个独立进程,可能发生竞态——compaction 在 extractMemories 完成前就把上下文压缩了,导致 extractMemories 读不到完整的对话历史。OpenClaw 通过显式排序(flush → compaction)消除了这个竞态。
17.4.4 和 Codex Phase1 的区别
| 维度 | Codex Phase1 | OpenClaw Pre-Compaction Flush |
|---|---|---|
| compaction 感知 | 完全不关心 | 显式前置于 compaction |
| 数据来源 | rollout(完整执行轨迹) | 当前 session 上下文 |
| 处理时机 | 下一个 session 启动时 | 当前 session compaction 前 |
| 信息完整性 | 高(rollout 是完整记录) | 中(依赖嵌入式 agent 的判断) |
| 延迟 | 对当前 session 无帮助(下一个 session 才生效) | 对当前 session 有帮助(compaction 后的记忆来自当前 session) |
Codex 不关心 compaction 的原因:Codex 的记忆是全局共享的,Phase1 在下一个 session 启动时才处理上一个 session 的 rollout。这意味着 Codex 假设”当前 session 的上下文足够大,不需要 compaction”——如果确实需要 compaction,Codex 依赖 LLM 的摘要能力保留关键信息,但不做显式的记忆保存。
17.4.5 Flush 的局限性
Pre-Compaction Flush 不是完美的:
- 重要性判断可能失误:嵌入式 LLM 可能把不重要信息当重要(浪费日记空间),或把重要信息当不重要(信息丢失)
- 阻塞延迟:flush 完成前用户不能继续输入,如果嵌入式 agent 推理慢,用户体验受影响
- 只防 compaction 丢失:如果 session 正常结束(不需要 compaction),flush 不触发——此时靠其他机制(如下次 session 的 Dreaming)保存信息
- 日记层膨胀:频繁 compaction 的长对话可能产生大量日记条目,需要 Dreaming 及时整合
17.5 Flush 模型可独立配置
OpenClaw 允许独立配置 flush 使用的模型,这是一个实用的工程优化。
17.5.1 配置方式
memory:
flush:
model: "qwen2.5-7b" # 用本地小模型做 flush
max_tokens: 2048 # flush 输出预算
temperature: 0.1 # 低温度,减少随机性
dreaming:
model: "deepseek-v3" # 用更强模型做 Dreaming
max_tokens: 4096
17.5.2 为什么 flush 可以用小模型?
flush 的任务是”从上下文中识别重要信息并写入日记”——这不需要深度推理,更像是信息提取:
- 识别重要性:基于启发式规则(如”用户显式声明的偏好”、”agent 发现的项目约定”、”报错信息”)
- 格式化输出:按日记模板写入,格式固定
- 不需要跨上下文推理:不需要比较”这条信息和上周的信息是否矛盾”
用 7B 参数的本地模型做 flush,推理延迟 <1s,成本几乎为零。而用 GPT-4 级模型做 flush,推理延迟 3-5s,成本 $0.01+/次。
17.5.3 为什么 Dreaming 不能用小模型?
Dreaming 的任务是”从日记中整合知识并晋升到长期层”——这需要更强的推理:
- 判断信息是否仍然有效:需要理解技术栈的版本变化
- 发现信息间的矛盾:需要跨条目推理
- 合并相似信息:需要语义理解能力
- 决定晋升/淘汰:需要价值判断
小模型在这些任务上表现明显差于大模型,因此 Dreaming 通常配置更强的模型。
17.5.4 模型配置的成本/质量权衡
| 配置方案 | flush 成本 | Dreaming 成本 | flush 质量 | Dreaming 质量 | 总评 |
|---|---|---|---|---|---|
| 全用大模型 | 高 | 高 | 高 | 高 | 质量最好但最贵 |
| 全用小模型 | 低 | 低 | 中 | 低 | 便宜但 Dreaming 质量差 |
| flush 小 + Dreaming 大 | 低 | 中 | 中 | 高 | 最佳性价比 |
| flush 大 + Dreaming 小 | 高 | 低 | 高 | 低 | 不推荐(关键环节用弱模型) |
第三种方案(flush 小 + Dreaming 大)是 OpenClaw 推荐的默认配置,也是实际生产中性价比最高的选择。
17.6 Memory Budget Compaction
当 MEMORY.md 超过 10000 字符预算时,需要压缩。OpenClaw 的方案比 Claude Code 的硬截断更温和。
17.6.1 触发条件
if (sizeof(MEMORY.md) > 10000 chars):
trigger_budget_compaction()
17.6.2 压缩策略:按日期删最旧段落
MEMORY.md 超预算
│
├─ 按段落时间戳排序(从旧到新)
├─ 删除最旧段落,直到总大小 <= 10000 chars
├─ 但跳过标记为 [persistent] 的段落
└─ 被删除段落的信息保留在 DREAMS.md 审计日志中
关键设计:
- 按时间顺序删除:最旧的信息最可能过时,最新的信息最可能有效——这是合理的默认假设
- 保留手写内容:标记为
[persistent]的段落不会被自动删除——用户显式标记的内容优先级最高 - 审计日志:被删除的段落不是真的消失,而是记录在 DREAMS.md 中——如果发现误删,可以从 DREAMS.md 恢复
17.6.3 段落晋升机制
删除前会尝试”晋升”——把长段落压缩成短段落:
原始段落(300 字符):
"使用 pnpm workspaces 管理依赖。配置方法:在根目录
创建 pnpm-workspace.yaml,列出 packages/*。注意
hoist-pattern 配置影响依赖解析,需要显式声明..."
晋升后(80 字符):
"pnpm workspaces: pnpm-workspace.yaml + hoist-pattern 配置"
晋升由 LLM 完成(和 Dreaming 用同一个模型),压缩比约 3-4x。晋升的好处是保留了信息的”指针”——即使细节丢失,agent 知道”这个项目用 pnpm workspaces”这个事实,需要时可以查阅文档补全细节。
17.6.4 和 Claude Code 硬截断的对比
| 维度 | Claude Code 硬截断 | OpenClaw Budget Compaction |
|---|---|---|
| 截断方式 | 200 文件上限,超限不写入 | 按时间删除最旧段落 |
| 保留策略 | 无(先到先得) | 有([persistent] 标记 + 段落晋升) |
| 恢复能力 | 无(删除即丢失) | 有(DREAMS.md 审计日志) |
| 信息压缩 | 无(要么全保留要么全丢) | 有(段落晋升压缩细节) |
| 温和程度 | 硬 | 温和 |
OpenClaw 的方案更温和因为:它不会突然丢弃信息(有晋升机制),有审计可追溯(DREAMS.md),用户可以显式保护重要内容([persistent] 标记)。
17.6.5 Budget Compaction 的局限
- 晋升质量依赖 LLM——压缩可能丢失关键细节
- [persistent] 标记需要用户手动添加——如果用户忘记标记,重要内容可能被自动删除
- 审计日志本身也会增长——如果频繁压缩,DREAMS.md 可能变得很大
17.7 Dreaming 后台整合
Dreaming 是 OpenClaw 的后台整合机制,负责把日记层的重要内容晋升到长期层。
17.7.1 触发条件
和 autoDream 类似,有冷却期门槛:
if (days_since_last_dream > 1 && unread_daily_files > 0):
trigger_dreaming()
17.7.2 Dreaming 流程
Dreaming 启动
│
├─ 1. 扫描 daily/ 目录,找到未整合的日记文件
├─ 2. 对每个日记文件,由 Dreaming agent 评估每条信息的价值
│ ├─ 价值高 + 长期有效 → 晋升到 MEMORY.md
│ ├─ 价值中 + 可能有参考价值 → 保留在日记层
│ └─ 价值低 + 已过时 → 标记为可删除
├─ 3. 晋升时检查 MEMORY.md 预算
│ ├─ 预算充足 → 直接追加
│ └─ 预算不足 → 先触发 Budget Compaction 再追加
├─ 4. 更新 DREAMS.md,记录晋升/淘汰决策
└─ 5. 标记已处理的日记文件(避免重复处理)
17.7.3 晋升判断标准
Dreaming agent 判断一条信息是否值得晋升的标准:
| 标准 | 权重 | 示例 |
|---|---|---|
| 复现频率 | 高 | “pnpm 安装后需要 restart IDE”——每次都遇到 |
| 长期有效性 | 高 | “项目用 Next.js App Router”——不会变 |
| 通用性 | 中 | “tRPC 中间件洋葱模型”——所有 tRPC 项目通用 |
| 独特性 | 中 | “这个 API 只在工作日可用”——特定场景但重要 |
| 时效性 | 低 | “临时 workaround”——可能很快过时 |
17.7.4 Dreaming vs autoDream vs Phase2
| 维度 | OpenClaw Dreaming | Claude Code autoDream | Codex Phase2 |
|---|---|---|---|
| 输入 | 日记文件 | 记忆文件 | stage1_outputs |
| 输出 | 晋升到 MEMORY.md | 整合去重记忆文件 | MEMORY.md + summary + skills/ |
| 推理强度 | Medium-High | Medium | Medium |
| 冷却期 | ~1 天 | ~1 天 + 5 session | 6 小时 |
| 预算约束 | 10000 字符 | 200 文件 × 4KB | top-256 输入 |
| 审计日志 | DREAMS.md | 无 | 无(usage_count 可参考) |
17.8 与 DB-Agent-Memory 集成的三层协同问题
OpenClaw 的文件记忆系统不是孤立运行的——它需要和 DB-Agent-Memory(基于数据库的 agent 记忆)协同工作,形成三层记忆架构。
17.8.1 三层架构
L1: MEMORY.md(文件记忆,10KB)
↓ 慢但精
L2: DB-Agent-Memory(数据库记忆,结构化查询)
↓ 快但泛
L3: 上下文窗口(工作记忆,最快但最易失)
| 层级 | 存储 | 容量 | 延迟 | 持久性 | 典型内容 |
|---|---|---|---|---|---|
| L1 | 文件 | ~10KB | 低(全量注入) | 永久 | 核心偏好、稳定知识 |
| L2 | 数据库 | GB 级 | 中(需查询) | 永久 | 结构化实体、关系图谱 |
| L3 | 上下文窗口 | ~200K tokens | 零 | session 级 | 当前对话、临时推理 |
17.8.2 协同问题一:一致性
同一信息可能存在于三层中,如何保证一致?
场景:用户说”从现在开始用 ESM 不用 CommonJS”——这个偏好应该更新在所有三层中:
- L1:MEMORY.md 中的”模块系统”段落
- L2:DB 中的 user_preference 表
- L3:当前上下文窗口
如果只更新了 L1 而没更新 L2,下次 session 从 DB 查到的还是旧的 CommonJS 偏好。
OpenClaw 的策略:以 L1(文件记忆)为 source of truth,L2 是 L1 的索引和补充。更新时先写 L1,再异步同步到 L2。L3 在下次注入时自动从 L1 获取最新值。
17.8.3 协同问题二:查询路由
不同类型的查询应该路由到不同层:
| 查询类型 | 路由目标 | 原因 |
|---|---|---|
| “我的编码偏好是什么” | L1 | 偏好是核心知识,MEMORY.md 全量在场 |
| “这个项目的所有 API 端点” | L2 | 结构化数据,数据库查询更高效 |
| “刚才用户说了什么” | L3 | 当前对话上下文,L1/L2 都没有 |
路由错误的后果:
- 把偏好查询路由到 L2 → 可能查到过时数据(DB 同步有延迟)
- 把结构化查询路由到 L1 → 可能查不到(MEMORY.md 不存详细数据)
- 把当前对话查询路由到 L1/L2 → 一定查不到(工作记忆不在持久层)
17.8.4 协同问题三:冲突解决
当 L1 和 L2 对同一事实有不同记录时:
L1: "项目用 pnpm"
L2: "项目用 yarn" (过时记录)
解决策略:L1 优先(文件记忆是 agent 直接维护的,更可信),L2 在检测到冲突时标记为”待验证”并异步更新。但这个策略不是完美的——如果 L1 的记录才是过时的(用户手动改了项目配置但没触发 flush),L2 的数据库记录(从实际文件系统扫描得到)可能更准确。
17.8.5 三层协同的现实挑战
- 运维复杂度:三层存储意味着三种备份/恢复策略、三种迁移路径、三种一致性检查
- 调试困难:行为异常时需要查三层的数据才能定位问题
- 性能开销:每次写入需要同步多层,每次读取需要路由决策
当前 OpenClaw 的方案偏实用主义——L1 是主记忆,L2 是辅助查询,L3 是工作记忆。三层不是平等协作,而是有明确的主次关系。
17.9 三个生产系统对比总结表
经过 Ch15-Ch17 的分析,我们对三个生产级 Coding Agent 的记忆系统有了全面了解。以下是关键维度的对比总结。
17.9.1 架构哲学
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 记忆哲学 | 实时学习 | 批量整合 | 临界保存 |
| 核心创新 | 索引 + LLM 语义检索 | Citation 正反馈循环 | Pre-Compaction Flush |
| 写入时机 | 每轮对话后 | Session 结束后 | Compaction 前 |
| 整合时机 | 24h + 5 session | 6h 冷却期 | ~1 天冷却期 |
| 所属公司 | Anthropic | OpenAI | 腾讯(tRPC-Agent-Go) |
17.9.2 读取路径
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 注入方式 | 索引全量 + LLM 选 5 文件 | memory_summary.md 全量 | MEMORY.md 全量 |
| 检索机制 | LLM 语义筛选 | 无检索(全量) | 无检索(全量) |
| 单次注入量 | ~20KB (5×4KB) | ~30-50KB (摘要) | ~10KB |
| session 累计限制 | 60KB | 无显式限制 | 无显式限制 |
| 新鲜度处理 | >1 天加警告 | 无 | 无(Dreaming 定期清理过时内容) |
17.9.3 写入路径
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 写入机制 | extractMemories (forked agent) | Phase1 (并行 rollout 提取) | Pre-Compaction Flush (嵌入式 agent) |
| 写入模式 | fire-and-forget | 异步并行 | 阻塞等待 |
| 和 compaction 关系 | 独立运行 | 不关心 | 显式前置于 |
| 分类/过滤 | 四类型分类 | 多层内容过滤 + secret 脱敏 | 重要性判断 |
| 存储位置 | .claude/memory/ |
SQLite stage1_outputs | daily/*.md |
17.9.4 整合机制
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 整合名称 | autoDream | Phase2 | Dreaming |
| 整合模型 | Sonnet | consolidation agent (Medium) | 可配置(推荐强模型) |
| 整合环境 | 正常运行 | 隔离沙箱(无网络/MCP/审批) | 正常运行 |
| 输入选择 | 所有记忆文件 | top-256 (usage_count + recency) | 未整合的日记文件 |
| 输出 | 去重后的记忆文件 | MEMORY.md + summary + skills/ | 晋升到 MEMORY.md + DREAMS.md |
| 容量管理 | 200 文件硬上限 | Citation 驱动柔性淘汰 | 10000 字符预算 + Budget Compaction |
17.9.5 独特优势和关键局限
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 独特优势 | 语义检索精度最高 | Citation 正反馈最优雅 | Pre-Compaction Flush 最安全 |
| 关键局限 | 每轮额外 LLM 调用成本 | 短期信息可能遗漏 | 阻塞延迟影响用户体验 |
| 适用场景 | 高频交互、偏好多变 | 多项目、长期积累 | 长对话、信息密集 |
| 最怕什么 | 索引漂移(死链/孤儿文件) | 马太效应(新记忆被过早淘汰) | flush 判断失误(记了不重要的,丢了重要的) |
17.9.6 信息安全保证
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 防止 compaction 丢失 | ❌ 无保证 | ❌ 无保证 | ✅ Pre-Compaction Flush |
| 防止 secret 泄露 | ✅ 写入时检测排除 | ✅ Phase1 脱敏 | ⚠️ 依赖 flush agent 判断 |
| 防止记忆污染 | ✅ 项目隔离 | ⚠️ 全局共享可能污染 | ✅ 层级隔离 |
| 可恢复性 | ❌ 删除即丢失 | ⚠️ usage_count 可参考 | ✅ DREAMS.md 审计日志 |
17.9.7 成本特征
| 维度 | Claude Code | Codex | OpenClaw |
|---|---|---|---|
| 日常成本 | 高(每轮额外推理) | 低(只注入摘要) | 低(全量注入小文件) |
| 整合成本 | 中(autoDream) | 高(Phase2 大规模推理) | 中(Dreaming + 段落晋升) |
| 成本分布 | 平滑(分散在日常) | 脉冲(集中在 Phase2) | 混合(flush 低成本 + Dreaming 中成本) |
| 模型可配置性 | 低(固定用 Sonnet) | 低(固定 reasoning 级别) | 高(flush/Dreaming 独立配置) |
17.10 从三个系统看记忆设计空间
三个生产系统不是孤立的方案,而是记忆设计空间中的三个点。通过对比,我们可以提炼出记忆设计的核心权衡维度。
17.10.1 核心权衡一:实时 vs 批量写入
实时 ←────────────────────→ 批量
Claude Code Codex
│ │
│ OpenClaw │
│ (临界时刻写入) │
└────────────────────────┘
- 实时:不丢短期信息,但碎片化和高日常成本
- 批量:整合质量高,但短期信息可能遗漏
- 临界时刻(OpenClaw):在信息最可能丢失的时刻保存,是实时和批量的折中
17.10.2 核心权衡二:检索精度 vs 注入效率
高精度检索 ←──────────────→ 高效率注入
Claude Code Codex + OpenClaw
(LLM语义筛选) (全量注入摘要/索引)
- 高精度检索:只注入相关记忆,上下文效率高,但每次检索消耗一次 LLM 调用
- 高效率注入:全量注入,零检索成本,但可能注入无关信息浪费 token
17.10.3 核心权衡三:项目隔离 vs 全局共享
项目隔离 ←───────────────→ 全局共享
Claude Code Codex
│
OpenClaw
(层级隔离:日记项目级,长期全局级)
- 项目隔离:避免污染但复用受限
- 全局共享:复用方便但需要精细整合区分适用范围
17.10.4 核心权衡四:硬约束 vs 柔性淘汰
硬约束 ←─────────────────→ 柔性淘汰
Claude Code Codex
(200文件硬上限) (Citation驱动)
│
OpenClaw
(预算+晋升+审计)
- 硬约束:简单可预测,但可能截断有用记忆
- 柔性淘汰:自适应,但有冷启动劣势和马太效应
- 预算 + 晋升 + 审计(OpenClaw):最温和,但有运维复杂度
17.10.5 compaction 感知:被忽视的关键维度
三个系统对比揭示了一个被普遍忽视的维度:记忆系统是否感知上下文压缩的时机。
| compaction 感知 | 系统 | 信息安全保证 |
|---|---|---|
| 无感知 | Claude Code, Codex | 无保证(compaction 可能丢信息) |
| 显式前置于 | OpenClaw | 强保证(flush 完成后才 compaction) |
compaction 是长对话 AI agent 的必经之路,但在记忆系统设计中常被忽视。OpenClaw 的 Pre-Compaction Flush 提醒我们:记忆保存的时机和上下文压缩的时机有强关联,忽略这种关联可能导致信息在压缩的缝隙中丢失。
17.11 章节小结
OpenClaw 的记忆系统是一个Pre-Compaction Flush 驱动的临界保存方案,核心设计可以概括为四句话:
- 三层布局:MEMORY.md(长期 10KB)+ daily/*.md(日记)+ DREAMS.md(审计),信息单向流动从日记到长期。
- 核心创新 Pre-Compaction Flush:在 compaction 前阻塞式运行嵌入式 agent,将重要信息 flush 到日记文件——唯一显式将记忆保存前置于上下文压缩的方案,消除 compaction 导致的信息丢失竞态。
- 温和的预算管理:Budget Compaction 按时间删最旧段落 + 段落晋升 + [persistent] 保护 + DREAMS.md 审计,比硬截断更温和,比柔性淘汰更可控。
- 模型可配置:flush 用小模型降成本,Dreaming 用强模型保质量,是三个系统中模型配置最灵活的。
三个生产系统的对比揭示了一个核心洞察:记忆设计没有银弹,只有权衡。Claude Code 用实时写入换不丢信息,Codex 用批量整合换精炼质量,OpenClaw 用临界保存换 compaction 安全。每种选择都有代价,关键是在具体场景下选择代价最小的方案。
下一章我们将跳出具体系统,从更高视角审视记忆设计空间的全景——什么是好的记忆,什么是差的记忆,以及如何评估一个记忆系统的效果。
导读目录:README.md 上一章:Ch16: Codex 记忆——AI 驱动的批量整合 下一章:Ch18: 八大记忆设计模式——从 Flush 到 Rules-as-Memory