CodeGraph:让 AI 真正读懂代码的底层基础设施

0 阅读35分钟

从 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' 里的 foobar.ts 里的 export function foo() 是同一个东西;
  • 它更不知道一个变量从 HTTP 请求参数流到 SQL 查询的"路径"长什么样。

当代码库只有几千行的时候,这些都不是问题,人脑可以脑补。一旦代码库上了百万行、横跨多个语言、嵌套多层框架,纯文本就会开始失能。

不是 grep 不好。

是代码早就不只是文本了。

1.2 编译器时代:AST 把代码"立体化"了

第一次把代码从"一维字符串"提升到"二维结构"的,是编译器。

编译器为了把 if (a > 0) { b = c + 1; } 翻成机器指令,必须先在内部构造一棵抽象语法树(AST)。根节点是 IfStatement,下面挂着 BinaryExpressionBlockAssignment 等节点。这棵树第一次让"语法结构"变成了可以被程序处理的对象。

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 指向对应定义节点,可能跨文件、跨包、跨仓库;
  • 类型系统:每个表达式的类型节点、函数签名、泛型、继承层级;
  • 模块依赖importrequireuse 形成的有向边;
  • 作用域:词法作用域、闭包捕获关系。

这一层是 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 经常返回 processOrderprocessOrderLegacyhandleOrderV2 等"语义相似但实际不对"的结果。

这正是用户最不能接受的失败模式。

自然语言问答里,差不多有时候可以接受。

代码里,差一个字符就是另一个函数。

硬伤三:超大规模下召回质量会退化

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 工具最现实的选择。流程通常是:

  1. 第一阶段(语义锚点):把用户的问题做 embedding,在向量库里取 top-K candidate chunks,作为"大概该看哪里"的锚点;
  2. 第二阶段(精确补充):用全文索引、符号索引找到显式实体、路径、错误码、配置名;
  3. 第三阶段(图扩展):每个 candidate chunk 对应到 CodeGraph 上的节点,沿着调用图、依赖图、引用图做 1~3 跳扩展;
  4. 第四阶段(重排序):用 LLM-based rerank 或规则特征,把相似度、中心性、修改 recency、call depth 等因素合并;
  5. 第五阶段(裁剪与组装):在 token budget 限制下,裁剪到最相关的 N 个片段,组装成 prompt 或暴露给 Agent 工具。

这一范式的核心思想是:

用向量解决"我大概该看哪里",用图解决"我必须看哪些",用全文搜索兜住那些不能模糊的名字。

范式三:Microsoft GraphRAG 风格(社区聚类 + 层次摘要)

Microsoft Research 2024 年提出的原始 GraphRAG 范式,本意是针对文档全局问答,比如"这个大型语料整体在讲什么"。

它的思路是:

  1. 用 LLM 抽取实体和关系,构建知识图;
  2. 用社区检测算法(如 Leiden)把节点聚成层次化社区;
  3. 对每个社区生成层次化摘要;
  4. 用户提问时,根据问题层级选择对应粒度的摘要。

这套方案在文档全局问答里很强,但成本不低。公开资料中,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 几个被忽略的工程结论

把上面几个范式放到生产环境里看,会沉淀出几个反直觉的工程结论:

  1. 不要单押 Vector:Vector 适合做"发现新关联",但大量精确查询本质上是符号、引用、调用和依赖遍历;
  2. 不要单押 Graph:纯图查询很难处理"语义相似但符号不同"的探索式问题;
  3. Hybrid 是当前更稳的工程解:向量做粗筛,全文做精确兜底,图做结构补全,LLM 做综合;
  4. GraphRAG 不是免费午餐:构建成本远高于普通 Vector RAG,要看清楚 ROI 再上;
  5. 增量更新比首次构建重要:代码库每分钟都在变,没有增量更新的 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 横向对比表

方案图深度检索范式商业模式适合场景工程成本
CursorAST/语义切块 + 轻量结构信号Vector + 结构化上下文 + 重排SaaS / 订阅个人 / 团队日常 AI Coding
Sourcegraph + CodySCIP 精确代码智能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-RAGtree-sitter + MemgraphGraphRAG开源自建实验
ast-grepAST 模式匹配结构化搜索/重写开源 CLIAgent 工具链极低

一句话总结:

没有银弹。

重资产玩家(Sourcegraph、CodeQL)押注精度,轻量玩家(Cursor、Continue)押注工程化和增量更新,新势力(Augment)押注上下文广度和 Agent 生态位。

5 · 自建 CodeGraph 工程蓝图:如果你要给自家公司搭一套

讲完调研,回到工程问题。

如果你所在的公司有几百万行私有代码,对数据合规有要求,不能把代码随便喂给外部 SaaS,又想给团队提供 AI Coding 体验,怎么自建?

下面给一个我认为在 2026 年比较稳的工程蓝图。

它不追求最先进,追求三件事:

  • 能落地;
  • 能增量演进;
  • 出问题时工程团队知道该从哪里查。

5.1 整体架构

canvas_node_generated_mp9u6er2e5ewpf2.png

下面逐层讲取舍。

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 检索器至少要做这些:

  1. Query 改写:把用户自然语言改写成"实体 + 意图"对,比如把"为什么 OrderService 慢"改写成 entity=OrderService, intent=performance_diagnostics
  2. 多路召回:向量 top-K、全文搜索、符号搜索、图遍历同时召回;
  3. 去重 + 合并:合并到节点粒度,而不是停留在文本 chunk 粒度;
  4. 重排序:综合相似度、符号精确命中、图中心性、修改 recency、call depth;
  5. Token 预算裁剪:在 LLM 上下文窗口预算内,优先保留高分节点的完整定义 + 邻居摘要;
  6. 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-cli changelog / 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…