Hermes记忆升级记:当 vecmem记忆层被污染之后
MVP 上线了,能跑,能搜。
跑了一阵发现——自动抽取存了大量不该存的东西,合并不了,治理不了。
这次升级只有一个目标:让vecmem记忆系统从"能记能搜"变成"记的准+可治理"。
前言:MVP 是起跑线,不是终点线
上一篇写了 vecmem 的 MVP——用 sqlite-vec 给 Hermes Agent 装上了语义搜索记忆。自动抽取、三级降级嵌入、FTS5 关键词兜底,该有的都有了。
但 MVP 嘛,核心假设是"能跑就行",至于"跑得好不好"——上线前没人知道。
用了一周之后,三个问题浮出水面:
- 垃圾进,垃圾出。 自动抽取存了大量不该存的东西——问句、临时进度、裸路径。记忆库涨得飞快,但真正有用的内容比例在下降。
- 重复堆积。 同样的内容不同表述反复写入,hit_count 虚高,查重成本越来越高。
- 没有治理手段。 合并不了、删不了(也没有权限删)、错了不知道、错了也追溯不了。
逼出了一个决定:不继续加功能,停下来建治理体系。
问题诊断:记忆污染是怎么发生的
先看几个真实的写入记录:
# 这些都是 vecmem 自动抽取存进去的
"这个功能有没有必要?"
"P1-2 已完成,下一步准备跑测试"
"https://example.com/some/page"
"偏好: 是这个"
"已配置 API_KEY"
"刚发现这个插件也许可以改一下"
每一条看起来都没啥,但加起来问题就大了——每条都要做一次嵌入计算、一次向量存储、一次内存加载。记忆库里有效信号越来越少,噪声越来越多。
再看重复问题:
# 同一条事实,被重复写了四次
"用户偏好:输出简洁准确" # 原始
" 用户偏好:输出简洁准确 " # 多了空格
"用户偏好:输出简洁准确。" # 多了句号
"用户偏好:输出简洁准确。" # 真的就是重复
四次写入,四条记录,四个向量。搜索时四条都被找回来了。不止浪费空间,搜东西也不够准了。
还有合并问题。两条语义相关的事实:
"项目使用 Python 3.11。"
"项目测试使用 pytest。"
它们应该合成一条"项目使用 Python 3.11 和 pytest",但 MVP 没有合并能力,只能各存各的。时间一长,对话上下文里全是零散碎片。
决策:建治理体系,而不是修 bug
面对这些问题,有两个方向:
A 方案: 继续优化抽取 Prompt、提高 LLM 准确率、在输入端修修补补。
B 方案: 在写入路径上加多层安全网——过滤、去重、冲突检测、人工审核、审计追溯。然后在此基础上加智能合并。
选了 B。理由很简单:LLM 不可能 100% 准确。 寄希望于模型不出错,不如在系统层面兜底。
第一层:写入安全阀(P0)
1. 源质量过滤器
一条事实进来,先过一道规则过滤器。不调模型、不调 API,100% 可预测。
拒绝写入的类别:
| 类别 | 示例 | 特征 |
|---|---|---|
| 问句/请求 | “这个功能有没有必要?” | 含问号/请问/能不能/要不要 |
| 临时进度 | “P1-2 已完成” | 已完成/正在运行/已修复 |
| 裸 URL/路径 | “https://example.com” | 纯链接或裸路径 |
| 半成型想法 | “刚发现这个插件也许可以改一下” | 模糊、无主语 |
| 无上下文密钥 | “已配置 API_KEY” | 值无上下文 |
允许写入的类别:
| 类别 | 示例 |
|---|---|
| 明确的用户偏好 | “用户偏好:回答简洁务实” |
| 配置信息 | “默认模型:deepseek/deepseek-v4-flash” |
| 项目事实 | “项目 hermes-vecmem 路径:E:/projects/hermes-vecmem” |
| 活跃上下文 | “active_context: 正在推进 P1 改造” |
| Idea backlog | “idea_backlog: Agent Skills Daily” |
规则是固定的、可预测的、不依赖模型好坏。MVP 版本里会被存进去的问句、进度、路径——源头就拦住了。
2. 精确去重与内容规范化
同一句事实反复写入,原因特简单:LLM 每次提取的说法不完全一样。
"用户偏好:输出简洁准确" # 第一次
" 用户偏好:输出简洁准确 " # 多了一个空格
"用户偏好:输出简洁准确。" # 多了一个句号
"用户偏好:输出简洁准确。" # 真的就是复制
三个版本说的是同一句话,但字符串不一样——FTS5 和向量搜索都会当成不同记录。
解决方案:写入前做内容规范化 + SHA-256 哈希去重。
具体来说:
- 写入前的标准 Pipeline:
strip → collapse_whitespace → normalize_punctuation - 用
content_hash = SHA-256(normalized_content + category)做唯一键 - 命中哈希的直接返回已有记录 ID,只增加
hit_count,不创建新行 - 对
active_context:前缀做覆盖式更新——同前缀直接替换,不留历史
一个哈希函数解决了重复堆积的问题。
3. 事件审计系统(memory_events)
这是整个治理体系的基石。MVP 版本对记忆做了什么——添加、修改、合并、归档——没有任何记录。
每个状态变更都记录以下信息:
{
"event_id": 1042,
"memory_id": 37,
"action": "update",
"before_content": "项目使用 Python 3.11。",
"after_content": "项目使用 Python 3.11 和 pytest。",
"source": "llm_merge",
"reason": "新事实补充了测试框架",
"created_at": 1748259000.123
}
事件系统覆盖了所有状态变更:add、duplicate、update、merge、archive、restore、review、approve、reject。
每条记忆的完整生命周期都可追溯——什么时候建的、谁改过、改之前是啥、改之后变成啥、为啥改。
没有审计,治理就是空话。 这是整个升级里性价比最高的一笔投入。
4. 预览与恢复(preview / dry-run / restore)
任何变更在生效前必须能预览。每个操作都有对应的 preview 版本:
| 动作 | Preview |
|---|---|
add → |
preview_add — 告诉你写入后会 dupliate / update / merge / review |
archive → |
preview_archive — 显示 before/after 状态 |
approve → |
preview_approve — 模拟审批结果 |
reject → |
preview_reject — 显示拒绝效果 |
Preview 是纯 dry-run,不改库、不写事件。反复 preview 确认,满意了再执行。
恢复也简单:归档不是删除。 archive 只是打个 archived 标记,restore 随时能恢复。没有硬删除,一切可回滚。
5. 计划系统(Plan)
需要批量操作时(比如从清理报告里一次性归档几十条噪音记录)——一条一条做太慢,直接改数据库又太危险。
弄了个计划系统,操作前走审批流程:
create_plan → 写 JSON 计划文件(dry-run,不改库)
list_plans → 查看所有待审批计划
get_plan → 查看计划详情和每一项操作
apply_plan → 输入确认词 "我确认执行计划" 后执行
apply_plan 有强制确认词保护。手滑点了?确认词没对上,一条都不改。
第二层:智能合并与冲突检测(P1)
安全网搭好了,下一步是让已有记忆更精准——合并相关的事实、检测并标出冲突。
6. LLM 合并四模式
新事实写入时,LLM 会被调用来判断该怎么做:
| 决策 | 说明 | 示例 |
|---|---|---|
store |
全新内容,直接写入 | |
duplicate |
命中缓存/哈希 | |
update |
新事实补充了已有记录 | “用 Python 3.11” → “用 Python 3.11 和 pytest” |
merge |
多条合成一条 | 两段关于 Dashboard 的信息合并 |
review |
可能冲突,需要人工 | “默认模型是 A” vs “默认模型是 B” |
自动合并有风险。LLM 可能把不相关的内容硬合在一起,或者拿不准的时候自作主张。
所以不靠"提高模型准确率",而是设了四种模式:
llm_merge_mode:
- off: 关闭 LLM 合并(默认安全)
- dry_run: 只记录建议,不改库
- review_only: 所有 update/merge 进 review 队列
- auto: 高置信度自动执行
推进路径:off → dry_run → review_only → auto,每步都用真实使用数据看看误判率。跟功能灰度发布一样——先观察,再放开。
注意 update 和 merge 的区别:
- update:新事实与单条已有记录语义互补,合二为一。旧记录标记为
superseded,但保留可查。 - merge:多条已有记录与新事实语义重叠,合并为一条全新记录。所有来源都标记
superseded。
搜索引擎里永远只返回 active 的记录,superseded 历史的只在审计事件中保留。
7. topic_key:确定性冲突检测
LLM 的语义相似度判断不太稳——同一个主题的不同取值,有时能发现冲突,有时就漏了。
冲突检测不能只靠 LLM,所以加了确定性 topic_key 规则:
"默认模型:deepseek/deepseek-v4-flash"
→ topic_key = "config.default_model"
"项目 hermes-vecmem 路径:E:/projects/hermes-vecmem"
→ topic_key = "project.path.hermes-vecmem"
"用户偏好:回答简洁务实"
→ topic_key = "user.preference.response_style"
"active_context: 正在推进 P1 改造"
→ topic_key = "active_context"
核心规则:同 topic_key 但内容不同 → 自动进入 review 队列,不走 LLM 判断。
比如"默认模型是 A"和"默认模型是 B"——LLM 可能觉得它们在说不同的事,但 topic_key 在规则层面就识别出冲突,直接扔 review。不靠模型判断。
三种情况的处理:
| 新内容 vs 已有内容 | 处理 |
|---|---|
| 同 topic_key,同内容 | duplicate,不创建新行 |
| 同 topic_key,不同内容 | review——人工判断 |
| 不同 topic_key | 正常 store / update / merge |
8. 结构化提取
MVP 版本的自动抽取返回纯文本数组。升级后,LLM 返回结构化的候选事实:
{
"content": "用户偏好:回答简洁务实",
"memory_type": "preference", # preference / project / environment / active_context
"subject": "user.response_style",
"predicate": "prefers",
"object": "简洁务实",
"durability": "long_term", # long_term / temporary / reject
"confidence": 0.96
}
写入规则也变得精确:
| 条件 | 处理 |
|---|---|
durability=reject |
直接丢弃 |
durability=temporary + 低置信度 |
丢弃 |
durability=long_term + 高置信度 |
写入 |
| old-style 纯文本 | 向下兼容,仍支持 |
手动 vecmem add 写入时,也会根据内容自动推导 memory_type 和 subject——"用户偏好:…"变成 preference,"项目 XXX 路径:…"变成 project。
第三层:可观测与运营工具(P2)
治理做完了,接下来让系统状态看得见、能诊断、能自动运维。
10. 自动清理工作流
记忆库运行久了必然积累噪音——auto 分类的临时碎片、过期的 active_context、重复记录的残留。
vecmem 内置了智能清理分析(dry-run 模式),扫描整个记忆库后生成报告:
清理报告 — 2026-05-25
========================
低风险清理候选: 3 条
[auto] "这个功能有没有必要?"
[active_context] "active_context: 正在做旧任务"
[duplicate] "用户偏好:输出简洁准确。" (与 ID:42 重复)
审核队列未处理: 1 条
[review] "默认模型:gpt-4.1"
数据一致性: ✅ 全部正常
memories: 47 条
vec_memories: 47 条(无孤儿向量)
memories_fts: 47 条(无缺失 FTS)
清理始终是 dry-run 先出报告,确认后再走 apply_plan。不会因为自动扫描把不该删的删了。
11. 记忆健康报告
配合 Hermes 的 cronjob 系统,可以定时生成健康报告:
📊 vecmem health report
窗口: 最近 24 小时
状态: attention(需要关注)
新增记录: 12 条
审核队列: 3 条未处理
清理候选: 2 条低风险
topic 冲突: 1 条
数据一致性: ✅
🟡 review_queue_nonempty
🟡 cleanup_candidates
🟡 topic_conflicts
本身也是 dry-run——不碰数据。可以安稳地挂 cronjob,每周收一封记忆健康邮件。
12. Explain 调试工具
这是我最喜欢的一个小功能。当你觉得 vecmem 搜出来的结果不对时:
vecmem explain query="Vue 前端框架"
它把搜索过程完全白盒化:
- 查询向量是什么(embedding 的前几个维度值)
- 向量库里有多少条候选
- 每条的相似度评分(精确到小数点后 4 位)
- 哪些因为 status=archived/review 被过滤了——过滤理由是什么
- 哪些因为低于 min_score 阈值被排除了
- 关键词搜索(FTS5)命中了什么
一个搜索操作从黑盒变成了白盒。调试记忆质量特有用——比如发现一条记忆明明该被召回却没有,explain 一看就知道是被过滤了还是相似度不够。
13. Dashboard 管理页
治理工作的最后一环——把命令行的能力搬到 GUI。
前面做的所有工作——事件审计、review 队列、健康报告、清理计划——如果只能通过命令行访问,对非技术用户来说门槛太高。
VecMem Manager Dashboard 是一个 Hermes Gateway 插件,直接在 Dashboard 上新增一个 tab 页:
- 按 status / category / type / topic 过滤查看记忆
- 搜索和详情展开
- 审批/拒绝 review 中的记忆
- 归档/恢复操作
- 查看决策理由和事件时间线
- 数据统计卡片(总量、维度、一致性检查结果)
部署方式:零修改 Hermes 核心代码,作为用户级插件放入 plugins/ 目录即可。前后端分离——FastAPI 后端 + SPA 前端,复用 Hermes Dashboard 的 UI 主题变量。
总结:治理体系全景
回顾整个升级过程,vecmem 从 MVP 到可治理的记忆系统,按三层结构演进:
P0:写入安全阀
源质量过滤 → 哈希去重 → 事件审计 → preview 预览 → 计划审批
P1:智能合并
LLM 四模式 → topic_key 冲突检测 → 结构化提取
P2:可观测
自动清理 → 健康报告 → Explain 调试 → Dashboard
每层解决一个核心问题:
P0 解决的是"能不能信任记忆系统"。 MVP 阶段存进去的东西没有保障——可能是噪音、可能是重复、可能是一次操作事故。P0 建了安全网:写入前过滤去重、写入后审计追溯、操作前 preview、误操作可恢复。
P1 解决的是"记忆质量能不能持续提升"。 仅仅是去重和过滤不够——语义相关的事实需要合并,冲突的事实需要标记。LLM 合并 + topic_key 规则 + 结构化提取,三者互补。
P2 解决的是"系统状态看不看得见"。 没 Dashboard 和报告,治理做得再好也是"改了不知道改对没有"。清理报告、健康报告、Explain——把内部状态亮出来。
一句话总结
MVP 解决的是"能跑吗"——治理体系解决的是"能放心用吗"。
vecmem 在真实使用中磨出的最大教训:自动化越强,治理越要跟上。没审计的自动化是赌博,没预览的批量操作是盲操作,不能回滚的系统不是生产系统。
在 P0 到 P2 的这个体系里,最值钱的三件事是:
- 事件审计表 — 成本最低、收益最大。没有它,后面所有工作都没有追溯能力。
- Preview/Dry-run — 所有变更在生效前都可预览。能预览就不怕犯错,能回滚就不怕误操作。
- 源质量过滤器 — 在存储层过滤比在应用层补救便宜一个数量级。
这三条不依赖任何模型能力——用确定性的代码解决确定性的问题。剩下的交给 LLM 去做它擅长的事。
项目地址:https://github.com/xing006/hermes-vecmem
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)