阿里刚开源的 zg:把 ripgrep、BM25 和向量搜索缝在一起,人和 Agent 都能用
我装完阿里 Zvec 团队刚开源的 zg(zvec-grep)之后做的第一件事,是在终端里敲了下面这行命令:
zg query --human "An unseen creature left a few marks. What did the detective infer?" --limit 3
它返回了《福尔摩斯回忆录》里对应的段落,带文件名、行号和偏移量。同一份语料里还有《爱丽丝漫游奇境》,语义上跟“动物留下的痕迹”沾点边,但没被排进前三。
这不是一个单纯的 grep 替换品。zg 把三种检索方式——ripgrep、BM25、向量语义搜索——揉进了一个命令行工具里,同时给 Agent 提供了一套统一的检索接口。索引建一次,终端里的人和 Agent 共用。
装起来有多快
Node.js 22 以上,全局安装:
npm install -g @zvec/zvec-grep
建索引是第一步。拿官方示例里的两份文本试一下:
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
potion-retrieval-32m 是一个 3200 万参数的本地 Embedding 模型。索引建在本机上,不会往外传。如果你想走云端服务,可以换成远端的 Embedding 端点,但数据会过网络。
索引过程同时生成两套东西:向量索引和 BM25 倒排索引。向量索引负责语义召回,BM25 处理词法匹配,两路结果在查询时合并排序。
终端里怎么搜
建完索引,终端里直接查:
zg query --human "你的问题" --limit 3
--human 参数会把自然语言转成内部检索表达式,同时走语义和词法两路。如果你明确知道要搜某个标识符,不加 --human 直接传关键词,走纯词法检索,更精准。
返回结果带来源位置,比如 sherlock-holmes.txt:5479-5486 这种格式。你可以直接跳过去看原文。
Agent 怎么用
安装的时候多带一个参数:
zg install --target opencode --yes
这步会在 OpenCode 的配置目录里注册一个叫 zvec_grep_search 的工具。之后在 OpenCode 里跑任务,Agent 自己决定什么时候调这个工具。
Prompt 里不需要指定工具,Agent 会根据问题判断是否需要检索。比如问“某种未被发现的动物留下了痕迹,侦探推断出了什么?”,OpenCode 会自主调用 zg 的工具,返回排序后的证据片段。
⚙ zvec_grep_zvec_grep_search {"root":".../zg-mystery","query":"An unseen creature left a few marks. What did the detective infer?","fts":["marks","unseen creature","inferred","detective"],"fuse":true}
→ Read sherlock-holmes.txt [offset=5440, limit=120]
Agent 拿到的不是整篇文章,而是按相关性排序的段落片段,每段都带来源。这意味着 Agent 可以直接引用具体文件和行号来组织回答,不需要反复调用 grep 去验证。
它在真实仓库里表现怎么样
官方跑了三个真实仓库的测试,我翻了一下具体任务,这几个例子能说明 zg 究竟在什么场景下帮得上忙。
Pylint(Python 静态分析器)
任务是理解 AST 节点处理如何区分带类型标注和不带标注的属性初始化。Pylint 代码库的架构入口事先不知道,靠 grep 瞎翻很难定位到核心实现。zg 的语义检索把“类型标注”和“属性初始化”映射到对应的 AST 处理模块,再通过词法检索锚定具体标识符。
Matplotlib(绘图库)
任务是追踪 FontInfo 这个 NamedTuple 在数学文本渲染管线里的传递路径——从字体度量到字形数据,再到 postscript_name 和 FT2Font 对象的使用时机。跨文件的数据流和控制流,单纯靠文本匹配做不了,得先语义召回把相关片段聚拢,再按排序追溯调用链。
Django(Web 框架)
任务是关联 username 唯一约束、ORM 事务和 formset 批量操作之间的耦合关系。Django 的 ORM 层抽象层次多,设计依据分散在多个模块的注释和实现里。这类问题要的不是找到一个关键字,而是把分散在各处的“设计理由”串起来。
这三个任务覆盖了三种问题类型:What(架构模式是什么)、Where(数据/控制流在哪)、Why(设计原理为什么)。zg 最适合的就是这类目标位置未知、证据跨文件分布的检索场景。
省了多少
官方做了配对 A/B 测试:同样的 Agent、模型、Prompt、环境,唯一变量是“有没有 zg”。
在 SWE-QA-Bench 上跑 Claude Code 加 Claude Opus 5,在 BrowseComp-Plus 上跑 Codex 配 gpt-5.6-sol,两边都用 Qwen3.7 Text Embedding 做向量化。
结果:用了 zg 的 Agent 对比不带检索工具的 Baseline,Token 消耗降了 37.6%,工具调用次数少了 43.5%,任务耗时缩短了 38.6%,回答质量没降。
这个结果的核心机制不难理解:语义发现先收窄搜索范围,排序后的词法检索再锚定精确标识符。Agent 拿到的是已经压缩过的证据片段,不需要大范围扫文件、反复调工具、往上下文里塞无关内容。
已知的限制和取舍
先说 Embedding 模型的选择。本地跑 potion-retrieval-32m,数据不出本机,但速度会慢一些。走云端端点速度快,但数据过网络。代码仓库本身不敏感的话走远程问题不大,内部文档或私有配置建议本地跑。
索引更新目前不是增量的。文件变化后需要重新跑 zg index。个人项目或小团队可以接受,大型 monorepo 频繁变动的场景会有点烦。Roadmap 里把增量索引列在计划里了。
权限控制上,默认 Agent 能访问所有已索引的工作区。如果多个项目混在一起,建议按工作区分别建索引,再通过 --root 参数限制检索范围。
Agent 集成这块,目前官方示例给的是 OpenCode。其他平台(Codex、Claude Code、Qwen Code、Cursor)的集成方式在文档的 Agent 集成章节有说明,配置逻辑类似,都是注册一个工具接口。
操作清单
-
安装: npm install -g @zvec/zvec-grep,Node.js 需 22 以上 -
建索引: zg index --embedding local/potion-retrieval-32m -
终端搜索: zg query --human "问题" --limit 3 -
Agent 集成(OpenCode): zg install --target opencode --yes -
工作区限制: --root参数指定检索范围 -
取消 --human走纯词法检索,加--human走混合检索
FAQ
zg 和 ripgrep 什么关系?
zg 内部集成了 ripgrep 作为词法检索的引擎之一,同时叠加了 BM25 和向量检索,三路结果合并排序后输出。
索引文件放哪了?
默认放在当前工作区的 .zvec 目录下。具体位置可以通过配置修改。
必须用本地 Embedding 模型吗?
不是。--embedding 参数可以指向远端服务端点,但数据会通过网络传输。
Agent 能访问所有文件吗?
默认能访问已索引的工作区。可以通过 --root 限制范围。
支持 Windows 吗?
支持。macOS、Linux、Windows 都可以。
索引是增量更新吗?
目前还不是。文件变动后需要重新跑 zg index,增量索引在计划中。
非技术文本和代码都能搜吗?
都能。代码索引会保留符号、签名和层级路径,通用文本按 section 和 chunk 返回证据,索引策略会根据文件类型自动适配。
不想用云端 Embedding,本地模型跑得动吗?
potion-retrieval-32m 只有 3200 万参数,普通笔记本的 CPU 就能跑,速度会慢一些但可用。

