背景 链接到标题
在 OpenClaw 的对话系统中,每次回复前的上下文由以下几个部分组成:
- 静态文件——
AGENTS.md、MEMORY.md、SOUL.md等 workspace bootstrap 文件在会话开始时注入 - Active Memory——可选的子 agent,在每次回复前自动运行
memory_search/memory_get,将检索到的记忆以隐藏前缀注入 prompt - memory_search / memory_get 工具——Agent 可以在对话中主动调用这些工具搜索历史记忆
其中 memory_search 的检索能力由 memory-core 插件提供。
Memory-Core 的检索架构 链接到标题
memory-core 的默认后端是 builtin(SQLite 引擎),采用混合检索(hybrid search)策略:向量搜索和 BM25 关键词搜索两路并行执行后按权重合并。
| 检索路径 | 技术 | 权重 |
|---|---|---|
| Vector search | bge-m3 embedding, 1024 维 | 0.7 |
| BM25 keyword search | SQLite FTS5 | 0.3 |
向量搜索负责语义匹配,BM25 负责字面关键词匹配。
问题:中文 BM25 检索效果差 链接到标题
根因 链接到标题
SQLite FTS5 默认的 unicode61 tokenizer 在处理 CJK(中文/日文/韩文)文本时,会将连续的中文字符合并成单个 token。例如 "混合检索配置说明" 这 7 个字在 FTS5 索引中是一个 token,搜索 "检索配置" 无法匹配。
官方文档提到了 CJK 支持 via trigram tokenizer,但 trigram 方案也有实现 bug,导致中文查询的 BM25 分数始终为 0。
相关 Issue 链接到标题
-
[#92061]
memory-core: CJK text FTS5 search returns textScore=0 with trigram tokenizerhttps://github.com/openclaw/openclaw/issues/92061 -
[#92164]
fix(memory-core): score CJK keyword search instead of textScore=0 with trigram FTS5(修复 PR,未合入) https://github.com/openclaw/openclaw/pull/92164 -
[#83384]
BM25 full-text search returns 0 results for Chinese queries with multiple termshttps://github.com/openclaw/openclaw/issues/83384 -
QMD #617
BM25 / FTS5 returns zero hits for CJK queries(第三方项目同样问题) https://github.com/tobi/qmd/issues/617
当前应对 链接到标题
保持现状,调整混合检索权重 链接到标题
当前配置的 vectorWeight=0.7、textWeight=0.3 已经偏向向量搜索。bge-m3 embedding 模型对中文语义理解质量良好,向量检索基本不受影响。BM25 部分即使贡献低,整体检索效果仍在可接受范围。
如果需要进一步规避 BM25 问题,可以调高 vectorWeight:
{
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
vectorWeight: 0.9,
textWeight: 0.1,
},
},
},
},
},
}
暂不切换 QMD 链接到标题
QMD 项目同样使用 SQLite FTS5 做 BM25,存在完全一样的中文 tokenizer 问题。虽有几个修复 PR(bigram、n-gram),但均未合入。
自定义插件补充中文 BM25 检索 链接到标题
如果未来需要更好的中文 BM25 检索,OpenClaw 插件 SDK 提供了 registerMemoryCorpusSupplement 接口,可以将自定义检索结果合并到 memory_search 的返回中。memory-wiki 插件就是用这个接口把自己的 wiki 数据注入到混合检索结果中的。
实现思路:
- 编写一个 OpenClaw 插件,内部使用
nodejieba对中文内容分词 - 分词后以空格分隔写入 SQLite FTS5(此时 unicode61 可以正确按词分割)
- 检索时同样对中文 query 做 jieba 分词后走 BM25
- 通过
registerMemoryCorpusSupplement注册为 memory_search 的补充 corpus - memory-core 原有的向量检索和 dreaming 不受影响,BM25 结果合并返回
这种方式是增量补充,不需要替换 memory-core,复杂度可控。
后续 链接到标题
上游 PR #92164 修复了 trigram 下的两个 bug(CJK token 拆分 + MATCH 空结果回退 LIKE),合入后升级即可恢复正常的混合搜索权重。届时可以将 vectorWeight 调回默认比例。
如果需要更精准的中文字面检索,自定义插件补充 jieba 分词 BM25 是中期可行的方向。