• 周皓

    zg(zvec-grep)把 向量语义检索、BM25 关键词检索和 ripgrep 精确匹配装进了同一个本地命令行工具,同时通过 MCP 提供给 Claude Code、Codex、Cursor 等 AI Agent 使用。0.3.0 版本用 Rust 完整替换了原来的 Node.js 实现:安装包体积减少 79.5%,CLI 启动耗时减少 82.5%,索引构建耗时减少 64.5%,构建期峰值内存降低 53.2%。

    项目地址:https://github.com/zvec-ai/zvec-grep

    一、zg 是什么

    zg(zvec-grep)是阿里巴巴开源的本地检索工具,面向人和 AI Agent,把向量语义检索、BM25 关键词检索和 ripgrep 精确匹配整合到同一个入口。

    rg 是很多 Rust 开发者每天都在用的工具。函数名、配置项、报错信息这类明确目标,用 rg 查又快又准,而且能搜全。

    但现在越来越多的检索请求来自 AI Agent,输入也从明确的符号变成了自然语言:“启动时怎么恢复主题偏好?”“用户权限在哪里校验?”。代码里对应的实现可能叫 hydratePreferences,文档里可能写成“账号授权与审批”,和问题本身没有一个相同的词。这种时候只用文本匹配,要么漏掉,要么把范围放得很大,得到一堆没有排序的匹配行。Agent 只能反复换关键词、搜索、读文件,工具调用次数、耗时和 Token 都会上去。

    zg(zvec-grep) 就是为这个问题做的本地检索工具。它保留 rg 精确、快速、可以穷尽匹配的优点,再补上语义发现、相关性排序和上下文组织:

    一个入口,多种检索:向量语义检索、BM25、二者混合检索(RRF 融合排序),以及 rg 风格的精确/正则匹配。可以先按语义找方向,再按关键词收窄,最后用正则精确核对。

    理解代码结构:借助 tree-sitter 解析 C/C++、Go、Java、JavaScript/TypeScript、Python、Rust 等语言,按符号、签名和层级切分;Markdown 按标题和章节切分;JSON、TOML、YAML、CSV 等文本数据也能参与检索。

    结果紧凑、来源可查:默认返回排序后的紧凑预览,每条结果带文件路径和行号,需要时再读全文,避免无关内容塞满 Agent 的上下文。

    默认本地运行:文件扫描、Embedding、索引和检索默认都在本机完成。内置多种端侧模型,远程 Embedding 必须经过用户明确授权才会启用。

    人和 Agent 共用一份索引:zg 底层用 Zvec https://github.com/alibaba/zvec 嵌入式向量数据库同时存放向量索引和 BM25 索引,不用另外部署数据库服务。CLI 和 MCP 读写的是同一份索引,并支持增量更新和自动刷新。

    在代码仓库问答 SWE-QA-Bench 和深度研究问答 BrowseComp-Plus 的配对 A/B 评测中(同一 Agent、同一模型、同一 Prompt,只比较是否接入 zg):

    SWE-QA-Bench:工具调用减少一半以上,输入 Token 减少近一半,评审得分提高 1.50 分;

    BrowseComp-Plus:准确率从 98.67% 提高到 99.00%,输入 Token 减少 37.56%,工具调用减少 43.52%,Agent 耗时减少 38.58%。

    二、从 Node.js 到 Rust:重写带来了什么

    为什么重写

    zg 的前几个版本(0.2.x)用 TypeScript/Node.js 实现。对一个高频调用的命令行检索工具来说,这个运行时有几个绕不开的成本:

    每次单独调用 CLI 都要启动 Node.js 运行时并加载 JS 模块,Agent 连续调用时,这部分时间会累积起来;

    部分索引路径要在 JavaScript 普通数组和 TypedArray 之间转换,还要在 worker 线程之间传数据,带来额外的复制和临时内存分配;

    安装包要带上整套 JS 依赖和原生插件,体积很大。

    大型工作区和 Agent 工作流对索引耗时、查询延迟和资源占用都很敏感,所以我们用 Rust 重写了整条核心执行链路。

    性能对比

    测试环境:Apple M3 Pro、18 GB 内存、macOS 27.2,Node.js v24.16.0。索引数据集使用 BEIR 中的 SciFact、NFCorpus、ArguAna 和 FiQA 四个公开语料,共 75,128 篇文档。两个版本使用同一个本地 Embedding 模型,都走 CPU 推理,Embedding 并发设为 4。

    指标
    Node.js 0.2.2
    Rust 0.3.0
    改善

    安装包体积(含依赖)
    167.5 MiB
    34.3 MiB
    减少 79.5%

    CLI 启动耗时
    153.1 ms
    26.8 ms
    减少 82.5%

    索引构建总耗时
    219.13 s
    77.84 s
    减少 64.5%

    平均构建峰值内存(RSS)
    4,210.26 MiB
    1,968.61 MiB
    降低 53.2%

    平均检索耗时(MCP)
    20.93 ms
    14.88 ms
    减少 28.9%

    换算成实际体验:四个语料的首次建索引时间从约 3 分 39 秒缩短到约 1 分 18 秒;构建期峰值内存从约 4.11 GiB 降到约 1.92 GiB,而且四组测试每一组都下降了。本机同时开着编辑器、Agent 和其他开发工具时,这部分内存节省很明显。

    性能从哪里来

    原生启动:直接运行编译好的原生程序,不再需要初始化 Node.js 运行时和加载 JS 模块。CLI 冷启动从 153 ms 降到 27 ms。

    计算路径更直接:文本编码和向量计算在原生代码中完成,使用明确的数值类型和连续内存数组,编译器更容易优化计算循环。

    减少中间转换:计算结果一直以原生数值数组的形式存在,不再在 JS 普通数组和 TypedArray 之间来回转换,数据复制和临时分配都少了。

    共享资源、统一调度:在支持的本地推理路径上,各计算线程共享已加载的分词器和模型数据,避免重复初始化,任务由原生线程池统一调度。

    三、上手:安装与使用

    1. 安装

    zg 目前通过 npm 分发(后续会支持其他安装方式),运行时直接执行原生程序,不依赖 Node.js。支持 macOS、Linux 和 Windows。

    npm install -g/zvec-grep --allow-scripts=/zvec-grep
    zg --version

    安装依赖 npm 的 postinstall 脚本把原生程序放入合适位置和按需下载 CUDA,所以要加上 --allow-scripts 允许它运行。

    1. 接入 AI Agent(可选)

    自动发现本机已安装的 Agent 并配置 MCP

    zg --install

    也可以指定目标,例如 Claude Code / Codex / OpenCode

    zg --install --target claude --yes
    zg --install --target codex --yes

    目前支持的目标包括 claude、codex、opencode、cursor、qwen、qoder、copilot、vscode、grok、pi。配置完成后重新连接 Agent,Agent 会根据问题自己判断什么时候调用 zg。

    1. 建立索引

    cd your-repository

    默认使用面向代码的轻量本地模型 local/potion-code-16m-v2

    zg --index

    查看索引覆盖范围、Embedding 模型和存储状态

    zg --status

    索引保存在工作区根目录下的 .zvec-grep/。之后文件有变化时只做增量处理,内容没变的文件不会重新计算 Embedding。如果要换模型,用 zg --index --rebuild --embedding <model> 重建索引。

    在交互式终端里,即使跳过这一步直接搜索,zg 也会先引导你选模型并建好索引。脚本或 CI 这类非交互环境不会自动建索引,需要先显式执行 zg --index。

    1. 检索

    自然语言 / 语义检索(默认混合检索:向量 + BM25,RRF 融合排序)

    zg "where is the connection pool timeout configured"
    zg "用户权限在哪里校验"

    只走 BM25 关键词检索,或只走向量检索

    zg --fts "AuthService"
    zg --vector "retry with exponential backoff"

    同时执行多个查询,--fuse 把多组结果合并后统一排序

    zg --hybrid "connection pool" --hybrid "socket timeout" --fuse

    用 rg 风格做精确/正则匹配(不需要索引)

    zg --rg -n "AuthService" src
    zg --rg -F "fn main(" crates

    限定范围:文件类型、glob、条数

    zg "error handling for invalid config" -t rust -g 'crates/**' --limit 5

    调整预览详细程度:none / short(默认)/ full / detail

    zg --preview detail "how indexing jobs are scheduled" --limit 3

    1. 示例:用小说测试一下

    mkdir zg-mystery && cd zg-mystery
    curl --retry 3 --retry-all-errors --progress-bar -fL \
    -o alice-in-wonderland.txt https://raw.githubusercontent.com/GITenberg/Alice-s-Adventures-in-Wonderland_11/master/11.txt \
    -o sherlock-holmes.txt https://raw.githubusercontent.com/GITenberg/The-Memoirs-of-Sherlock-Holmes_834/master/834.txt

    语料是英文小说,换用面向文本检索的本地模型

    zg --index --embedding local/potion-retrieval-32m

    zg --preview detail "An unseen creature left a few marks. What did the detective infer?" --limit 3

    查询里没有出现 Holmes、weasel、foot-marks 这些原文用词,zg 依然会把《福尔摩斯回忆录》中《驼背人》里根据脚印推断动物的段落排在最前面,并给出具体行号。

    四、写在最后

    zg 0.3.0 是 Rust 版的第一个正式版本。接下来我们会继续推进图检索与重排、PDF/Office 等更多内容格式、更高的上下文效率,以及本地模型和索引的性能优化。

    欢迎 Rust 社区的朋友试用,也欢迎提 Issue、PR,或者分享你在大型代码库、知识库和 Agent 工作流里的使用情况:

    GitHub:https://github.com/zvec-ai/zvec-grep

    文档:https://zvec.org/zh/docs/zvec-grep/

    Rust 版发布博客:https://zvec.org/zh/blog/2026-11-03-zvec-grep-rust/

    开源发布博客:https://zvec.org/zh/blog/2026-08-28-zvec-grep-open-source/

    如果觉得有用,欢迎给项目点个 Star。

    图片

    主楼
  • 彭白

    这个 Rust 重写后性能提升很大,请问内存降低主要是得益于什么优化措施?

    #1
  • 彭天

    之前用 Rust 重写搜索工具也遇到过内存优化问题,这种替换方案确实能大幅提升性能。

    #2
  • 萧映雪

    建议在配置文件中增加 memory_limit 参数,允许用户自定义索引构建时的内存使用上限。

    #3

发表回复

登录后回复