从 AST、CPG 到 GraphRAG,再到 Cursor / Sourcegraph / Augment 背后那张你看不见的图
0 · 引子:你以为 Cursor 是怎么"看懂"你那 200 万行祖传代码的?
如果你这两年重度用过 Cursor、Claude Code、Augment 这类 AI Coding 工具,大概率会遇到一个很微妙的时刻。
你对着一个几百万行、横跨几十个微服务、上千个 package 的私有代码库,敲一句自然语言,让它帮你改一段跨 5 个文件、涉及 3 个仓库的逻辑。
然后它真的找到了该看的文件。
它不只是搜到了几个关键词,而是知道:你要改的这个 processOrder 函数在 services/order.ts 第 47 行,它被一组调用点引用,依赖几个外部包,和 Payment 类有数据流耦合,最近某个 PR 还改过相关逻辑。
这件事在 2022 年还很难想象。
那时候早期 Copilot 主要依赖当前文件和有限邻近上下文,稍微跨一下文件、跨一下模块,就很容易开始胡说八道。今天的 AI Coding 工具,至少在一些成熟代码库和成熟索引条件下,已经能做出接近"工程师读项目"的动作。
这套"上帝视角"不是 LLM 自己长出来的,也不是靠把所有代码硬塞进上下文窗口。它的底层有一类所有头部 AI Coding 工具都在补强、但很少出现在用户视线里的基础设施,我在这篇文章里先统称为:
CodeGraph(代码图)。
严格说,CodeGraph 不是一个像 LSP、SCIP、CodeQL 那样有统一协议边界的标准名词。本文里说的 CodeGraph,指的是一组围绕代码建立的结构化索引能力:AST、符号表、类型关系、调用图、依赖图、数据流、版本演进、PR 历史、文档关系,以及它们和向量检索、全文检索、Agent 工具调用之间的组合。
更准确地说,AI Coding 真正依赖的不是一张孤立的图,而是:
CodeGraph + 向量索引 + 全文索引 + Graph-enhanced Retrieval 管线。
这篇文章会试着把这张"看不见的图"扒清楚,包括:
- 为什么纯文本搜索和单纯 Vector RAG 在代码场景下很快会撞墙;
- CodeGraph 从 AST 到 CPG,再到 AI 时代到底演进了什么;
- 普通 RAG vs GraphRAG,在代码理解上到底差在哪里;
- Cursor、Sourcegraph、Augment、Continue、CodeQL、Joern、tree-sitter 这些主流方案,各自押了哪一注;
- 如果你要给自家公司私有代码库自建一套 CodeGraph + AI 问答系统,工程蓝图应该长什么样。
全文约 8000 字,假设读者是 AI Coding / Dev Tools / 后端基础设施方向的工程师或架构师。
1 · 一段被压缩了 50 年的历史:从 grep 到 LSP 再到 CodeGraph
要理解 CodeGraph 为什么重要,必须先理解它要解决什么。
一句话总结:代码本质上不是字符串,但我们之前很长时间都把它当字符串处理。
1.1 文本时代:grep 是怎样统治了 50 年的
grep 诞生于 1973 年,至今仍是绝大多数工程师查代码的第一反应。它的世界观很简单:代码是一行行字符流,搜索就是字符匹配。
文本搜索的优点是极致简单、零开销、几乎没有偏差。但它的天花板也很明显:
- 它不知道
user是变量名、函数名,还是注释里的英文单词; - 它不知道
getUser()在 A 文件里是函数定义、在 B 文件里是函数调用; - 它不知道
import { foo } from './bar'里的foo和bar.ts里的export function foo()是同一个东西; - 它更不知道一个变量从 HTTP 请求参数流到 SQL 查询的"路径"长什么样。
当代码库只有几千行的时候,这些都不是问题,人脑可以脑补。一旦代码库上了百万行、横跨多个语言、嵌套多层框架,纯文本就会开始失能。
不是 grep 不好。
是代码早就不只是文本了。
1.2 编译器时代:AST 把代码"立体化"了
第一次把代码从"一维字符串"提升到"二维结构"的,是编译器。
编译器为了把 if (a > 0) { b = c + 1; } 翻成机器指令,必须先在内部构造一棵抽象语法树(AST)。根节点是 IfStatement,下面挂着 BinaryExpression、Block、Assignment 等节点。这棵树第一次让"语法结构"变成了可以被程序处理的对象。
AST 是 IDE 跳转、重构、Lint、Format 工具的共同基石。但 AST 还远远不够:它只知道代码"写成什么样",不知道代码"会怎么跑",数据"会怎么流"。
于是后来又出现了:
- 控制流图(CFG, Control Flow Graph):把代码切成基本块,描述执行路径,能回答"这段代码是不是死代码"、"会不会死循环";
- 程序依赖图(PDG, Program Dependence Graph)/ 数据流图(DFG, Data Flow Graph):描述变量赋值之间的依赖,能回答"用户输入到底有没有流进 SQL 拼接"。
1.3 CPG 时代:把三张图合一
2014 年,Fabian Yamaguchi、Nico Golde、Daniel Arp、Konrad Rieck 在 IEEE S&P 论文 Modeling and Discovering Vulnerabilities with Code Property Graphs 中提出了一个后来被 SAST 行业反复引用的概念:Code Property Graph(CPG,代码属性图)。
它的思想朴素但深刻:
既然 AST 描述"代码长什么样",CFG 描述"代码怎么执行",PDG 描述"数据怎么流",为什么不把这三张图叠加成同一张图,用同一套图查询语言来问问题?
CPG 把节点统一为"程序元素"(语句、表达式、变量、参数等),边按类型分(AST 边、CFG 边、DDG 边、CDG 边等)。一旦合一,安全研究员就能用图查询语言写出复杂的语义查询,比如经典的 SQL 注入污点查询:
"找出所有从 HTTP 参数节点出发,沿数据流边,未经过 sanitizer 节点,最终到达 SQL 执行节点的路径。"
这句话用 grep 写不出来,用普通 AST 工具也写不出来,但在 CPG 上可以表达成一段图查询。Yamaguchi 后来开源了 Joern,CPG 从此成为 SAST 静态安全检测领域的重要表示方法之一。
注意,这里有一个容易混淆的点:CPG 不是今天所有 AI Coding 工具背后那张图的同义词。
CPG 是安全分析场景里的重型语义图。AI Coding 里的 CodeGraph 往往更轻,可能只有 AST、符号、import、调用关系、版本信息和向量索引。它们不是一回事,但共享一个核心判断:代码需要被结构化理解,而不是只被字符串匹配。
1.4 LSP 时代:把"图"标准化、协议化
与此同时,IDE 阵营也在用另一条路径解决同一个问题。
2016 年微软推出了 Language Server Protocol(LSP)。LSP 的本质是:把语义信息(跳转、悬停、补全、引用、重命名)抽象成一套与编辑器无关的 RPC 协议,让每种语言只需要写一个 Language Server,就能服务所有 IDE。
LSP 解决了实时交互的问题,但它默认语言服务器在本地启动、本地分析。对于"在浏览器上打开超大规模代码库做跳转"这种需求,LSP 本身并不够。
于是微软又推出了 LSIF(Language Server Index Format),把语义信息预先计算成一份索引文件,代码托管平台读这个文件就能在网页上提供接近 IDE 的代码阅读体验。
后来 Sourcegraph 推出了 LSIF 的继任者:SCIP(SCIP Code Intelligence Protocol)。SCIP 用 Protobuf 定义 schema,目标是提供更紧凑、更强类型、更适合跨仓库代码智能的索引格式。到 2025 年 10 月,Sourcegraph 的 src-cli 移除了 LSIF 支持,SCIP 在 Sourcegraph 代码智能生态里成为主格式。
这一段历史说明一件事:在 LLM 出现之前,"代码图"这件事已经存在很久了。
只是那时候它主要服务 IDE、安全扫描和代码托管平台。普通开发者感知不到。
1.5 AI 时代:图被 LLM 复活
让 CodeGraph 第一次真正走到舞台中央的,是 LLM。
当我们试图让 LLM 理解一个百万行级别的代码库时,很多团队在 2023 年都做过类似的第一版方案:把代码切片,灌进向量库,做 Vector RAG。
然后大家很快撞上同一面墙:
单纯 Vector RAG 在代码场景下不够用。
为什么不够用?
这就是下一章要展开的事,也是 CodeGraph 在 AI 时代被重新发现、被包装成 "GraphRAG for Code" 或 "Graph-enhanced Code Retrieval" 的根本原因。
2 · CodeGraph 的核心组成:一张图到底装了什么
在深入 GraphRAG 之前,先把"现代 AI 时代的 CodeGraph"的内部结构讲清楚。
它远不止 AST/CFG/PDG,也不一定重到完整 CPG。面向 AI Coding 的 CodeGraph,更像一个由多层索引叠起来的工程系统。
2.1 语法层:AST / Tree-sitter
底层依旧是 AST。今天很多轻量级、多语言代码索引系统,会优先采用 tree-sitter 这类增量解析器。
tree-sitter 的几个特性让它非常适合 AI Coding 场景:
- 增量解析:编辑一行代码,只重解析附近受影响的子树;
- 错误恢复:代码写到一半语法错了,也能给出一棵尽可能可用的树;
- 统一接口:大量语言可以复用同一套解析接口和查询语法(S-expression)。
GitHub 的 Code Navigation、ast-grep 等项目明确使用了 tree-sitter。Cursor、Augment 这类商业 AI Coding 系统,即使没有把所有内部实现完全公开,也普遍会依赖类似的 AST/符号解析能力来做语义切块、结构搜索和上下文构建。
这里不要把 tree-sitter 神化。它解决的是"代码长什么样",不是"代码到底指向谁"。真正跨文件、跨包、跨仓库的精确引用关系,还需要语言服务器、编译器前端、SCIP indexer 或类似的语义分析能力。
2.2 语义层:符号表 / 类型图
AST 之上必须叠一层语义信息,否则你只知道某行有个 foo(),但不知道它到底指哪个 foo。
语义层至少包括:
- 符号定义/引用:每个 identifier 指向对应定义节点,可能跨文件、跨包、跨仓库;
- 类型系统:每个表达式的类型节点、函数签名、泛型、继承层级;
- 模块依赖:
import、require、use形成的有向边; - 作用域:词法作用域、闭包捕获关系。
这一层是 LSP/LSIF/SCIP 的核心产物。如果你用 Sourcegraph、GitHub Code Search 跳转过代码,跳的就是这一层。
2.3 调用与控制流层:Call Graph / CFG
再往上是:
- 调用图(Call Graph):函数 A 调用函数 B 的边集合,区分静态调用、虚函数、动态分派、回调;
- 控制流图(CFG):每个函数内部的基本块和分支边;
- 过程间控制流图(ICFG):把多个函数的 CFG 通过 call edge 串起来。
调用图是 AI Coding 工具做"影响面分析"的关键。当你问 "我改了 parseConfig 会影响哪些地方?" 时,背后理想情况下跑的就是调用图的反向遍历。
但这里也要保留一点工程诚实。
不同语言的调用图精度差异很大。Go、Rust、Java 这类语言相对容易做得精确一些;JavaScript、Python、Ruby 这种动态语言里,框架注入、反射、动态分派会让调用图天然带噪声。所以很多 AI Coding 产品并不会追求一次性构建"完美调用图",而是用静态图、全文索引、运行时信号、LLM 重新排序一起补。
2.4 数据流层:DFG / PDG / 污点图
这是安全场景最看重、但 AI Coding 场景也越来越重视的一层:
- 数据流图(DFG):变量赋值传播的路径;
- 程序依赖图(PDG):数据依赖 + 控制依赖;
- 污点图(Taint Graph):source(不可信输入)到 sink(敏感操作)的可达路径。
CodeQL、Joern 的核心查询能力都建在这一层。
对普通 AI Coding 来说,数据流图还不是所有场景的标配。它的构建成本高,语言差异大,误报漏报也难完全避免。但一旦进入安全修复、隐私合规、金融风控、权限边界这类场景,数据流会从"加分项"变成"必选项"。
2.5 现代扩展:跨制品图 / 演进图 / 上下文图
最近两年,工业界把 CodeGraph 又扩展了几个新维度。这些扩展是普通编译原理教材里很少覆盖的:
- 跨制品图(Cross-Artifact Graph):把代码节点和 commit、PR、issue、设计文档、API 接口定义连起来。Augment Code 的 Context Engine 公开强调会索引代码、提交历史、文档、工单、团队模式,本质上就是这类跨制品上下文;
- 演进图(Temporal Graph):每个节点带时间维度,能查询"这个函数最近 90 天的修改频率"、"哪些函数和它一起共变(co-change)";
- 上下文图 / Agent Memory Graph:把 LLM 交互过程中的工具调用、任务状态、局部结论作为节点记录下来,让 Agent 在长任务里拥有可追溯的工作记忆。
到这一步,CodeGraph 已经从"代码的图表示"扩展为"代码 + 工程上下文 + 时间 + Agent 记忆"的复合知识图。
这也是为什么我越来越觉得,未来 AI Coding 的竞争不会只发生在模型层。
模型当然重要,但代码上下文从哪里来、如何更新、如何被验证、如何暴露给 Agent,会变得同样重要。
3 · 为什么 AI Coding 必须用图:GraphRAG 在代码场景的价值
这一章是全文的核心论点:
普通 Vector RAG 在代码理解任务上有结构性缺陷,CodeGraph 不是锦上添花,而是很多复杂代码任务里的必要补充。
注意,我不是说 Vector 没用。
恰恰相反,Vector 很有用。它擅长发现语义相近、命名不完全一致、用户自己也说不清楚的上下文。
问题是,代码世界里很多关键关系不是"相似",而是"引用、调用、依赖、继承、覆盖、流动、共变"。
这些关系天然更像一张图。
3.1 Vector RAG 在代码场景的四个硬伤
Vector RAG 的工作模式所有人都熟:把代码切块,embedding,存向量库,用户提问也 embedding,取 top-k 相似,喂给 LLM。
这套流程在文档问答上非常好用,但搬到代码上之后,会撞上以下几面墙。
硬伤一:语义相似 ≠ 代码相关
向量检索找的是"看起来语义相似"的代码块。但代码里"和你的问题相关"的代码块,往往不长得相似。
举个工程里很常见的例子。
你问:"为什么订单创建会失败?"
真正相关的可能是:
OrderService.create()的入口;Payment.charge(),它在 create 中被调用;InventoryClient.reserve(),charge 之前还要扣库存;PaymentGatewayConfig,charge 依赖的配置;- 某个最近合入的 PR,把超时时间从 3 秒改成了 800 毫秒。
这些代码在词面上不一定相似。"order"、"payment"、"inventory"、"config" 是不同领域词,最近 PR 的 commit message 里甚至可能一个都没出现。
但它们在调用图、依赖图、演进图上是相邻的。
沿着 call edge、dependency edge、change edge 走几步,才更可能拿全。
硬伤二:精确标识符查询不能只靠相似度
当用户的问题里出现 processOrderV2 这种精确符号名时,Vector RAG 经常返回 processOrder、processOrderLegacy、handleOrderV2 等"语义相似但实际不对"的结果。
这正是用户最不能接受的失败模式。
自然语言问答里,差不多有时候可以接受。
代码里,差一个字符就是另一个函数。
硬伤三:超大规模下召回质量会退化
Tian Pan 在 2026 年 4 月关于生产检索栈的分析里提到一个值得警惕的现象:
- 512 维 embedding 在文档数超过约 50 万时,检索质量可能开始显著退化;
- 4096 维 embedding 在更大规模语料下也会遇到边界。
这组数据不应该被理解成所有系统的普适物理定律。不同 embedding 模型、切块策略、语料分布、重排序方案都会影响结果。
但它提醒我们一件事:dense embedding 是一种有损压缩。语料规模越大、约束越复杂、标识符越稀有,单向量检索越容易把关键差异压掉。
一个真实的大型企业代码库如果把 monorepo、历史版本、依赖库、文档、PR、issue 都算进去,很容易进入这个区间。
硬伤四:多约束查询会被"平均掉"
当用户问:
在 payment 模块里、最近一个月被修改过、且涉及 Stripe API 的函数有哪些?
Vector RAG 会把三个约束糅进同一个向量里,结果是三个约束都被模糊化。
而在 CodeGraph 上,这其实是三个可以精确求交的过滤条件:
- 模块路径约束;
- 时间约束;
- API 调用关系约束。
这类问题不是语义相似问题,而是结构化查询问题。
3.2 GraphRAG 在代码场景的几种范式
针对上面这些痛点,业界这两年沉淀出了几种 GraphRAG for Code 的范式。
这里的 GraphRAG 不一定等同于 Microsoft Research 那套原始 GraphRAG。更宽泛地说,它指的是:检索时不只看文本相似度,还显式利用图结构。
范式一:Symbol-Level Retrieval(符号级检索)
最朴素的版本:用户提问里的实体名(函数、类、变量)作为锚点,直接在符号表里精确命中,然后沿着调用图、引用图扩展 1~2 跳。
代表实现包括 IDE 跳转、Sourcegraph 代码导航、一些 AI Coding 工具里的 @symbol 或代码库检索能力。
优点:精确、快、幻觉少。
局限:依赖用户提问里出现确切的符号名。
范式二:Hybrid Retrieval(向量 + 全文 + 图)
这是当前很多 AI Coding 工具最现实的选择。流程通常是:
- 第一阶段(语义锚点):把用户的问题做 embedding,在向量库里取 top-K candidate chunks,作为"大概该看哪里"的锚点;
- 第二阶段(精确补充):用全文索引、符号索引找到显式实体、路径、错误码、配置名;
- 第三阶段(图扩展):每个 candidate chunk 对应到 CodeGraph 上的节点,沿着调用图、依赖图、引用图做 1~3 跳扩展;
- 第四阶段(重排序):用 LLM-based rerank 或规则特征,把相似度、中心性、修改 recency、call depth 等因素合并;
- 第五阶段(裁剪与组装):在 token budget 限制下,裁剪到最相关的 N 个片段,组装成 prompt 或暴露给 Agent 工具。
这一范式的核心思想是:
用向量解决"我大概该看哪里",用图解决"我必须看哪些",用全文搜索兜住那些不能模糊的名字。
范式三:Microsoft GraphRAG 风格(社区聚类 + 层次摘要)
Microsoft Research 2024 年提出的原始 GraphRAG 范式,本意是针对文档全局问答,比如"这个大型语料整体在讲什么"。
它的思路是:
- 用 LLM 抽取实体和关系,构建知识图;
- 用社区检测算法(如 Leiden)把节点聚成层次化社区;
- 对每个社区生成层次化摘要;
- 用户提问时,根据问题层级选择对应粒度的摘要。
这套方案在文档全局问答里很强,但成本不低。公开资料中,Microsoft GraphRAG 的传统索引成本常被拿来和普通 Vector RAG 对比:同样规模的语料,GraphRAG 的实体抽取和社区摘要会贵很多。后来 Microsoft 又推出 Dynamic Community Selection,把 token 用量降低 79%;LazyGraphRAG 则通过懒构建思路,把前置索引成本大幅压低。
这套范式在代码场景还处于早期探索,但已经有几个开源项目在尝试,比如 Code-Graph-RAG(Tree-sitter + Memgraph + 多语言支持)、codegraph-rust(Rust + SurrealDB)。
范式四:Agentic Graph Traversal(智能体图遍历)
最近这一两年最有意思的方向,是不再让 LLM 一次性接收一个组装好的 context,而是让 Agent 自主决定:
我现在需要去图上的哪个节点看一眼?
典型动作包括:
- Agent 先看入口函数;
- 觉得需要看实现,调用
goto_definition(symbol); - 觉得需要看影响面,调用
find_callers(symbol); - 觉得需要看引用,调用
find_references(symbol); - 觉得需要看数据流,调用
taint_path(source, sink); - 觉得需要看历史,调用
get_pr_history(symbol, days=30)。
Cursor 的 Agent 模式、Claude Code 的工具调用、Augment 的 Context Engine MCP,都在往这个方向走。
Augment 公开材料里提到过一组厂商自测数据:在 Elasticsearch 300 个 PR 的测试集上,接入 Context Engine MCP 后,Claude Code + Opus 4.6 整体质量提升 80%,Cursor 提升 71%,并且 token 用量下降。
这组数据可以作为趋势信号,但要记住它来自厂商 benchmark,不能当成独立第三方结论。
真正重要的是它指向的方向:
CodeGraph 正在从"被动检索对象"变成"主动暴露给 Agent 的工具 API"。
3.3 几个被忽略的工程结论
把上面几个范式放到生产环境里看,会沉淀出几个反直觉的工程结论:
- 不要单押 Vector:Vector 适合做"发现新关联",但大量精确查询本质上是符号、引用、调用和依赖遍历;
- 不要单押 Graph:纯图查询很难处理"语义相似但符号不同"的探索式问题;
- Hybrid 是当前更稳的工程解:向量做粗筛,全文做精确兜底,图做结构补全,LLM 做综合;
- GraphRAG 不是免费午餐:构建成本远高于普通 Vector RAG,要看清楚 ROI 再上;
- 增量更新比首次构建重要:代码库每分钟都在变,没有增量更新的 GraphRAG 在生产环境很快会失真。
4 · 业界主流方案调研:八家在卷什么、各自押了哪一注
这一章把市面上影响较大的 8 个 CodeGraph / 代码检索方案拉出来做横向对比。
每家的"押注"都不同,背后是商业模式和工程哲学的差异。
4.1 Cursor
公开信息里,Cursor 的索引架构大致包括:
- 语义切块:使用 AST/结构化解析,把代码按函数、类、方法等语义单元切块,而不是简单按字符长度盲切;
- 嵌入存储:每个 chunk 转成向量,公开案例中提到 Cursor 使用 Turbopuffer 作为向量数据库;
- 增量与复用:Cursor 官方博客提到用 Merkle Tree 追踪文件变更,并利用组织内代码相似性复用已有索引。官方材料里给出的一个关键观察是:组织内代码库平均有 92% 相似度;
- 检索流水线:公开资料和业界拆解普遍认为,Cursor 会把向量检索、代码结构信号、文件/符号上下文和重排序组合起来,而不是只做 embedding top-k。
这里要谨慎区分"官方明确公开"和"外部推测"。
Merkle Tree、92% 相似度、Turbopuffer 属于公开材料能支撑的部分;至于具体如何做调用/依赖图扩展、如何按 recency 或 call depth 重排,属于产品内部实现细节,不应写得像已经完全公开。
Cursor 的押注可以概括为:
Hybrid + 极致工程化:增量、缓存、索引复用、低延迟检索。
它不一定要自己重造 SCIP/CodeQL 那种重资产语义图,而是把 AST、向量、全文、局部结构关系这套轻量组合优化到非常顺手。
4.2 Sourcegraph(SCIP + Cody)
Sourcegraph 是这场战争里"重资产代码智能"的代表玩家。
它的核心资产是 SCIP:一套 Protobuf 定义的代码索引格式,目标是比 LSIF 更紧凑、更强类型、更适合大规模代码导航。
公开生态里,SCIP indexer 覆盖 Go、TypeScript、Java、Python、Rust 等语言,索引粒度可以精确到 token 的定义、引用和类型。2025 年 10 月,src-cli 移除了 LSIF 相关功能,只保留 SCIP 支持。
SCIP 之上是 Cody。Cody 押的是"精确代码智能 + Hybrid 检索":keyword search、embedding search、代码导航/图关系多路召回,再交给模型综合。
Sourcegraph 的优势是精度和企业级代码导航积累。
代价也明显:每种语言都要有高质量 indexer,工程量巨大;部署、权限、索引更新、跨仓库关系,也比轻量工具复杂得多。
4.3 GitHub CodeQL
CodeQL 是 GitHub 自家的高级安全扫描引擎。它的世界观是把代码库 extract 成一个可查询数据库,然后用 QL 语言写查询。
它本质上是 CPG 思想在工业级 SAST 场景里的强落地之一:
- 截至 2026 年 5 月,CodeQL 2.25.4 的 Default 套件公开显示有 496 个安全查询,覆盖 169 个 CWE;Extended 套件还会增加 131 个查询;
- 2.25 系列对 Java/C# 的 CFG 相关能力有重要更新;
- Models-as-data 支持把框架、库、source/sink、sanitizer/validator 等建模数据化;
- 新增 Hibernate SQL 注入 sink、ASP/ASP.NET remote source 等能力。
CodeQL 的押注是:
强语义建模 + DSL 查询 + 安全场景深耕。
CodeQL 在 AI Coding 主场景里不一定直接出现,但它代表了"代码图在安全分析里能精确到什么程度"的上限。任何想做企业级代码安全的 AI 工具,最终都会遇到 CodeQL 这类能力边界。
4.4 Joern(开源 CPG)
Joern 是 CPG 思想的开源代表之一,定位更接近安全研究和程序分析工具。
它把 AST + CFG + PDG 统一成一张 CPG,并提供类似 Scala 风格的 DSL 来查询程序模式。Joern 在学术界和独立安全研究员中影响力很高,是研究污点分析、漏洞挖掘、程序切片的常用工具。
它的押注是:
开源 CPG 标杆。
它在 AI Coding 产品前台没有 Cursor、Claude Code 那么高的声量,但它定义了"重型程序分析图"可以长什么样,也给很多后来者提供了参考。
4.5 Augment Code(Context Engine)
Augment 是过去一年最值得关注的玩家之一。它的核心叫 Context Engine,野心比传统 IDE 助手大得多。
公开材料里,Augment 强调几件事:
- 大规模上下文索引:支持大型代码库和多仓库场景;
- 多源融合:不只是代码,还包括 commit history、文档、工单、团队模式;
- MCP 化输出:Context Engine MCP 允许 MCP 兼容的 Agent 接入,比如 Claude Code、Cursor、Codex、Copilot 等;
- 效果数据:Augment 自己在 Elasticsearch 300 个 PR 上做对照测试,公开称 Claude Code + Opus 4.6 接入 Context Engine 后整体质量提升 80%,Cursor 提升 71%,并减少 token 和工具调用。
这组数据的价值在于显示"上下文质量"对 Agent 表现的影响非常大;但它是厂商自测,引用时必须带上这个边界。
Augment 的押注是:
做 Agent 时代的上下文供应商。
它不一定要和 Cursor / Claude Code 抢前端,而是把"图 + 检索 + 上下文压缩"作为 MCP 服务暴露给所有人。这是一个很聪明的生态位。
4.6 Continue.dev
Continue 是这场战争里最开源、最透明的方案之一。它的 CodebaseIndexer 可以直接在 GitHub 上看到。
它的索引架构包括:
- 多路索引:全文搜索、代码片段、chunking、embedding 等能力组合;
- 批处理:默认 200 文件一批,控制内存和 embedding 调用频率;
- 向量后端可选:默认 LanceDB,也支持 Qdrant 等后端;
- 检索流水线:可配置
nRetrieve初步召回、nFinal最终留存、可选 LLM rerank; - 本地优先:很多场景可以在本地跑 embedding,索引存在本机目录。
Continue 的押注是:
开源 + 本地优先 + 可定制。
它适合对数据敏感、有强定制需求、愿意自己运维和改造的团队。
4.7 ast-grep + tree-sitter 生态
ast-grep 不是一个 CodeGraph 产品,但它是 AI Agent 时代代码工具链里很容易被低估的一环。
- 结构化搜索/重写:基于 tree-sitter 的 AST 模式匹配,可以写"匹配所有
func foo() error { return nil }这种空实现"这类结构模式; - 多语言:基于 tree-sitter,覆盖多种常见语言;
- Agent 友好:它给 Agent 提供的不是脆弱正则,而是结构化、可验证、可批量改写的代码操作能力。
如果没有可核验来源,就不建议把它写成带排名的外部评价。更稳的判断是:
ast-grep 的价值不在于建图,而在于给 Agent 一个更可靠的结构化操作接口。
它和 CodeGraph 的关系,类似 jq 和 JSON 的关系。你不一定单独用它建图,但很多结构化搜索和批量重写场景都可以受益。
4.8 横向对比表
| 方案 | 图深度 | 检索范式 | 商业模式 | 适合场景 | 工程成本 |
|---|---|---|---|---|---|
| Cursor | AST/语义切块 + 轻量结构信号 | Vector + 结构化上下文 + 重排 | SaaS / 订阅 | 个人 / 团队日常 AI Coding | 中 |
| Sourcegraph + Cody | SCIP 精确代码智能 | Keyword + Embedding + Code Intelligence | 企业版 / SaaS | 大型组织代码导航 + AI | 高 |
| CodeQL | 安全分析级代码数据库 / CPG 思想 | QL 查询 | GitHub Advanced Security | 企业安全 SAST | 极高 |
| Joern | 完整 CPG | 类 Scala DSL | 开源 | 安全研究 / 漏洞挖掘 | 高 |
| Augment | 跨制品上下文图 | Hybrid + MCP 化 | SaaS | 大企业 + Agent 生态 | 中 |
| Continue | 多路索引 + 可扩展检索 | 可配置 Hybrid | 开源 | 本地优先 / 自托管 | 低 |
| Code-Graph-RAG | tree-sitter + Memgraph | GraphRAG | 开源 | 自建实验 | 低 |
| ast-grep | AST 模式匹配 | 结构化搜索/重写 | 开源 CLI | Agent 工具链 | 极低 |
一句话总结:
没有银弹。
重资产玩家(Sourcegraph、CodeQL)押注精度,轻量玩家(Cursor、Continue)押注工程化和增量更新,新势力(Augment)押注上下文广度和 Agent 生态位。
5 · 自建 CodeGraph 工程蓝图:如果你要给自家公司搭一套
讲完调研,回到工程问题。
如果你所在的公司有几百万行私有代码,对数据合规有要求,不能把代码随便喂给外部 SaaS,又想给团队提供 AI Coding 体验,怎么自建?
下面给一个我认为在 2026 年比较稳的工程蓝图。
它不追求最先进,追求三件事:
- 能落地;
- 能增量演进;
- 出问题时工程团队知道该从哪里查。
5.1 整体架构
下面逐层讲取舍。
5.2 数据采集层
第一选择:tree-sitter + SCIP 双轨。
- tree-sitter 解析所有语言:拿到 AST,做基础语法节点、函数/类边界、import 等关系。它轻、快、增量友好;
- SCIP indexer 跑主力语言:对公司主力语言(比如 Go、TypeScript、Python、Java)跑官方或社区 indexer,拿到精确的符号定义/引用/类型边。次要语言先用 tree-sitter 顶。
调用图和数据流:
- 简单调用图:tree-sitter 抽符号 + SCIP 引用边可以覆盖一部分;
- 精确调用图(虚函数、动态分派):需要语言级编译器前端、LSP 或专门分析器;
- 数据流/污点:除非有强安全需求,不建议第一期做,复杂度高、ROI 不一定清楚。
跨制品图:
- 用 Git API 抓 commit、PR、issue;
- 把"PR 改动 → 函数节点"建立边;
- 文档(Confluence、Wiki、Notion)以 entity link 形式接入;
- 关键设计文档可以要求作者显式标注模块、接口、函数名。
这一层最容易犯的错,是一上来就想做完美图。
别这样。
第一期要先让 AI 在真实任务里找到正确文件、正确函数、正确调用链。能做到这三件事,价值就已经很大。
5.3 图存储层
候选:
- Neo4j:成熟、Cypher 生态丰富、运维难度中等。代码量在百万行级别可以优先考虑;
- Memgraph:Cypher 兼容,性能和实时更新能力有优势,适合更偏在线查询的场景;
- SurrealDB:多模数据库(图 + 文档 + 关系),适合"代码图 + 工单 + 文档"复合场景;
- 自研内存图:如果代码量超大且对查询延迟极敏感,可以考虑内存图 + 持久化快照,但这会显著抬高工程门槛。
关键建议:图存储和向量存储分离部署。
不要过早追求一个"图 + 向量 + 全文"全包数据库。听起来很美,生产里常常会在性能、成本、可观测性和故障隔离上同时变复杂。
5.4 索引调度层
这是最容易被低估、但最决定线上稳定性的一层。
- 首次构建(cold build):百万行规模通常是几十分钟到几小时,必须支持断点续传;
- 增量更新(incremental):参考 Cursor 官方公开的 Merkle Tree 思路,按目录树做哈希,只重算变更子树;
- PR 级增量:每个 PR 提交时增量重算这次 diff 涉及的节点和边,能力强的可以做"预览图",让 AI 在 PR review 时看到改动影响面;
- 依赖图变更传播:当 A 文件变了,所有依赖 A 的文件的相关边都可能需要重算,一定要做传播深度限制;
- 跨语言一致性:多语言混合代码库,必须有一个"主图"做统一节点 id 分发,否则跨语言边会乱掉。
真正上线后,最容易把系统打挂的不是第一次构建,而是日常变化。
一个大重构、一次大规模 rename、一轮 dependency upgrade,都可能让索引集群进入雪崩式重算。
所以这层要早做限流、队列、优先级和可观测性。
5.5 检索编排层
检索是用户体验的最终决定者。
一个生产级的代码 GraphRAG 检索器至少要做这些:
- Query 改写:把用户自然语言改写成"实体 + 意图"对,比如把"为什么 OrderService 慢"改写成
entity=OrderService, intent=performance_diagnostics; - 多路召回:向量 top-K、全文搜索、符号搜索、图遍历同时召回;
- 去重 + 合并:合并到节点粒度,而不是停留在文本 chunk 粒度;
- 重排序:综合相似度、符号精确命中、图中心性、修改 recency、call depth;
- Token 预算裁剪:在 LLM 上下文窗口预算内,优先保留高分节点的完整定义 + 邻居摘要;
- Prompt 组装:把代码块、调用关系、commit 摘要、已知 negative result 拼成结构化 prompt。
反模式提醒:
- 不要一次性把所有可能相关的内容塞进 prompt,再大的窗口都不够;
- 不要纯靠 embedding 相似度排序,代码里很多关系不是相似关系;
- 不要忽略 negative result,告诉 LLM "我们没找到 X" 比让它自由发挥更安全;
- 不要把检索结果当真理,检索结果只是候选上下文,仍然需要模型和工具验证。
5.6 与 LLM 的整合
两种主流模式:
模式 A:传统 RAG
一次性把检索结果组装好喂给 LLM。简单、稳定、可预测。适合大多数问答和解释场景。
模式 B:Agentic 模式(推荐逐步演进)
把 CodeGraph 包装成一组工具(tool calls)暴露给 Agent,让 Agent 自主决定查什么:
tool: goto_definition(symbol)
tool: find_callers(symbol)
tool: find_references(symbol)
tool: get_file_structure(path)
tool: get_call_chain(from, to)
tool: get_pr_history(symbol, days=30)
tool: search_by_pattern(ast_pattern)
这套工具其实就是 CodeGraph 的 MCP 暴露,可以对接 Claude Code、Cursor 等 MCP 客户端。
Augment 已经在做这件事,它的价值不只是"又多了一个检索接口",而是把上下文基础设施从某个产品内部拆出来,变成 Agent 可以调用的公共能力。
5.7 落地节奏建议
如果是从零开始,建议按以下节奏:
- 第 1 个月:tree-sitter 解析 + 简单符号表 + 全文索引 + 向量库,对接公司主力语言;
- 第 2~3 个月:SCIP indexer 上线主力语言,补精确符号边、跨文件跳转和增量更新;
- 第 4~6 个月:跨制品图(commit、PR、issue)接入,重排器引入图中心性、recency;
- 第 6~9 个月:MCP 化暴露,对接 Claude Code / Cursor,让 Agent 主动用图;
- 第 9~12 个月:增量优化、跨仓库联邦、按需引入数据流/污点分析。
不要试图一上来就建完整 CPG。
那是一个 5+ 人团队 1 年起步的工程量,而且还不一定是你第一阶段最需要的东西。
6 · 趋势:CodeGraph 的下一站
最后简单聊几个值得跟踪的方向。
6.1 多模态 CodeGraph
代码图正在快速吸收周边制品:commit、PR、issue、设计文档、ADR、Runbook、监控告警、性能 profile。
Augment 是这个方向比较激进的玩家。未来几年,"代码图"和"工程知识图谱"的边界大概率会变得越来越模糊。
6.2 Runtime Graph
静态图 + 动态执行 trace 的融合,是下一阶段很关键的方向。
把生产环境的 distributed tracing、CPU profile、慢查询日志反向映射到代码节点上,做"运行时增强的 CodeGraph"。这件事 Datadog、Sentry、Honeycomb 等可观测性厂商都在相关方向上探索,但还没有形成统一事实标准。
真正有价值的不是"我知道函数 A 调用了函数 B",而是:
我知道线上 80% 的慢请求,最后都卡在这条调用链的第三个节点。
这时候 CodeGraph 就不只是代码理解工具,而是研发、观测、性能和事故复盘之间的桥。
6.3 Agent 时代的 CodeGraph
最大的范式变化在这里:CodeGraph 会从"被检索对象"变成"主动暴露的 API"。
MCP 标准的成熟让这件事变得可行。CodeGraph 不再只是隐藏在产品内部的黑盒,而是以一组 tool 的形式暴露给任何 Agent。
未来 2~3 年内,我更愿意做一个谨慎判断:
会有越来越多企业,把代码图能力以 MCP / tool API 的形式暴露出来。
谁能占住"企业代码上下文服务商"这个生态位,谁就有机会掌握 Agent 时代 dev tools 的关键入口。
6.4 LLM 反哺图的构建
LLM 越来越多地参与图本身的构建:
- 用 LLM 抽取静态分析抓不到的"隐式关系";
- 用 LLM 给节点生成自然语言摘要,做层次化检索;
- 用 LLM 帮工程团队发现图 schema 缺了哪些关系;
- 用 LLM 对跨制品信息做 entity linking,比如把 PR 描述里的模块名连回代码节点。
但 LLM 抽图的成本和不确定性,需要谨慎对待。
这也是 LazyGraphRAG 这类思路值得关注的原因:不要一上来就把所有图都建完,而是在查询时按需构建、按需摘要、按需扩展。
工程里真正贵的,往往不是能不能做。
而是你能不能持续、便宜、可解释地做。
7 · 结语
回到开头那个问题:
Cursor 是怎么"看懂"你那 200 万行祖传代码的?
答案现在应该更清楚了。
它不是靠 LLM 自己长出"理解能力",也不是靠把整个代码库塞进上下文窗口,而是靠一套你平时看不见、但每次提问都在背后高速运转的代码上下文基础设施。
这套基础设施融合了 AST、符号关系、调用关系、依赖关系、版本演进、PR 历史、全文搜索、向量检索和图遍历,最后把最相关的几十 KB 内容尽可能准确地交给 LLM 或 Agent。
CodeGraph 是这个时代的 dev tools 基础设施。
它从 1970 年代的编译器走到今天的 AI Agent,经过了 50 年工程积累。它不是某个具体产品,而是一种对代码本质的世界观:
代码不是字符串,代码是一张图。
但更准确地说,代码也不只是图。
代码是文本、结构、历史、运行时行为和工程上下文叠在一起的复杂系统。图只是我们第一次有机会,把这些关系显式地交给 AI。
谁先建好这套上下文基础设施,谁先把它 MCP 化,谁先让 Agent 学会在图上自由行走,谁就拿到了下一代 AI Coding 的入场券。
如果你正在构建私有代码库的 AI 助手、构建企业 dev tools,或者只是想搞清楚 Cursor 背后到底在做什么,希望这篇文章给了你一张足够清晰、也足够谨慎的地图。
参考资源
- Yamaguchi et al., Modeling and Discovering Vulnerabilities with Code Property Graphs, IEEE S&P 2014
- Joern Documentation, Code Property Graph
- Sourcegraph, SCIP - a better code indexing format than LSIF
- Sourcegraph
src-clichangelog / LSIF removal commit - Cursor Blog, Securely indexing large codebases
- Turbopuffer, Cursor scales code retrieval to 1T+ vectors with turbopuffer
- Microsoft Research, GraphRAG: New tool for complex data discovery
- Microsoft Research, GraphRAG: Improving global search via dynamic community selection
- Microsoft Research, LazyGraphRAG: Setting a new standard for quality and cost
- Augment Code, Context Engine MCP
- Continue.dev Docs, Custom Code RAG
- Continue.dev 开源仓库, github.com/continuedev…
- GitHub CodeQL Changelog (2.25.x 系列)
- ast-grep 项目, ast-grep.github.io
- Code-Graph-RAG, github.com/picassio/co…