shoal 长期记忆层

个人项目 · 独立开发

shoal
一套给 AI 对话产品用的长期记忆层

01这是什么

一套让 AI 助手在跨会话之后仍然接得上的记忆系统。

它要解决的不是存储,是取用:在有限的上下文预算里,每次对话开始时应该放进去什么。

02为什么做

现有方案还有一个共性问题:普遍把记忆压缩成事实摘要,事实留住了,语气和现场丢了。而在对话产品里,用户判断“它还记不记得我”,依据往往是语气而非事实的准确度。shoal 把这一条作为设计的第一原则。

03怎么拆的

写入 对话中选中的 短原文片段 原文层 唯一事实源 写入后不改写 自动 索引层 便签 · 关键词 · 向量 可重建,不能取代原文 取用 当前视图 少量原文 + 便签 每次对话开始时注入 直接读到,无需调用 需要更早的内容时: 检索层 关键词 + 向量 RRF 融合 候选卡片 ID · 时间 · 摘要 · 便签 不含原文 选一条 完整原文 read 展开 回到当时的现场
四层结构与两条取用路径:常驻视图直接注入,更早的内容按需两步取回

四条原则:

  1. 原文是唯一事实源。写入后不允许任何中间模型改写、合并成摘要或“优化措辞”。便签、关键词、向量都只是索引,可以重建,不能取代原文。
  2. 合并只合并归属,不合并原文。同一件事的多个片段可以归为一组,每段原文仍保持独立完整。
  3. 自动化处理日常,人只处理例外。索引、归组、摘要全部自动;用户只处理冲突、连续失败和删除确认。
  4. 当前视图是视图,不是数据库。它由完整记忆库生成,可随时重建,删掉重算即可。

04几个关键取舍

取舍一 搜索只返候选,读取才展开全文

常见做法是搜索直接返回文本片段,命中率高但极费上下文。shoal 里设计为两步:搜索只返回 ID、时间、一句摘要和最新便签四个字段,模型看完候选卡片后再决定读哪一条。代价是多一次调用,换来搜索环节的上下文占用下降一个数量级。

取舍二 宁可工具数量多,也不塞万能参数

对外提供 21 个工具,每个只做一件事。另一种做法是合并成少数几个带 action 参数的入口,工具列表更干净。shoal 里选择了前者:对调用方而言单义工具歧义更低、误调用更少,代价是工具列表更长。

取舍三 第一版明确不做九件事

包括自动读取每一轮完整对话、多人格隔离、查询改写模型、完整遗忘曲线、自动删除旧记忆等,逐条写进文档。范围不控住,个人项目会烂尾,因此“不做什么”与“要做什么”同等重要。

取舍四 一批参数不在设计阶段定死

候选阈值、token 预算、批处理触发时机、各区占比这些,文档里单列一节,标为需通过少量真实数据测试后调整,不能凭感觉写死。设计阶段能确定的是架构,确定不了这些数值。

05现在什么状态

已上线并在每天真实使用中。

网页端 memory 列表界面示意
网页端 memory 列表(界面示意,示例数据):列表只呈现 ID、状态、时间与一句摘要,原文需进入详情页才展开

06已知的欠债

设计文档定稿于 V4.2.3,写的是 21 个工具;后续按另一条需求线扩展到了 35 个(媒体库、日记、日历投影等),实现已完成,但没有回写文档,两份稿目前未合并。

这是已知问题,也是下一步要处理的。项目说明里如果只列做成的部分,它就成了宣传材料。