Files
memory_research/OpenClaw对话和记忆优化初步方案.md

302 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenClaw 对话和记忆优化初步方案
> 研究日期2026-02-17
> 研究者Ami + 阿米狗
> 状态:已实施并上线
---
## 背景与目标
OpenClaw 默认配置下存在两个核心痛点:
1. **对话 context 超限**会直接中断会话,体验割裂
2. **记忆搜索被禁用**(需要 OpenAI/Gemini/Voyage API key成本高
本方案目标:在不依赖任何外部 API key 的前提下,实现:
- 对话 context 的主动管理(不被动等爆)
- 本地向量语义搜索(完全离线)
- 跨会话记忆自动恢复
---
## 核心约束
> 我们假设暂时解决不了对话 context 上限这一概念和顶层限制200k token 硬上限由模型决定,无法改变)。
> 因此,所有优化都是在这个硬上限内做最大化利用。
---
## 三步方案
### Step 1 — Token 优化 + 自动压缩
**问题**context 默认无上限地增长,直到 API 报错才触发压缩,体验差。
**解决**
| 配置项 | 值 | 作用 |
|--------|-----|------|
| `contextTokens` | `120000` | 软上限,到达后触发剪枝(低于模型 200k 硬上限,留出安全边际) |
| `contextPruning.mode` | `cache-ttl` | 在 Anthropic 缓存 TTL 到期前删除老 tool output减少 cacheWrite 费用 |
| `contextPruning.keepLastAssistants` | `3` | 保留最近 3 条 assistant 消息,删除更早的 |
| `compaction.mode` | `safeguard` | 确保 Pi runtime 的 compaction 有足够预留空间 |
| `compaction.reserveTokensFloor` | `20000` | compaction 预留底线 20k token防止压缩时空间不足 |
**原理**:把原来的"被动爆仓"改成"主动管理",在 context 超限前就开始清理。
---
### Step 2 — 新会话自动恢复历史QMD 本地向量搜索)
**问题**`memory_search` 工具默认需要 OpenAI/Gemini/Voyage embedding API没有 key 则完全禁用。
**解决**:安装并启用 **QMD**Quick Markdown / 本地向量搜索引擎)
#### QMD 是什么
- GitHub: [tobi/qmd](https://github.com/tobi/qmd)
- OpenClaw 官方支持的实验性本地搜索后端
- 技术栈BM25 + 向量node-llama-cpp+ reranking
- **完全本地运行**GGUF 模型首次自动下载,无 API key 需求
#### 安装步骤
```bash
# 1. 安装 BunQMD 运行时)
curl -fsSL https://bun.sh/install | bash
# 2. 安装 QMD
bun install -g https://github.com/tobi/qmd
# 3. 解锁 postinstallbun 默认阻止)
cd ~/.bun/install/global && bun pm trust --all
# 4. 补充缺失的 @types/node 并 build
cd ~/.bun/install/global/node_modules/@tobilu/qmd
bun add -d @types/node && bun run build
# 5. 验证
qmd --version # → qmd 1.0.6
```
**注意**`bun install -g` 安装的 qmd 包没有预编译 dist需要手动 build TypeScript 源码。这是一个安装坑,已记录。
#### OpenClaw 配置
```json
{
"memory": {
"backend": "qmd",
"citations": "auto",
"qmd": {
"command": "/Users/mini/.bun/bin/qmd",
"includeDefaultMemory": true,
"sessions": {
"enabled": true,
"retentionDays": 30
},
"update": {
"interval": "5m",
"debounceMs": 15000
},
"limits": {
"maxResults": 6,
"timeoutMs": 4000
},
"scope": {
"default": "deny",
"rules": [{ "action": "allow", "match": { "chatType": "direct" } }]
}
}
}
}
```
**关键配置说明**
- `backend: "qmd"` — 切换为本地引擎(替代内置 SQLite 索引)
- `sessions.enabled: true` — 自动导出 session 对话记录到 QMD 索引(实现跨会话搜索)
- `retentionDays: 30` — 保留 30 天历史
- `scope.rules` — 仅限直接私聊可搜索(不在群组里暴露私人记忆)
- `citations: "auto"` — 搜索结果自动附带来源文件路径
**效果**:新会话开始时,`memory_search` 可以检索过去 30 天的对话历史摘要和记忆文件,自动恢复上下文。
---
### Step 3 — Context 快满时自动提醒
**问题**:用户不知道 context 什么时候快满,只能被动等待中断。
**解决**:在压缩前的"软阈值"触发主动通知
#### 工作流程
```
context 使用量
[120k 软上限] → contextPruning 开始清理老消息
[还剩 ~5k token] → memoryFlush 触发(比 compaction 更早)
├── 1. 把重要上下文写入 memory/YYYY-MM-DD.md
└── 2. 发 Telegram 通知:⚠️ 对话快满了,建议发 /new
[用户发 /new 开启新会话]
[新会话] → memory_search 自动检索历史 → 无缝续接
```
#### 配置
```json
{
"agents": {
"defaults": {
"compaction": {
"memoryFlush": {
"enabled": true,
"softThresholdTokens": 5000,
"prompt": "Context is nearing the compaction limit. Do TWO things:\n1. Write important context/decisions from this conversation to memory/YYYY-MM-DD.md (today's date).\n2. Use the message tool to send a Telegram notification to the user (target: 5588544200, channel: telegram) saying: '⚠️ 对话快满了,建议发 /new 开启新会话,我会自动从历史记忆中恢复上下文。'\nReply with NO_REPLY after completing both steps.",
"systemPrompt": "Pre-compaction housekeeping: persist memories and notify user. Silent turn."
}
}
}
}
}
```
**原理**
- `softThresholdTokens: 5000` — 在 Pi runtime 触发 compaction **之前** 5000 token 就介入
- `prompt` 中的双任务:写记忆 + 发通知
- `NO_REPLY` — 对话中不显示任何内容(静默操作),但 tools 仍然执行Telegram 消息照常发)
---
## 整体架构图
```
用户对话
[OpenClaw Gateway]
├── contextTokens: 120k → 软上限保护
├── contextPruning: cache-ttl → 清理老 tool output
├── [context 剩 5k] → memoryFlush 触发
│ ├── 写 memory/YYYY-MM-DD.md
│ └── 发 Telegram 通知 → 用户
├── compaction: safeguard → 自动压缩摘要(最后防线)
└── [用户 /new 开新会话]
[新会话启动 — AGENTS.md 规则]
├── 自动读取 MEMORY.md系统注入
├── 自动读取 memory/今日+昨日.md系统注入
└── 自动调用 memory_search("最近对话 上下文")
QMD 本地向量索引(上限 5k tokens
├── MEMORY.md长期记忆
├── memory/*.md日志
└── sessions/*.jsonl30天对话历史
自动恢复上下文,无缝续接
```
---
## Step 4 — 新会话自动触发历史检索AGENTS.md 规则)
**问题**QMD 搜索是"按需"的,新会话开始时需要主动触发,否则历史上下文不会自动加载。
**解决**:在 `AGENTS.md` 的"每次会话"规则中加入自动搜索指令。
#### 触发机制说明
| 层级 | 内容 | 加载方式 |
|------|------|----------|
| `MEMORY.md` | 长期记忆(核心事实、偏好) | 系统自动注入 context |
| `memory/YYYY-MM-DD.md` | 今日 + 昨日日志 | 系统自动注入 context |
| QMD session 历史 | 近 30 天对话记录 | **需调用 `memory_search` 触发** |
#### AGENTS.md 新增规则
```markdown
## Every Session
Before doing anything else:
1. Read SOUL.md — this is who you are
2. Read USER.md — this is who you're helping
3. Read memory/YYYY-MM-DD.md (today + yesterday) for recent context
4. **If in MAIN SESSION**: Also read MEMORY.md
5. **If in MAIN SESSION**: Run memory_search("最近对话 上下文") to retrieve
relevant history from QMD — restore any ongoing topics or tasks automatically
```
**Token 消耗评估**
| 场景 | 消耗 |
|------|------|
| QMD 本地搜索计算 | 0纯本地 |
| 搜索结果注入 context | 1k5k tokens |
| 上限(`maxInjectedChars: 20000` | ~5000 tokens 硬上限 |
**`maxInjectedChars` 的作用**:无论搜到多少内容,最终注入 context 的字符数不超过 20000约 5000 tokens防止历史检索本身消耗过多 context 空间。
#### QMD limits 完整配置
```json
{
"memory": {
"qmd": {
"limits": {
"maxResults": 6,
"maxSnippetChars": 700,
"maxInjectedChars": 20000,
"timeoutMs": 4000
}
}
}
}
```
**效果**:开新会话后无需任何提示,我会自动检索近期历史并将相关上下文带入当前会话,实现无缝续接。
---
## 当前局限性
1. **QMD 首次搜索较慢**:需要自动下载 GGUF 模型reranker + query expansion约几百 MB
2. **session 索引延迟**:对话结束后才导出,不是实时的
3. **根本上限无法突破**200k token 硬上限由 Anthropic 决定,所有优化只是更好地利用这 200k
4. **QMD build 依赖**:安装时需要手动 build TypeScriptbun 全局安装的包缺少 dist 目录,已知坑)
---
## 文件位置
| 文件 | 说明 |
|------|------|
| `~/.openclaw/openclaw.json` | 所有配置的实际存储位置 |
| `/Users/mini/clawd/MEMORY.md` | 长期记忆(每次主会话加载) |
| `/Users/mini/clawd/memory/YYYY-MM-DD.md` | 每日日志 |
| `~/.openclaw/agents/main/qmd/` | QMD 索引数据库 + 缓存 |
| `~/.openclaw/agents/main/sessions/*.jsonl` | 对话历史(被 QMD 索引)|
---
## 后续可探索方向
- **3层记忆架构**@Ktaohzk 方案Fact/Belief 分层 + 衰减评分,进一步减少 token 占用
- **session memory search 实验性功能**`memorySearch.experimental.sessionMemory: true`(内置 SQLite 版的 session 索引,与 QMD sessions 二选一)
- **混合搜索调优**:调整 `vectorWeight` / `textWeight` 比例优化检索精度
- **embedding 缓存**`memorySearch.cache.enabled: true` 避免重复 embedding
---
*本文档由 Ami + 阿米狗共同研究整理2026-02-17v1.1 更新于同日*