HexaMind 运维篇:中文搜索、自动去重、热缓存双向同步

记忆系列第四篇写于 7 月 7 号。那是 HexaMind 搭好后的一个基本形态:六层架构在那儿,290 条事实在 SQLite 里,LanceDB 每天凌晨同步一次,能用。

但能用和不用管之间还隔着一大截。这 17 天里修了六件事,每件都是"用着用着发现不对"然后改的。

截止今天,HexaMind 的状态是:290 条事实、290 条向量全覆盖、52 条教训(44 条标注了领域标签)、33 个实体 187 条边、32 条中文镜像。热缓存从 86% 压到 72%。两条 cron:02:30 每日整理 + 03:30 全层同步,管着所有自动化。

一、为什么中文搜不到自己的事实

问题出得很早。我写了不少事实在 L1 里,中文搜"gunicorn 部署"打不到,搜"ECharts 图表规范"也打不到。搜了一圈发现:L1 里 271 条事实,只有不到 30 条是中文的,大部分是英语。HexaMind 的检索链路是 FTS5 优先,FTS5 没法跨语言,中文查询对着一堆英文事实只能抓瞎。

L3 语义检索理论上能跨语言,但中→英的余弦相似度只有 0.45 到 0.56,太低,基本不顶用。

解决这件事的办法我叫它 zh-mirror:给每条高频英文事实写一条 50 到 100 字的中文镜像,不删英文原文。tag 带 zh-mirror 标记,source 打上日期。一条典型镜像长这样:

原文: gunicorn zero-downtime reload: find master PID (PPID=1), sudo kill -HUP <pid>
镜像: gunicorn 零停机重载:找 master PID(PPID=1 的那个进程)sudo kill -HUP <pid>
      部署 venxine.vip 用。nginx 改完同理 sudo cp sites-availablesites-enabled + reload

第一轮手动补了 24 条,覆盖部署流程、ECharts 规范、常见坑(Python dict.get 的 None 陷阱、Jinja2 endif、Nginx location 前缀吞并、CSS sticky/flexbox)、博客流水线、SEO 配置、热缓存机制这些高频领域。补完后中文搜索从"基本搜不到"变成"FTS 直接命中第一条"。

手动补 24 条花了半小时,但 L1 里还剩一百多条英文事实。不能每次都手动补。所以在 02:30 的"每日记忆整理"cron 里加了一步:当天没有新对话需要整理时,别空转,扫存量英文事实,每次补 1 到 2 条中文镜像。这样两个月内就能把存量消化干净。补完以后 03:30 的同步任务会自动跑 embedding 和重建 L3 索引。

二、热缓存快撑爆了

Hermes 自带的热缓存(MEMORY.md)每轮对话都会被原封不动塞进上下文。它有 15,000 字符的硬顶。

到 7 月 24 号,这个文件已经胀到 152 行、12,992 字符,使用率 86%。再涨一点就要开始报满了。

翻了一遍,发现不是信息太多,而是同一件事被记了很多遍。网关重启这件事出现了 4 处(一条初始记录 + 三条不同时间的更新),Demo 入口导航出现了 3 处,AI 新闻 cron 的踩坑出现了 5 处。HexaMind 架构那段有将近 800 字符,其实一句"skill:hexamind-memory-system"就够。X/Twitter 的支付细节写了 600 字符,也已经进了 L1 的 fact 库里。

处理方式很直接:合并同类项,删掉过时的,把冗长的压缩成关键词引用。16 组合并下来,152 条缩到 65 条,12,992 字符压到 10,644,使用率 70%,空出 2,300 字符。

三、L4 教训:三个月 55 条,有 3 组是重复的

7 月初写 L4 去重脚本的时候,逻辑很保守:只删 action 和 insight 完全相同的条目。跑到今天,55 条教训里藏了 3 组近重复:

  • Flask 自调用诊断(2 条,一正一反,说的是同一件事)
  • Nginx location 块缺失→404(3 条,action 措辞略不同,insight 几乎一模一样)
  • /system/ 版本排查(2 条,一条是 Agent 版本,一条是 Studio 版本:这条其实不算重复,是同 root cause 的两个 symptom)

问题出在:02:30 cron 写 lesson 的时候,它做了一个语义查重,但只对 facts 生效,lessons 没有走这个流程。去重脚本也是机械兜底,不认模糊匹配。

修了两处:去了那 3 组里的 5 条(合并 insight 到最早那条),然后给去重脚本加了模糊匹配(SequenceMatcher > 0.85 且同领域 tag 加分)。

顺手做了一件事:给 lessons 表加了 tags 列。52 条教训里 44 条回填了领域标签(deployment / frontend / backend / cron / data / config / blog / agent),同领域的近似条目在去重时多给 0.05 分的加成,更容易被合并。02:30 cron 写 lesson 时也得带上 tags。

四、L5 实体时间戳一直不更新

L5 的实体(entities)有个 last_updated 字段,设计上是每次有新 fact 连到这个实体时就更新。但实际上,03:30 cron 的 link_entities.py 只管连边,不管更新时间戳。导致一些老实体:比如 CORE-V2、Venxine 的 last_updated 还停在 6 月 17 号。

加了一个 refresh_entity_timestamps.py,03:30 cron 在连边之后跑一次:对比当前边数和上一次记录的值,变了就更新所有实体的 last_updated。这样实体时效性能反映真实活跃度。

同时补了 4 个今天新增的实体:heatmap-optimization(热力图优化)、blog-desc-fix(博客文章首段重复修复)、zh-mirror(中文镜像系统)、static-homepage-seo(首页 SEO 描述)。实体从 29 涨到 33,边从 174 涨到 187。

五、热缓存和 L1 之间的双向裂缝

之前的数据流是单向的:02:30 cron 从当天对话里提炼事实,写进 L1。但 L1 里积累的事实,并不会自动回到热缓存。如果一条事实在 L1 里躺了半个月,agent 在对话里还是看不到它,除非热缓存里本来就有,或者 agent 刚好跑了 hexamind_search

补了一个双向同步:hexamind-hotcache-sync.py,挂在 03:30 cron 里。每次全层同步之后,扫 L1 里新增的 daily-digest 类事实,摘出首句摘要(不超过 130 字符),追加到 MEMORY.md。同一条不会重复加。首次运行加了 5 条。

方向反过来,热缓存 → L1,02:30 cron 已经在做了,它本来就是从对话里提炼写 L1。

六、会话中也能搜 HexaMind 了

之前 agent 在对话里需要事实的时候,只看热缓存。热缓存没写的,它不知道 L1 里有。266 条事实大部分是白存的。

加了最简单的一步:在热缓存末尾塞了一条触发规则:遇到 venxine / fund-web / deployment / cron / 已知错误 / 配置 / 路径 类问题时,如果热缓存不够,就调 hexamind_search 查 L1→L3。不是什么复杂的自动注入,就是一条记忆提示。

命令是一条 terminal 调用:

~/.hexamind-venv/bin/python hexamind_search.py "gunicorn 部署 HUP" 5

返回 FTS 优先 + L3 语义补缺的混合结果。

收尾

HexaMind 这套系统写了快一个月。从最早的"记不住"到六层架构,到搭建攻略,到今天的运维优化。现在它不需要我每天看着了。02:30 自动整理对话和补中文镜像,03:30 重建索引、连边、去重、刷新时间、同步热缓存。每天凌晨两段 cron 跑完,微信上收到一条报告。

记忆系列:五层记忆体系 · 六层架构进化 · 搭建攻略 · 完整实践