Sift:本地混合搜索,无需基础设施税
Source: Dev.to
请提供您希望翻译的完整文本内容(除代码块和 URL 之外),我将把它翻译成简体中文并保持原有的 Markdown 格式。
概述
sift 是一个本地 Rust CLI,用于文档检索。指向一个目录,提出一个问题,它会运行完整的混合搜索管道——BM25、稠密向量、融合、可选的重新排序——并返回排序后的结果。无需守护进程、后台索引器,也不依赖云服务。一个二进制文件。
它为需要在原始代码库、文档和混合格式语料库上进行可靠、可重复搜索的代理和开发者而构建,无需启动基础设施。
您可以立即在 macOS、Windows 和 Linux 上安装它。
检索管道
每个查询都会经历四个阶段:
- 扩展 – 生成查询变体,以在检索开始前扩大召回范围。
- 检索 – 对语料库执行 BM25(关键词)、短语匹配和稠密向量检索。每种方法捕获不同的信号。
- 融合 – 使用 Reciprocal Rank Fusion (RRF) 合并结果,在检索方法之间平衡信号,无需手动权重调优。
- 重新排序 – 可选的本地 LLM(通过 Qwen)对融合后的候选集合进行语义消歧重新排序。
每个阶段都可以独立调优。如果只需要 BM25 的速度,可跳过向量检索阶段。想要最佳精度则运行完整流程。
Architecture
实现分为 domain 和 adapters 两大部分:
- Domain objects 用于建模搜索计划、候选项和评分输出。
- Adapters 实现具体的 BM25、短语、向量和重排序后端。
共享的搜索服务在 CLI、基准测试和评估流程中执行相同的策略模型——在开发运行和 CI 评估之间没有任何变化。
Performance highlights
- SIMD‑accelerated dot‑product 用于 CPU 密集型工作负载下的向量评分。
- Zig‑inspired incremental cache ——一种借鉴自 Zig 构建系统的两层设计。manifest 存储跟踪文件系统元数据(inode、mtime、size),并映射到 BLAKE3 内容哈希,从而
sift能准确知道哪些文件已更改而无需重新读取。内容可寻址的 blob 存储保存预提取的文本、预计算的 BM25 词频以及预嵌入的稠密向量——这意味着重复查询根本不触及神经网络。不同项目中相同的文件共享同一个 blob 条目。 - Per‑query embedding reuse 跨多阶段管道的嵌入复用。
- Mapped I/O and tight tokenization hot loops 以在大语料库上保持低延迟。
开发过程中的一个具体权衡:将嵌入的 max_length 从 48 降至 40,既恢复了延迟预算,又保持了质量高于 BM25 基线——这是证据驱动调优胜过盲目猜测的典型例子。
完整内部实现请参阅 ARCHITECTURE.md。
评估
Comparative strategy run over 5,185 SciFact documents (~7.8 MB) on an AMD Ryzen Threadripper 3960X:
| Strategy | nDCG@10 | MRR@10 | Recall@10 | p50 (ms) |
|---|---|---|---|---|
| bm25 | 0.7262 | 0.7000 | 0.8000 | 5.41 |
| legacy‑hybrid | 0.7893 | 0.7250 | 1.0000 | 50.29 |
| page‑index | 0.7000 | 0.6667 | 0.8000 | 16.79 |
| page‑index‑hybrid | 0.5701 | 0.4367 | 1.0000 | 41.09 |
| page‑index‑llm | 0.7893 | 0.7250 | 1.0000 | 41.28 |
| page‑index‑qwen | 0.7893 | 0.7250 | 1.0000 | 41.18 |
| vector | 0.8262 | 0.7667 | 1.0000 | 25.94 |
关键要点
- BM25 在 5.41 ms p50 时是延迟受限情况下的合适默认选项,适用于关键词召回已足够的场景。
- Vector 在 25.94 ms 时实现了最佳 nDCG@10(0.8262)和完美召回——是大多数工作负载最平衡的策略。
- LLM 重排序(page‑index‑llm、page‑index‑qwen)在相近速度下匹配 legacy‑hybrid 的质量,验证了本地 Qwen 路径是比更重的混合流水线更实用的替代方案。
- page‑index‑hybrid 是唯一在 nDCG 上表现不如 BM25 的策略,提醒我们增加复杂性并不总能提升质量。
缓存命中率 (100/0/100 %) 证实缓存层在所有策略中均正常工作。详细输出 (-v, -vv) 在 CLI 中直接显示缓存命中率、阶段时间以及排序元数据。
为什么这对代理很重要
对于代理而言,延迟和可靠性是必需的,而不是可有可无的特性。当搜索速度慢、上下文丢失或依赖的服务可能不可用时,工具循环会严重失效。
sift 消除了这些摩擦:检索是本地的、确定性的,并且重复成本低。无需守护进程进行健康检查。无需嵌入服务来限制速率。也不需要管理云端依赖。该二进制文件通过 Homebrew 和静态 Linux 构件提供,因而代理可以依赖固定版本而不受环境漂移的影响。
构建方式
项目在一次专注且几乎不间断的 24 小时冲刺中完成——实现、评估设计、基准测试、性能优化、打包以及发布准备全部在同一持续流程中进行。每个主要单元在标记为完成之前,都附有验收标准和可衡量的证据。
促成这种速度的因素尚未准备好详细讨论。但 sift 是第一个真正证明它在高速、真实约束下且不走捷径的案例。稍后会有更多信息。
开始使用
- README — 安装和基本用法
- CONFIGURATION — 策略和模型设置
- EVALUATION — 运行您自己的语料库评估
- ARCHITECTURE — 内部深度解析
- 代码: