向量检索有用,但 Windows 本地环境把 normalized 记录、SQLite/FTS5、命名空间和轻量 fallback 做稳更现实。
windows-bot-memory/maintenance-summary
给本地机器人做记忆系统时,很容易一上来就想做向量检索。
向量当然有用。它能处理语义相似、同义表达和模糊提问,比关键词搜索灵活很多。
但维护过一轮本地记忆之后,我更确信一件事:向量检索不能当唯一底座。尤其是在 Windows 本地环境里,依赖安装、镜像源、证书、模型下载都可能出问题。向量失败时,系统也得能查、能重建、能解释。
原始记录不是直接检索层
本地机器人记忆里会有很多来源:
- 云端群聊摘要。
- 本地 Windows 任务记录。
- Codex 工作流记忆。
- 项目索引。
- 每日整理。
- 人工确认过的事实、规则和偏好。
这些材料不能直接混在一个搜索池里。
原始记录适合作为证据,但不适合作为默认检索层。它们格式不统一,噪声多,私密程度不同,也可能包含只适合存档、不适合主动召回的内容。
所以第一步我先把材料变成 normalized 记录,向量库往后排。
normalized 层是可重建的
normalized 层的价值在于:它是一个干净的读模型。
每条记录至少应该知道:
- 来自哪里。
- 属于哪个命名空间。
- 原始证据路径是什么。
- 是否适合召回。
- 是否经过整理。
- 可用于搜索的正文是什么。
这样做之后,SQLite、FTS、向量索引都可以从 normalized 层重建。索引坏了可以删掉重来,规则变了可以重新生成,不会反过来污染原始记录。
这和写博客草稿很像:原始聊天先留作材料,整理后的提纲才适合继续加工。
FTS5 是最稳的第一层
SQLite/FTS5 不性感,但非常适合本地记忆。
它的优点很直接:
- 不需要常驻服务。
- 文件可备份。
- 查询可解释。
- 能返回来源路径和行号。
- 能在低配置机器上跑。
- 失败模式简单。
当我问“某个项目之前怎么处理过”时,FTS 命中结果虽然不一定最聪明,但它能告诉我为什么命中。对于记忆系统来说,这比“看起来语义相关”更重要。
尤其是涉及跨项目记忆时,可解释性就是安全范围。
命名空间比召回更重要
本地记忆最怕的其实是串台。
一个项目里的部署经验,不一定能套到另一个项目。群聊里的事实,不一定适合进入私聊上下文。Codex profile 的配置经验,也不该默认污染某个业务项目。
所以检索前要先按命名空间、项目路径或项目 id 缩小范围,再谈关键词或语义匹配。
这也是为什么记忆维护里要有项目索引和 workspace 范围。召回不是越多越好,召回错了比没召回更糟。
向量失败时要有 fallback
一次维护里,向量依赖因为 SSL 和镜像源问题装不上。这个问题很现实:不是所有机器都能稳定下载模型依赖,也不是所有环境都适合跑重模型。
如果系统把“能不能召回”绑定在一个外部依赖上,那么维护链就会被卡死。
更稳的做法是:
normalized records -> SQLite/FTS5 -> optional vector index -> lightweight fallback向量可用时,它提供语义补充。
向量不可用时,可以退回本地轻量索引,例如字符 n-gram 或哈希特征。它不如 embedding 聪明,但能让系统继续产出候选、继续验证、继续服务。
维护链要能被验证
本地记忆不是写完文件就结束。
每一轮维护至少应该验证:
- normalized 记录数量是否增长合理。
- SQLite/FTS 是否能重建。
- 搜索索引数量是否和记录数量对得上。
- lifecycle 是否能跑完。
- audit 是否没有明显问题。
- 典型查询能找到预期项目材料。
这让记忆系统从“我觉得整理过了”,变成“我能证明它现在可用”。
语义检索放在后面
我现在更喜欢的顺序是:
先整理范围再重建结构化索引再做全文检索再补语义检索最后用典型问题验证这样做没有直接上向量库酷,但它更适合长期运行。
本地记忆系统不是用来展示新技术栈的。下次真的需要它时,能从正确范围里找回证据就够了。
能重建,能解释,向量坏了还能 fallback,本地优先记忆系统才比较稳。
继续读