> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/openclaw_guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/openclaw_guide/di-er-bu-fen-jin-jie-shi-yong/06_context_memory/6.3_memory_mechanism.md).

# 6.3 记忆机制：写入、检索与失效

本节以官方记忆系统为准讲清“记忆存在哪里、如何被检索、如何避免污染”。OpenClaw 的长期记忆以工作区文件为中心，并配套向量索引与内置记忆工具（例如 `memory_search`、`memory_get`）。掌握这些机制后，才能把记忆从“越积越乱”变成“可维护资产”。

## 6.3.1 双层记忆结构：MEMORY.md 与每日日志

根据官方设计，OpenClaw 的记忆基于“文件即真相（files are the source of truth）”的思想存储于工作区，主要由两层组成：

* **长期记忆（`MEMORY.md`）**：存放精选持久化偏好、配置决定与沉淀经验，放在工作区根目录。
  * **安全与隐私边界**：更稳妥的说法是，`MEMORY.md` 主要面向主会话/私密上下文使用；但它的自动注入范围会受具体 session 类型、bootstrap 缩减规则与版本实现影响，不应写成“绝不会进入群聊”这样的绝对规则。
* **每日日志（`memory/YYYY-MM-DD.md`）**：存放阶段性项目进展、当天的探讨细节。当前实现更接近“作为 startup context / bare `/new`、`/reset` 的首轮 prelude 读取最近 N 天”，默认常见值是“今天加昨天”，但这不是所有会话、所有轮次都无条件固定执行的规则。

这种设计的工程意义是：把“可复用事实”与“过程噪声”分开，让事后的检索与上下文注入保持清爽的信噪比。

## 6.3.2 写入规则与时机：仅记录有价值的事实

官方关于“何时写入记忆”的 **最佳实践** 建议如下：

* **写入 `MEMORY.md`**：记录高价值的用户偏好、重要决策或稳定状态配置。
* **写入 `memory/YYYY-MM-DD.md`**：记录频繁但阶段性的开发操作、项目调试进度的日常流水。
* **立即写入**：无论何时，当用户明确表达“记住这个（remember this）”时，第一时间将该条目持久化。

此外，记忆写入最常见的失败是 **将推测当作事实**。我们建议把写入规则收敛为以下硬约束：

* **稳定**：跨会话复用，短期不易过期。
* **可追溯**：必须来自工具明确回执或有显式确诊依据，而不是基于大模型的一句猜测推理。
* **可纠错**：允许随时撤销更新替换，拒绝将错误信息永久固化。

**实战防坑：坏记忆与好记忆**

* ❌ **坏记忆（模型的主观推测或短时情绪记录）**：“用户今天好像心情不好，且遇到了一个难以排查的 Node.js OOM BUG。”这种文字明天就失效了，且浪费 Token。
* ✅ **好记忆（客观、可追溯的事实与参数配置）**：“用户偏好默认在工作流脚本中使用 Python。当前生产 Kubernetes 集群为 `prod-cluster-us`，且需使用指定服务账号运维（来源：2 月 20 日会话）。”

操作示例：在 `MEMORY.md` 用结构化小节记录事实，并附带来源与更新时间；在 `memory/YYYY-MM-DD.md` 记录过程性日志。

```md
## 部署区域

- 结论：生产环境部署在 us-east-1
- 来源：变更单 CHG-12345
- 更新时间：YYYY-MM-DD
```

## 6.3.3 检索机制：混合向量搜索与精确读取

针对存储的内容（`MEMORY.md` 加上 `memory/**/*.md`）中的各类碎片，官方记忆工具提供了两种主流检索方式：

* **记忆搜索：`memory_search`**— 默认采用 **混合搜索算法（BM25 加上向量相似度）**，将数据切成小块（400 token/分块并设置小额重叠带）。返回带详细文件路径和行号的查询片段。
* **精确读取：`memory_get`** — 基于已有依据读取内容，精确命中特定行，防止信息污染。

**常见配置陷阱：embedding API 密钥依赖**

`memory_search` 的语义检索能力通常需要独立的 embedding 供应商（默认走 OpenAI，也可显式改为 Gemini、Voyage、Mistral、Bedrock、Ollama 或本地 GGUF 等）。即使主对话模型使用的是 Claude，也常常需要额外配置 embedding 能力。这里有一个**容易踩反的分叉**：**缺少 embedding 并不总是等于记忆搜索完全失效，但也不总是会静默降级**——`memory.search.provider` 未设置、写成 `"auto"`、显式写成 `"none"`（有意只用关键词）或 `"local"` 时，检索会退化到 lexical / keyword 路径，只是相关性与跨表述匹配明显下降；而一旦**显式指定**了某个远端 provider（如 `openai`、`gemini`、`ollama`）却在请求时不可用，`memory_search` 会直接报告记忆不可用（fail closed），而不是悄悄给你一份关键词结果。请在 `openclaw.json` 中确认 embedding 相关配置是否就绪，并通过日志或 `doctor` 观察索引与 provider 状态。

**可调的是结果闸门，不是混合权重**

记忆搜索的配置面统一收在顶层 `memory.search`（按智能体覆盖走 `agents.entries.*.memory.search`）。混合检索本身常开，向量与关键词的权重、recency 衰减半衰期与 MMR 多样性系数都是内建的固定实现，**没有对外暴露的权重旋钮**；当前 `memory.search.query` 下可调的只有两项：

```jsonc
{
  memory: {
    search: {
      query: {
        maxResults: 6,    // 注入前返回的最大命中数
        minScore: 0.35    // 命中所需的最低相关性分数
      }
    }
  }
}
```

想收紧噪音就压 `maxResults` 或抬 `minScore`，而不是去找“把向量权重调高一点”的字段。

操作要点：检索结果永远要遵循少而精的逻辑。把大量候选项一股脑子全灌入上下文，只会起到让模型“盲目重视全体噪音”的副作用。

## 6.3.4 索引构建管线：从文件保存到可检索

混合检索的前提是索引已就绪。OpenClaw 的索引管线在文件落盘后自动运行，无需手动触发。从使用者角度只需知道两件事：

* **延迟约 2 秒**：文件保存后系统自动重建索引，期间有防抖机制避免高频写入导致重复构建。
* **验收方法**：修改任意记忆文件后，等待约 2 秒，用 `memory_search` 检索刚写入的关键词。如果能命中则索引管线正常工作；如果结果只有关键词命中、没有明显语义召回，再优先检查 embedding provider 配置（见 6.3.3）。

> \[!NOTE] **可选深潜：索引管线内部实现**
>
> 对于需要排查“改了文件却检索不到”问题的开发者，以下是管线的内部流程：
>
> 1. **监听与防抖**：系统使用 Chokidar 对 `MEMORY.md` 和 `memory/*.md` 实时监听，设置 1.5 秒防抖延迟——文件连续变化时，只有最后一次保存后 1.5 秒静默期过后才启动索引。
> 2. **分块策略**：文件内容按约 400 token 为单位分块，相邻块保留 80 token 重叠区域，防止关键语义被切断。
> 3. **向量生成与存储**：每个文本块送入 embedding 模型（默认 `text-embedding-3-small`，1536 维），结果存入本地 SQLite 数据库。当前核心表包括 `files`、`chunks`、`chunks_fts`，以及可选的 `embedding_cache`；embedding 数据保存在 `chunks.embedding` 等字段中。

## 6.3.5 失效与清理：让记忆有生命周期

长期系统一定会遇到“事实过期”。建议为每条记忆补齐“来源/更新时间/有效期”，并定期做一次复核：

* 过期条目标注失效或迁移到每日日志。
* 新事实覆盖旧事实时保留变更链。
* 对冲突事实显式标注冲突点，避免模型自行选择。

> \[!TIP] 踩坑实录：记忆搜索“语义检索退化”之谜
>
> 配好了 Anthropic API Key 就认为配置完毕，却发现 `memory_search` 的效果一直很差。调试后才发现：记忆搜索的高质量语义检索通常需要**独立的 embedding 能力**（OpenAI、Gemini、Voyage 或本地 provider），与主对话模型的密钥相独立。没有 embedding 时，未指定 provider 的配置往往会退化为关键词检索而不是完全报错；但如果你**显式**指定了一个远端 provider 而它不可用，记忆搜索会直接判为不可用，好让坏配置暴露出来。建议配置后用 `openclaw doctor` 或相关状态命令验证 embedding provider 状态。
