Appearance
OpenClaw:memory.md vs Skill 的本质差异
整理日期:2026-03-27 来源:OpenClaw 官方文档、phppan.com 技术分析、实际使用经验
先说结论
把流程放在 MEMORY.md 和放在 SKILL.md 里,表面上都是"写一个 Markdown 文件让 AI 读",但它们在系统里走的是完全不同的两条路,解决的也是两个不同的问题:
- MEMORY.md 解决的是"AI 记住了什么"——跨会话的事实持久化,靠语义检索按需召回
- SKILL.md 解决的是"AI 知道怎么做"——结构化的操作流程,靠目录注入按需展开
这两条路的加载时机、注入方式、触发机制、适用内容都不一样。混用会导致流程失效或记忆污染。
一、两者的加载机制
MEMORY.md 的加载路径
OpenClaw 的记忆系统是"文件即真相"的设计哲学:模型只"记住"写入磁盘的内容,内存里的东西不算记忆。
记忆文件有两层:
memory/YYYY-MM-DD.md:每日日志,仅追加,会话开始时自动读取今天和昨天的内容MEMORY.md:长期记忆,精心整理的持久化事实,仅在主要私人会话中加载(群组上下文中不加载)
关键点:MEMORY.md 不是直接注入 system prompt 的。它的内容通过向量索引 + BM25 混合检索来召回。当模型需要某段记忆时,它调用 memory_search 工具,系统返回相关片段(约 700 字符上限),模型再通过 memory_get 精读具体行段。
这是一套"先定位,再精读"的渐进式披露机制,目的是控制 token 预算——不是把整个 MEMORY.md 塞进上下文,而是按需取用。
SKILL.md 的加载路径
Skill 的加载走的是完全不同的路:
- 发现阶段:启动时扫描多个目录,找到所有
SKILL.md文件,合并成候选集 - 过滤阶段:根据配置开关、环境依赖、allowlist 等条件筛选出可用 skill
- 注入阶段:把所有可用 skill 的名称和 description 生成
<available_skills>目录清单,直接注入 system prompt - 读取阶段:模型看到目录清单后,如果判断某个 skill 匹配当前请求,才通过 Read 工具读取对应
SKILL.md的完整内容
关键点:skill 的目录清单是 system prompt 的一部分,始终存在;但 skill 的正文内容是按需读取的,作为 toolResult 追加进消息流。
二、触发方式的根本差异
这是两者最核心的区别。
MEMORY.md 是被动召回的。模型不会主动去翻 MEMORY.md,它需要在对话中遇到相关话题,然后主动调用 memory_search 去检索。如果模型没有意识到需要查记忆,或者检索词不准,记忆就不会被用到。记忆的触发依赖模型的判断,不是确定性的。
SKILL.md 是主动匹配的。每次对话,模型都能在 system prompt 里看到完整的 skill 目录清单。只要用户的请求和某个 skill 的 description 明确匹配,模型就会去读那个 skill 的正文。触发是基于 description 的显式匹配,相对确定。
这个差异决定了什么内容适合放哪里:
- 需要"在特定场景下必须被执行"的流程 → Skill(触发更可靠)
- 需要"在相关话题出现时作为背景知识参考"的内容 → Memory(按需召回)
三、内容性质的差异
适合放 MEMORY.md 的内容
MEMORY.md 的官方定位是"决策、偏好和持久性事实"。具体来说:
- 用户的个人偏好("我喜欢简洁的代码风格")
- 项目的关键决策("我们选择了 PostgreSQL 而不是 MySQL,原因是...")
- 调试经验("这个项目的 X 问题是因为 Y,解决方法是 Z")
- 历史上下文("上周我们讨论了 A 方案,最终因为 B 原因放弃了")
- 用户身份信息("我是后端工程师,主要用 Go")
这些内容的特点是:它们是事实,不是指令。它们描述"是什么",而不是"怎么做"。
适合放 SKILL.md 的内容
Skill 的定位是"结构化的操作流程"。具体来说:
- 特定任务的执行步骤("发送大象消息的完整流程")
- 工具的使用规范("如何用 catdesk CLI 操作浏览器")
- 领域专项知识("MRN 项目的代码规范和禁止事项")
- 复杂工作流("从需求到代码提交的完整 AI 辅助流程")
这些内容的特点是:它们是流程,不是事实。它们描述"怎么做",而不是"是什么"。
四、一个容易犯的错误
很多人会把"流程"写进 MEMORY.md,比如:
markdown
# 发送大象消息的流程
1. 先用 catdesk 查找群 ID
2. 然后构造消息体
3. 最后调用发送接口这样写有几个问题:
问题一:召回不确定。MEMORY.md 靠语义检索,如果用户说"帮我发个大象消息",模型不一定会先去搜记忆,它可能直接开始行动,用自己训练数据里的知识来操作,而不是你写的流程。
问题二:内容混杂。MEMORY.md 里既有事实("我的大象 ID 是 xxx")又有流程("发消息的步骤是..."),检索时两类内容会互相干扰,召回质量下降。
问题三:无法强制执行。Skill 的 description 会出现在 system prompt 里,模型每次都能看到。但 MEMORY.md 里的流程只有被检索到才能被看到,而且即使看到了,它的权威性也只是一条 toolResult,不如 system prompt 里的指令有约束力。
正确做法:把流程写成 Skill,把流程执行过程中产生的上下文(比如"这个群的 ID 是 xxx")写进 Memory。
五、上下文预算的影响
两者对 token 预算的影响方式不同。
MEMORY.md 的预算影响是动态的。每次检索只返回约 700 字符的片段,不是全文。整个 MEMORY.md 可以很长,但每次对话消耗的 token 取决于实际检索到的内容量。这是一种"按需付费"的模式。
SKILL.md 的预算影响分两部分:
<available_skills>目录清单是固定成本,每次对话都要消耗(skill 越多,这个成本越高)- skill 正文是变动成本,只有被触发时才消耗
当 skill 数量过多时,OpenClaw 会把目录清单降级为 compact 格式甚至截断,这会影响 skill 的触发准确性。所以 skill 不是越多越好,要控制数量和 description 的质量。
六、生命周期的差异
MEMORY.md 是持续演化的。它随着每次对话不断积累,通过压缩机制(Compaction)在上下文快满时自动触发记忆刷新,把重要内容写入磁盘。它的内容会随时间增长,需要定期整理。
SKILL.md 是相对稳定的。一个 skill 写好之后,除非流程本身发生变化,否则不需要频繁修改。它更像一份操作手册,而不是一个动态增长的日记本。
七、实践建议
判断内容应该放哪里,问自己两个问题:
这是"事实/背景"还是"流程/操作步骤"?
- 事实/背景 → MEMORY.md
- 流程/操作步骤 → SKILL.md
这个内容需要"在特定任务触发时必须被执行",还是"在相关话题出现时作为参考"?
- 必须被执行 → SKILL.md(触发更可靠)
- 作为参考 → MEMORY.md(按需召回)
一个典型的配合使用场景:
假设你要让 AI 帮你管理一个项目的代码审查流程:
- SKILL.md 里写:代码审查的完整步骤(检查哪些维度、用什么工具、输出什么格式)
- MEMORY.md 里写:这个项目的特殊约定("这个项目不用 ESLint,用 Biome")、历史决策("我们决定不强制要求单元测试覆盖率")
Skill 保证流程被正确执行,Memory 保证执行时能用上项目特有的上下文。
八、底层原理总结
| 维度 | MEMORY.md | SKILL.md |
|---|---|---|
| 加载时机 | 会话开始时建立向量索引,按需检索 | 启动时扫描,目录清单注入 system prompt |
| 触发方式 | 模型主动调用 memory_search | 模型匹配 available_skills 目录后读取 |
| 内容性质 | 事实、偏好、历史决策 | 操作流程、执行步骤、工具规范 |
| 权威性 | toolResult(较弱) | system prompt 目录 + toolResult 正文 |
| 预算模式 | 按需付费(片段召回) | 固定成本(目录)+ 变动成本(正文) |
| 生命周期 | 持续积累,动态演化 | 相对稳定,按需更新 |
| 适合内容 | "是什么" | "怎么做" |
两者不是竞争关系,而是互补关系。Memory 是 AI 的"长期记忆",Skill 是 AI 的"操作手册"。一个好的 OpenClaw 配置,应该让两者各司其职:Memory 积累上下文,Skill 规范行为。