Hermes 的记忆层有 8 种实现:我为什么选了最反常识的那个

时间:2026-07-06 08:10:46 来源:互联网

在Hermes Agent的8种记忆实现中,为何Holographic方案能成为作者的首选?本文详细剖析方案对比、存储范式差异,并解释这一反常识选择背后的实际优势。

img_6a4af28684ae530.webp

在研究Hermes Agent的过程中,发现一个有趣的现象:其记忆层并非单一方案,而是提供了8个可热插拔的Provider。这些Provider的存储方式从最古老的Markdown文件到最前沿的知识图谱,部署方式从单个SQLite文件到整套云端托管。其中名为Holographic的方案最为特别,它既不依赖向量也不使用图谱,而是采用在数值分析课上被忽视的数学方法——HRR(Holographic Reduced Representations)。经过实际体验,我将默认配置切换为Holographic,下面将详细阐述原因。

先把8个方案摆上桌

Hermes的Memory Provider设计十分克制,并非试图提供"一个方案打天下"的模式,而是承认不同场景需要不同的存储与检索策略。我按照"有多轻"的标准进行排序,从最轻到最重排列如下:

img_6a4af2868ec8a31.webp

排名Provider存储后端数据结构部署方式初始化
1HolographicSQLiteHRR代数向量 + 事实三元组纯本地零配置
2ByteRoverMarkdown文件树层级知识树(L0/L1/L2)本地优先 + 可选云同步装CLI
3HindsightPostgreSQL知识图谱 + 事实 + 实体本地daemon / Dockerhermes memory setup
4OpenViking自托管文件数据库文件系统层级跑openviking-server启动服务
5Mem0Qdrant / pgvector向量嵌入 + 图谱云端 / Docker Compose简单设置
6HonchoPostgreSQL + Redis用户表示 + 会话摘要云端 / Docker/K3s配置较复杂
7RetainDB云端托管数据库向量 + BM25索引仅云端API Key
8Supermemory云端托管数据库向量 + 会话图谱仅云端API Key

排序的逻辑非常简单:外部依赖越少的方案越轻量,初始化过程越简便的越轻量,检索时越少依赖LLM的越轻量。

三种存储范式,三种哲学

将8个方案按存储方式归类,可以发现它们代表了三种截然不同的"记忆哲学"。

范式一:文档即记忆(Markdown)

代表:ByteRover、Hermes自带的MEMORY.md

这是最朴素也最符合人类直觉的设计——记忆就是一堆Markdown文件,人类能读取,Agent也能读取。ByteRover的巧妙之处在于分层加载:L0摘要(100 tokens)→ L1概览(2K tokens)→ L2全文。Agent先查看摘要,需要细节再深入,官方宣称能节省80-90%的token。

优点:透明、可读、支持Git版本控制、可离线使用。 缺点:检索主要依赖关键词或LLM阅读全文,模糊语义搜索是明显的短板。

范式二:向量即记忆(Vector)

代表:Mem0、Honcho、RetainDB、Supermemory

这是当下最主流的方案。将每条记忆转换为embedding向量,检索时计算余弦相似度。Mem0是该流派的明星产品(GitHub 25k+ stars),其管线清晰明确:对话 → LLM提取事实 → 冲突检测去重 → 存入向量库 → 检索时向量召回 + reranker。

优点:模糊语义搜索能力强,能够很好回答"类似这样的有哪些"这类问题。 缺点:需要自己运行Qdrant/pgvector或使用云端付费服务,检索精度并未如宣传般神奇——在LongMemEval基准测试中,Mem0仅有67.6%,是所有方案中最低的。

范式三:图谱即记忆(Graph)

代表:Hindsight、Mem0的图模式

不仅记录事实,还记录事实之间的关系。例如"小明养了橘子"+"橘子是一只猫"+"猫通常讨厌洗澡"——图谱能推理出"小明家可能需要宠物沐浴服务"这种跨三条边的关联。Hindsight是该方向的标杆,采用本地嵌入式PostgreSQL + 知识图谱 + 多策略检索(语义+BM25+图谱+时序)+ reranker,在LongMemEval测试中达到94.6%。

优点:复杂关系推理能力强,支持时序演变。 缺点:最重——需要PostgreSQL,需要LLM抽取实体关系,检索延迟最高。

番外篇:代数即记忆(HRR)

代表:Holographic(独一份)

这就是那个反常识的方案。它既不算是向量,也不属于图谱,而是将记忆表示为可叠加的复值向量,检索时并非计算相似度,而是直接进行代数运算。第一次看到文档时的反应是:"这不就是数值分析课上学过的那节课的内容吗?"但实际使用起来,体验非常不错。

Holographic实测:亚毫秒检索是怎么做到的

接下来分享一些真实的使用体验。

一条命令开跑

hermes memory setup   # 选 holographic
hermes config set memory.provider holographic

它只需要两样东西:

  1. ✅ SQLite(Python自带)
  2. ✅ NumPy(可选,没有则降级到FTS5)

不需要:Docker、PostgreSQL、Redis、Qdrant、API Key、云账号、网络连接。所有数据存放在~/.hermes/memory_store.db一个文件中。

HRR代数检索到底在干嘛

这部分需要多花些篇幅讲解,因为这是Holographic最独特的地方,也是文档中语焉不详的部分。先回顾传统向量检索的工作原理:

  1. 用预训练模型(BGE、OpenAI embedding)将每条记忆转换为一个向量。
  2. 对提出的问题也进行向量转换。
  3. 将问题向量与库中存储的向量逐一计算余弦相似度。
  4. 选取最相似的top-k结果返回。

其复杂度为O(N×D):N是记忆条数,D是向量维度。记忆越多,查询越慢,而且离不开预训练embedding模型。HRR则走了完全不同的道路——没有预训练模型,也没有向量库。它依靠哈希函数实时生成向量,将所有记忆叠加进同一个1024维向量中,查询时直接"解出"答案。

第0步:每个词的1024维向量从哪来?

这是最反常识的地方。传统RAG需要大模型预训练才能生成词向量,HRR则完全不需要——它对每个单词使用固定的哈希函数实时计算得出:

DIM = 1024  # 源码里硬编码的全局常量
def encode_atom(word: str):
    # 1. 拿单词文本做SHA256,算出固定随机种子
    seed = int(sha256(word.encode()).hexdigest()[:16], 16)
    # 2. 用这个种子生成1024维的随机相位向量
    rng = np.random.default_rng(seed)
    return rng.uniform(0, 2*np.pi, size=DIM)

两个关键性质:

  1. 确定性:同一个词(例如橘子),无论何时运行或者重启多少次程序,计算出的1024维向量始终完全相同——因为种子来自哈希。
  2. 近似正交:不同单词的哈希种子不同,生成的向量在1024维空间中天然几乎垂直(相似度接近0)。这是HRR卷积运算的数学基础。

这些向量不存储于磁盘。运行时在内存中维护一个cache = {单词: 向量}字典,首次用到某个词时计算一次并存入,后续直接读取。重启清空也无妨,再次计算仍是同一个向量。

存的时候:把事实揉成向量,全部相加

每条事实首先拆分为(主语, 关系, 宾语)三元组。例如存储"小明养了橘子":

  1. 拆分三元组:(小明, 养了, 橘子)
  2. 三个词分别调用encode_atom获得3个1024维向量(缓存命中则直接读取)
  3. 使用圆周卷积将三个向量融合成一个binding(仍然为1024维):
    binding = vec(小明) ⊛ vec(养了) ⊛ vec(橘子)
  4. 将这个binding添加到全局记忆向量M上
    M = M + binding
  5. 写入磁盘:原始三元组文本和binding存储到SQLite的fact_store表,更新后的M写入hrr_global_state表(仅一行,专门存储这1024个浮点数)。

最关键的一步在于——所有事实的binding直接相加,全部叠加进同一个1024维向量M:

M = binding(小明养了橘子)
  + binding(橘子讨厌洗澡)
  + binding(小明给橘子梳毛)
  + ...

无论存储了多少条事实,M始终保持1024维。所有记忆都"叠加"在这个向量中,互相干扰但能够近似恢复。这是HRR最反直觉的地方:信息并非按条目存储,而是按叠加方式存储。

查的时候:给一个cue,反卷积解出答案

当你想知道"小明养了什么",构造一个cue(提示向量):

cue = vec(小明) ⊛ vec(养了)          # 使用相同的卷积运算生成钥匙
result = unbind(M, cue)              # 反卷积,将答案分量"解"出来

在数学上,反卷积会"对齐"到最初绑定时使用的vec(橘子)分量;其他事实由于使用不同的key绑定,对齐后变为背景噪声。最后将result与缓存中的所有原子向量(小明、橘子、洗澡、梳毛……)计算一次相似度,最接近的就是答案——橘子。

img_6a4af2869fd0832.webp

为什么能做到亚毫秒

整个查询过程仅涉及几次固定大小的向量运算(卷积+反卷积+点积),没有"扫表"步骤。其复杂度为O(D),D固定为1024。无论库中有100条还是10万条事实,单次查询的计算量完全相同。加上M常驻内存(SQLite中的那份仅作为持久化备份,重启时重新加载到内存),实际查询甚至无需读取磁盘。这就是"亚毫秒"的来源——它把检索问题转变为固定维度的代数运算

不过代价是:它擅长精确匹配,不擅长模糊查询。询问"小明养了什么"能准确回答,因为这是按key取value;但问"类似橘子的宠物有哪些"则难以应对,因为原子向量是随机哈希生成的,词与词之间没有语义关系橘子的向量相似度,与橘子键盘的相似度一样,都接近0)。

双引擎:HRR + FTS5

Holographic的设计很务实,并未将所有希望寄托在HRR上。它内部采用混合检索:

引擎擅长操作
HRR代数实体关系组合查询probe / related / reason / contradict
FTS5全文关键词模糊匹配search

9个操作中有4个是HRR独门算法,其余为常规CRUD以及关键词搜索。

信任评分:非对称惩罚的小心思

每条事实都拥有一个0.0–1.0的trust分数,默认值为0.5。用户反馈机制如下:

  1. helpful → trust += 0.05
  2. unhelpful → trust -= 0.10

注意惩罚力度是奖励的两倍。这是一个聪明的设计——记忆系统最大的敌人并非漏记,而是噪声累积。一旦确认错误信息,需要快速清理;确认有用信息,则逐步增加分数。这个理念与之前研究OpenClaw的Dreaming巩固机制相通:重要的事情说三遍才能记住,错误的事情一次就要纠正

一段真实的使用

举个与工作无关的例子——假设你需要Agent帮助管理宠物信息,让它记录几条事实:

> fact_store(action='add', content='小明养了橘子')
> fact_store(action='add', content='橘子讨厌洗澡')
> fact_store(action='add', content='小明每周给橘子梳毛')

下次会话时,Holographic自动从这些事实中抽取实体:小明橘子洗澡梳毛。然后你可以这样查询:

> fact_store(action='reason', entities=['小明', '橘子'])
→ 返回:"小明养了橘子" + "小明每周给橘子梳毛"

reason是HRR的杀手锏——它能回答"同时涉及A和B的事实"。这是纯关键词搜索无法实现的,因为单条事实中可能根本没有同时出现这两个词。

SQLite里能看到什么

sqlite3 ~/.hermes/memory_store.db "SELECT fact_id, content, trust_score FROM facts ORDER BY trust_score DESC LIMIT 10;"
fact_id | content   | trust_score
--------+-------------------------------+------------
f_0042  | 小明每周给橘子梳毛              | 0.65
f_0039  | 橘子讨厌洗澡                    | 0.55
f_0038  | 小明养了橘子                    | 0.50

数据清晰透明,没有任何黑盒。这一点对我是决定性的——我不希望自己的"记忆"变成一坨自己都看不懂的向量矩阵。

我选Holographic的真实理由

讲完这么多技术细节,现在说说最朴素的理由。

  1. 我是懒人。 配置PostgreSQL、编写Docker Compose、注册云账号、申请API Key——每多一步,实际使用概率就降低一半。Holographic零配置,安装好Hermes即可使用。
  2. 经常离线。 飞机上、高铁上、咖啡馆的弱Wi-Fi都是常态。云端方案在这些场景下完全失效。
  3. 想要数据主权。 我的记忆属于我自己。一个SQLite文件,可以备份、可以Git跟踪、可以使用sqlite3命令查询、可以编写脚本批量修改。换成云端服务,这些自由都将消失。
  4. 性能足够。 对于几百条事实的库,HRR运算几乎实时完成。我并不需要在亿级数据上做实时推理。
  5. 概念优雅但门槛低。 HRR数学原理很深,但即使不懂也能轻松使用——add/search/reason三个操作覆盖了90%的应用场景。

但它确实有短板

不说缺点就成了软文。

  1. 模糊语义搜索能力不足。 "类似XXX的东西有哪些"这类问题,Holographic的FTS5经常答非所问。如果重度依赖语义召回,建议选择Mem0或Hindsight。
  2. 单用户设计。 SQLite文件锁不支持并发写入,多个Agent同时输入事实会导致竞争。团队场景下应使用Hindsight或ByteRover Cloud。
  3. 数据量存在天花板。 没有进行分片处理,数十万条数据时性能会下降。但对于个人用户而言,很难达到这个上限。
  4. 记忆提取依赖会话后批处理。 不像Mem0那样拥有服务端LLM实时抽取能力,Holographic默认在会话结束时一次性提取(auto_extract),实时性稍弱。

选型决策树

将所有方案总结为一句话:

  1. 追求极致轻量、离线、可控Holographic(本文重点推荐)
  2. 需要Markdown透明 + Git版本控制ByteRover
  3. 需要图谱推理 + 高精度(94.6%)Hindsight
  4. 自托管团队、需要节省tokenOpenViking
  5. 最快启动、无需管理Mem0云端版
  6. 多Agent深度用户建模Honcho

如果仍然无法决定,可以先用Holographic运行两周。经过实践你会发现——大部分人的记忆需求,根本不需要知识图谱和向量数据库。

写在最后

Hermes这套8 Provider的设计给我一个重要启示:记忆系统没有银弹,只有合适的权衡。向量数据库很酷,知识图谱也很美,但"我的记忆存储在一个我可以打开的SQLite文件中,亚毫秒检索,零依赖,离线可用"——这种朴素的安全感,是任何花哨方案都无法替代的。至少对我这样的个人用户来说,这已经足够了。

你目前的Agent使用的是什么记忆方案? 还是根本没有配置?欢迎在评论区分享,我很想知道大家在这方面遇到过哪些坑——尤其是从向量数据库换回Markdown的反向操作,是否只有我一个人这样做。

本文基于Hermes Agent官方文档与源码分析,HRR原理参考Plate 1995的原始论文。所有命令与配置均已实测。

记忆系统没有万能方案,找到适合自身场景的权衡才是关键。对于追求轻量、离线与可控的个人用户,Holographic提供了令人安心的选择。