catalog/repos/abczsl520--openclaw-memory-cn.md

242 lines
7.2 KiB
Markdown
Raw Permalink Normal View History

2026-04-06 22:24:03 +08:00
# OpenClaw中文记忆搜索修复
`OpenClaw` `SQLite` `FTS5` `中文搜索` `Ollama` `记忆优化`
<div align="center">
# 🧠 openclaw-memory-cn
**让 OpenClaw 的中文记忆搜索从「废物」变「能用」**
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![OpenClaw](https://img.shields.io/badge/OpenClaw-2026.3+-blue.svg)](https://github.com/openclaw/openclaw)
[![Ollama](https://img.shields.io/badge/Ollama-compatible-green.svg)](https://ollama.ai)
*55% → 100% 命中率 | 0 代码修改 | 5 分钟部署*
[English](README_EN.md) · [技术分析](#-核心发现fts5-的中文-bug) · [快速开始](#-快速开始) · [效果对比](#-效果对比)
</div>
---
## 😡 你是不是也遇到过这种情况?
```
你: 我老婆怀孕要去哪个医院来着?
AI: 抱歉,我在记忆中没有找到相关信息。
你: ???我明明上周跟你说过啊!!
```
**这不是你的问题,是 SQLite FTS5 的 bug。**
OpenClaw 用 FTS5 做全文搜索,但它的 `unicode61` 分词器会把 `老婆刚怀孕选定广东省妇幼保健院` 当成**一整个 token**。你搜 `怀孕`?不好意思,匹配不上。
本项目用**纯配置方案**0 代码修改)解决这个问题。
## 📊 效果对比
| 指标 | 优化前 | 优化后 | 提升 |
|------|--------|--------|------|
| 中文搜索命中率 | 55% | **100%** | +82% |
| 零召回查询 | 10/20 | **0/20** | 🎉 |
| 最高检索分数 | 0.67 | **0.80** | +19% |
| 记忆体积 | ~780KB | ~460KB | -41% |
> 测试环境OpenClaw 2026.3.2 + qwen3-embedding:0.6b + 80个记忆文件
## 🚀 快速开始
### 30 秒版本(老手)
```bash
# 应用搜索参数 + memoryFlush prompt
openclaw config patch < config/memory-search.json
openclaw config patch < config/memory-flush-prompt.json
# 给项目文件加标签 + 重建索引
python3 scripts/add-tags.py ~/path/to/workspace/memory/projects/
openclaw memory index --force
```
### 5 分钟版本(新手)
**第一步:诊断**
```bash
git clone https://github.com/abczsl520/openclaw-memory-cn.git
cd openclaw-memory-cn
./scripts/diagnose.sh
```
脚本会告诉你:
- ❌ FTS5 是否有中文分词 bug
- ❌ 哪些文件过大需要压缩
- ❌ 哪些项目文件缺少标签
**第二步:优化搜索配置**
```bash
openclaw config patch < config/memory-search.json
```
这会设置:向量搜索权重 0.75(因为 FTS5 中文不可靠)、更小的 chunk size帮助弱模型精确匹配、MMR 去重、时间衰减等。
**第三步:优化写入格式**
```bash
openclaw config patch < config/memory-flush-prompt.json
```
以后 memoryFlush 写日志时会自动:
- 第一行加 `<!-- tags: 关键词 -->` 标签
- 中文关键词空格分隔(`老婆 怀孕` 而非 `老婆怀孕`
- 控制在 5KB 以内
**第四步:清理和标记**
```bash
# 给现有项目文件批量加标签
python3 scripts/add-tags.py ~/workspace/memory/projects/
# 压缩膨胀的日志(>8KB 的压缩到 <5KB
python3 scripts/compress-logs.py ~/workspace/memory/ --max-kb 5
# 清理垃圾文件
./scripts/cleanup.sh ~/workspace/memory/
# 重建索引
openclaw memory index --force
```
**第五步:自动维护(可选但推荐)**
设置每周 cron 自动压缩日志 + 清理 archive + 补标签 + 重建索引:
复制 `templates/cron-job.json` 的内容,通过 OpenClaw 的 cron 功能添加。
## 🔬 核心发现FTS5 的中文 Bug
### 问题
SQLite FTS5 默认的 `unicode61` 分词器把**连续中文字符视为一个 token**
```sql
-- "老婆刚怀孕" 在索引中是 1 个 token
-- 搜索 "怀孕" → 0 results ❌
SELECT * FROM chunks_fts WHERE chunks_fts MATCH '怀孕'; -- → 0 ❌
```
### 证据
从 FTS5 词汇表中查到的实际 token
| 原文 | FTS5 token | 字符数 |
|------|-----------|--------|
| 元宝老婆刚怀孕 | `元宝老婆刚怀孕` | 7 |
| 选定广东省妇幼保健院天河院区 | `选定广东省妇幼保健院天河院区` | 13 |
| 也叫刘二虎 | `也叫刘二虎` | 5 |
### 解决方案
在关键词之间加空格,让 FTS5 把它们索引为独立 token
```
❌ "老婆刚怀孕,选定广东省妇幼保健院" → 1个token
✅ "老婆 刚怀孕,选定 广东省 妇幼保健院" → 4个token搜索可命中
```
详细技术分析见 [docs/fts5-unicode61-bug.md](docs/fts5-unicode61-bug.md)
## 📐 三层记忆架构
```
workspace/
├── MEMORY.md (P0) ← 核心事实,每次启动必读(<2KB
│ ├── 用户关键信息
│ ├── 服务器/凭证(指针)
│ └── 核心工作规则
└── memory/
├── projects/ (P1) ← 项目档案,带 tags 标签
├── lessons/ (P1) ← 经验教训,搜索命中率最高的文件类型
├── YYYY-MM-DD.md (P2) ← 每日日志(自动生成+自动分词)
└── archive/ ← 完整备份30天自动清理
```
模板文件见 [templates/](templates/)
## ⚙️ 推荐参数
| 参数 | 值 | 原因 |
|------|-----|--------|
| `vectorWeight` | 0.75 | FTS5 中文不可靠,向量主导 |
| `textWeight` | 0.25 | FTS5 只对英文和分词后的中文有效 |
| `chunking.tokens` | 250 | 小 chunk 帮助弱模型精确匹配 |
| `chunking.overlap` | 60 | 保证上下文连贯 |
| `minScore` | 0.15 | 小模型分数偏低,阈值要低 |
| `halfLifeDays` | 90 | 项目配置长期有效 |
| `MMR lambda` | 0.7 | 适度去重 |
## 🤔 适用范围
| ✅ 适用 | ❌ 不适用 |
|---------|----------|
| OpenClaw 2026.3+ | 其他 AI 框架 |
| Ollama 本地小模型 | OpenAI/Voyage 云端大模型* |
| 中文为主的使用场景 | 纯英文场景FTS5英文正常 |
| qwen3-embedding:0.6b | text-embedding-3-large |
| nomic-embed-text | voyage-3 |
| mxbai-embed-large | |
*云端大模型用户:文件结构和 memoryFlush prompt 仍然适用,但搜索参数需要调整(大模型不需要这么极端的 vectorWeight
## 📈 为什么这些优化有效
```
写入时优化memoryFlush prompt
tags 标签 → FTS5 精确命中 ✅
中文空格 → FTS5 正确分词 ✅
大小控制 → chunk 更精确 ✅
搜索时优化config 参数)
vectorWeight 0.75 → 绕过 FTS5 中文缺陷 ✅
小 chunk → 弱模型更容易匹配 ✅
低 minScore → 不漏掉低分但相关的结果 ✅
MMR → 不重复返回相似内容 ✅
维护时优化cron job
压缩旧日志 → 减少噪音 ✅
补 tags → 新文件也有标签 ✅
重建索引 → 保持索引新鲜 ✅
```
## 🤝 贡献
欢迎提交 Issue 和 PR特别欢迎
- 📊 其他小模型nomic-embed-text、mxbai 等)的测试数据
- 🇯🇵🇰🇷 日文/韩文的 FTS5 分词问题验证(理论上同样受影响)
- 🔧 更好的中文分词解决方案
- 📝 其他语言的翻译
## ⭐ Star 历史
如果这个项目帮到了你,请给个 Star ⭐ 让更多人看到!
## 📄 许可证
[MIT](LICENSE)
---
<div align="center">
*从实际生产环境中总结,所有数据均为真实测试结果。*
**[OpenClaw](https://github.com/openclaw/openclaw)** · **[Ollama](https://ollama.ai)** · **[SQLite FTS5](https://www.sqlite.org/fts5.html)**
</div>