代码库 RAG:跨仓库语义检索 本节摘要:2026 年每家正经的工程组织都在内部跑一套「懂语义而非只懂字符串」的代码搜索。Sourcegraph Amp、Cursor 的 codebase answers、Augment 的企业级图谱、Aider 的 repomap、Pinterest 的内部 MCP——形态一致:摄取多个仓库,用 tree-sitter 解析,按函数/类粒度切块,混合检索,重排序,带引用作答。本节要求你构建一个能处理横跨 10 个仓库、200 万行代码的系统,并在每次 git push 后存活增量重索引。你会学到 AST 感知切块、混合(稠密+BM25)检索、交叉编码器重排序、引用忠实度后过滤,以及把 50 个文件的 push 重索引压到 60 秒内的基础设施功夫。
本节摘要:2026 年每家正经的工程组织都在内部跑一套「懂语义而非只懂字符串」的代码搜索。Sourcegraph Amp、Cursor 的 codebase answers、Augment 的企业级图谱、Aider 的 repomap、Pinterest 的内部 MCP——形态一致:摄取多个仓库,用 tree-sitter 解析,按函数/类粒度切块,混合检索,重排序,带引用作答。本节要求你构建一个能处理横跨 10 个仓库、200 万行代码的系统,并在每次 git push 后存活增量重索引。你会学到 AST 感知切块、混合(稠密+BM25)检索、交叉编码器重排序、引用忠实度后过滤,以及把 50 个文件的 push 重索引压到 60 秒内的基础设施功夫。
对应原课程:Phase 19 · Lesson 02 ·
rag-over-codebase(原英文phases/19-capstone-projects/02-rag-over-codebase/docs/en.md)。
阅读完本节,你应当能够:
到 2026 年,每个前沿编程 Agent 都自带代码库检索层,因为光靠上下文窗口解决不了跨仓库问题。Claude 的 100 万 token 上下文有帮助,但消除不了对排序检索的需求。在原始块上做朴素余弦搜索,会在生成的代码、monorepo 重复、罕见导入符号的长尾上把结果搞砸。生产答案是:在 AST 感知块上做混合(稠密 + BM25)检索加重排序,背后是一张符号引用图。
你要学的,是去索引一支真实的舰队(不是一个教程仓库),并度量 MRR@10、引用忠实度、增量新鲜度。失败模式是基础设施性的:10 万文件的 monorepo、一次触碰半数文件的 push、一个需要跨四个仓库才能答对的问题。
AST 感知摄取流水线用 tree-sitter 解析每个文件,提取函数和类节点,在节点边界而非固定 token 窗口切块。每个块得到三种表示:一个稠密嵌入(Voyage-code-3 或 nomic-embed-code)、稀疏 BM25 词项、一段简短的自然语言摘要。摘要增加了第三种可检索模态——用户问「X 是怎么被授权的」,摘要里提到「authz」,哪怕代码里只有 check_permission。
块摘要器骨架(批量 + 提示缓存):
SUMMARY_PROMPT = ( "用一句话总结这个函数,点明它的公开契约与副作用。\n\n代码:\n{body}" ) # 批量进 Haiku 4.5,系统前导词 prompt-cache,存到块记录里 chunk = {"repo","path","start_line","end_line","symbol","body","summary"}
检索是混合的。一次查询同时触发稠密与 BM25 搜索,合并 top-k,把并集交给交叉编码器重排序(Cohere rerank-3 或 bge-reranker-v2-gemma-2b)。重排序后的列表送给长上下文合成器(Claude Sonnet 4.7 配提示缓存,或自托管的 Llama 3.3 70B),指示它对每条论断按文件与行号范围引用。没有引用的答案被后过滤器拒掉。
BM25 字段加权(让「按名找」与「按义找」并存):
TANTIVU_WEIGHTS = { "symbol_name": 4, # 权重最高:按名找函数 "summary": 2, # 自然语言桥接 "symbol_body": 1, # 正文兜底 }
增量新鲜度是基础设施题。git push 触发 diff:哪些文件变了、哪些符号变了。只对受影响的块重嵌入。受影响的跨文件符号边(导入、方法调用)重算。索引在不每次提交重处理 200 万行的前提下保持一致。
可复用技能 outputs/skill-codebase-rag.md:给定一组仓库语料,它搭起摄取流水线、混合索引与查询 Agent,对任意跨仓库问题返回带引用的答案。评分量表:
| 权重 | 标准 | 度量方式 |
|---|---|---|
| 25 | 检索质量 | 100 题留出集上的 MRR@10 与 nDCG@10 |
| 20 | 引用忠实度 | 答案论断中带可验证 file:line 锚的比例 |
| 20 | 延迟与规模 | 索引语料规模下 1 万 QPS 的 p95 查询延迟 |
| 20 | 增量索引正确性 | 50 文件 commit 从 git push 到可查的耗时 |
| 15 | UX 与答案格式 | 引用可点击、片段预览、追问能力 |
| 100 |
一次典型问答:
$ code-rag ask "how is S3 multipart abort wired into our retry budget?" [retrieve] 12 chunks dense + 7 chunks bm25, 16 unique after dedup [rerank] top-5 kept (cohere rerank-3) [synth] claude-sonnet-4.7, cache hit rate 68%, 2.1s answer: Multipart aborts are triggered by `AbortMultipartOnFail` in services/uploader/retry.go:122-148, which decrements the per-bucket retry budget defined in config/budgets.yaml:34-51 ... citations: [services/uploader/retry.go:122-148, config/budgets.yaml:34-51, libs/s3client/multipart.ts:44-61]
Qdrant 的原生混合搜索开箱即用,适合中等规模;pgvector + pgvectorscale 对已有 Postgres 栈的团队更友好,但 p99 在大批量下需调优;Vespa 在多向量与 MaxSim 上更专业,但运维更重。嵌入侧,Voyage-code-3 托管质量最稳,nomic-embed-code 自托管省成本,差距在开了重排序后通常会收窄。合成器层面,Claude Sonnet 4.7 配提示缓存是性价比之选,1M 上下文能装下大量重排序块。
generated 标志并对这类命中降权。下一节,我们把战场从「文本」搬到「语音」——构建一个端到端延迟低于 800ms 的实时语音助手。