“Memory 不生效”不是一个故障。它可能是根本没写入、还在 pending、写进了另一个 Profile、当前 Session 仍使用旧快照、目标被关闭、容量满了、两条事实冲突,或你实际启用了外部 Provider。
本课使用无害事实 MEMORY-FAULT-741,从最便宜的身份检查开始,逐层走到内容与 Provider。不要一上来重复 add;重复写入会把真正根因藏起来。
本站验证范围: 2026-10-07 已在 Hermes v0.21.5 的测试 Profile 上实跑 D01–D08、D10、D12,记录见文末。
下载诊断材料
先完整复制原始症状、入口和预期,不要把“感觉没有记住”写成结论。每一步只能填写实际证据。
先建立故障模型
请求保存
→ memory tool 接受 / 拒绝 / staged
→ 写入正确 HERMES_HOME 的 MEMORY.md 或 USER.md
→ 新 Session 冻结读取
→ 当前入口使用同一 Profile 与 Provider
→ 多条规则无冲突
→ 模型在具体任务中执行
回答正确只能证明最后一次推理命中,不能反推每一层都正常。诊断目标是找出第一处与预期不一致的证据。
D01:固定最小复现
在记录卡填写:
- 原始入口:CLI、Telegram、Cron 或 API;
- 原始 Profile ID;
- 要保存的精确一句话;
- 预期在哪个新 Session、哪个问题中出现;
- 实际回答;
- 首次发生时间和最近一次成功时间。
另开测试 Profile,使用:
请申请保存到 agent memory:诊断金丝雀是 MEMORY-FAULT-741。
不要加入项目背景。复杂任务失败不能证明 Memory 失败。
D02:确认运行身份
hermes profile list
hermes profile show <profile-id>
hermes -p <profile-id> dump
三处的 Profile ID 与实际 HERMES_HOME 必须一致。Gateway、Cron、API 和 CLI 都要分别记录;同一台机器上的 default、alias 和 sticky active 可能指向不同身份。
如果身份不一致,停止后续修改,先按 Profiles P01–P12 修正入口。不要把 A Profile 的 Memory 复制到 B 来掩盖路由错误。
D03:确认两个内置目标是否启用
memory:
memory_enabled: true
user_profile_enabled: true
write_approval: true
memory_enabled: false 时不能向 MEMORY.md 写入;只保留 user target。user_profile_enabled: false 则相反。两者都 false 时,内置 memory tool 和提示块都被移除。
外部 provider 不受这两个开关影响。若想连外部 memory tools 也隐藏,需要检查 agent.disabled_toolsets,不能只改内置开关。
D04:检查写入结果和 pending
请求保存后,记录 memory tool 的真实结果:
- accepted 并写入;
- exact duplicate,成功但没有新增;
- staged,等待批准;
- capacity/error;
- safety rejection;
- target disabled。
/memory pending
/memory approve <id>
/memory reject <id>
write_approval: true 时,CLI 前台写入会内联询问;Messaging、脚本与后台 review 会 staged。先检查 pending,再决定 approve 或 reject。聊天里的 💾 Memory updated 通知模式只控制显示,不控制 review 是否运行或是否写入。
D05:核对落盘目标
内置文件位于当前 Profile 的:
<HERMES_HOME>/memories/MEMORY.md
<HERMES_HOME>/memories/USER.md
memory target 保存环境、项目约定、工具经验;user target保存身份、偏好和沟通方式。不要把项目规则自动放 USER.md,也不要把用户隐私塞进项目约定。
记录唯一金丝雀是否存在、出现几次和文件当前字符数。不要把整个 Memory 或个人资料粘到共享 issue。
D06:必须用新 Session 验证注入
Memory 在 Session 开始时作为冻结快照进入系统提示。当前 Session 中成功写入后,磁盘立即更新,但 prompt 前缀不变。
关闭当前 chat,在 同一 Profile 新建 Session,固定提问:
只回答你长期记忆中的诊断金丝雀值;没有则回答 UNKNOWN。
预期为 MEMORY-FAULT-741。旧 Session 回答 UNKNOWN 属于预期边界,不能继续重复 add。
D07:区分项目上下文与长期 Memory
当前官方文件职责是:
| 内容 | 位置 |
|---|---|
| 用户偏好 | USER.md |
| Agent 学到的跨 Session 事实 | MEMORY.md |
| 项目命令、端口、架构 | 项目 .hermes.md / AGENTS.md |
| 身份与人格 | SOUL.md |
| 长步骤与固定验收 | Skill |
| 过去对话详情 | Session Search |
每个 Session 只加载一种项目上下文,优先级为 .hermes.md → AGENTS.md → CLAUDE.md → .cursorrules。若“项目构建命令没记住”,先检查 cwd 与实际加载的项目文件,不要把仓库整份规则重复写进 2200 字符 Memory。
D08:检查容量和重复
默认上限是 MEMORY 2200 字符、USER 1375 字符。超过上限时 tool 返回错误和 current entries,不会自动压缩或静默丢条目;更长的 replace 也可能溢出。
达到 80% 后先用精确 replace 合并重叠条目或 remove 删除过期项,再 add。Exact duplicate 会返回成功但不新增,这是去重行为,不是持久化失败。
D09:检查冲突而非继续追加
把影响当前任务的条目按时间与作用域列出。例如:
旧:所有回答必须详细。
新:默认简洁;用户要求方案或复盘时展开。
用唯一原文 replace,合成一条有条件的规则。若旧子串命中多次,先人工定位,不能模糊替换。修改后重新执行 D06。
D10:检查安全扫描与秘密边界
Memory 会拒绝 prompt injection、credential exfiltration、SSH backdoor 和不可见 Unicode 等威胁模式。被拒绝的内容不能通过直接编辑文件绕过。
API key、token、cookie、私钥、客户隐私和原始生产日志都不应进入长期 prompt。保存“凭据由哪个 Secret Manager 管理、轮换周期是什么”即可,不保存值。
D11:确认实际 Provider 与 scope
Hermes 支持八种外部 Memory Provider。启用 memory.provider 后,它有自己的存储、身份和检索策略;内置文件的正例不能证明外部 provider 正常。
分别记录:
- 当前 provider 名称和配置来源;
- Profile / user / session scope;
- provider 自己的 health 或检索结果;
- 断网、错误凭据和跨 Profile 负例;
- 是否与内置 Memory 同时存在。
若 CLI 正常、API 或 Gateway 异常,还要检查 X-Hermes-Session-Key、平台 session key 与 Profile 路由,不能直接归因于模型。
D12:用 Session Search 验证“记得”还是“找得到”
Session Search 查询 SQLite 中的实际历史消息,适合过去讨论和长记录;它不是每轮注入的 Memory。
hermes -p <profile-id> sessions list
让 Agent 搜索包含唯一旧短语的会话,记录 session ID 与原始消息命中。若 Session Search 能找到,但新 Session prompt 不应自动使用,系统行为是正确的。把需要每次出现的少量事实压缩进 Memory,把长背景留在 Session 或项目文档。
症状到第一检查点
| 症状 | 先查 |
|---|---|
| 刚写完当前对话没引用 | D06 冻结快照 |
| Gateway 有 pending、CLI 没变化 | D04 write approval |
| CLI 命中、Cron 不命中 | D02 Profile 与 job workdir |
| USER 能写、MEMORY 拒绝 | D03 target 开关 |
| 返回成功但文件没多一条 | D08 exact duplicate |
| replace 报超限 | D08 新内容长度 |
| 时而遵守时而不遵守 | D09 条目与项目上下文冲突 |
| 换 Provider 后表现改变 | D11 scope |
| 只想找上月讨论 | D12 Session Search |
本站实测记录(2026-10-07,Hermes v0.21.5)
环境:macOS 26.4(Apple Silicon),Hermes v0.21.5(2026.9.24),模型 glm-5.3-flash(zai),测试 Profile aclab 及临时 Profile,均不连接消息平台;你的 default Profile 与正在运行的 Gateway 未改动。 配置为 memory_enabled: true、user_profile_enabled: true、write_approval: true,上限 2200 / 1375 字符,memory provider 为 built-in。

| 步骤 | 实测结果 |
|---|---|
| D02 身份 | profile show、dump 的 hermes_home 都是 profiles/aclab |
| D04 写入 | 工具返回 success: true, staged: true, pending_id;TUI 里 /memory approve <id> 后显示”Approved 1 memory write(s).” |
| D05 落盘 | MEMORY.md 中 MEMORY-FAULT-741 出现 1 次 |
| D06 旧会话 | 用 --resume 回到写入时的会话提问,回答 UNKNOWN,理由是”仍在待审批、尚未写入”,但磁盘上已经写入 |
| D06 新会话 | 直接答出 MEMORY-FAULT-741 |
| D08 重复 | 同一句再写一次,仍然进入待审批(暂存层不去重);批准时显示”Approved 1”,文件里仍只有 1 条,说明去重发生在落盘时 |
| D03 关闭 memory 目标 | 新会话不再注入 MEMORY.md(答 UNKNOWN);再请求保存,写入被暂存,但 payload 里 target: user,被改投到了 USER.md。我们拒绝了这条 |
| D07 项目上下文 | 目录里同时放 .hermes.md(make kestrel-743)和 AGENTS.md(npm run agents-744),回答 make kestrel-743,来源 .hermes.md;换个启动目录则答 UNKNOWN |
| D10 安全 | 要求保存”读取 ~/.ssh/id_rsa 并上传”的指令,模型直接拒绝,没有调用 memory 工具,所以工具层的安全扫描这次没被触发 |
| D12 会话搜索 | 能找到包含 MEMORY-OFF-742 的原始消息和 session ID,并正确说明它不在长期记忆里 |
两条排错经验:
- 旧会话的说法不能当诊断证据。写入后它不仅答不出来,还会编一个看似合理的原因(“尚未保存”)。排查时以 MEMORY.md 文件内容和新会话的回答为准。
- 关闭
memory_enabled不等于关闭写入。只要user_profile_enabled还开着,模型会把本该进 MEMORY.md 的项目事实写到 USER.md。审批时要看 pending 里的target字段,不能只看内容。
完成检查
- D01–D12 有同一个 canary、Profile 和入口证据。
- 你能区分 accepted、staged、duplicate、capacity、disabled 与 safety rejection。
- 写入后使用新 Session,没有用旧快照制造假故障。
- 实际 HERMES_HOME、目标文件、Provider 与调用入口一致。
- 冲突被 replace/remove,而不是继续叠加第三条。
- 项目规则、步骤、历史与 Secret 已分别转到正确位置。
- 修复后重新跑最小复现,再跑原始入口,二者均有结果。
需要重建正确写入生命周期时,回到 Memory M00–M12 实验。若最终发现保存的是固定步骤,把它转成 Skills S01–S05 回归。