MVP 上线了,能跑,能搜。
跑了一阵发现——自动抽取存了大量不该存的东西,合并不了,治理不了。
这次升级只有一个目标:让vecmem记忆系统从"能记能搜"变成"记的准+可治理"。


前言:MVP 是起跑线,不是终点线

上一篇写了 vecmem 的 MVP——用 sqlite-vec 给 Hermes Agent 装上了语义搜索记忆。自动抽取、三级降级嵌入、FTS5 关键词兜底,该有的都有了。

但 MVP 嘛,核心假设是"能跑就行",至于"跑得好不好"——上线前没人知道。

用了一周之后,三个问题浮出水面:

  1. 垃圾进,垃圾出。 自动抽取存了大量不该存的东西——问句、临时进度、裸路径。记忆库涨得飞快,但真正有用的内容比例在下降。
  2. 重复堆积。 同样的内容不同表述反复写入,hit_count 虚高,查重成本越来越高。
  3. 没有治理手段。 合并不了、删不了(也没有权限删)、错了不知道、错了也追溯不了。

逼出了一个决定:不继续加功能,停下来建治理体系。


问题诊断:记忆污染是怎么发生的

先看几个真实的写入记录:

# 这些都是 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
}

事件系统覆盖了所有状态变更:addduplicateupdatemergearchiverestorereviewapprovereject

每条记忆的完整生命周期都可追溯——什么时候建的、谁改过、改之前是啥、改之后变成啥、为啥改。

没有审计,治理就是空话。 这是整个升级里性价比最高的一笔投入。

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,每步都用真实使用数据看看误判率。跟功能灰度发布一样——先观察,再放开。

注意 updatemerge 的区别:

  • 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_typesubject——"用户偏好:…"变成 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 的这个体系里,最值钱的三件事是:

  1. 事件审计表 — 成本最低、收益最大。没有它,后面所有工作都没有追溯能力。
  2. Preview/Dry-run — 所有变更在生效前都可预览。能预览就不怕犯错,能回滚就不怕误操作。
  3. 源质量过滤器 — 在存储层过滤比在应用层补救便宜一个数量级。

这三条不依赖任何模型能力——用确定性的代码解决确定性的问题。剩下的交给 LLM 去做它擅长的事。


项目地址:https://github.com/xing006/hermes-vecmem

*上一篇:给Hermes Agent打造个外挂大脑 - 开发记忆插件实录

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐