记忆系统:让 Agent 记住你
本教程共 25 篇 · 第 11 篇 · 更新于 2026-07-26 · 约 14 分钟阅读
11. 记忆系统:让 Agent 记住你
本节目标:搞清楚 Hermes Agent 的记忆系统怎么运作—三层记忆架构各自管什么,MEMORY.md 和 USER.md 怎么读写,跨会话搜索怎么找回历史对话,记忆提供者(Memory Providers)怎么换后端,Curator 怎么自动策展,以及 Honcho 怎么做辩证推理。学完你能在脑子里画出完整的记忆流转图。
大多数 AI 的痛点:每次对话从零开始
如 §01 所述,AI 失忆是多数工具的通病——你跟它聊了半小时项目细节,第二天开新会话全忘了。这不是个别体验,是大多数 AI 工具的基础设计:每次会话都是独立的,没有持久记忆。
Hermes Agent 当前最新稳定版 v2026.7.20 的核心差异化能力之一,就是它真的记得你。不是简单的”记住上次对话”,而是三层相互独立、功能互补的记忆结构。
三层记忆架构
Hermes 的记忆系统分三层,理解这个分层是掌握记忆系统的钥匙:
第一层:持久记忆(Persistent Memory)
MEMORY.md(环境事实)+ USER.md(用户画像)
→ 每次会话启动时自动注入系统提示词,始终可见
第二层:情节日志(Session History)
SQLite + FTS5 全文检索,存储所有历史对话
→ Agent 主动搜索时按需加载,不占用固定 Token
第三层:用户建模(Honcho,可选)
辩证推理引擎,提取跨会话模式、偏好与目标
→ 比你亲口说出来的更深层地理解你
三层之间不是替代关系,而是互补:
| 记忆层级 | 回答的问题 | 存储位置 | 容量 | 加载方式 |
|---|---|---|---|---|
| 持久记忆 | ”我总是需要知道这些” | ~/.hermes/memories/ 下的 Markdown 文件 | ~1,300 tokens | 会话启动时自动注入 |
| 情节日志 | ”我们上周聊过这个问题吗” | SQLite 数据库 + JSONL 文件 | 无限 | Agent 按需搜索 |
| 用户建模 | ”你真正想要的是什么” | Honcho 服务端 API | 按 Agent 隔离 | 后台推理注入 |
持久记忆:两个文件搞定核心信息
持久记忆是记忆系统最基础的一层,由两个 Markdown 文件组成,放在 ~/.hermes/memories/ 下。
MEMORY.md 和 USER.md 各管什么
| 文件 | 用途 | 字符上限 | 约等于 |
|---|---|---|---|
MEMORY.md | Agent 的个人笔记—环境事实、项目规范、工作中学到的东西 | 2,200 字符 | ~800 tokens |
USER.md | 用户画像—你的偏好、沟通风格、工作习惯、技能水平 | 1,375 字符 | ~500 tokens |
Note字符上限是有意设计的。它保证记忆内容保持精炼、聚焦,不会无限膨胀。如果一条新条目超出上限,
memory工具会返回错误让 Agent 先整理空间再写入,而不是悄悄丢弃旧条目。
记忆怎么注入系统提示词
每次会话启动时,两个文件的内容以固定格式注入系统提示词:
══════════════════════════════════════════════
MEMORY(Agent 个人笔记)[67% - 1,474/2,200 字符]
══════════════════════════════════════════════
用户的项目是位于 ~/code/myapi 的 Rust Web 服务,使用 Axum + SQLx
§
本机运行 Ubuntu 22.04,已安装 Docker 和 Podman
§
用户偏好简洁回复,不喜欢冗长解释
几个关键设计细节:
-
冻结快照模式:系统提示词中的记忆内容在会话开始时捕获一次,中途不会更新。这是为了保持 LLM 的前缀缓存(Prompt Cache)有效,降低 Token 成本。Agent 在会话中修改记忆,变化立即写入磁盘,但要等下次会话启动才会出现在上下文中。
-
用量百分比可见:
[67% - 1,474/2,200]让 Agent 随时知道剩余容量,接近上限时主动整理。 -
§ 作为条目分隔符:每条记忆之间用
§分隔,条目本身可以是多行文字。
Agent 怎么操作记忆
Agent 通过内置的 memory 工具管理记忆,支持三种操作:
| 操作 | 说明 | 参数 |
|---|---|---|
add | 新增一条记忆条目 | target(memory/user)、content |
replace | 替换已有条目(子串匹配定位) | target、old_text、content |
remove | 删除已有条目(子串匹配定位) | target、old_text |
没有 read 操作—记忆内容在会话启动时已经注入系统提示词,Agent 直接在上下文中看到,不需要额外读取。
replace 和 remove 用子串匹配定位条目,不需要提供完整条目文本:
# 场景:当前记忆中有 "用户所有编辑器都偏好深色主题"
# 现在需要更新为更精确的版本
memory(
action="replace",
target="memory",
old_text="深色主题", # 唯一子串即可定位原条目
content="用户 VS Code 用浅色主题,终端用深色主题" # 替换后的新内容
)
如果子串匹配到多个条目,工具会返回错误,要求提供更精确的匹配串。
什么该记,什么不该记
Agent 会自动判断并保存有价值的信息,你通常不需要显式要求。但了解判断标准有助于理解 Agent 的行为。
应该写入 MEMORY.md 的信息(环境与工作):
| 类型 | 示例 |
|---|---|
| 环境事实 | 本机运行 Debian 12,PostgreSQL 16,Docker 用 Podman 替代 |
| 项目规范 | ~/code/api 使用 Go 1.22,sqlc 查询,chi 路由;测试用 make test |
| 工具经验 | staging 服务器 SSH 端口是 2222,不是 22 |
| 纠正记录 | 不要用 sudo 运行 Docker 命令,用户已在 docker 用户组 |
| 完成工作 | 2026-01-15 完成数据库从 MySQL 迁移到 PostgreSQL |
应该写入 USER.md 的信息(关于你):
| 类型 | 示例 |
|---|---|
| 身份信息 | 姓名、职位、时区 |
| 沟通偏好 | 偏好简洁回复,不需要解释显而易见的步骤 |
| 厌恶项 | 不要在代码里加过多注释 |
| 工作习惯 | 每天下午 3 点前不看消息 |
| 技能水平 | 熟悉 Rust 和 Python,Go 是新学的 |
不应该保存的内容:
| 类型 | 示例 | 原因 |
|---|---|---|
| 过于笼统 | ”用户有个项目” | 无信息量,无法复用 |
| 可随时重查 | ”Python 3.12 支持 f-string 嵌套” | 搜索即可,不值得占空间 |
| 原始数据 | 大段日志、代码块、数据表 | 超出字符限制,结构化记忆更有用 |
| 临时性内容 | 本次调试的临时文件路径 | 下次用不上 |
| 已在上下文中 | 项目 SOUL.md、AGENTS.md 里已有的信息 | 重复注入浪费 Token |
Tip好记忆一条顶十条。把相关信息打包成一条密度高的条目,比拆成十条零散记忆强得多。比如”用户的 macOS 14 Sonoma,Homebrew,Docker Desktop,Shell 是带 oh-my-zsh 的 zsh,编辑器是 VS Code + Vim 键位”比五条单独的记忆更有用。
容量管理:接近上限怎么办
当新条目会导致超出字符上限时,工具返回错误而非静默截断:
{
"success": false,
"error": "Memory 已用 2,100/2,200 字符。新条目(250 字符)会超出上限。请先整理。",
"current_entries": [
"用户的 macOS 14 Sonoma,Homebrew,Docker Desktop",
"项目 ~/code/api 使用 Go 1.22,sqlc 做 DB 查询"
],
"usage": "2,100/2,200"
}
收到这个错误后,Agent 的正确做法是:
- 读取当前所有条目(错误响应中已经包含)
- 找出可以删除或合并的条目
- 用
replace将几条相关条目合并为一条更精炼的版本 - 然后重试添加新条目
Tip当系统提示词显示记忆使用率超过 80% 时,主动整理,不要等到报错。预防永远比补救更省 Token。
控制记忆写入权限
默认情况下,Agent 可以自由写入记忆—包括后台自动触发的自我改进回顾(一轮对话结束后在后台运行,提炼记忆和技能)。
如果你希望在任何内容写入记忆前先审核,可以开启写入审批:
# 文件路径:~/.hermes/config.yaml
memory:
write_approval: true # 默认 false(自由写入)
开启后的行为变化:
| 场景 | 行为 |
|---|---|
| CLI 交互中 Agent 要写记忆 | 在终端内联提示你审批 |
| 消息平台 / 后台自动回顾 | 写入被暂存,等待你手动审批 |
使用斜杠命令管理待审批的记忆写入:
/memory pending # 查看待审批的记忆写入(自动触发的标记 [auto])
/memory approve <id> # 批准指定 ID 的写入
/memory approve all # 批准全部
/memory reject <id> # 拒绝指定 ID 的写入
/memory reject all # 拒绝全部
/memory approval on # 运行时开启审批(设置持久保存)
/memory approval off # 运行时关闭审批
Warning如果你不想让 Agent 保存某个错误假设,或者想完全掌控记忆内容,开启
write_approval是最直接的方式。但注意:开启后后台自动回顾的记忆写入也会被暂存,需要定期清理。
后台自我改进回顾
每轮对话结束后,Hermes 会在后台运行一次自我改进回顾(background review),分析这轮对话并提炼值得保留的记忆或技能。默认会在聊天中显示一行提示 Memory updated。
你可以调整通知的详细程度:
# 文件路径:~/.hermes/config.yaml
display:
memory_notifications: on # off | on(默认)| verbose
| 值 | 效果 |
|---|---|
off | 不显示通知,但回顾仍在运行、仍会写入 |
on | 简短提示,如 Memory updated |
verbose | 包含变更预览,如 Memory + 用户偏好简洁回复 |
如果主模型费用较高,可以让后台回顾跑在更便宜的模型上:
# 文件路径:~/.hermes/config.yaml
auxiliary:
background_review:
provider: openrouter
model: google/gemini-3-flash-preview # 默认 auto = 主模型
情节日志:跨会话搜索找回历史
第二层记忆—情节日志(Session History)—存储所有历史对话的完整记录,支持全文检索和按需召回。
所有对话都自动保存
每一次会话—无论来自 CLI、Telegram、Discord 还是其他任何平台—都自动存入两个位置:
| 存储位置 | 格式 | 内容 |
|---|---|---|
~/.hermes/state.db | SQLite 数据库 + FTS5 全文索引 | 结构化元数据、完整消息历史(含工具调用和结果)、Token 用量、时间戳 |
~/.hermes/sessions/ | JSONL 转录文件 | 原始对话转录,包含工具调用记录 |
session_search 工具
Agent 内置 session_search 工具,可以在所有历史对话中执行全文检索。整个过程无需 LLM 参与搜索阶段,直接由 SQLite FTS5 引擎完成:
- FTS5 按相关性排序检索匹配消息
- 按会话分组,取最相关的若干会话(默认 3 个)
- 加载各会话对话,截取匹配点附近约 10 万字符
- 用轻量摘要模型生成聚焦摘要
- 返回各会话的摘要与上下文给 Agent
支持的搜索语法(FTS5 标准):
| 语法 | 示例 | 说明 |
|---|---|---|
| 关键词检索 | docker deployment | 匹配包含任一关键词的消息 |
| 短语匹配 | "exact phrase" | 精确匹配整个短语 |
| 布尔 OR | docker OR kubernetes | 匹配任一关键词 |
| 布尔 NOT | python NOT java | 排除特定关键词 |
| 前缀通配符 | deploy* | 匹配以 deploy 开头的词 |
Tip你不需要手动调用
session_search。当你提到”上次我们讨论过的……”或”之前那个方案……”时,Agent 会自动调用它,而不是让你重复解释。
session_search vs 持久记忆
两者功能互补,不是替代关系:
| 对比维度 | 持久记忆 | 情节日志 |
|---|---|---|
| 容量 | ~1,300 tokens 总量 | 无限(所有历史对话) |
| 速度 | 即时(已在系统提示词中) | ~20ms(FTS5 查询) |
| Token 成本 | 每次会话固定消耗 | 按需,不查不花 |
| 用途 | 关键事实,始终可见 | 查找特定历史讨论 |
| 管理方式 | Agent 主动整理 | 全自动,无需干预 |
会话管理
每条会话都可以被命名、恢复、导出和清理。Hermes 会在第一轮对话后自动生成一个简短的会话标题(3-7 个词),在后台异步运行,不影响响应速度。
常用会话管理命令:
hermes sessions list # 列出最近 20 条会话
hermes sessions list --source telegram # 按来源平台筛选
hermes sessions list --limit 50 # 显示更多条
hermes sessions rename <id> "新标题" # 重命名指定会话
hermes sessions export backup.jsonl # 导出所有会话到文件
hermes sessions delete <id> # 删除指定会话
hermes sessions prune --older-than 30 # 清理 30 天前的旧会话
hermes sessions stats # 查看统计信息
恢复会话的几种方式:
hermes --continue # 恢复最近一次会话
hermes -c "重构认证模块" # 按标题恢复会话
hermes -r <session_id> # 按会话 ID 恢复
Note当会话经过上下文压缩时,Hermes 自动创建延续会话并编号:
"我的项目"->"我的项目 #2"->"我的项目 #3"。按标题恢复时,自动选取最新的延续会话。
默认情况下会话历史永久保留。如果需要自动清理:
# 文件路径:~/.hermes/config.yaml
sessions:
auto_prune: true # 默认 false
retention_days: 90 # 保留最近 90 天
vacuum_after_prune: true # 清理后回收磁盘空间
min_interval_hours: 24 # 两次清理之间的最小间隔
记忆提供者:可插拔的记忆后端
Hermes 的记忆系统不局限于本地文件。通过记忆提供者(Memory Providers)机制,你可以把记忆后端换成外部服务,获得更强的推理能力或跨设备同步。
八个可选提供者
当前最新稳定版 v2026.7.20 支持以下记忆提供者:
| 提供者 | 特点 |
|---|---|
honcho | Plastic Labs 开发的 AI 原生记忆后端,辩证推理 + 深度用户建模 |
openviking | 开源记忆引擎,注重语义检索 |
mem0 | 轻量级记忆层,API 简洁 |
hindsight | 事后分析型记忆,从对话中自动提取洞察 |
holographic | 全息记忆,支持多维关联 |
retaindb | 专用记忆数据库,高性能检索 |
byterover | 字节跳动出品的记忆方案 |
supermemory | 通用记忆即服务平台 |
怎么切换提供者
最简单的方式是用交互式向导:
hermes memory setup # 交互式选择提供者 + 配置
hermes memory status # 查看当前激活的提供者
hermes memory off # 禁用外部提供者,回到内置记忆
也可以手动配置:
# 文件路径:~/.hermes/config.yaml
memory:
provider: honcho # 换成你想用的提供者
Note切换提供者不会丢失本地记忆数据。MEMORY.md 和 USER.md 始终保留在
~/.hermes/memories/下,外部提供者是在它们之上的增强层,不是替代。
Curator:自动策展你的技能
Curator(记忆策展)是 Hermes 记忆系统的延伸—它管的不只是记忆文件,还有 Agent 在使用过程中积累的技能。
随着你不断使用 Hermes,Agent 会自己创建技能(详见第 13 章)。时间一长,技能目录可能堆积大量过时、重复或不再使用的技能。Curator 就是来解决这个问题的。
Curator 做什么
Curator 定期扫描技能目录,根据使用频率自动管理技能生命周期:
- 活跃(active):最近使用过的技能,保持原位
- 归档(archived):长时间未用的技能,移到归档目录,从系统提示词中移除
- 合并(consolidate,可选):用 LLM 把多个相关技能整合成一个伞形技能
配置 Curator
# 文件路径:~/.hermes/config.yaml
curator:
enabled: true # 是否启用
interval_hours: 168 # 扫描间隔(默认 7 天)
min_idle_hours: 2 # 最近 2 小时用过的不会被处理
stale_after_days: 30 # 30 天没用标记为过时
archive_after_days: 90 # 90 天没用归档
consolidate: false # 是否启用 LLM 合并(默认关闭,仅清理)
prune_builtins: true # 是否也清理内置技能(hub 技能始终豁免)
Curator 命令
hermes curator status # 查看上次运行时间、技能数量、pinned 列表
hermes curator run # 立即触发一次扫描
hermes curator pin <skill> # 固定某技能,永不自动处理
hermes curator restore <skill> # 把归档的技能恢复到活跃状态
Tip如果你有些技能不想被自动清理(比如季节性使用的技能),用
hermes curator pin固定它。pinned 的技能完全跳过 Curator 的所有自动操作。
Honcho:辩证推理深度理解你
Honcho 是由 Plastic Labs 开发的 AI 原生记忆后端,以记忆提供者形式集成到 Hermes 中。它不替换 MEMORY.md 和 USER.md,而是在它们之上增加辩证推理层—通过分析你的对话模式,自动推导你未曾明确表达的偏好、目标和习惯。
Honcho 比内置记忆强在哪
| 能力 | 内置记忆 | Honcho |
|---|---|---|
| 跨会话持久化 | 本地文件 | 服务端 API |
| 用户画像 | 手动策划(USER.md) | 自动辩证推理 |
| 会话摘要 | 无 | 会话级上下文注入 |
| 多 Agent 隔离 | 无 | 按 Agent 分开建模 |
| 语义搜索 | FTS5 全文 | 基于推理结论 |
| 推导洞察 | 无 | 从对话模式中自动提取 |
打个比方:内置记忆像是你主动记在笔记本上的东西,Honcho 像是一个一直在旁边观察你的朋友,它能注意到你自己都没意识到的习惯。
两层上下文注入
每一轮对话,Honcho 组装两层上下文注入系统提示词:
-
基础层(Base Context):会话摘要 + 用户表征 + 用户 Peer Card + AI 自我表征。按
contextCadence(每 N 轮)刷新一次。这是”这个用户是谁”层。 -
辩证层(Dialectic Supplement):由 Honcho 的 LLM 引擎实时推理生成,关注”当前最相关的是什么”。按
dialecticCadence刷新。
辩证推理有冷启动和热启动两种模式:
| 模式 | 条件 | 查询方式 |
|---|---|---|
| 冷启动 | 无历史数据 | 通用查询—“这个用户是谁?他们的偏好、目标和工作方式是什么?“ |
| 热启动 | 已有历史数据 | 会话聚焦查询—“基于本次会话已讨论的内容,关于这个用户最相关的上下文是什么?“ |
三个独立调节旋钮
成本和深度由三个完全独立的旋钮控制:
| 旋钮 | 控制内容 | 默认值 |
|---|---|---|
contextCadence | 基础层刷新间隔(每 N 轮调用一次 API) | 1 |
dialecticCadence | 辩证层刷新间隔(每 N 轮调用一次 LLM) | 2(推荐 1-5) |
dialecticDepth | 每次辩证的推理深度(1-3 次 pass) | 1 |
三个旋钮完全独立。你可以高频刷新基础层、低频运行辩证推理,也可以反过来:
{
"contextCadence": 1,
"dialecticCadence": 5,
"dialecticDepth": 2
}
以上配置表示:每轮刷新基础层,每 5 轮做一次 2-pass 深度辩证推理。
Note深度 3 不一定等于 3 次 LLM 调用。如果上一轮已产出高质量输出,下一轮会提前退出,节省 Token。
三种召回模式
Honcho 的记忆召回方式可以切换:
| 模式 | 行为 | 适用场景 |
|---|---|---|
hybrid(默认) | 上下文自动注入 + 工具可用,模型自己决定何时查询 | 大多数用户 |
context | 仅自动注入,工具隐藏 | 想要稳定上下文,不想让模型自己决定 |
tools | 仅工具,不自动注入。Agent 必须显式调用 | 精确控制,省 Token |
快速上手 Honcho
# 交互式设置,选择 honcho 提供者
hermes memory setup
或手动配置:
# 文件路径:~/.hermes/config.yaml
memory:
provider: honcho
# 将 API Key 写入环境变量文件
echo 'HONCHO_API_KEY=your_key' >> ~/.hermes/.env
在 honcho.dev 获取 API Key。
Honcho 提供的工具
开启 Honcho 后,Agent 可以使用五个专属工具:
| 工具 | 用途 |
|---|---|
honcho_profile | 读取或更新用户 Peer Card |
honcho_search | 基于推理结论的语义搜索(原始片段,无 LLM 综合) |
honcho_context | 获取完整会话上下文(摘要、用户表征、近期消息) |
honcho_reasoning | 调用 Honcho LLM 推理(可指定 reasoning_level) |
honcho_conclude | 创建或删除推理结论 |
Honcho CLI 命令
hermes honcho status # 连接状态、配置和关键设置
hermes honcho strategy # 查看或设置会话策略(per-session/per-directory/per-repo/global)
hermes honcho mode # 查看或设置召回模式(hybrid/context/tools)
hermes honcho tokens # 查看或设置 Token 预算
hermes honcho identity # 设置或查看 AI peer 的身份
hermes honcho sessions # 列出已知的 Honcho 会话映射
Warning选择使用 Honcho 时,对话数据会发送到 Honcho 的服务器进行处理。这是一个有意的权衡:用数据上传来换取更深的推理能力。如果对数据隐私有顾虑,可以使用内置记忆或自托管 Honcho。
记忆安全与隐私
安全扫描
记忆内容在写入前会经过安全扫描,检测注入攻击和数据窃取模式:
| 威胁类型 | 检测内容 |
|---|---|
| 提示词注入 | 试图覆盖 Agent 系统指令的注入模式 |
| 凭据窃取 | 诱导 Agent 泄露 API Key 或 Token 的指令 |
| 后门安装 | SSH 后门或远程访问的安装指令 |
| 隐藏字符 | 不可见 Unicode 字符(零宽空格、方向覆盖等) |
匹配到威胁模式的内容会被拒绝写入。
敏感信息脱敏
API Key、Token 等敏感信息在所有日志文件中自动脱敏:
# 文件路径:~/.hermes/config.yaml
security:
redact_secrets: true # 默认开启
数据本地存储
所有内置记忆数据(MEMORY.md、USER.md、state.db)默认存储在本地 ~/.hermes/ 目录,不上传到云端。只有选择使用 Honcho 等外部提供者时,对话数据才会上传到对应服务器。
记忆配置完整参考
以下配置可直接复制到 ~/.hermes/config.yaml 使用:
# --- 持久记忆配置 ---
memory:
memory_enabled: true # 是否启用持久记忆(MEMORY.md)
user_profile_enabled: true # 是否启用用户画像(USER.md)
memory_char_limit: 2200 # MEMORY.md 字符上限(约 800 tokens)
user_char_limit: 1375 # USER.md 字符上限(约 500 tokens)
write_approval: false # true = 所有记忆写入需要手动审批
# provider: honcho # 可选:启用外部记忆提供者
# --- 会话自动清理(可选,默认关闭)---
sessions:
auto_prune: false
retention_days: 90
vacuum_after_prune: true
min_interval_hours: 24
# --- Curator 记忆策展 ---
curator:
enabled: true
interval_hours: 168
stale_after_days: 30
archive_after_days: 90
consolidate: false
prune_builtins: true
# --- 后台回顾通知 ---
display:
memory_notifications: on # off | on | verbose
# --- 后台回顾使用更便宜的模型(可选)---
auxiliary:
background_review:
provider: openrouter
model: google/gemini-3-flash-preview
自然语言操作记忆速查
你不需要记忆任何命令,用自然语言就能操控记忆:
# 新增记忆
记住:我们这个项目用 Poetry 管理依赖,不用 pip
# 删除或覆盖记忆
忘记之前关于 MySQL 的记录,我们已经迁移到 PostgreSQL 了
# 更新记忆
把 staging 服务器的 IP 更新为 10.0.2.100
# 查询记忆
告诉我你现在记住了哪些关于我的信息
记忆文件是普通 Markdown,也可以直接用编辑器打开修改:
cat ~/.hermes/memories/MEMORY.md # 查看记忆内容
nano ~/.hermes/memories/MEMORY.md # 用编辑器修改
Warning直接编辑文件后,变化会在下次会话启动时生效,不会立即体现在当前会话的上下文中。这是因为系统提示词中的记忆内容在会话开始时就冻结了。