工作区内存 v2(离线):研究笔记
目标: Clawd 风格的工作区(agents.defaults.workspace,默认 ~/.openclaw/workspace),其中"内存"存储为每天一个 Markdown 文件(memory/YYYY-MM-DD.md)加上一小组稳定文件(例如 memory.md、SOUL.md)。
本文档提出了一个离线优先的内存架构,将 Markdown 作为规范的、可审查的真实来源,但通过派生索引添加结构化回忆(搜索、实体摘要、置信度更新)。
为什么要改变?
当前设置(每天一个文件)非常适合:
- "仅追加"日志记录
- 人工编辑
- 基于 git 的持久性 + 可审计性
- 低摩擦捕获("直接写下来")
它的弱点在于:
- 高召回率检索("我们对 X 决定了什么?","上次我们尝试 Y 时?")
- 以实体为中心的答案("告诉我关于 Alice / The Castle / warelay")而不重新阅读许多文件
- 观点/偏好的稳定性(以及当它改变时的证据)
- 时间约束("2025 年 11 月期间什么是真实的?")和冲突解决
设计目标
- 离线: 无需网络即可工作;可以在笔记本电脑/Castle 上运行;无云依赖
- 可解释: 检索的项目应该是可归因的(文件 + 位置)并且可与推理分离
- 低仪式感: 日常日志保持 Markdown,无需繁重的 schema 工作
- 增量: v1 仅使用 FTS 即可有用;语义/向量和图是可选的升级
- Agent 友好: 使"在令牌预算内回忆"变得容易(返回小事实束)
北极星模型(Hindsight × Letta)
两个要融合的部分:
Letta/MemGPT 风格的控制循环
- 在上下文中始终保留一个小的"核心"(persona + 关键用户事实)
- 其他所有内容都超出上下文,并通过工具检索
- 内存写入是显式工具调用(append/replace/insert),持久化,然后在下一轮重新注入
Hindsight 风格的内存基底
- 分离观察到的 vs 相信的 vs 总结的
- 支持保留/回忆/反思
- 带置信度的观点,可以随证据演变
- 实体感知检索 + 时间查询(即使没有完整的知识图谱)
提议的架构(Markdown 真实来源 + 派生索引)
规范存储(git 友好)
将 ~/.openclaw/workspace 作为规范的人类可读内存。
建议的工作区布局:
~/.openclaw/workspace/
memory.md # 小:持久事实 + 偏好(核心-ish)
memory/
YYYY-MM-DD.md # 日志(追加;叙述)
bank/ # "类型化"内存页面(稳定、可审查)
world.md # 关于世界的客观事实
experience.md # agent 做了什么(第一人称)
opinions.md # 主观偏好/判断 + 置信度 + 证据指针
entities/
Peter.md
The-Castle.md
warelay.md
...
注意事项:
- 日志保持日志。无需将其转换为 JSON
- bank/ 文件是经过策划的,由反思作业生成,仍然可以手动编辑
- memory.md 保持"小 + 核心-ish":您希望 Clawd 在每个 session 中看到的内容
派生存储(机器回忆)
在工作区下添加派生索引(不一定被 git 跟踪):
~/.openclaw/workspace/.memory/index.sqlite
支持:
- 用于事实 + 实体链接 + 观点元数据的 SQLite schema
- 用于词汇回忆的 SQLite FTS5(快速、微小、离线)
- 用于语义回忆的可选嵌入表(仍然离线)
索引始终可以从 Markdown 重建。
保留 / 回忆 / 反思(操作循环)
保留:将日志规范化为"事实"
Hindsight 在这里很重要的关键洞察:存储叙述性的、自包含的事实,而不是微小的片段。
memory/YYYY-MM-DD.md 的实用规则:
- 在一天结束时(或期间),添加一个 ## Retain 部分,包含 2-5 个要点:
- 叙述性(保留跨轮次上下文)
- 自包含(独立后仍有意义)
- 标记类型 + 实体提及
示例:
## Retain
- W @Peter: 目前在马拉喀什(2025 年 11 月 27 日至 12 月 1 日)参加 Andy 的生日。
- B @warelay: 我通过在 try/catch 中包装 connection.update 处理程序修复了 Baileys WS 崩溃(参见 memory/2025-11-27.md)。
- O(c=0.95) @Peter: 在 WhatsApp 上更喜欢简洁的回复(<1500 字符);长内容放入文件。
最小解析:
- 类型前缀:W(世界),B(经验/传记),O(观点),S(观察/摘要;通常是生成的)
- 实体:@Peter、@warelay 等(slug 映射到 bank/entities/*.md)
- 观点置信度:O(c=0.0..1.0) 可选
如果您不希望作者考虑它:反思作业可以从日志的其余部分推断这些要点,但拥有明确的 ## Retain 部分是最简单的"质量杠杆"。
回忆:对派生索引的查询
回忆应该支持:
- 词汇: "查找精确术语/名称/命令"(FTS5)
- 实体: "告诉我关于 X"(实体页面 + 实体链接的事实)
- 时间: "11 月 27 日左右发生了什么" / "自上周以来"
- 观点: "Peter 更喜欢什么?"(带置信度 + 证据)
返回格式应该是 agent 友好的并引用来源:
- kind(world|experience|opinion|observation)
- timestamp(源日期,或如果存在则提取时间范围)
- entities(["Peter","warelay"])
- content(叙述事实)
- source(memory/2025-11-27.md#L12 等)
反思:生成稳定页面 + 更新信念
反思是一个计划作业(每日或 heartbeat ultrathink),它:
- 从最近的事实更新 bank/entities/*.md(实体摘要)
- 基于强化/矛盾更新 bank/opinions.md 置信度
- 可选地对 memory.md 提出编辑("核心-ish"持久事实)
观点演变(简单、可解释):
-
每个观点都有:
- 陈述
- 置信度 c ∈ [0,1]
- last_updated
- 证据链接(支持 + 矛盾事实 ID)
-
当新事实到达时:
- 通过实体重叠 + 相似性查找候选观点(首先是 FTS,稍后是嵌入)
- 通过小增量更新置信度;大跳跃需要强烈矛盾 + 重复证据
CLI 集成:独立 vs 深度集成
建议:在 OpenClaw 中深度集成,但保留可分离的核心库。
为什么要集成到 OpenClaw?
-
OpenClaw 已经知道:
- 工作区路径(agents.defaults.workspace)
- session 模型 + heartbeat
- 日志记录 + 故障排除模式
-
您希望 agent 本身调用工具:
- openclaw memory recall "…" --k 25 --since 30d
- openclaw memory reflect --since 7d
为什么仍然拆分库?
- 使内存逻辑可测试,无需 gateway/runtime
- 从其他上下文重用(本地脚本、未来的桌面应用等)
形状:内存工具旨在成为一个小型 CLI + 库层,但这仅是探索性的。
"S-Collide" / SuCo:何时使用它(研究)
如果"S-Collide"指的是 SuCo(Subspace Collision):这是一种 ANN 检索方法,通过在子空间中使用学习/结构化碰撞来定位强召回/延迟权衡(论文:arXiv 2411.14754,2024)。
对 ~/.openclaw/workspace 的务实看法:
- 不要从 SuCo 开始
- 从 SQLite FTS + (可选)简单嵌入开始;您将立即获得大部分 UX 胜利
- 仅在以下情况下考虑 SuCo/HNSW/ScaNN 类解决方案:
- 语料库很大(数万/数十万个块)
- 暴力嵌入搜索变得太慢
- 召回质量明显受词汇搜索瓶颈
离线友好的替代方案(复杂性递增):
- SQLite FTS5 + 元数据过滤器(零 ML)
- 嵌入 + 暴力(如果块计数低,效果出奇地好)
- HNSW 索引(常见、稳健;需要库绑定)
- SuCo(研究级;如果有可以嵌入的可靠实现,则很有吸引力)
待解决的问题:
- 在您的机器(笔记本电脑 + 台式机)上,用于"个人助理内存"的最佳离线嵌入模型是什么?
- 如果您已经有 Ollama:使用本地模型嵌入;否则在工具链中提供一个小型嵌入模型
最小可用试点
如果您想要一个最小但仍然有用的版本:
- 在日志中添加 bank/ 实体页面和一个 ## Retain 部分
- 使用 SQLite FTS 进行带引用的回忆(路径 + 行号)
- 仅在召回质量或规模需要时添加嵌入
参考资料
- Letta / MemGPT 概念: "核心内存块" + "档案内存" + 工具驱动的自编辑内存
- Hindsight 技术报告: "保留 / 回忆 / 反思",四网络内存,叙述事实提取,观点置信度演变
- SuCo: arXiv 2411.14754(2024):"子空间碰撞"近似最近邻检索