持久化 AI 记忆究竟是怎么工作的
「AI 记得我」这句话承担了太多含义。模型里什么都没变。变的是它前面那个东西,变得很会取东西了。
模型的权重是冻结的。跟它说话不会教会它任何东西,关掉标签页也不会让它遗忘——那份记忆从来就没有可去之处。你体验到的「助手记得我」,是一套朴素得多的安排:文本被保存在某个地方,而在模型作答之前,一个程序去把相关的片段找出来,贴了进去。
全部诀窍就在这里。但一份 AI 记忆的质量,几乎完全等于取这一步的质量,而这正是这个品类里各家产品差异巨大、自我描述却如出一辙的地方。
上下文窗口不是记忆
这两者一直被混淆,所以说清楚:上下文窗口是模型的工作台。是它此刻、这一轮能够考虑的全部内容。在当前的模型里它很大,而且在两次对话之间会被完全抹掉。
记忆是一个比对话活得更久的存储。两者的关系是:记忆*喂*给窗口——有选择地。
而且它必须有选择,因为天真的做法在成本和准确度上都会失败。如果你有一年的笔记,每一轮都全部倒进去,你会为这些 token 在每一条消息上付费,而模型会表现更差而不是更好:埋在一百页无关细节里的相关细节会被稀释。检索之所以存在,是因为选得好的少,胜过多。
存储:看起来无足轻重、其实不然的那部分
写入时会做出两个决定,而两个都会在日后纠缠你。
保留什么。 保存完整对话记录很便宜,也几乎无用——你最后是在自己亲手堆起来的草垛里找针。保存提炼过的事实要好检索得多,但需要对「什么是要紧的」作出判断,而任何自动抽取都难免有时丢掉你在意的那一条。大多数产品落在这条轴线的某处,而它们落在哪里,比任何功能清单都更能预测半年之后用起来是什么感觉。
怎么切分。 文本以块(chunk)的形式进入,而块就是被检索的单位。切得太大,一次命中会连带拖进三个不相干的主题。切得太小,句子回来时失去了让它有意义的上下文。没有正确答案,只有调出来的答案。
查找:嵌入,以及它们的盲区
第二个模型——一个嵌入模型,不是你在跟它聊天的那个——把每个块变成一个由几百到几千个数字组成的向量。意思相近的文本会落在彼此附近。你的问题接受同样的处理,于是搜索变成了几何:返回最近的那些块。
彻底遍历地做会很慢,所以真实系统用近似索引——HNSW 是最常见的一种,一个可导航的图,不必访问每一个点就能到达一个不错的答案。它用少许召回率换取数量级的速度,而在 pgvector 里它就是一行索引。
下面是推销时没人提的盲区。语义搜索*只是*语义的。去找一个确切的发票号、一个姓氏、一个库的版本号、一个变量名——那些你知道精确字符串的情况——向量相似度会很乐意给你五个*关于*那个主题的东西,而不是含有那个字符串的那一个。
这就是为什么关键词索引,BM25 或者数据库全文搜索,并不是被向量取代掉的老办法。它是向量不擅长的那一半。
混合搜索与重排序
一条认真的检索流水线会把两种搜索都跑一遍再合并。标准的合并方法是倒数排名融合:每个结果按它在各个列表中的*排名*来打分,而不是按原始分数,这样就绕开了「余弦距离和 BM25 分数不在同一量纲上、不能相加」这个事实。
接下来是那个贡献了大部分可见质量、却被许多产品跳过的步骤,跳过的原因是它耗算力。融合大概给你三十个候选。一个交叉编码器重排序器把问题和每个候选*一起*读进去,给出这一个回答那一个的程度。它比比较两个各自独立生成的向量准确得多,也慢得多——慢到不可能跑遍整个存储——这正是它放在最后、只作用于短名单的原因。
如果你用不止一种语言工作,有一个提醒。这两个阶段都依赖模型,而不少嵌入和重排序模型是英语优先的。一条在英语上得分很好的流水线,可能在法语或德语上悄悄退化,而你体验到的会是「它忘了」,而不是「重排序器是在错误的分布上训练的」。如果你不是在用英语工作,请核实这些模型是不是真的多语言——multilingual-e5 就是这样的一个系列。
当我们把自己的流水线从单纯的向量搜索换成混合融合加一个多语言交叉编码器时,我们评测集上的平均倒数排名提升了 139%。请把这个数字当作它本来的样子:我们的测量,在我们的数据上,用我们的切分方式。它说明这一步值得做;它不是一个你可以指望在另一个语料上复现的数字。
它失败的四种方式
- 它从来没被存下来。 遥遥领先的最常见失败。检索链路里没有任何东西能找回一条从未被写下的事实,而自动抽取会漏。
- 没有阈值。 如果系统总是返回它的前五条,那么当根本不存在相关内容时,它返回的就是五条不相关的东西——而模型出于配合,会把它们编织进去。一个在无结果时就返回空的相似度下限是一项功能,它的缺席正是某些助手信心十足地记错的原因。
- 过期的矛盾。 你搬了城市;旧的事实和新的事实都在存储里,都能被检索到。没有时效加权或显式的取代机制,模型可能挑中任意一个。
- 大海捞针问题。 精确标识符,在纯向量系统里。见上文。
该向记忆产品问什么
五个问题,每一个都有一个事实性的答案,厂商要么给你,要么回避:
- 除了向量之外还有关键词搜索吗,还是只有向量?
- 有没有重排序阶段,用的是什么模型?
- 有没有一个低于它就什么都不返回的相关性阈值?
- 嵌入和重排序模型是多语言的吗,在我的语言上评测过吗?
- 我能查看、编辑和删除单条记忆吗——还是这个存储对我是不透明的?
最后一个和检索质量无关,但它会是你最先在意的那个——在第一次有错误的东西被记到你头上的时候。
Pryzm 跑的是混合融合加多语言交叉编码器重排序器和一个相关性阈值,建在 PostgreSQL 上并使用 HNSW 索引,而且每一条记忆都可以单独查看和删除。替代方案的对比在我们的逐项对照里。