Skip to content

memory_search 向量查询使用全表扫描,有 190 倍加速空间(sqlite-vec KNN 未生效)

问题

memory_search 工具调用时(in-gateway 路径)响应极慢,随着记忆条目增加,搜索时间线性增长。

根本原因searchVector 使用了非索引的全表扫描模式——在 SELECT 中直接调用 vec_distance_cosine(...) 并配合 ORDER BY ... LIMIT,而非使用 sqlite-vec 提供的 KNN 虚表索引(MATCH 语法)。

社区测试数据:切换为 KNN 查询后实测约 190 倍速度提升。

影响版本:OpenClaw 2026.4.15

解决方案

方案一:等待官方修复

该 bug 已提交性能优化报告,关注后续版本 release notes。

方案二:理解规避方式

限制 memory 条目总量可以缓解问题。较小的知识库受影响程度更低(全表扫描在小数据集上仍然快):

yaml
agents:
  defaults:
    memory:
      maxChunks: 500    # 减少条目数以降低全表扫描耗时

方案三:本地 patch(高级用户)

searchVector 中的查询从全表扫描改为 KNN 索引查询,但有重要注意事项:

js
// ⚠️ 错误的简单修复(返回零结果)
// SELECT v.distance FROM chunks_vec v WHERE v.embedding MATCH ? AND k = ?
// 问题:chunks_vec 默认使用 L2 距离,v.distance 可能 > 1.0
//       score = 1 - dist 为负数,被 minScore 过滤掉

// ✅ 正确修复:同时处理距离度量类型
// 选项 A:重建 chunks_vec 时指定余弦距离
//   CREATE VIRTUAL TABLE chunks_vec USING vec0(
//     embedding float[N] distance_metric=cosine
//   )
// 选项 B:保持 L2 距离,但调整 minScore 的计算方式(不推荐,破坏语义)
// 选项 C:使用 KNN 但在应用层对 L2 距离做归一化处理

关键陷阱:直接套用 KNN 语法但不处理距离度量类型,会导致搜索返回零结果。这是社区在测试时踩过的坑,完整修复需要同时修改向量表创建和查询两个地方。

常见问题

Q: 如何判断是否命中此性能问题?

A: 观察 memory_search 的响应时间随记忆条目数量变化。若从几十条变到几千条后搜索时间成比例增加(而非接近常数),则是全表扫描特征。

Q: 降低 maxChunks 会丢失记忆吗?

A: 会导致旧记忆被淘汰。如果是线上生产 agent,先备份 memory.db 再调整配置。