Hermes,补上了 Agent 记忆系统最关键的一块
公众号名称:Halo咯咯
作者名称:jilolo
发布时间:2026-04-30 12:11

想必Hermes Agent对于大家来说已经极其不陌生了,今天我们就从Hermes开源的代码路径中来看下:它怎么构建提示词状态,怎么持久化会话,怎么刷新记忆,又怎么查询过去的对话。
简短地说:Hermes 不是只有一个记忆系统。它有四个。
-
一个很小、经过筛选的提示词记忆,存放在
MEMORY.md和USER.md。 -
一个可以搜索的 SQLite(轻量级嵌入式数据库)历史会话档案,通过
session_search暴露出来。 -
由智能体管理的技能,充当过程记忆。
-
一个可选的 Honcho 层,用于更深的用户建模。
把这些串起来的关键设计很简单:为了缓存,让提示词保持稳定;其他东西都交给工具。
那我们直接进入正题。
Hermes 的上下文结构
在理解记忆之前,先要理解 Hermes 实际发送给模型的是什么。

系统提示词大致是这样组装的:
[0] 默认智能体身份
[1] 面向工具的行为指导
[2] Honcho 集成块(可选)
[3] 可选系统消息
[4] 持久化的 MEMORY.md 快照
[5] 持久化的 USER.md 快照
[6] 技能索引
[7] 上下文文件(AGENTS.md、SOUL.md、.cursorrules、.cursor/rules/*.mdc)
[8] 日期/时间 + 平台提示
[9] 对话历史
[10] 当前用户消息
这很关键,因为 Hermes 优化的是服务商侧提示词缓存,也就是让模型服务商复用稳定的提示词前缀,从而降低延迟和成本。源码里的提示词构建器对此写得很明确:稳定前缀应该尽可能长时间地保持稳定。
只这一个决定,就能解释 Hermes 记忆架构里的大部分设计。
如果某条信息每一轮都应该可用,Hermes 会尽量把它压得很小,然后只注入一次。如果它很大、属于历史信息,或者只是偶尔有用,Hermes 就把它移出提示词,等需要时再检索。
第一层:持久化的提示词记忆
内置记忆系统小得有点出人意料。
Hermes 把持久记忆存在 ~/.hermes/memories/ 下的两个文件里:
| 文件 | 用途 | 限制 |
|---|---|---|
MEMORY.md | 智能体关于环境、约定、工具怪癖、经验教训的笔记 | 2,200 字符 |
USER.md | 用户画像:偏好、沟通风格、身份 | 1,375 字符 |
这并不多。合起来大约 1,300 个 token。
而且这是有意为之。
会话开始时,Hermes 会加载这两个文件,把它们渲染成一个提示词块,然后在整个会话期间冻结这个快照。会话中途写入的内容会立刻持久化到磁盘,但不会修改已经构建好的系统提示词。那些变更只会在新会话开始时出现,或者在压缩触发提示词重建之后出现。
渲染出来的格式大概是这样:
══════════════════════════════════════════════
MEMORY (your personal notes) [67% — 1,474/2,200 chars]
══════════════════════════════════════════════
User's project is a Rust web service at ~/code/myapi using Axum + SQLx
§
This machine runs Ubuntu 22.04, has Docker and Podman installed
§
User prefers concise responses, dislikes verbose explanations
这里有几个细节我很喜欢。
- 它限制的是字符数,不是 token 数。
这样一来,记忆逻辑就不依赖具体模型。Hermes 不需要为了判断记忆是否已满,就去适配某个模型专属的 token 计数方式。
- 它使用简单的分隔符文件格式。
条目之间用 § 分隔。没有向量数据库,没有自定义二进制存储。就是普通文本文件。
- 它有意把系统提示词里的记忆压得很小。
这可能是整个设计里最重要的一点。Hermes 并不想把完整历史塞进提示词记忆。它只希望最高价值的事实留在那里。
- 它把记忆视为经过整理的状态,而不是日记。
这正是 Hermes 和 OpenClaw 很不一样的地方。
OpenClaw 的每日日志有一种追加式记录的味道。Hermes 明确往相反方向走。工具模式定义和测试说得很清楚:
-
保存用户偏好
-
保存环境事实
-
保存反复出现的纠正
-
保存稳定约定
-
不保存任务进度
-
不保存会话结果
-
不保存临时 TODO 状态
说到底,Hermes 希望 MEMORY.md 和 USER.md 始终保持热、紧凑,并且适合缓存。
memory 工具
Hermes 通过一个 memory 工具管理这些文件。它有三个动作:
-
add -
replace -
remove
当前工具表面上没有真正的读取动作,因为记忆已经在会话开始时注入到提示词里了。
一个不错的易用性细节是:replace 和 remove 使用子字符串匹配。你不需要内部 ID,只要传入现有条目里独一无二的一段文本即可。
例子:
memory(
action="replace",
target="memory",
old_text="dark mode",
content="User prefers light mode in VS Code, dark mode in terminal"
)
系统还会拒绝完全重复的内容,并在记忆进入提示词之前拦截危险内容。源码会扫描记忆条目,查找提示词注入、凭据外泄、SSH 后门提示以及不可见 Unicode 字符等模式。
这很合理。任何写入记忆的东西,实际上都会成为未来系统提示词的一部分。
第二层:用 session_search 做情景式回忆

如果说 MEMORY.md 和 USER.md 是 Hermes 的热记忆,那么 session_search 就是它的长尾回忆系统。
所有历史会话都会存到 ~/.hermes/state.db。这是一个 SQLite 数据库,里面有:
-
sessions表 -
messages表 -
FTS5(SQLite 的全文搜索扩展)全文搜索索引
-
通过
parent_session_id连接起来的父子会话谱系
当模型需要回忆之前某次对话里的内容时,Hermes 搜索的不是 MEMORY.md。它搜索会话数据库。

流程大致如下:
对历史消息做 FTS5 搜索
-> 按会话分组结果
-> 解析父/子会话谱系
-> 加载最匹配的几个会话
-> 围绕相关匹配截断转录文本
-> 用便宜的辅助模型总结每个会话
-> 把聚焦后的回顾交还给主模型
这和那些试图对每一条记忆笔记做语义索引的系统,哲学上很不一样。
Hermes 基本上是在说:
-
始终注入的记忆要小
-
真正的历史放进 SQLite
-
只有需要时才搜索历史
-
搜到结果后先总结,再交给模型
这个设计很务实。
也比把漫长历史一股脑塞进每次提示词里机智。
文档把 session_search 描述为用来回答这类问题的工具:
-
“Did we discuss this last week?”
-
“What did we do about X?”
-
“As I mentioned before…”
换句话说,MEMORY.md 用来保存持久事实,session_search 用来做情景式回忆。
第三层:压缩和记忆刷新
Hermes 另一个聪明的地方,是它在压缩长对话之前会做什么。
随着会话变长,Hermes 最终会总结对话中间部分,以便留在模型上下文窗口以内。但总结是有损的,重要事实可能会消失。
所以 Hermes 会先做一次记忆刷新。
压缩前,它会注入一条合成的 system/user 指令,大意是:
-
会话即将被压缩。
-
保存任何值得记住的内容。
-
优先保存用户偏好、纠正和反复出现的模式,而不是任务细节。
然后它额外跑一次模型调用,而且只开放 memory 工具。
如果模型判断某些东西应该熬过这次压缩,就会在对话被总结掉之前,把它写进 MEMORY.md 或 USER.md。
这是个很好的模式。
它给了模型最后一次机会,在对话中段被折叠之前,把耐久信息提炼出来。
更好的是,压缩之后,Hermes 会让缓存的系统提示词失效并重建,从磁盘重新加载记忆。这意味着压缩前刚刷进去的任何内容,都会成为下一个稳定提示词快照的一部分。

所以流程是:
长对话
→ 把持久事实刷新到记忆
→ 压缩旧轮次
→ 重建提示词
→ 带着更小的上下文和更新后的记忆继续
这种设计让 Hermes 看起来像一个真正的记忆架构,而不是临时外挂的笔记仓库。
第四层:作为过程记忆的技能
Hermes 的记忆故事不只是事实和转录文本。
它还有技能。
技能放在 ~/.hermes/skills/ 下,像可复用的知识文档。文档明确把它们称为智能体的过程记忆。
当 Hermes 发现一个不简单的工作流,修好一个棘手问题,或者学会一种更好的做法时,它可以把这些保存为技能,之后再复用。
这事很关键。
大多数记忆系统只关注语义回忆:名字、偏好、事实和总结。但智能体也需要记住怎么做事,而不只是记住发生过什么。
Hermes 通过把过程知识和提示词记忆分开来处理这个问题:
-
MEMORY.md/USER.md保存紧凑、持久的事实 -
session_search做情景式回忆 -
skills保存可复用工作流
这里还有一个不错的 token 效率技巧。Hermes 不会把每个技能完整注入提示词。它只注入一个紧凑的技能索引,只有需要时才加载完整技能内容。
这样,过程记忆保持可用,但不必每一轮都支付完整 token 成本。
第五层:用 Honcho 做更深的用户建模
然后是可选的 Honcho 层。
如果本地记忆是 Hermes 经过整理的笔记本,那么 Honcho 就是它对更丰富用户模型的一次尝试。
默认情况下,Honcho 会以 hybrid 模式和内置记忆系统并行运行。它会增加:
-
跨会话用户建模
-
跨机器、跨平台连续性
-
对用户上下文的语义搜索
-
关于用户或 AI 同伴的、由 LLM 生成的辩证式回答
有意思的是,Hermes 集成它时并没有破坏提示词缓存。
第一轮和后续轮次是不一样的。
在一个会话的第一轮,预取到的 Honcho 上下文可以烘进缓存的系统提示词里。
到了后续轮次,Hermes 会避免修改那段稳定的系统提示词。它只是在 API 调用时,把 Honcho 召回内容附加到当前用户轮次上。这意味着:
-
稳定前缀仍然稳定
-
提示词缓存仍然有效
-
第 N 轮可以消费第 N-1 轮之后后台预取到的上下文
这是一个很聪明的折中。
Honcho 自己还会建模两个同伴:
-
用户
-
AI 助手
所以 Hermes 不只是想记住你。它也可以随着时间推移,建立对自身的表征。
这既酷,又有点疯狂。
Hermes 和 OpenClaw 有什么不同

OpenClaw:
-
记忆更接近 Markdown 优先的存储方式
-
每日日志和长期记忆文件是主要事实来源
-
记忆召回更依赖对存储笔记做混合搜索
Hermes:
-
提示词记忆被压得很小
-
会话历史存在 SQLite,而不是提示词记忆文件里
-
过去的工作通过
session_search召回 -
过程记忆被推入技能
-
更深的用户建模可选地交给 Honcho
这里的关键洞察是:Hermes 比 OpenClaw 更有缓存意识。
OpenClaw 更偏向“记忆就是可搜索的存储知识”。Hermes 更偏向“记忆是热工作集加冷检索层”。
我确实觉得,这是生产级智能体更应该走的方向。
不是所有东西都值得住进系统提示词。
Hermes 做对了什么
看完仓库和文档之后,我觉得 Hermes 做对了三件大事。
- 它把热记忆和冷召回分开了。
这是核心的架构胜利。
总是重要的东西,放进小小的提示词记忆。只是偶尔重要的东西,搜索时再找。
- 它把提示词稳定性当成一等约束。
很多智能体系统谈记忆,却不谈缓存。Hermes 显然两者都在意。
冻结快照、延迟提示词更新、按轮次注入 Honcho、压缩后的提示词重建,这些都指向同一个设计原则:如果你想要好的延迟和成本,就不要随便改你的提示词。
- 它承认记忆是复数。
Hermes 没有假装一个存储层能解决所有问题。
它有:
-
语义画像记忆
-
情景式会话回忆
-
通过技能实现的过程记忆
-
通过 Honcho 可选实现的更高阶用户建模
这更接近智能体实际需要的东西。
结论
Hermes 的记忆系统不是一个巨型知识库,也不是换了个名头的向量库。它是一个分层的连续性架构。
中心是一小块经过整理的提示词记忆:MEMORY.md 和 USER.md。外面是一套可搜索的 SQLite 历史,用于情景式回忆。再往外,是用于复用流程的技能系统。如果启用 Honcho,Hermes 还会在这一切之上加一层更深的用户模型。
最让我印象深刻的,是它背后的设计原则:记忆应该让智能体持续有用,同时不破坏提示词稳定性。
真正难的地方就在这里。
不是记得更多。而是在正确的层里,用正确的成本,记住正确的东西。
如果你喜欢这篇文章,别忘了 _关注_我们!
AI在持续学习,你我也该更新了。

Original jilolo Halo咯咯
内容效果不满意?点此反馈