菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI教程 > Claude Code放弃RAG改用grep:代码搜索架构深度解析
进阶教程 代码搜索架构深度

Claude Code放弃RAG改用grep:代码搜索架构深度解析

2026-06-06
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

ClaudeCode采用四层检索架构,放弃向量RAG,通过grep、glob、read等工具让LLM自主决策搜索路径

Claude Code 为何舍弃 RAG:用 grep 完成代码搜索的底层架构拆解

先厘清问题:当一个 agent 需要修复一个 bug,第一步必须是精准定位到相关代码。 Claude Code 为何舍弃 RAG:用 grep 执行代码搜索的真实架构分析 典型场景如下:用户提出“修复 payment API 的 auth bug”。agent 必须依次回答—— 1. 项目整体结构(目录布局 / 模块划分) 2. payment API 的确切文件路径(精准定位) 3. auth 相关逻辑的分散位置(跨文件依赖) 4. 执行测试所需的命令(项目约定) 这些信息并不存在于模型的训练数据中——它们全部位于用户当前的代码库。因此这是一个“动态上下文获取”问题。 行业内主流有三种方案: | 方案 | 代表 | 思路 | |------|------|------| | 向量 RAG | Cursor | 将整个代码库 embedding,存入向量库,查询时召回 top-K chunk 拼入上下文 | | 传统索引引擎 | JetBrains | PSI 树 + stub 索引,强符号导航 | | Agentic search | Claude Code | 不建索引,提供三个工具(grep / glob / read),让 agent 自行多轮探索 | Anthropic 早期版本走的是第一条路线。Boris Cherny 在 2025 年 5 月的博客访谈 Claude Code: Anthropic's Agent in Your Terminal 中透露,他们试过 RAG + 本地向量库,但 benchmark 结果显示“agentic search 在性能上远超其他所有方案”。随后 Claude Code 重新定位: 业内常见解释是“grep 比向量搜索更精准”。这不算错,但它把所有难点都塞进一个“准”字里——深入源码后会发现,真实判断远比这复杂。 ## 核心架构分层解析 Claude Code 的代码探索能力并非单一的“grep 工具”,而是一套四层架构。这套架构本身回答了“agent 如何获取上下文”: ``` Claude Code 代码探索:四层检索架构 ┌──────────────────────────────────────────────────┐ │ Layer 3: 子 Agent 委托检索 │ │ Explore Agent(只读 / Haiku 模型 / 独立上下文 │ │ / 防火墙作用:原始结果留在子上下文,只回精炼摘要 │ │ 给主 Agent) │ │ ▲ │ │ │ 委托 │ │ Layer 2: 模型驱动检索 │ │ Glob ──▶ Grep ──▶ Read(多轮循环) │ │ 由主 Agent 在 while(true) 里决定 │ │ 下一步搜什么、读什么 │ │ ▲ │ │ │ 调用 │ │ Layer 1: 智能预注入 │ │ Memory Prefetch(用 Sonnet 跑 sideQuery │ │ 挑 ≤5 条相关记忆)+ @file 扫描 │ │ + Skill 自动发现 │ │ ▲ │ │ │ 启动时 │ │ Layer 0: 静态上下文 │ │ System Prompt + CLAUDE.md + Git Status │ │ + MEMORY.md 索引 │ │ │ └───────▲ 用户输入“修复 payment API 的 auth bug” │ ``` 每层承担不同角色: - **Layer 0** 在会话开始时即注入——`CLAUDE.md`(项目惯例)、`git status`(当前修改)、`MEMORY.md` 索引。这些是确定性信息,不进入 agent 决策流程。 - **Layer 1** 在会话启动时并行预取——例如使用轻量 Sonnet 调用执行“side query”,从历史记忆中筛选 ≤5 条可能相关的记录;扫描用户消息中的 `@file` 引用;加载可能用到的 skill 描述。这是有预测的预注入,并非 RAG(不涉及向量查询)。 - **Layer 2** 是真正的 agentic search——`Glob` / `Grep` / `Read` 三个工具,在 while(true) 循环中被主 Agent 反复调用。搜索什么、搜索几次、何时停止,全部由 LLM 自行决定。 - **Layer 3** 为子 Agent 委托——当遇到大规模探索(例如“梳理整个项目的 auth 流程”),主 Agent 可以 spawn 一个 Explore Agent。该子 agent 使用更便宜的 Haiku 模型、独立上下文、只读权限,最后仅将摘要回传给主 Agent。这一层值得单独拎出——它是 Claude Code 极为巧妙的设计。 这一分层中隐藏着一个关键设计判断:将“决策权”放在 LLM 那一层,而非产品层。Cursor 的 RAG 在产品层已决定“召回 top 30 chunk”——LLM 拿到的是已被裁剪的上下文。Claude Code 不做裁剪,把工具交给 LLM,让 LLM 自主决定如何使用。两种哲学都对,但产生的产品形态截然不同。 ## 一次代码搜索的完整流程 抽象讲解容易飘忽。以“修复 payment API auth bug”这个具体案例,拆解 Layer 2 的多轮调用。以下是真实的调用序列(基于 Claude Code 行为逆向与官方文档描述): ``` 一次“修复 auth bug”任务的检索流程(简化版) T0: 会话启动 │ 加载 Layer 0:System Prompt + CLAUDE.md + git status │ 并行 Layer 1:sideQuery 拉 3 条相关 memory + 扫描 skill │ T1: Glob "**/payment*" ← 查找入口文件 └─ 返回 8 个候选文件路径(按 mtime 排序) │ T2: Read src/api/payment.ts ← 读取最可能的入口 └─ 返回 全文(< 25K tokens) │ T3: Grep "import.*auth" ← 在 src/api/ 中查找 auth 相关引用 └─ 返回 5 个文件 + 上下文行 │ T4: Read src/auth/middleware.ts ← 读取关键依赖 └─ 已读过?检查 mtime→ 未变化 → 返回 "File unchanged"(节省 ~25K tokens) → 变化 → 重新读 │ T5: ─── LLM 判断:上下文是否足够 ─── │ 足够 → 进入修复阶段(Edit + Bash test) │ 不足 → 继续 Grep / Read │ T6: Edit src/api/payment.ts ← 修复 │ T7: Bash "npm test -- payment" ← 验证 └─ 失败 → Read 错误日志 → 回到 T6 └─ 成功 → 完成 ``` 几个值得深挖的工程细节: **漏斗式调用**。调用顺序并非随机——`Glob → Grep → Read` 是一个收敛漏斗。`Glob` 类似目录浏览(按文件名筛选候选),`Grep` 类似内容过滤(在候选集中搜索模式),`Read` 成本最高(读取全文)。每一跳都将范围收窄。LLM 内化了这一模式,几乎不会上来就 `Read` 100 个文件。 **Token 预算硬限制**。 | 工具 | 限制 | |------|------| | `Grep` | 默认 head_limit=250 行,结果 ≤ 20KB | | `Glob` | 最多返回 100 个文件,按 mtime 倒序 | | `Read` | 单次最多 25,000 tokens / 256KB / 2000 行 | 这些数字并非随意设定——它们确保单轮调用的 token 消耗上限可预测,模型不会因一次 `Read` 一个 50000 行的文件而直接崩溃。 **Read 去重**。这是一个令人会心一笑的优化——`Read` 工具在调用前会检查目标文件的 mtime,如果与上次读取时相同,直接返回字符串 `"File unchanged"`,省去整个文件内容的传输。官方测算命中率为 18%,每次节省约 25K tokens。 这一优化能成立的前提是:mtime 是文件系统层面的真理,而非 agent 维护的状态。Claude Code 不需要“记住已读过哪些文件”——文件系统已经记录了。 **Prompt Cache 分区**。System Prompt 使用 `__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__` 分隔静态与动态部分,静态区使用 `scope: 'global'`,所有用户共享同一份缓存——这意味着 Anthropic 服务器端只为 system prompt 计算一次 KV cache,所有 Claude Code 用户的请求均命中该缓存。这是 Anthropic 自家产品才能实现的优化。 将这些细节汇总,你会发现 Claude Code 的“agentic search”并非简单的“模型自己 grep”——它是一套配合 LLM 工作模式的完整工程系统。grep 只是可见部分,水面之下还有 token 预算、去重、缓存、子 agent 隔离等一系列机制。 ## 为什么 grep 击败了向量索引 讲完 how,回头讲 why。这部分最为关键。 行业默认 RAG 是优秀方案。它确实是优秀方案——对很多场景而言。但 Anthropic 的判断是:代码这一特定场景,RAG 的优势无法发挥。 将其理由归纳为四条: **第一,代码场景下“精确匹配”比“语义相似”更重要。** 向量搜索的优势在于语义召回——搜索“用户认证”,能找到 `login` / `authenticate` / `verifyUser` 等词义相近但写法不同的代码。这在产品文档、客服问答中极具价值。 但代码并非如此。代码的核心特征是符号即真理。当你说“修复 `processPayment` 函数的 bug”时,你需要的是那个确切名为 `processPayment` 的东西。不是“语义相似的”,而是“那个”。`grep "processPayment"` 一次获取所有引用——精确、完整、零幻觉。`embedding.similarity("processPayment")` 返回一堆“看起来相关”的结果——其中可能包含 `processOrder`、`handlePayment` 等结构相似但实际无关的函数。 代码搜索失败时,向量搜索的失败是模糊的:是嵌入模型不够好?是 chunk 切分错误?还是 embedding 已过期?而 grep 的失败是清晰的:关键词拼写错误。可调试性差了一个数量级。 **第二,状态是 bug 的温床。** 向量索引需要维护。代码每改动一行,理论上对应的 chunk 都需要重新 embedding。Cursor 使用 Merkle 树进行增量更新,已是工程上相当优雅的方案——但即便如此,“索引滞后于代码”的问题仍会反复出现。 grep 没有这个问题。它每次搜索的都是当前文件系统的真实状态。你 git checkout 一个分支,下一次 grep 立即反映新分支的代码——无需“重建索引”。 这背后是一个更深刻的判断:有状态系统的复杂度是叠加的。索引启动 / 更新 / 失效 / 崩溃恢复 / 缓存一致性,每一项都是潜在的 bug 来源。grep 是 stateless 的——崩溃了重跑即可,没有人会觉得“丢失了什么”。 读到这里不禁想起 Roy Fielding 在 REST 论文中的那句话:服务端的 statelessness 不是性能优化,而是错误模式的简化。 同样的判断在 2025 年的 AI agent 上再次成立。 **第三,隐私是架构问题,而非政策问题。** Cursor 使用 RAG 必须将代码 embedding 后传输到向量库。学术研究已证明 embedding 可以反推回原始内容——这对企业用户是真实痛点。 Claude Code 使用 grep 完全在本地执行(agent 发出 grep 命令,本地工具运行),原文上下文仅在每次回传给 Anthropic 时进入上下文,不存在“持久化的代码副本留存”这种情况。这对合规敏感的客户而言是根本性差异——不是“我们不会上传”的承诺,而是“架构上就没有上传这一步骤”的事实。 **第四,agent 时代的稀缺资源不是召回,而是可预测性。** RAG 在 2020-2023 年大行其道,是因为那时模型上下文小、推理慢、调用昂贵——一次 LLM 调用是稀缺资源,必须预先将最相关的内容塞入。 到了 2025 年,Claude Sonnet 4 的上下文达到 200K-1M、Haiku 便宜到可以并行十几个、tool use 已成为模型的一等公民。稀缺的东西变了——不再是“一次 LLM 调用”,而是“输出的一致性和可调试性”。在这个新约束下,让 LLM 自己多调几次 grep(每次便宜且可预测),比让 RAG 一次性塞 30 个 chunk 进入上下文(高方差、调试困难)更为经济。 实测数据印证了这一判断。第三方在 2026 年初做的 5 个重构任务对比: | 工具 | 平均 Token | 平均时长 | 一次成功率 | |------|------------|----------|------------| | Cursor (RAG) | 11,000 | 90 秒 | 60% | | Claude Code (agentic) | 2,000 | 180 秒 | 75% | | Cline (agentic + auto sub-task) | 8,500 | 240 秒 | 80% | Claude Code 比 Cursor 少用 5.5 倍 token,但慢一倍,成功率高 15 个百分点。这个组合在生产环境的 agent 工作流(人挂着等结果)中是划算的——慢 90 秒不痛,节省 80% token 并提升成功率则直接创造价值。 ## 设计判断中的取舍 讲述至此,似乎 agentic search 完胜。事实并非如此。它有非常明确的代价。 **速度慢。** 多轮调用本质上是串行的——Glob 完才能 Grep,Grep 完才能 Read。即使工具内部有并发,整体时长仍被“轮次”拉长。Cursor 一次 RAG 召回即可搞定,时长更短。在“实时交互”场景(边写代码边问 Claude)中,这一延迟是劣势。这也是 Cursor 在 IDE 内嵌体验中更顺手的原因——其 90 秒级响应配合人坐在屏幕前等待,不会令人不适;而 Claude Code 的 180 秒级响应更适合“挂在 terminal 后台运行”的用例。 **大型 monorepo 首次冷启动慢。** 假如让 Claude Code 第一次进入一个 50000 文件的 monorepo 执行任务,其多轮 Glob/Grep 探索会花费相当多时间在“弄清楚这是什么项目”上。Cursor 因有预先索引,进入后可直接工作。这一差距在小项目中不明显,大项目中则非常突出。 **对模型能力的强依赖。** agentic search 的有效性建立在“LLM 知道何时搜索什么”这一假设上。Sonnet / Opus 级别的模型在这方面表现良好;换成弱模型,多轮调用很容易陷入“反复搜索同一个东西”“搜索了不该搜索的内容”的困境。这意味着 agentic search 并非普适解——若给你一个 7B 开源模型做 coding agent,老老实实建索引可能更靠谱。 **并非非此即彼。** 必须强调这一点:放弃 RAG 并不等于“所有 agent 都不应该使用 RAG”。Claude Code 自己的 Layer 1 中就有“使用 Sonnet 做 sideQuery 拉取历史记忆”的步骤——这本质上就是一个轻量 RAG。它的判断是:主代码搜索使用 agentic search,但跨会话记忆这种“内容稳定、量大、需要语义召回”的场景,仍然采用 RAG 风格的预取。 将这几条 trade-off 综合来看,agentic search 的适用场景大致如下: ``` 是否选择 agentic search 而非 RAG? ① 检索对象的“真理来源”是否在文件系统/数据库中? ├─ 是(代码、文件、数据)→ 继续 └─ 否(文档、知识、对话历史)→ 倾向 RAG ② 模型是否 ≥ Sonnet 4 / GPT-4o 级别? ├─ 是 → 继续 └─ 否 → 倾向 RAG ③ 需求是精确匹配,还是语义召回? ├─ 精确(符号、文件、API)→ 继续 └─ 语义(概念、意图)→ 倾向 RAG ④ 用户能否接受 2-3x 延迟以换取 token 节省、可调试性、隐私保护? ├─ 能 → 选择 agentic search └─ 不能 → 选择 RAG 四个全是“是/能”→ agentic search 有一个“否” → 考虑 RAG / 混合方案 ``` ## 自己做 agent 工具时该带走什么 如果正在开发一个 agent 类工具,对照 Claude Code 的判断,有几条具体可借鉴的经验: **1. 检索对象的“真理来源”在哪里,决定是否建索引。** 文件系统是真理来源 → 不要建索引(grep 就够了)。一份每月更新一次的产品手册是真理来源 → 建索引很合理。混合场景(代码 + 文档)→ 分别处理,不要一刀切。 **2. 工具集要让 LLM 形成“漏斗”。** Claude Code 的 Glob/Grep/Read 并非随意选择——它们是天然的收敛序列(粗 → 细)。给 agent 设计工具时,要思考它们之间是否具有这种关系。给十个并列的搜索工具,agent 会迷失。 **3. Token 预算必须硬封顶。** 每个工具的单次返回值必须有上限(行数 / 字节 / token),否则一次 grep 返回 100MB 会直接把上下文撑爆。Claude Code 的 250 行 / 20KB / 25K tokens 是经过打磨的数字,可借鉴这一思路。 **4. 重视“无操作”的优化。** Read 的 mtime 去重看似不起眼,18% 的命中率却相当可观。任何“可以不做”的工作都值得一个 fast path。这种优化只能在 stateless 系统中实现——一旦你维护了“我读过什么”的状态,反而无法做。 **5. 给探索任务专门的子 Agent。** 主 Agent 的上下文非常宝贵(需要保留判断逻辑、用户对话历史)。将“读取 100 个文件然后总结”这类任务委托给一个独立上下文的子 Agent,结果返回时仅是一段摘要——这个隔离层非常有用。Claude Code 的 Explore Agent 使用 Haiku 运行(便宜)+ 只读权限(安全)+ 独立上下文(不污染主 agent),这三者配合起来值得复制。 **6. 别把 RAG 当作默认选项。** 这条不是说“不要用 RAG”——而是说在没想清楚之前不要默认上 RAG。问自己:我真的需要语义召回吗?我的“知识”会变化吗?变化频率是多少?如果答案是“代码每天改动几十次”,agentic search 大概率比 RAG 更香。 ## 写在最后 读完 Claude Code 这套设计,想起 Boris Cherny 那句“它不是产品,是 Unix 工具”。这句话在 2025 年的 AI 时代听起来有些违和——大家都在做“产品”。但他们的判断是:在 agent 这个层级,最值钱的并非“自动决策”“智能召回”等黑盒能力,而是可预测、可调试、可组合——这些 Unix 哲学早在 1973 年就讲清楚了。 模型在变强,工具会变多,但“知道何时遗忘”这件事——把状态扔回文件系统、把决策权交还给 LLM、把架构剥到只剩三个 Unix 工具——这套判断会比任何具体的模型 / 框架活得更久。 参考资料: - Anthropic 博客《Claude Code: Anthropic's Agent in Your Terminal》 - Boris Cherny 公开访谈与播客原话 - Finisky Garden《拆解 Claude Code 的 RAG 机制》逆向分析 - TIMEWELL Inc. 2026-01 三工具 benchmark - Claude Code 工具系统源码(Tool.ts / GrepTool.ts / GlobTool.ts / ReadTool.ts)

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多