
你好,我是郑工长。
最近在用 OpenClaw 的时候,遇到一个很诡异的问题——
明明之前跟它约定好的规则,新会话就"失忆"了。
比如:我让它每次回复都标注当前使用的模型名称。这个约定在主会话好好的,但一用 /new 创建新会话,它就忘了。
更离谱的是,之前创建过的技能,新会话里它又重新创建了一遍。
这让我很困惑:OpenClaw 不是号称有长期记忆吗?怎么还会失忆?
带着这个问题,我翻了一遍 OpenClaw 的官方文档,终于搞清楚了原因。
记忆丢失的真相
问题根源在于:不同文件的加载时机不同。
OpenClaw 的记忆系统由多个文件组成,但它们不是每次都被加载:
| 文件 | 加载时机 | 存什么 |
|---|---|---|
| SOUL.md | 每个会话 | AI 身份定义 |
| USER.md | 每个会话 | 用户基本信息 |
| TOOLS.md | 每个会话 | 工具配置、环境变量 |
| memory/YYYY-MM-DD.md | 每个会话 | 日常记忆 |
| MEMORY.md | 仅主会话 | 长期记忆 |
看到问题了没?
MEMORY.md 只在主会话加载!
当你用 /new 创建新会话时,MEMORY.md 不会被加载。所以写在里面的约定,新会话根本看不到。
为什么会这样设计?
这不是 bug,是设计权衡。
MEMORY.md 用于存储真正重要的长期记忆。如果每个子会话都加载,会导致:
- 上下文膨胀
- 响应变慢
- 记忆冗余
但这个设计有个问题:用户不知道哪些内容应该放哪。
很多人(包括我)习惯把所有约定都塞进 MEMORY.md,结果一换会话就丢失。
解决方案
核心原则:把需要每次都加载的内容,放进每次都会加载的文件。
1. 关键约定迁移
把"每次回复标注模型名称"这种约定,从 MEMORY.md 迁移到 USER.md。
## 回复约定
- 每次回复必须标注当前使用的模型名称
- 格式:**当前模型:** `provider/model`
USER.md 每个会话都加载,约定就再也不会丢了。
2. 技能索引
在 TOOLS.md 里添加已注册技能的索引:
## 已注册技能
| 技能 | 位置 | 功能 |
|------|------|------|
| notion | workspace/skills/notion/ | Notion 操作 |
| mysql | workspace/skills/mysql/ | 数据库操作 |
调用技能时请直接使用现有技能,不要重新创建。
这样 OpenClaw 就知道哪些技能已存在。
3. 在 openclaw.json 注册技能
{
"skills": {
"entries": {
"notion": { "apiKey": "${NOTION_API_KEY}" },
"mysql": { "enabled": true }
}
}
}
修改前后对比
修改前:
- 约定写在 MEMORY.md → 新会话丢失 ❌
- 技能没注册 → 重复创建 ❌
修改后:
- 约定写在 USER.md → 每个会话都有 ✅
- 技能已注册 + TOOLS.md 有索引 → 不会重复 ✅
记忆文件的最佳实践
根据内容的重要性,选择正确的文件存储:
| 内容类型 | 推荐文件 | 原因 |
|---|---|---|
| 身份定义、角色设定 | SOUL.md | 每会话加载 |
| 用户信息、关键约定 | USER.md | 每会话加载 |
| 工具配置、技能索引 | TOOLS.md | 每会话加载 |
| 重要事件、项目里程碑 | MEMORY.md | 仅主会话,但永久保存 |
| 日常对话、临时记录 | memory/YYYY-MM-DD.md | 按日期存储 |
我的判断
OpenClaw 的记忆架构设计本身没问题,问题是用户不知道加载机制。
文档里写了,但没人仔细看。这是产品设计的问题,不是用户的问题。
核心原则就一句话:
如果某个约定你希望每次都生效,就别放在 MEMORY.md 里。
把它放在 USER.md 或 TOOLS.md,每个会话都会加载,永远不会丢。
对了,如果你也遇到过 OpenClaw"失忆"的问题,不妨检查一下你的约定写在哪个文件里。





