← 返回文章

智能体记忆的本地搜索:无需向量数据库,查询链路不用 LLM

fidx 将本地关键词搜索与向量检索结合,查询链路不调用 LLM,并与 QMD 对比了延迟、检索质量和各自局限。

fidx 对本地文件进行混合搜索,适合那些你希望让人或智能体当作长期记忆来使用的文件。它用 SQLite FTS5/BM25 匹配准确的名称和标识符,用 ONNX 嵌入处理“那篇讲 X 的文档”这类模糊查询,再通过 RRF 融合两路排名。查询链路里没有向量数据库、检索服务、API 密钥或 LLM。索引就是一个本地 SQLite 文件,可以复制、备份或删除;嵌入模型只需下载一次,此后搜索完全离线。

我开发它,是因为我想要一个能按含义搜索的 grep。但我测过的那些引入 LLM 的本地混合搜索方案,包括 QMD 的 query 模式,回答一个问题动不动就要十秒。套路总是一样:为了再提高一点召回率,查询链路里就加上了 LLM,用来扩展查询、重排结果,有时两样都做。在 CPU 上,每次查询要花 12–36 秒。人偶尔问一个问题,还能接受;智能体如果每走一步都想查几次记忆,这样的延迟就没法用了。说实话,对我也一样,因为搜索一旦需要等,你就会渐渐不用它。

fidx 本地搜索的终端操作演示
fig 01 fidx 本地搜索的终端操作演示

终端录屏保留原始命令和输出,展示 fidx 本地搜索的实际操作。

我不想接受这种取舍,所以做了 fidx。每次查询中,模型只运行一次,生成查询的嵌入向量:

  • 混合检索。 SQLite FTS5 BM25 匹配准确的名称和标识符;768 维 ONNX 嵌入匹配“那篇讨论索引项目的文档”;倒数排名融合(RRF,k=60)合并两路排名。同时被两路检索找到的文档,会排在只被一路找到、即使在那一路排名第 1 的结果前面。这就是混合检索的核心思路。

  • 无需检索基础设施。 不需要 Qdrant/Chroma/Postgres 服务、docker-compose、身份验证或数据库结构迁移。文档、BM25 和向量仍然存放在一个本地 SQLite 索引里,可以复制、备份或删除。

  • 只用 CPU,完全离线。 嵌入模型下载一次后,就不再需要网络调用、API 密钥,也没有遥测。

  • 为智能体设计。 fidx serve 通过 Unix 套接字提供服务,让模型和索引保持就绪;--json 提供结构化输出,并针对每次查询建议是优先保留召回率、裁掉较弱结果,还是采用更严格、经过校准的拒答策略。模型和索引就绪后的查询实测延迟:文档语料为 18–49 ms(单个 ONNX 线程),92k 文件的代码语料为 452 ms。

坦诚地看这些数字

fidx 与 QMD 的基准测试对比:四个语料库的召回率、前十条结果的纯净程度与延迟
fig 02 fidx 与 QMD 的基准测试对比:四个语料库的召回率、前十条结果的纯净程度与延迟

我选 QMD 做基准对比。它是最接近的本地同类工具,fidx 也明确借鉴了它的存储设计。测试覆盖四个语料库:20 Newsgroups 文档、一个模拟 WhatsApp 风格的合成聊天语料库,以及涵盖 10 种语言、共 92k 个文件的真实代码。每个语料库有 500 条查找已知目标的查询,小语料库则是 150 条。

大多数搜索基准测试会跳过两件事。第一,纯净度:总是返回 10 条结果的工具,以末尾一批不相关结果为代价,换取更高的召回率。因此,我让 LLM 评判器逐一标注所有返回的文档,除了召回率,还统计了 noise-rate@10 和 clean@10。第二,承认自己输在哪里。

启用 fidx 内置的自适应截断后——只需一个开关,默认关闭,让调用方可以选择召回率优先——相较 QMD 引入 LLM 的混合 query 模式,fidx 的实际优势不只在速度:四个语料库的噪声都更低,文档和代码的召回率更高,小文档集的召回率持平,聊天召回率也相近。重点是实际延迟相差多少:文档集上,R@10 为 0.962 对 0.914,clean@10 为 0.482 对 0.060,延迟为 49 ms 对 36 s。QMD 的优势也要说清楚:它的纯 FTS 模式在 92k 文件的代码语料上更快,121 ms 对 fidx 暴力扫描向量的 452 ms;它在两个语料库的 R@1 上领先;在测量过的文档、聊天和代码语料上,它的原始 FTS 结果列表最干净。完整表格、按编程语言拆分的代码结果,以及明确说明什么时候不该相信这些数字的测量局限分析,都在 BENCHMARKS.md 中。局限包括查找已知目标带来的偏差、机器生成的查询,以及仅在单台机器上测试。

为什么“查询链路里没有 LLM”就是整个设计的核心

其他工具 10 秒的延迟,不是实现细节,而是在你与索引之间放一个生成式模型的代价。对个人规模的语料库来说,这么长的等待换来的收益却很有限:在我的测量中,QMD 的 LLM 模式相较 fidx 的普通混合检索,召回率提升很小,甚至没有提升。更糟的是,LLM 还带来了可靠性风险:在按代码仓库分别测试的基准中,唯一出现的引擎故障,就是 LLM 嵌入阶段卡住和会话过期,10 个仓库中有 3 个未能完成测试(DNF)。fidx 根据分数分布做计算,替代这些 LLM 处理步骤:在融合后的分数曲线上做确定性的尾部截断,再通过 fidx calibrate,利用自检索探测和乱码负样本,为每个语料库推导分数下限。不需要标注,不针对基准测试调参,查询时只需微秒级计算。

试一试

uv tool install fmdidx   # PyPI name; the command is `fidx`
fidx doctor
fidx collection add ~/notes --name notes
fidx index
fidx search "that doc that discussed the indexing timeline"

macOS 需要使用 Homebrew Python,因为苹果(Apple)提供的 sqlite 不支持加载扩展;fidx doctor 会提示你。许可证详情见代码仓库:github.com/williamliu-ai/fidx。

如果你跑了基准测试,得到不同的数字,我很想知道。这正是这套基准测试框架存在的意义。