jevgrep 架构剖析:分层遍历 + 内容预览,Jev 如何不上传整棵树就锁定代码位置
【免费下载链接】jevgrepFind code by asking what it does. A CLI for coding agents that uses Jev to discover relevant files and source context.项目地址: https://gitcode.com/gh_mirrors/je/jevgrep
jevgrep 是一款面向编程智能体的代码搜索 CLI:你用一句自然语言提问,它基于 Jev 模型通过分层遍历仓库目录、内容预览文件,返回最相关的文件与源码片段,帮助 coding agent 快速定位代码。本文剖析它的内部架构,看懂它如何在不上传整棵树的前提下锁定代码位置。
它解决什么问题 🧩
编程智能体接一个陌生任务时,最耗 token 的环节往往是"找文件":反复ls、rg、读文件,把半个仓库塞进上下文。jevgrep 的思路是——让 Jev 替 agent 判断哪些目录值得进、哪些文件值得读,最后把"文件列表 + 逐字源码摘录 + 行号"一次性打到 stdout。
一句话流程(来自 docs/architecture.md):
问题 → 目录 → 文件 → 源码单元 → stdout
它先不上传整棵树,而是用"目录元数据 + 内容预览"决定往哪走。这正是下面三个阶段的核心。
第一阶段:分层遍历,目录级"试读" 🌲
遍历逻辑在 retrieve.ts 的discover()里(约 L297–L395),是一个逐层广度优先搜索:
- 第 0 层目录只看名字:根目录的直接子目录直接进队列,连预览都省了;
- 更深的目录先做"目录预览":previewDirectory() 只采样最多 64 个条目、约 4KB 的元数据(子项名称、文件/目录计数、扩展名分布),就够 Jev 判断"这个目录值得探索吗";
- Jev 回答布尔问题,概率 > 0.5 才放行:每个目录/文件都会收到一个
navigationRequest(见 requests.ts),问题大意是"这个目录是否值得为本次查询探索?文件名与元数据作为证据"。低于阈值的分支直接剪掉; - 没有固定 top-N:通过标准的文件全部保留,不会因为"只取前两名"漏掉证据;
- 硬性资源上限:单次搜索最多看 10 万个条目、单文件 1MB 封顶,防止失控。
这意味着:一个只有目录名就足以排除的vendor/,永远不会被打开读取。
第二阶段:内容预览,文件级"试读" 👀
对通过目录关的分支,jevgrep 同样不上传全文,而是构造有预算的内容预览:
- 文件预览 = 开头 16KB 文本(previewFile());超限文件则切分成 12KB 的采样块逐块送评,"判断这段源码是否直接实现了目标行为,而不是泛泛相关";
- Python / TypeScript / JavaScript 额外附声明索引:先用内置解析器(source.ts)抽出函数/类声明与行号范围,让 Jev 一眼看清文件骨架;
- 目录的内容级复查有精细预算:withDirectoryContent() 给目录内每个文件按
16000/文件数字节分配预算(最低 80 字节),采样"开头 + 中部 + 结尾"三段,整体超 28KB 就按比例缩水——每次发给 Jev 的内容都有硬上限。
其他语言(含无法解析的文本)统一退化为有界源码块,保证任何仓库都不会卡死在解析上。
第三阶段:声明级选择,精确到行 🎯
文件入选后,selection.ts 的selectFile()把文件切成语法单元(声明级单元,超 24KB 的单元按 16 行再切块),然后向 Jev 提出三类布尔判断(evidenceRequest):
| 问题 | 作用 |
|---|---|
q(相关性) | 这段代码是否直接实现或测试目标行为?"包含 bug 的当前实现"也算 |
scope(范围) | 是否属于查询点名的那个 API/组件,而非"功能相似的另一个 API" |
ref(引用) | 是否被已选证据具体引用,用于把相关声明拉回来 |
通过判断的声明连同其局部调用上下文(call-context.ts)成为最终摘录;被标记为测试文件的还会额外挑选相关 test body(test-body-selection.ts)。解析失败时退化为 3000 字节的有界文本块——失败不丢证据,只降级粒度。
一次"反悔"机制:锚点复查 🔁
剪掉的目录并不会彻底出局。若某候选文件里发现了.context类锚点,jevgrep 会把之前所有被剪枝的目录重新做内容级评估(retrieve.ts),问题变成"该目录是否声明/继承/使用了锚点类"。这相当于给首轮"只看名字"的判断一次带上下文的重审机会——但只允许一轮,代价可控。
新鲜度与安全:内容哈希守门 🔒
每次向 Jev 发请求或取缓存答案前,都会用contentHash校验源文件没被改过(filesystem.ts 提供快照读取):
- 文件变了 → 丢弃对应旧结论,标记
sourceOmitted,而不是硬着头皮返回过期证据; - 部分失败(provider 错误、请求超限)→ 结果标记
incomplete,已获得的证据不被一次失败擦掉; - 默认过滤隐藏文件、依赖/构建产物、二进制与明显含凭据的文件,尊重
.gitignore——但选择搜索根目录依然是你的责任。
实测效果:同样解题,成本更低 📉
在 10 个 SWE-bench Python 任务上的对照(含失败任务):
- 无 Jev 基线:8/10完成,Sol 成本$7.62;
- 用 jevgrep:8/10完成,成本$5.44,降幅28.6%;
- 后续 speed-2026-09-28.md 的优化版本还快29.16%,token 少 0.97%。
更多细节见 evals/results/relevance-threshold-2026-09-27.md 与 evals/cost-quality-policy.md。
总结:小数据决策,大上下文收益 ✅
jevgrep 的架构可以浓缩为三条原则:
- 分层决策:目录看名字 → 文件看预览 → 声明看源码,越贵的判断越晚、范围越小;
- 每次交互都有字节预算:64 条目目录预览、16KB 文件预览、38KB 请求上限,绝不上传整棵树;
- 诚实的失败语义:剪枝可反悔一次、缓存必校验哈希、部分失败标
incomplete,让 agent 知道"哪些是已证实的,哪些只是线索"。
这套设计让编程智能体拿到的是早期可用的证据,而不是一份完整索引——这也是它"同样智能、约 30% 更低成本"的底气所在。想深入了解设计取舍,可阅读 docs/architecture.md 与 specs/done/jevgrep/README.md;agent 侧的使用约定见 skills/jevgrep/SKILL.md。
【免费下载链接】jevgrepFind code by asking what it does. A CLI for coding agents that uses Jev to discover relevant files and source context.项目地址: https://gitcode.com/gh_mirrors/je/jevgrep
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考