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

242 lines
7.2 KiB
Markdown
Raw Permalink 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中文记忆搜索修复
`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>