记一次 AI 记忆系统的彻底重构:SummerMemory v2.0 实战

三个月前我给自己搭了个 AI 记忆系统 SummerMemory——PostgreSQL + pgvector + Ollama 跑中文向量模型,配合 BM25 全文检索,纯本地零成本。当时觉得挺完美:博客写下"混合搜索 60% 向量 + 40% BM25,搜索 78ms"。

然后用着用着,问题来了。

问题:记忆明明有,就是搜不到

最典型的一次:我下午刚和 AI 聊完《美丽的新世界》这本书,晚上搜"美丽的新世界"——搜不到。记忆确实在库里,检索就是不出来。

类似的情况反复发生。我忍了两个月,直到有天晚上下定决心:把三个月的搜索日志、历史踩坑记录、真实查询数据全部翻出来,一次性搞清楚到底哪里坏了。

翻旧账:三个月踩过的 9 个坑

把所有历史问题摆出来之后,发现远比想象的严重:

序号 问题 根因
1 目标文件进不了候选池 召回深度不够
2 BM25 检索 30 个文件同分 归一化后无法区分
3 ts_rank 对同分文件无区分力 PostgreSQL tsvector 固有限制
4 Reranker 截断丢候选 同分随机截断
5 关键信息被截断切掉 分块策略缺陷
6 空标题块和内容分离 分块合并方向错了
7 搜"部署工具"返回"豆包说话风格" 向量模型排序质量差
8 大文件永远霸榜 RRF 同文件累加的天然缺陷
9 短查询被挤出前五 默认返回数太小

归类下来:5 个排序层问题、2 个分块问题、2 个向量引擎问题。

我还统计了 2075 次真实搜索的分布:80% 是 8 字以上的自然语句(比如"怎么部署新工具"),12% 是短词("待办"、"yx"),8% 带日期。这个数据后来直接决定了新架构的设计方向。

最疼的坑:向量模型是个"演员"

逐个排查到第 7 个坑时,我做了组对照实验——用同一批文档测两个向量模型的排序能力:

查询 jina 排第一 bge-m3 排第一
怎么部署新工具 豆包说话风格(错) 部署规范(对)
排插控制关机 豆包说话风格(错) 排插控制文档(对)
数据库连接失败 陪看电影规范(错) PostgreSQL 排查(对)

无关文件的相似度分数反而更高——这个模型跑了三个月的"语义理解"基本是失效的。这就是"记忆里有却搜不到"的最大元凶。

更戏剧的是,查的时候发现这个模型已经从 Ollama 官方库下架了,想重装都装不回来。

重构方案:三层漏斗

问题查清后,新架构的思路自然就出来了:

查询进来
   |
  【缓存】搜过的词直接返回(13ms)
   |
  【第一层】精确直达:文件名/日期直接匹配(<1ms)
   |
  【第二层】BM25 关键词:jieba 分词 + 标题加权(5-25ms)
   |
  【第三层】向量语义:bge-m3 1024 维(约 230ms)
   |
  融合:向量 0.55 + BM25 0.45,同文件只取最高分块

三个关键决策:

短查询不走向量。 "待办"两个字字面匹配又快又准,走向量纯属浪费。4 字以内纯 BM25,13 毫秒返回。

BM25 升为主力。 旧架构里它只是配角,实测才发现它又快又稳。加了标题命中加权后,80% 的查询场景它一个人扛住了。

同文件只取最高分块。 RRF 的坑:一个 99 个分块的大杂烩文件,靠累加分数永远排第一。改成同文件只取最高分的那块参与排名,大小文件公平竞争。

向量引擎换血:bge-m3

替代品选了 bge-m3(北京智源 BAAI 出品,HuggingFace 下载量 3600 万):

  • 1024 维(原来 768 维)
  • Q8 量化版 630MB,纯 CPU 推理 230ms(24 核老至强)
  • 常驻内存 1.25GB
  • 实测排序:4 组对照全对,分差 0.065 到 0.335——拉得开,不含糊

分块重做

两个分块坑一起修:

空标题节原来并到上一块,导致"待办"标题和待办内容分家——改成并到下一块。

每个分块现在自带标题链:

[tool-deploy > 第三步:配置 nginx]
location /工具名/api/ { proxy_pass ... }

向量模型看到的不再是孤立片段,而是"这属于部署文档的 nginx 章节",语义判断准确得多。

实测结果

20 个真实查询的基准测试(含全部历史坑案例):

指标 旧版 新版
第一名命中率 17% 85%
前三命中率 无数据 95%

历史坑全部翻身:"美丽的新世界"从搜不到变成第一名直接命中。

性能:

场景 耗时
缓存命中 13ms
关键词查询 13-25ms
语义查询 约 300ms

300ms 里 230ms 是 bge-m3 在 CPU 上把查询句转向量的物理耗时,无 GPU 服务器的极限。配合 Ollama 的模型常驻参数,冷启动也消灭了。

几点心得

实测数据大于理论架构。 RRF 是业界标准,Elasticsearch 和 Azure 都在用——但在我的数据规模(约 2000 个分块)和大文件分布下就是灾难。别人的最佳实践不一定是你的。

先查真实查询分布再设计。 80% 长语句对 12% 短词的分布,让我敢做"短查询跳过向量"的分流。没有这个数据,我不知道该在哪切。

量化模型要看排序质量,不看参数表。 旧模型参数表漂亮:768 维、8192 上下文、116MB。实际排序是错的。一个简单的相关性对照测试(相关对对比无关对)就能提前暴露,选型时就应该测。

坑要记全。 这次重构的依据,就是三个月攒下的 9 个坑的完整记录。没有这些记录,同一个地方我会摔第二次。

开源

GitHub:https://github.com/Likefr/SummerMemory

在线图谱 Demo:https://ai.likefr.com/graph


v1 诞生于 2026-05-30 | v2.0 重构于 2026-08-26 | Likefr × Summer

最后修改:2026 年 08 月 26 日
如果觉得我的文章对你有用,请随意赞赏