做 Coding Agent 搜代码:到底该选 RAG 还是 Grep?扒完 Claude Code 源码我顿悟了
大家好,我是不会喷火的小火龙。
很多团队自研 Coding Agent,第一步就是去搭向量数据库——Chroma、Qdrant、Weaviate 随便选一个,跑 Embedding,切片,建索引。看起来很"AI",很高大上。
但你有没有想过:Claude Code,目前公认最强的 AI 编程工具之一,它的代码检索底层,其实就是一个 50 年前的命令行工具——grep?
如图 1 所示,这就是很多团队盲目上 RAG 之后经历的真实工程困局,和 Anthropic 自己走过的弯路。

这篇文章想帮你搞清楚三件事:代码检索场景下 RAG 为什么频繁翻车、Claude Code 的极简方案如何跑通、以及你自己的项目到底该怎么选。
一、为什么代码检索场景下,传统 RAG 频频翻车?
代码是符号系统,不是自然语言。这句话听起来像废话,但绝大多数 RAG 翻车的根源就在这里。
向量语义检索的逻辑是意思相近的文本在向量空间里彼此靠近,这在自然语言里成立,但在代码里会系统性失效。举个例子:createD1HttpClient 和 buildD1HttpClient 语义高度相近,向量距离极小,但它们在代码里是两个完全不同的函数;而同一条调用链里相互依赖的函数,语义可能毫无关联,向量检索根本找不到它们之间的联系。
如下表所示,代码符号场景下,语义向量召回和精确匹配之间的准确率差距相当触目:
代码精确符号 vs 语义向量召回偏差对比
| 查询类型 | 示例查询 | 向量检索结果 | 精确匹配结果 |
|---|---|---|---|
| 函数名精确查找 | createD1HttpClient | 召回 buildD1HttpClient(相似但错误) | 精准命中,第 1 条结果 |
| 错误码定位 | ERR_DB_CONNECTION_TIMEOUT | 召回语义模糊的错误描述文本 | 直接定位到常量定义行 |
| 调用链追踪 | handlePaymentCallback 的全部调用方 | 召回支付相关的无关业务代码 | 逐个匹配调用点,一个不漏 |
| 变量赋值查找 | MAX_RETRY_COUNT = 3 在哪里定义 | 无法区分定义和引用 | 精确定位定义行 |
RAG 在代码场景还有三个硬伤。
第一,Chunk 切片会破坏 AST。按字符数盲目切片,会把一个类或一个函数切成两半,上下文彻底断裂。第二,索引永远赶不上代码变化。代码是秒级变动的,向量索引构建慢、增量同步复杂,极易产生脏数据,让 LLM 基于过期上下文产生幻觉。第三,全量代码送第三方向量化,隐私泄露风险不可忽视;本地跑大型 Embedding 模型,GPU 成本直接劝退。
二、扒开 Claude Code 源码:极简的 Agentic Search 是怎么跑通的?
Anthropic 没有预先构建任何静态索引。Claude Code 的做法是把搜索变成 LLM 的"多轮自主探索循环"。
三大并发安全工具构成整个检索引擎:
GlobTool:按文件名模式快速扫描项目骨架,类似人类第一步看目录结构,确定大致位置。GrepTool(底层是 ripgrep):毫秒级全文精确正则搜索,类似人类在 IDE 里按Cmd+Shift+F搜关键词。ReadTool:按需读取具体行号范围,类似人类定位到文件后翻开那几十行上下文。
为什么选 ripgrep 而不是普通 grep?ripgrep 用 Rust 开发,内置 SIMD 硬件加速,万级文件的全文扫描仅需约 200ms,自动跳过 .gitignore 指定的目录,天然适配代码仓库。内置的 head_limit=250 截断保护,防止搜索结果把上下文窗口撑爆。
如图 2 所示,两者的底层架构存在根本性的范式转移:
图 2:静态 RAG 检索管线 vs Agentic Search 多轮自主探索流程

这个设计里最巧妙的地方:LLM 本身就是最顶级的动态 Reranker。每轮检索结束后,LLM 自己判断这个线索够不够、要不要继续顺藤摸瓜,完全替代了传统架构里那个静态的 Rerank 模型。
三、权威佐证:Anthropic 踩坑实录与亚马逊论文实锤
放弃 RAG 不是 Anthropic 拍脑袋的激进决定,是被真实实验数据逼出来的。
Boris Cherny(Claude Code 技术负责人)在 2025 年 5 月的 Latent Space 播客里说过:Claude Code 早期确实搭建过基于 Voyage Embedding 的向量 RAG 检索系统,效果"还行"。但在实测用 Glob + Grep + Read 构成的 Agentic Search 之后,他的原话是:
"outperformed everything, by a lot. You avoid all the problems with security, staleness, and indexing."
安全问题没了,索引过期没了,增量同步也不用维护了。
学界的数据同样说明问题。亚马逊科学团队在 AAAI 2026 发表的论文《Keyword search is all you need》(arXiv:2602.23368)严格对比了标准向量 RAG 和纯关键词检索的 Agent 系统,结论是:关键词搜索在综合性能上达到 RAG 的 90% 以上,在代码等高度结构化的符号系统中,精确匹配的表现还显著优于向量语义检索。
从工程实践到学术实验,两份证据指向同一个结论:代码这个特殊领域里,精确性比语义相似性更重要。
如图 3 所示,代码搜索工具链使用图:

四、反方视角:Cursor 为什么坚持重仓向量?
读到这里,你可能会问:Cursor 呢?它也是 AI 编程工具里的顶流,技术路线和 Claude Code 截然不同,难道走错了?
没有。两者的架构选择,背后是产品形态的差异。
Claude Code 是轻量 CLI 工具,面对频繁切换的项目,零冷启动是第一要务。每次打开一个新项目,没有时间也没有必要预建索引,Glob + Grep 随开随用,几毫秒就能工作。
Cursor 是 IDE 插件,常驻用户系统,面对的往往是几十万文件的超大 Monorepo。在这个规模下,每次查询都做全量 ripgrep 扫盘,性能会出现瓶颈。
如图 4 所示,Cursor 并没有抛弃 grep,而是构建了一套双轨混合系统:
图 4:Cursor 混合检索双轨架构

Cursor 工程团队在官方博客(Instant Grep & Codebase Indexing)里直说:纯语义搜索在精确标识符、错误码、函数名上表现太差,所以他们自研了基于三元组(trigram)倒排索引的"Instant Grep"来弥补。两套系统并联,精确归精确,语义归语义,用 Merkle Tree 实现分钟级增量同步保持索引新鲜。
Cursor 的一个典型场景是:用户说"微信支付退款重试逻辑在哪里",记不住具体函数名,这时候语义向量检索才真的有用。
五、实战选型指南:自研 Coding Agent 到底怎么选?
扔掉非黑即白的架构争论。正确的问题是:你的产品形态和业务场景是什么?
我把这套选型逻辑整理成了一张清晰的决策树,如图 5 所示:
图 5:Coding Agent 代码检索技术选型决策树

三个场景的核心判断:
模式 1,极简优先,适合 90% 的个人开发者和轻量 CLI 工具。零依赖、零维护,直接用 ripgrep + Glob + Read 先把产品跑起来,有实际用户反馈再说向量的事。
模式 2,混合检索,适合 IDE 插件和常驻大型 Monorepo 的服务。精确符号归 trigram 倒排,模糊语义归轻量向量,两者并联。不要上重型托管向量数据库,自研 trigram 索引成本比你想象的低得多。
模式 3,LSP 语法感知,有明确跨文件引用追踪需求时接入 Language Server Protocol,获取符号定义和引用关系图。这才是"语义理解"真正应该发生的地方。
结语
Anthropic 用 50 年前的 grep 打败了自己搭的向量 RAG,这不是反智,这是工程上的诚实:代码是精确的符号系统,grep 是精确的符号匹配工具,用对了工具比堆技术栈更管用。
希望这篇文章能帮你在自研 Coding Agent 的路上少走一段弯路。
如果你对这类技术拆解感兴趣,欢迎关注公众号「小火龙AI 手记 」。
这里持续挖掘 GitHub 等开源社区里真正好用、能打的高价值项目,拆解它们背后的工程逻辑;同时也记录我自己用 AI 搓工具、做产品、踩坑填坑的全过程实录。都是有一点技术基础就能看懂的干货,跟你一起把 AI 驯化成真正趁手的生产力工具。
参考资料:
- Boris Cherny & Cat Wu on Claude Code,Latent Space Podcast,May 2025:https://www.latent.space/p/claude-code
- Claude Code 官方文档:https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview
- Shreyas Subramanian et al.,"Keyword search is all you need",AAAI 2026:https://arxiv.org/abs/2602.23368
- Cursor Engineering,"Instant Grep & Codebase Indexing":https://www.cursor.com/blog/instant-grep
