| 1 | # 用户记忆 |
| 2 | |
| 3 | > 英文原文:[MEMORY.md](../MEMORY.md)。 |
| 4 | > 最后与英文同步日期(last synced with English revision):2026-09-29。 |
| 5 | |
| 6 | 用户记忆给模型提供一小块本地持久存储,用来存放应当跨会话保留的偏好和约定—— |
| 7 | “我更喜欢 pytest 而不是 unittest”、“这个代码库用 4 空格缩进”——这样就不用每次 |
| 8 | 对话都重复一遍。 |
| 9 | |
| 10 | 从 v0.9.4 起,**原生记忆存储**是唯一的记忆系统。它由 Markdown 文件组成, |
| 11 | 用 SQLite FTS5 建索引,完全离线,作用范围按仓库 git origin 的哈希划分。 |
| 12 | 旧的单文件(`~/.deepseek/memory.md`)推送/注入路径,以及计划中的 Moraine MCP |
| 13 | 后端,都已移除。仓库里从未发布过 Moraine 服务器,而原生存储已经提供了同样的架构: |
| 14 | 持久的 Markdown 数据源,加上可重建的搜索索引。 |
| 15 | |
| 16 | 记忆需要**主动启用**。默认禁用状态下,不会加载任何内容,不会拦截任何输入, |
| 17 | `remember` 工具也不会出现在模型面前。 |
| 18 | |
| 19 | ## 启用记忆 |
| 20 | |
| 21 | 方式一,设置环境变量: |
| 22 | |
| 23 | ```bash |
| 24 | export DEEPSEEK_MEMORY=on |
| 25 | ``` |
| 26 | |
| 27 | 可接受的“真值”有 `1`、`on`、`true`、`yes`、`y` 和 `enabled`。 |
| 28 | |
| 29 | 或者,在 `~/.codewhale/config.toml` 里添加: |
| 30 | |
| 31 | ```toml |
| 32 | [memory] |
| 33 | enabled = true |
| 34 | ``` |
| 35 | |
| 36 | 切换后需要重启 TUI。关闭记忆就是反过来做同样的设置。 |
| 37 | |
| 38 | ## 目录结构 |
| 39 | |
| 40 | 存储放在旧版 `memory_path` 锚点旁边,是一个 `memory/` 目录。默认的 |
| 41 | `memory_path = "~/.codewhale/memory.md"` 会重新落到 `~/.codewhale/memory/`: |
| 42 | |
| 43 | ```text |
| 44 | ~/.codewhale/memory/ |
| 45 | ├── global/MEMORY.md # user-scoped notes (follow you everywhere) |
| 46 | ├── workspace/<id>/MEMORY.md # repo-scoped notes (hash of git origin) |
| 47 | └── index.sqlite3 # rebuildable SQLite FTS5 cache |
| 48 | ``` |
| 49 | |
| 50 | 作用域目录是 `workspace`(单数)——见 `MemoryScope::directory`, |
| 51 | `crates/runtime/src/native_memory.rs:31-36`。索引文件名是 `index.sqlite3` |
| 52 | (`native_memory.rs:175`)。 |
| 53 | |
| 54 | Markdown 是持久的数据源;`index.sqlite3` 是可丢弃的全文缓存 |
| 55 | (用 `/memory native reindex` 重建)。配置的 `memory_path` **只是一个锚点**: |
| 56 | 文件名会被丢掉,父目录里会多出一套 `memory/global/MEMORY.md` 目录树。 |
| 57 | 不要把 `memory_path` 设成原生布局本身的路径——那样目录树会多套一层。 |
| 58 | 随包提供的示例保留 `~/.codewhale/memory.md`,所以存储最终落在 |
| 59 | `~/.codewhale/memory/global/MEMORY.md`。 |
| 60 | |
| 61 | ## 注入什么内容 |
| 62 | |
| 63 | 启用记忆后,系统提示词里会带上一段记忆条目:有大小上限,带来源标记, |
| 64 | 最多 32 条 / 12,000 字符,涵盖全局作用域和当前工作区作用域。这段内容外面包了一层标记, |
| 65 | 标明它是**不可信的用户数据**,而不是第二层指令。注入部分之外还需要更多内容时, |
| 66 | 模型可以对 FTS5 索引调用 `memory_search` / `memory_get` 工具。 |
| 67 | |
| 68 | 初始记忆快照属于会话开始时冻结的提示词前缀。会话过程中发现的变更会作为历史追加, |
| 69 | 具体见 [CACHE.md](./CACHE.md);原生笔记更新和外部召回,都不得在每一回合 |
| 70 | 重写系统提示词或工具目录。 |
| 71 | |
| 72 | ## 三种添加记忆的方式 |
| 73 | |
| 74 | ### 1. 输入框里的 `# ` 前缀(#492) |
| 75 | |
| 76 | 在输入框里输入以 `#` 开头(但不是 `##` 或 `#!`)的单行内容: |
| 77 | |
| 78 | ``` |
| 79 | # remember to use 4-space indentation in this repo |
| 80 | ``` |
| 81 | |
| 82 | TUI 会拦截这行输入,并通过模型工具所用的同一条 `NativeMemoryStore::remember` |
| 83 | 路径,把笔记追加到**全局**原生存储。**不会触发回合**——这行输入会被直接收走, |
| 84 | 状态行会显示写入了哪个文件,你可以接着输入真正想问的问题。 |
| 85 | |
| 86 | 多个 `#` 组成的前缀会刻意当成普通回合提交,这样粘贴 Markdown 标题时 |
| 87 | 不会有意外。 |
| 88 | |
| 89 | ### 2. `/memory` 斜杠命令 |
| 90 | |
| 91 | 用来查看和维护原生存储: |
| 92 | |
| 93 | `/memory` 分成两部分。不带 `native` 的子命令,针对的是 `config.memory_path()` |
| 94 | 指向的那个单文件;原生存储的功能全在 `/memory native …` 之下 |
| 95 | (`crates/tui/src/commands/groups/memory/memory.rs:236-268`)。 |
| 96 | |
| 97 | | 子命令 | 效果 | |
| 98 | |-----------------|-----------------------------------------------------------| |
| 99 | | `/memory` | 打印 `memory_path` 文件的路径和内容 | |
| 100 | | `/memory show` | 等同于裸 `/memory` | |
| 101 | | `/memory path` | 打印 `memory_path` 文件的位置 | |
| 102 | | `/memory clear` | 清空该文件 | |
| 103 | | `/memory edit` | 打印针对它的 `$EDITOR` 调用命令 | |
| 104 | | `/memory help` | 显示该命令的帮助 | |
| 105 | |
| 106 | 其他任何输入都会返回 `unknown subcommand`。原生存储通过 `native` 前缀访问 |
| 107 | (`memory.rs:221`): |
| 108 | |
| 109 | | 子命令 | 效果 | |
| 110 | |-----------------------------------------|-------------------------------------| |
| 111 | | `/memory native status` | 存储根目录、当前生效的数据源、索引 | |
| 112 | | `/memory native path` | 原生存储根目录 | |
| 113 | | `/memory native remember [global\|workspace] <note>` | 追加一条笔记 | |
| 114 | | `/memory native search <query>` | FTS5 搜索 | |
| 115 | | `/memory native get <id>` | 读取一条条目 | |
| 116 | | `/memory native reindex` | 重建 FTS5 索引 | |
| 117 | | `/memory native import` | 导入旧的单文件存储 | |
| 118 | | `/memory native export` | 导出条目 | |
| 119 | | `/memory native delete [all\|global\|workspace]` | 删除条目 | |
| 120 | |
| 121 | 没有 `/memory add`,也没有不带 `native` 的 `/memory reindex`;请用 |
| 122 | `/memory native remember` 和 `/memory native reindex`。 |
| 123 | |
| 124 | ### 3. `remember` 工具(自动捕获,#489) |
| 125 | |
| 126 | 启用记忆后,模型会得到一个 `remember` 工具: |
| 127 | |
| 128 | ```json |
| 129 | { |
| 130 | "name": "remember", |
| 131 | "input_schema": { |
| 132 | "type": "object", |
| 133 | "properties": { |
| 134 | "note": { "type": "string" }, |
| 135 | "scope": { "type": "string", "enum": ["global", "workspace"] } |
| 136 | }, |
| 137 | "required": ["note"] |
| 138 | } |
| 139 | } |
| 140 | ``` |
| 141 | |
| 142 | 模型一旦发现值得跨会话保留的东西——偏好、约定或事实——就会用它记下来。 |
| 143 | 这个工具会自动批准:写入范围限定在用户自己的记忆文件里,要是还得走标准的 |
| 144 | 写入审批流程,自动记忆捕获就失去意义了。工作区作用域要求有一个带 `origin` |
| 145 | remote 的 git 仓库(作用域 id 就是它的哈希)。 |
| 146 | |
| 147 | ## 什么不该写进记忆 |
| 148 | |
| 149 | 记忆只存放**持久**的信号。下面这些不应该放进去: |
| 150 | |
| 151 | - **机密信息**——不要放 API 密钥、令牌、密码。这些文件是磁盘上的明文, |
| 152 | 条目还会被注入系统提示词。 |
| 153 | - **临时任务状态**——“我现在正在改解析器”每次会话都会变,不属于跨会话记忆。 |
| 154 | - **对话片段**——引文式的笔记应该写进笔记工具(`note`),不是记忆。 |
| 155 | - **长篇指令**——超过几句话的内容应该放在 `AGENTS.md`(项目级)或技能(skill)里。 |
| 156 | |
| 157 | ## 隐私与作用域 |
| 158 | |
| 159 | 原生存储保存在你自己的机器上,不会自动同步到云端记忆服务。启用记忆后, |
| 160 | 召回的记忆条目会作为提示词上下文发送给所选的提供商(provider)。不要把机密写进去。 |
| 161 | 工作区作用域的记忆以仓库 git origin 的哈希为键,因此一个仓库的笔记永远不会 |
| 162 | 泄漏到另一个仓库的提示词里。 |
| 163 | |
| 164 | ## 外部记忆服务 |
| 165 | |
| 166 | 持久记忆靠原生存储就已经能用了。一等后端选择目前只接受 `native` 和 `off`; |
| 167 | 没有受支持的 `external`、`mem0` 或 `memcode` 后端设置。 |
| 168 | |
| 169 | 第三方记忆服务可以通过现有的 [MCP](./MCP.md) 或[插件](./PLUGINS.md)集成来提供 |
| 170 | 工具。那些工具是服务自己的,不会替代 `remember`、`memory_search`、 |
| 171 | `/memory native`,也不会替代 `#` 快捷添加路径。启用之前,先看看插件要哪些权限, |
| 172 | 以及服务会把数据送到哪里。外部服务不可用时必须如实报告失败,而不是悄悄把笔记发到别的 |
| 173 | 后端。 |
| 174 | |
| 175 | 未来的一等后端,必须在每个记忆入口覆盖捕获、搜索、纠正、删除, |
| 176 | 以及作用域和错误报告。它还必须在上面的缓存契约下,把易变的召回内容放进只追加的历史里。 |
| 177 | 这次完整迁移记录在 [#6050](https://github.com/codewhale-hq/CodeWhale/issues/6050) 里。 |
| 178 | 0.9.13 没有声称完成这次迁移,也没有声称提供商业记忆集成。 |
| 179 | |
| 180 | ## 配置参考 |
| 181 | |
| 182 | ```toml |
| 183 | # ~/.codewhale/config.toml |
| 184 | [memory] |
| 185 | enabled = true # default false; or set DEEPSEEK_MEMORY=on |
| 186 | # Optional explicit backend selection: |
| 187 | # backend = "native" # "native" or "off" (default: off) |
| 188 | ``` |
| 189 | |
| 190 | | 设置项 | 默认值 | 覆盖方式 | |
| 191 | |-----------------------|-------------------------------|---------------------------------------| |
| 192 | | 记忆开关 | `false` | `[memory] enabled = true` 或 `DEEPSEEK_MEMORY=on` | |
| 193 | | 后端 | `off` | `[memory] backend = "native"` | |
| 194 | | 存储根目录 | `~/.codewhale/memory/` | 由 `memory_path` 推导 | |
| 195 | |
| 196 | ## 相关文档 |
| 197 | |
| 198 | - `docs/SUBAGENTS.md`——子智能体(sub-agent)会继承记忆,也可以使用 `remember` 工具。 |
| 199 | - `docs/CONFIGURATION.md`——完整的配置参考。 |
| 200 | - Issue [#489](https://github.com/codewhale-hq/CodeWhale/issues/489) |
| 201 | ——跟踪这项工作的第一阶段 EPIC。 |
| 202 |