Context. dev 开源了一个 Rust 编写的本地语义代码/文档搜索 CLI「sgrep」
sgrep 用一个 ~32MB 的本地 CPU 模型,首次搜索后完全离线,代码和查询永不出本机。来解决传统代码搜索有两个极端问题:
· ripgrep:适合已知名称、精确文本、正则。面对意图型查询(如 "when does a failed scrape consume credits"),宽泛的模式会返回海量噪音,狭窄的模式又会漏掉目标。
· 云端语义搜索(如 mgrep):需要账号、网络、把源码同步出去;对隐私和离线场景都不友好。
开源地址:https://github.com/context-dot-dev/sgrep
技术架构:四步搜索流程
1. 文件枚举:复用 ripgrep 列文件、遵守 .gitignore、跳过隐藏和二进制文件。不自己造轮子。
2. 语法感知分块:用 Tree-sitter + Chonkie 把代码切成约 2048 字符的段落(passage),保留完整行。Tree-sitter 支持 Python、C/C++、Go、Java、Rust、JS/JSX、TS/TSX;其他类型文件退化为纯文本切分。这意味着分块边界是语法单元(函数、类),不是任意字符位置;这直接决定了检索结果的可读性。
3. 静态嵌入(static embeddings):这是全项目最关键的技术决策。用的是 MinishLab 的 model2vec 风格静态模型:
· Code 模型:Potion Code 16M v2(从 CodeRankEmbed 蒸馏,用代码/查询对训练),约 32–34MB
· Text 模型:Potion Base 8M(自动模式下仅当所有候选段落都是纯文档时才启用)
· 工作方式:每个 token 对应一个预学习的 256 维向量,查询时只需对 token 向量求平均并归一化,完全不做 transformer 前向传播
· 代价是明确的:向量平均丢失了 token 顺序信息,也无法捕捉深层上下文语义。
4. 混合评分:为了弥补静态嵌入的弱点,最终得分 = 75% 语义 + 25% BM25(各自归一化到 0–1 后加权),并且大小写敏感的精确标识符匹配排在最前。也就是用词法信号去校正语义信号的方向性错误。嵌入向量由"文件路径 + 段落文本"共同构成;路径本身携带语义信息(如 billing/ 目录),这是个聪明的小技巧。
基准评测
· SWE-bench Verified(GPT-6,50 任务 × 2 次):管道模式下的 sgrep 比 ripgrep 节省 21.3% 的 LLM API 开销,解题数 70/100 vs 68/100。即:更少的检索轮次、更省钱的上下文,达到了略好的效果;这是面向 agent 经济性的核心卖点。
· 检索质量:在 RepoQA(完整函数检索)上 sgrep 领先;但在 CoSQA(代码片段检索)上 CK 的语义模式更强。作者对此毫不讳言。
