AI 为什么记不住事:从自带 memory 到 HexaMind 六层记忆的完整实践

跟 AI 打交道久了,你迟早会碰到一件让人有点泄气的事:它记不住。

昨天你跟它一起把一个 bug 查了两个小时,讲清楚了来龙去脉;今天开一个新对话,它一脸茫然,好像那两个小时从没发生过。你告诉过它三遍你喜欢的代码风格,第四次它还是给你写成另一个样子。这不是它笨,是它天生就没有记忆这个东西。

这篇文章想把这件事从头讲清楚:AI 的记忆到底是什么、为什么它默认记不住、能怎么补救,以及我给自己的 AI 助手(跑在 venxine.vip 上的 Hermes Agent)搭的那套叫 HexaMind 的六层记忆系统,是怎么一步步长成现在这样的。

这是记忆系列的第四篇,也是我特意写得最完整、最适合当第一篇读的一篇。前三篇分别讲分层设计六层架构的进化照着能复现的搭建攻略,都偏技术。这篇不一样,我尽量从零讲起,不用你懂向量数据库也能看明白。


一、先搞懂:AI 的记忆到底是什么

要理解 AI 为什么记不住,得先知道它是怎么"想"的。

大语言模型(就是 ChatGPT、Claude、DeepSeek 这类东西)本质上是个函数:你给它一段文字,它算出下一段文字。它没有硬盘,没有笔记本,算完这一句,脑子就清空了。它唯一能"看到"的,是你这次连同历史一起发给它的那一整段文字,这段东西有个名字,叫上下文窗口。

打个比方。想象一个记性完全归零的接线员,每通电话开始时他什么都不记得。你打进去,得先把之前聊到哪了、你是谁、要办什么,全部重新说一遍,他才能接着办。挂了电话,他又忘光。AI 默认就是这个接线员。

所谓给 AI 加"记忆",做的事情其实很朴素:找个地方把该记的东西存下来,下次对话开始时,想办法塞回那段上下文里,让接线员"看起来"记得。区别只在于,你是把一整本流水账每次都塞给他(简单粗暴,但很快就塞不下了),还是给他配个能查的档案柜,用到哪查到哪(复杂一点,但能装得多、翻得快)。

Hermes 自带的 memory 是前者。HexaMind 是后者。下面一个一个说。


二、Hermes 自带的 memory:够用,但有天花板

它是什么

Hermes Agent 自带一套记忆功能,落地非常简单:两个 markdown 文本文件。

  • MEMORY.md:存我这个助手自己的笔记,比如项目的环境、部署命令、踩过的坑。
  • USER.md:存关于我这个用户的事,比如我是谁、我的偏好、我做事的习惯。

这两个文件放在 ~/.hermes/memories/ 下。每次开新对话,系统会把它们的内容原封不动塞进上下文的最前面。所以助手一上来就"看得见"这些内容,不需要去查,天然就知道。

怎么用

用起来也直白。当我说出一个偏好、纠正一个做法、或者交代一个稳定的事实,助手就把它写进去。写的时候有个讲究:要写成陈述句式的事实,别写成命令。

举两个例子,一个好一个坏:

写法 例子 好不好
陈述事实 "用户偏好简洁的回复,不要铺垫"
写成命令 "永远简洁地回复用户" 不好
陈述事实 "项目用 pytest 加 xdist 跑测试"
写成命令 "用 pytest -n 4 跑测试" 不好

为什么?因为命令句会在以后每一轮被当成一条指令重新读一遍,很容易在你这次明明想干别的时候,把它当成硬性要求执行,反而添乱。事实句就没这个问题,它只是背景知识。这是我用下来体会最深的一条。

效果如何

真话是:好用,而且有一个 HexaMind 给不了的好处,就是永远在线、零延迟。它每轮都在上下文里,助手不用"决定去查"就知道。最高频、必须常驻的偏好放这儿最合适。

但它也就到此为止了。用久了会撞到两堵墙。

第一堵是容量。两个文件各有一个字符上限,塞满了就得删旧的腾新的。第二堵更隐蔽:这两个文件每一轮对话都要原样塞进上下文。记得越多,每一轮就越贵、越占地方。一个几十轮的长对话,同一段内容会被重复塞几十遍。

重点说说:字符上限,我是怎么一步步调大的

这一节值得单独讲,因为它是我这套记忆系统演进的起点,也最能说明"够用但有天花板"是什么意思。

Hermes 的这个字符上限是可以配的(在 config.yaml 里),出厂默认值很小。我不是一步到位调到现在的,而是撞一次墙、往上抬一档,前后经历了好几个版本。翻我自己的配置备份,真实的时间线是这样的:

时间 MEMORY.md 上限 USER.md 上限 触发原因
出厂默认 2,200 1,375 Hermes 的原始设定
5 月及以前 2,200 1,375 一直没动,够用
6 月 2 日 3,000 3,000 第一次塞满,往上抬一档
6 月 10 日 5,000 5,000 又满了,再抬
6 月下旬 9,999 一度以为 9999 是硬顶
7 月 3 日至今 15,000 15,000 确认可以随便配,直接给到 15000

有意思的是中间那个 9999。我当时改到 9999,是因为下意识觉得"四位数应该到头了",还真以为撞到了系统硬上限。后来才搞明白,这个数纯粹是个配置项,想写多大写多大,跟硬件、跟模型都没关系。搞清楚这点之后,我直接抬到了 15000。

(顺便一个坑:这个值只能用 hermes config set 命令改,不能手动去编辑 config.yaml,那样会被拦。这种"以为是硬限制、其实是可配项"的错误认知,我后来专门记进了记忆库,免得下次又凭印象瞎断言。)

但抬到 15000 就够了吗?没有。两个文件加起来 3 万字符封顶,听着不少,可我知识越攒越多,很快又逼近上限。而且别忘了那个隐性成本:这 3 万字符每一轮都要重塞一遍。抬上限只是把墙往后挪了挪,墙还在那儿。

真正的解法不是把这堵墙推得更远,而是换个思路:让常驻的东西尽量少,把大部分知识挪到一个能查的深库里,用到再捞。这就是 HexaMind 的出发点。


三、对五层系统的尝试

自带 memory 撞了墙之后,我做的第一版并不是现在这个六层,而是一套五层的记忆系统。这一节先讲这次尝试:五层是什么、怎么用、有什么用。

先回到那个接线员的比方。自带 memory 相当于给接线员塞一叠便签,他每次上班前必须全文背一遍,便签越多背得越久、越容易背串。我想干的是另一件事:给他配一个档案柜,平时便签只留最常用的几张,其余全部归档进柜子,需要的时候伸手精确抽出相关的那几份。

档案柜要好用,得满足几个条件:能装很多(不受那 3 万字符限制)、能按关键词查、还能按意思查(换个说法也能翻到)。我第一版就照着这几个条件搭了五层,每一层管一件事:

五层(第一版) 管什么 落地成什么
结构化存储 精确记住事实、偏好、配置 一个 SQLite 数据库,带全文关键词索引
向量编码 把每条事实翻译成一串数字 调编码模型,一条事实算出 1536 个数
语义检索 换个说法也能翻到 拿上面的向量算相似度
自我进化 把踩过的坑记下来别重犯 单独存"教训"
知识图谱 记住谁和谁有关系 存实体和它们之间的连线

(另外还有一个按天写的操作日志,和一个当时还没成气候的小角色叫"主动性",先按下不表,后面它很关键。)

用起来是什么感觉?举个我天天在做的动作。当我交代一件该记住的事,就往结构化存储里写一条,比如"部署要先 touch 模板再 restart"。写完它先能按关键词查到。等向量补上之后,我哪天换个说法问"网站怎么上线",语义检索照样能把这条捞出来,哪怕两句话没一个共同的字。

效果最直观的一次,是我给网站做一轮优化的时候。搜"nginx 配置",它直接召回了我之前存的"配置里有 26 个重复块";搜"gunicorn worker",它把"gthread 在低内存机器会 OOM"这条教训翻了出来,让我没有再踩一遍。这就是五层的价值:它不让 AI 变得多聪明,只是让它不必每次都从头再来。想看五层每一层的技术细节,我单独写过一篇


四、从五层到六层:HexaMind 的完整搭建

五层用了一阵子,短板慢慢冒出来。我在它的基础上重构出了六层,也就是现在的 HexaMind。这一节讲两件事:为什么要从五层换成六层,以及六层最终完整长成了什么样。

4.1 为什么要从五层换成六层

短板出在哪?五层有个共同的毛病:它们全是被动的。

你不问,它们就不动。它们安静地待在库里,等你开口提问,然后才去检索、召回、补全。这没错,但总差一口气。就像那个档案柜配了个很尽职的管理员,你来要什么他都能精准找到,可他从不会在你进门前就把今天可能用到的卷宗先抽出来摆在桌上。

于是我把之前那个不起眼的"主动性"小角色正式扶成了独立的第六层。它不等你开口,而是先读前面几层的内容,在你开口之前就把可能要用的东西备好。举两个真实的例子:

  • 我一打开终端,它自动把当前的持仓快照、上次没做完的任务推到我面前,不用我问"上次做到哪了"。
  • 我一提"部署",它已经把当前模板的状态、上次部署的时间、那几个已知的坑一起加载好了,不用我一条条去查。

顺带,我也趁这次重构把语义检索的引擎换成了更抗造的 LanceDB(生产级的向量索引,扛得住更大规模),并且把"编码"和"检索"拆成两层看得更清楚。所以五层到六层,变的不只是多了一层,而是三件事叠在一起:

维度 五层 六层
工作方式 被动:你问才动 多了主动:开口前先备好
层数由来 五个"记住/找回"的职责 把"主动性"从小角色扶正成第六层
检索引擎 基础向量存储 换成 LanceDB 生产级索引
一句话 管"记住什么" 多管一件"提前做什么"

这段进化的技术细节,包括六条层间协作铁律,我写在了专门讲 L5 到 L6 的那篇里。

4.2 HexaMind 六层记忆系统搭建

先说名字。这套系统我叫它 HexaMind。Hexa 是希腊语里的"六",六边形叫 hexagon、六足动物叫 hexapod,都是这个词根。HexaMind 直译就是"六层的记忆",名字本身就是它的架构。

再看它长什么样。从最底层的存储,到最顶层的行动,六层从下往上是这样:

┌─────────────────────────────────────────────┐
│  L6  主动性    预判需求、提前把东西备好          │
├─────────────────────────────────────────────┤
│  L5  知识图谱   实体和它们的关系                 │
├─────────────────────────────────────────────┤
│  L4  自我进化   从纠正里学,不重复踩坑            │
├─────────────────────────────────────────────┤
│  L3  语义检索   换个说法也能查到(向量搜索)       │
├─────────────────────────────────────────────┤
│  L2  向量编码   把文字翻译成向量                 │
├─────────────────────────────────────────────┤
│  L1  结构化存储  精确事实、偏好、配置(数据库)     │
└─────────────────────────────────────────────┘

配一张更接地气的对照表:

一句话职责 举个例子
L1 结构化存储 精确记住事实 "用户持有 7 只 A 股基金"、"部署要先 touch 模板再 restart"
L2 向量编码 把文字变成能算相似度的数字 把上面那句话编码成 1536 个数字
L3 语义检索 换个说法也能翻到 搜"网站怎么上线",命中那条讲部署的事实
L4 自我进化 记住教训别重犯 "gthread 在低内存机器会 OOM,改用 sync workers"
L5 知识图谱 记住谁和谁有关 "黄金基金 → 避险资产 → 与 QDII 负相关"
L6 主动性 开口前先备好 打开终端,自动推来持仓快照和未完成任务

有一点必须说清楚,不然容易误会:L1 到 L5 不是六个各自为政的库。事实只存一份,在 L1;L2 给它算向量,L3 拿向量做模糊搜索,L4 和 L5 挂在同一个数据库里。它们是一套东西的六个侧面,不是六个东西。这也是它区别于"把记忆散在一堆文件里"的关键。

最后说怎么用。平时我不用手动指挥这六层,它们按两条固定流程自己跑。

查东西的时候:先用 L1 做精确关键词匹配,命中就直接返回;没命中,走 L3 的语义搜索按意思召回;再用 L5 补上关联的实体,用 L4 检查有没有相关的"已知陷阱"要提醒;最后 L6 综合前面所有信息,判断下一步该干什么。

存东西的时候按类型分流:精确事实进 L1(然后自动走 L2 编码、写进 L3);我的纠正进 L4,同时更新 L1 里的旧事实;涉及实体关系的进 L5;行为模式进 L6。一条信息可以同时触发好几层。比如我纠正了一个部署命令,会一次性触发 L1(改事实)、L4(记下这次纠正)、L6(下次一提部署就自动用新命令)。

这里有个我踩过的坑值得单独提:往 L1 写一条事实,它默认只建关键词索引,不会自动算向量。也就是说,你以为写进去就能语义搜到了,其实 L1 到 L3 这条管线是断的,新事实语义搜不到。得手动跑一遍回填脚本补上向量,再重建 L3 索引。这个坑后来靠一个每天自动跑的任务兜底,下面第六节会讲。


五、HexaMind 对比自带 memory:拿数字说话

光说不练没意思,上真实对比。都是我这套系统当前(7 月 7 日)的实测数字。

维度 自带 memory HexaMind
容量 两文件各 15,000,共 3 万字符封顶 光 L1 事实正文就 31,205 字符,无上限,底库 7.0 MB
每轮成本 当前塞了 15,512 字符,每一轮都重塞进上下文 按需检索,一次拿几条,多数轮次是 0
检索方式 靠模型在一大段扁平文本里自己翻 关键词精确匹配 + 向量语义搜索,换词也能命中
结构 一堆用分隔符隔开的纯文本 事实 / 教训 / 实体,带标签、可信度、软删除、126 条实体关系
满了怎么办 删旧的腾地方 不用删,继续长

先看容量这一行。自带 memory 满打满算 3 万字符封顶,而我 HexaMind 里光事实正文就有 31,205 字符,已经超过了自带 memory 的物理上限。换句话说,这些知识就算我想全塞进自带 memory 也塞不下了。这还没算教训、实体关系这些。

再看每轮成本。自带 memory 现在塞了 15,512 字符,这个数字每一轮对话都要原样重发一次。一个 40 轮的会话,等于把这一万五千多字符重复发了 40 遍。HexaMind 不一样,它只在助手真的去搜的时候才注入,而且只注入搜到的那几条,通常几百字符,很多轮次一个字都不注入。

向量搜索为什么能"读懂意思"

你可能好奇,L2 把一句话变成 1536 个数字,L3 拿这串数字就能"按意思"搜,这中间到底发生了什么。用大白话讲一遍,不涉及公式。

想象一个巨大的空间,里面每一句话都是一个点。这个空间的坐标轴不是东南西北,而是"意思"的各个方向。意思相近的两句话,坐标就挨得近;意思差得远的,隔得远。"网站加速"和"CDN 优化"字面上一个字都不沾,但它们在这个空间里几乎贴在一起;"网站加速"和"今天午饭吃什么"就隔了十万八千里。

把一句话变成坐标的过程,就是 L2 干的"编码",那 1536 个数字就是它在这个空间里的坐标。搜索的时候,L3 把你的问题也编码成一个坐标,再找空间里离它最近的那几个点。所谓"相似度 0.484",就是在量两个点有多近,越接近 1 越贴。

这就是它比关键词搜索强的地方。关键词搜索比的是"字面上有没有重合的词",向量搜索比的是"意思上像不像"。你换个说法、用个近义词、甚至跨了中英文,只要意思接近,它照样能找到。代价是得先花一点算力把每句话都编码成坐标,这就是 L2 存在的理由。

一个语义检索能做、关键词做不到的实例

这是 HexaMind 最能打的地方,举个真实的查询。我在库里搜"网站上线部署的正确流程",返回的第一条是:

部署命令:touch 模板文件 && restart。Flask 模板缓存必须 touch+restart 双重操作。(相似度 0.484)

注意:查询里说的是"上线部署",命中的事实里一个字都没提"上线",讲的是"touch 模板"和"重启"。两句话没有一个共同的关键词,纯靠关键词匹配根本搜不到。是向量语义搜索按"意思相近"把它捞了出来。这就是 L2 加 L3 存在的意义。

再来一个。搜"怎么让图表颜色好看不刺眼",命中的是我之前存的一条 ECharts 配色规范(相似度 0.523),里面讲的是"暖橙到玫红 7 色"这种具体色板。查询用的是大白话,事实用的是专业术语,照样对得上。


六、我现在怎么用这套记忆,以及怎么让它自动维护

搭好了不等于用好了。这一节讲我实际的用法,重点是自动化。

分工:一个当热缓存,一个当深库

我不是二选一,是让两套东西各干各的:

  • 自带 memory 当热缓存。只放最高频、必须每轮常驻的东西:我的核心偏好、正在做的项目的关键约定。追求的是零延迟、永远在线。
  • HexaMind 当深库。放长尾知识:那些不常用、但用到的时候必须准确的事实、教训、关系。追求的是装得多、查得准。

这么分工之后,自带 memory 自然就轻了,因为该下沉的都下沉了。深库越充实,热缓存反而越不需要撑满。

关键:让记忆自己维护自己

手动维护记忆是件很容易半途而废的事。今天记得写,明天忙起来就忘了。所以我给它挂了两个每天凌晨自动跑的任务,一个负责"提炼",一个负责"上线和体检",职责分得很清楚:

凌晨 2:30,每日记忆整理。这是个由 AI 驱动的任务。它读取过去一天里我和助手的新对话(用一条"水位线"记录上次读到哪,只读新的、且排除掉各种自动任务产生的噪声),从里面提炼出真正耐用的知识,写进 L1。这一步有条铁律叫"宁缺毋滥":每次最多写三五条事实、两条教训,大多数平淡无奇的日子就写"无新增"。宁可漏记,也绝不让记忆膨胀成流水账,重大的事我会自己手动补。

凌晨 3:30,全层体检。这是个纯脚本任务,不动脑子只干活,按顺序做五件事:给 2:30 新写的事实补算向量(L2)、重建语义索引(L3)、核对 L1 和 L3 的条数是否一致、把新实体在图谱里连上边(L5)、清理重复的教训(L4)。全部正常就往我微信推一条简报告诉我今天记忆涨了几条,出问题就告警。平时它就是个哨兵,只在异常时出声。

这两个任务前后不重叠:2:30 只管"读对话、提炼、写库",不碰向量;3:30 只管"把新东西向量化上线、做卫生",不读对话。这么切开,是为了避免两个任务抢着重建索引。

记忆不是越多越好

搭记忆系统的人容易有个误区:以为记得越多越好,恨不得把每句话都存下来。我踩过这个坑,结论正相反,记忆膨胀是有害的。

原因不难理解。语义检索是按"意思相近"召回的,库里噪声越多,一次查询就越容易捞上来一堆似是而非、其实没用的东西,把真正相关的那几条挤下去。记忆多了不是更聪明,是更容易分心。所以我给凌晨那个提炼任务定了条铁律:宁缺毋滥,每次最多写三五条,大多数平淡的日子写"无新增"。

什么该记、什么坚决不记,我有一条很简单的判断标准:这事一周之后还成立吗?

  • 该记的:我的偏好和纠正(最高优先级)、稳定的架构和配置、能复用的教训、长期存在的实体。这些放一个月、半年还管用。
  • 坚决不记的:某个变量叫什么名、某次排查的具体过程、"今天修好了 X"这种流水账、一周就过期的临时状态。这些记下来只会变成噪声。

还有一种情况,是记过的东西过时了,比如我把生产服务器从一台换成了另一台。这时不是把旧记录硬删掉,而是标记成"已被取代",让新事实顶上。旧的留着可查,但检索时不再返回。既不丢历史,又不会拿过时信息误导自己。

写入管线:一条事实的完整旅程

如果是我在会话里手动存一条重要事实,完整的动作是这样的(也是那两个 cron 在自动做的事):

1. remember("事实内容", tags=[...])   → 写进 L1,建关键词索引
2. embed_missing.py                     给它补算向量L2),调一次编码模型
3. build_l3_index.py                    复用刚才的向量重建 L3这步不花钱
4. l3_diag.py                           体检六层是否通畅条数是否对齐

第 2 步是唯一要联网、要花点钱的地方,但一条事实只编码一次,之后一直复用,成本基本可以忽略。第 3 步复用已有的向量,一分钱不花。有了 3:30 的自动体检兜底,我平时手动存完 L1 就行,向量化交给凌晨的任务。

几乎全本地,成本几乎为零

有两个很多人关心的问题:这套东西贵不贵、数据安不安全。答案都挺让人放心。

先说成本。整套系统里唯一要花钱的,是 L2 把文字编码成向量那一步,走的是一个按量计费的编码模型。但一条事实只编码一次,之后一直复用,重建 L3 索引是拿现成的向量,一分钱不花。我把当前全部两百多条事实从头编码一遍,加起来也就几分之一美分的量级,日常那点增量更是可以忽略。

再说数据。除了编码那一步要把文字发给模型,其余全在本机:事实存在本地的一个 SQLite 文件里,向量索引也在本地。没有云端账号,没有第三方托管,整个记忆库就是我服务器上的两个文件,随时能打开看、能备份、能整个搬走。对不想把私人信息交出去的人来说,这点很重要。

一条事实的一生

把前面这些机制串起来,看一条记忆从生到用的完整旅程,可能更直观。

假设某天我发现一个部署命令用错了,纠正了它。这一下同时惊动好几层:L4 把"原来那样做会出事"记成一条教训,L1 把旧事实改成正确的命令,L6 顺手更新了预判规则。当天夜里 2:30,提炼任务扫过这段对话,确认这是条该长期留的知识,正式写进 L1。3:30,体检任务给这条新事实补算向量、推进 L3 索引,往我微信发一条"今天记忆 +1"的简报。

一周后,我早忘了当时的细节,换了个完全不同的说法问"网站怎么发布上线"。L1 的关键词没匹配上,L3 的语义搜索接手,把那条部署事实按"意思相近"捞了出来;同时 L4 查到相关教训,主动提醒我"上次那样做翻过车"。我不用重讲一遍,它自己就把该知道的都摆到了台面上。

这条事实从我随口一句纠正,到一周后主动回到我面前,中间没有任何一步需要我记着去做。这才是这套系统真正想要的东西。


七、HexaMind 现在长什么样:最新状态与量化收益

当前体检报告

跑一遍全层诊断,这是 7 月 7 日的真实输出,未经修饰:

L1 FTS5 关键词检索  : OK
L2 向量覆盖率        : 212/212  全覆盖
L3 向量 + 条数对齐   : L3=212  L1已编码=212   OK
L3 向量空间自检      : 余弦 1.0000  同空间无漂移
L4 教训             : 41 条
L5 知识图谱          : 17 个实体,17/17 全连边,126 条边
标签卫生            : 0 条非法,OK

结论:全部通畅

翻译成人话:

现状 说明
L1 结构化 212 条事实 从 6 月中旬的一百多条长到现在
L2 向量 212 / 212 全覆盖 每条事实都有向量,没有漏网
L3 语义 212 条向量,完全对齐 自检余弦 1.0000,证明查询和存储用的是同一个向量空间
L4 自我进化 41 条教训 41 个踩过一次、以后自动规避的坑
L5 知识图谱 17 实体 / 126 边 无孤立节点
底库大小 7.0 MB 一个 SQLite 文件

那条"余弦 1.0000"值得多说一句。它是把一条事实自己的内容重新编码,再和它存着的向量算相似度,结果应该是 1.0(完全相同)。这个测试能证明查询端和存储端用的是同一个编码模型;如果不是,语义搜索会失真。1.0000 说明这条管线是干净的。

记忆里都记了些什么

212 条事实、41 条教训听起来还是抽象,看看它们都贴了什么标签就具体了。库里每条记忆都带标签,按出现次数排下来,前几名是这样:

标签 条数 大致是什么
config 83 配置、参数、开关怎么设
venxine 74 跟我本人、我的项目相关
fund-web 58 那个基金网站的方方面面
website 43 网站通用的事
preference 30 我的偏好
critical 28 标了"关键"、不能忘的
fund 23 基金业务逻辑
ui 21 界面、排版

(一条记忆可以贴多个标签,所以数字加起来超过总条数;另外还有一批按日期打的标签没列进来。)

从这份分布能看出这套记忆的"性格":它高度围绕我实际在做的事长出来,config 和 fund-web 占大头,因为我大部分时间在折腾那个基金网站;preference 和 critical 这类标签则保证我的习惯和红线不会被忘掉。它不是一个什么都懂的通用知识库,而是一份"关于我和我的活儿"的私人档案。这也是记忆系统和搜索引擎的根本区别:搜索引擎什么都知道,记忆系统只知道跟你有关的。

坏了会怎样:一层挂了,不瘫全身

一套天天在用的系统,得考虑某个环节出问题时会怎样。HexaMind 的设计是坏一块、不瘫全身。

最可能出问题的是编码那一步,因为它要联网。万一编码接口临时不可达,语义检索会自动退回到关键词搜索。也就是说 L3 用不了的时候,L1 的关键词匹配还在,我照样查得到东西,只是暂时搜不了"换个说法"的那部分。系统不会因为一个环节掉线就整个罢工。

另一个隐患更隐蔽:查询和存储万一用了不同的编码模型,向量对不上,搜出来的结果会悄悄失真,还不报错。所以每天的体检里专门有一项防这个,就是前面那份报告里的"余弦 1.0000"。它比"能返回结果"更能说明这条管线是真的健康,而不是看起来在工作、实际在乱搜。

知识图谱,看得见的记忆

L5 的知识图谱不只是个数字,我给它做了个能实时渲染的可视化页面。下面这张就是当前的真实状态:

HexaMind L5 知识图谱:17 个实体、126 条边、105 个事实点,按实体类型配色

图里每个彩色的大点是一个实体,点越大表示挂在它下面的事实越多;灰色小点是一条条具体的事实;连线表示"这条事实跟这个实体有关"。几个最大的枢纽一眼能看出来:

  • fund-web(橙色,项目)挂了 35 条事实,是整张图最大的中心,因为我大部分工作都围着这个基金网站转。
  • Venxine(粉色,就是我本人)挂了 31 条,全是关于我的偏好、习惯、工作方式。
  • Hermes Agent(蓝色,工具)挂了 17 条。
  • 还有 daily-pl.json(数据文件,13 条)、CORE-V2(版本,5 条)、HexaMind 自己(4 条)。

有意思的是,其中 18 条事实同时挂在多个实体下面,它们就是把不同实体间接连起来的"桥"。整张图是"实体到事实"的二部结构,不是实体直连实体。

这个页面是实时读取记忆库渲染的,每次刷新都是最新状态。它本身也在 venxine.vip 上(/memory/graph)。等哪天凌晨的自动整理又写进新东西,这张图会自己长大。

量化收益:省了多少 token,少走了多少弯路

这是最难量化、但也最该说清楚的一节。我尽量只用能站住脚的数字。

先说省 token。最硬的一个事实:自带 memory 现在每轮无条件注入 15,512 字符,而 HexaMind 里的知识(光事实就 31,205 字符)如果也想常驻,根本塞不进那 3 万字符的上限。所以严格说,HexaMind 不是帮我"省"了 token,是让我能持有一份自带 memory 物理上装不下的知识量,同时还不用为它每轮付费。

举个能算的账。假设我把这 31,205 字符的事实硬塞进每轮注入,一个 40 轮的对话,就是 31,205 × 40 ≈ 125 万字符被反复重读。折算成 token 大概是七八十万(中英文混合,粗略按 1.5 到 2 字符一个 token 估)。而 HexaMind 的做法是:只在语义相关时注入那么几条,一次几百字符,多数轮次为 0。同样一个 40 轮对话,注入量通常是几千字符量级,差着两三个数量级。这个估算不精确,但方向是确定的:常驻式记忆的成本随对话轮数线性膨胀,按需检索式基本是常数。

再说少走弯路。L4 那 41 条教训,每一条都对应一个我踩过一次的坑。它们现在会在相关场景自动跳出来警告。随手举几个真实的:

  • "gthread workers 在 3.6GB 内存的机器上会反复 OOM,改用 sync workers。" 这个坑要是重踩,又是半天的排查。
  • "别去 restart fund-web 服务,会和 gunicorn 抢端口把整个站点搞崩,部署要用 HUP 信号平滑重载。" 这条是拿一次线上事故换来的。
  • "SQLite 的 datetime('unixepoch') 不加 localtime 参数,早间任务的数据会全部归错日期。" 一字之差,38 条会话归错了天。

这些都写成了单独的文章。它们的价值不在于多深奥,而在于每一条都是"栽过一次、以后不用再栽"。41 条,就是 41 次不用重来的排查。

最后一个收益不太好量化,但我感受最深:我不用一遍遍重复自己了。它记得我上次为什么那么改,记得部署的正确姿势,记得我讨厌鸡汤式的收尾。少解释几遍,本身就是省时间。


八、接下来

这套 HexaMind 我打算整理成一个开源的 skill 放到 GitHub 上,让其他用 Hermes Agent 的人也能照着装一套自己的。到时候前面那篇搭建攻略就是配套的操作手册,这篇则是给还没决定要不要折腾的人看的:先搞明白它解决什么问题、值不值得。

如果你也在用 AI 助手,被"它怎么又忘了"折磨过,那答案其实不复杂:给它配个能查的档案柜,把该记的存进去,别指望每次都靠一段全文背诵的便签。至于要不要搭到六层这么细,看你的知识量。我这套长到 200 多条事实、100 多条关系才显出必要,你可能三十条就够,一个能语义搜索的小库就解决问题了。

工具是死的,关键是你愿不愿意花那么点时间,让它记住你已经教过的东西。