记得,也知道自己记错了

llm-long-term-memory · SQLite + FTS5 · MIT

把对话变成有时间边界的结构化事实:事实变了就让旧的失效,而不是堆在一起;压缩丢掉了细节,就回原始对话里把它捞回来。

下面是一个可点击的演示。人物和对话都是虚构的示例数据,全部内置在这个页面里——它不连接任何服务,也不读取你的任何数据。页面底部是真实基准测试的数字。

演示

A
Alex
虚构人物
四段跨越两年的对话已经写入记忆。挑一个问题,看系统用了什么、跳过了什么、为什么。

回答

用了哪些记忆,为什么

三个设计选择

事实会过期

每条记忆是一行有类型的记录,键是 (主语, 谓语, 宾语),带两条时间轴:事情何时为真,系统何时知道。同一个键出现新值时,旧值的有效期被关闭并标记为 superseded——不是删除,历史仍然可查。

压缩是有损的,所以留着原文

抽取会保住大意、丢掉细节。「助手推荐过一台咖啡机」是真的,却答不了「链接是多少」。原始对话存在同一个数据库里并建了 BM25 索引;只有当回答器明确说「需要原文」时才付第二次检索的代价。

也告诉你它没用什么

检索会同时返回命中的和被排除的,并给出原因:superseded(已经不成立)还是 below_rank(仍然成立,但分数没进前列)。后者才是排序出问题时该盯的那一半。

实测数字

方案(LongMemEval-S,dev50) 准确率 上下文中位 token
整段对话全塞进上下文56.0%109,260
朴素 RAG:对原始会话做向量检索54.0%13,057
只用结构化记忆56.0%1,415
结构化记忆 + 条件回原文72.0%1,455
这张表必须配着两句话读。 dev50 是开发集,提示词和阈值都是照着它的失败案例调的,所以 72.0% 同时也在衡量这些选择对它的拟合程度。真正没参与任何决策的 100 道题上,冻结并哈希后单次跑出 70.0%(其中 50.0% 靠结构化记忆、20.0% 靠原文兜底,上下文中位 1,468 token),另外两次重复是 71 和 73。而基线从未在那 100 道题上跑过——所以「结构化记忆追平朴素 RAG」这句话目前只有 dev50 的证据。