Grep / Zoekt:确定性命中
适合找字面量、符号名、错误码、配置 key。它不懂语义,但它最快、最可解释、最适合兜底。
原文讲的是一件事:想让人和 AI 真正理解一个大型代码库,不能只靠向量库,也不能只靠 grep。可靠的代码知识库是一条从文本、语法、符号、关系到语义的分层流水线。
原文先把代码理解拆成五层:Grep/Ripgrep 负责最朴素也最可靠的文本命中,AST/Tree-sitter 把文本变成可切割的结构,LSP 提供 IDE 级的定义跳转和引用查询,CodeGraph/LSIF/SCIP 把跨文件、跨仓库关系提前算好,Embeddings/Vector DB 负责把自然语言意图映射到代码片段。
真正的重点在第二部分:行业实践不是五选一,而是把这些能力串成漏斗。先用文本和向量做粗召回,再用 CodeGraph、LSP 和 Tree-sitter 做精确扩充,最后把更干净的上下文交给 LLM 推理。
适合找字面量、符号名、错误码、配置 key。它不懂语义,但它最快、最可解释、最适合兜底。
适合按函数、类、方法、import、注释切上下文。它保证 chunk 是代码单位,而不是固定 token 窗口。
适合当前工作区的实时跳转、诊断和引用查询。优点是准,缺点是需要语言服务常驻。
适合跨仓库 definition/reference、调用链、影响面分析。它把昂贵分析前置到 CI 或索引任务。
适合“支付兜底逻辑在哪里”这种模糊问题。但结果必须回到文本、符号和图谱层验证。
生产系统通常不是单路召回,而是 BM25 + 向量 + 图谱扩充,再融合、重排、去重。
| 实践 | 代表技术 | 为什么重要 | 落地建议 |
|---|---|---|---|
| 全文搜索要独立建设 | Zoekt / Elastic / ripgrep | 向量检索可能漏掉精确符号,全文搜索提供确定性 fallback。 | 先索引默认分支和活跃分支,支持 repo/path/lang/filter。 |
| 语法切块不能用固定长度替代 | Tree-sitter / AST | 代码 chunk 的最小可信单位通常是函数、类、方法,而不是 1K token。 | 按函数/类切块,保留 import、注释、文件路径和符号名。 |
| 精确关系要离线预计算 | SCIP / LSIF / CodeGraph | 跨仓引用和影响面分析不能靠在线 LSP 临时扫全仓。 | CI 或索引服务按 commit 产物上传,缺失时回退到搜索。 |
| 自然语言查询要混合召回 | BM25 + Vector + RRF | BM25 抓专名和错误码,向量抓意图,RRF 把两者合并。 | TopK 粗召回后做 rerank,再按 token 预算选择上下文。 |
| 答案必须带引用链 | file path / line range / symbol id | 代码问答最怕“像真的”。没有引用的答案无法 review。 | 每段上下文都携带来源,最终答案必须可跳回代码。 |
输入:Git 仓库、分支、commit、语言生态、构建配置。
产物:全文索引、语法 chunk、符号表、调用图、向量索引、权限元数据。
输入:用户查询、当前文件、光标位置、最近 diff、项目范围。
动作:意图分类:找定义、查影响面、问业务逻辑、改代码、排障。
精确查询:优先 symbol/text search。
语义查询:BM25 + vector 并行召回,再用 RRF 合并。
从命中的函数出发,用 CodeGraph 找 caller/callee、接口实现、测试文件、配置入口;用 Tree-sitter 补齐完整函数体和 import。
LLM 只拿经过排序、去重、截断的上下文;答案带文件引用。做代码修改时,再通过测试、静态检查和 review 反馈闭环。
以下资料用于核对业界实现路径:Sourcegraph 的代码搜索与精确代码智能、Zoekt 的 trigram 索引设计、Tree-sitter 的增量解析定位,以及 Milvus/LlamaIndex 的混合检索实践。
搜索解决“代码在哪里”,图谱解决“它和谁有关”,语义解决“用户到底想问什么”,引用链解决“答案是否可信”。这四件事连起来,才是 AI 编程时代真正有用的代码知识库。