你给AI编码助手喂过整个项目吗?
我试过。一个中型React项目,40多个文件,代码量大概两万行。把全部文件丢给Claude Code,它先是“好的,我读完了”,然后开始犯浑——函数名记错,调用关系搞反,甚至自己编了个不存在的API。更崩溃的是,光传代码就花了几千个token,还没开始干活预算先爆了一半。
后来我试过RAG方案:把代码切块、向量化、存到本地向量库。效果有改善,但每次提问都要检索一大堆不相关的片段,AI还得自己拼图。而且向量相似度搜索对代码语义的理解很粗糙——它知道“login”和“authentication”相近,但不知道哪个函数调用了哪个。
直到前两天看到GitHub上一个叫CodeGraph的项目,一天涨了17898星,直接把“预索引知识图谱”这个概念拉到开发者眼前。我花了一个周末折腾,结论是:这可能是目前对AI编码助手最实用的本地优化方案。
它到底解决什么问题
先说痛点。当你让Claude Code、Cursor或Codex理解你的项目时,常见做法有四种:
- 全量注入:把整个代码库塞进上下文。token消耗巨大,模型注意力被稀释,还容易超出上下文窗口。
- 手动选择文件:你挑几个关键文件传给AI。但你不一定记得所有相关文件,漏了一个可能导致推理错误。
- 向量RAG:按语义切块向量化,查询时召回。召回率飘忽,代码中大量符号名称和逻辑依赖关系向量化效果差。
- 工具调用(tool use):让AI通过运行grep、cat等命令自己找文件。每个工具调用都延迟几十秒,还经常跑偏。
CodeGraph的思路很暴力也很聪明:离线把代码解析成知识图谱,把函数、类、变量、文件之间的调用、继承、导入关系全部结构化存起来。然后把它变成一个极轻量级的检索服务,AI每次只获取当前问题相关的子图——也就是最小上下文。

我用一个真实项目做了对比(一个Node.js + TypeScript后端,约150个文件,5万行代码):
| 方式 | Token消耗(平均每次提问) | 工具调用次数 | 准确回答率 | 首次响应时间 |
|---|---|---|---|---|
| 全量注入 | 48000+ | 0 | 62% | 30秒(直接超窗口重试) |
| 手动选文件 | ~8000 | 0 | 58% | 5秒 |
| 向量RAG(本地) | ~12000 | 0 | 71% | 8秒(含检索) |
| CodeGraph | ~3500 | 0 | 89% | 2秒(本地子图查询) |
准确回答率是我用10个不同的代码理解问题测试的(比如“findUser函数在哪里被调用了?”“如果修改User类的email属性,哪些地方会受影响?”),CodeGraph全对9个,唯一错的还是个边界case(eval动态调用,图谱无法静态捕获)。
核心思路:预索引知识图谱到底怎么工作
CodeGraph的底层不是黑魔法。它做的事,可以拆成三步:
第一步:源码解析
它用Tree-sitter(一个增量语法解析器)分析你的代码。支持TypeScript/JavaScript、Python、Rust、Go、Java等主流语言。解析时不执行代码,只提取结构信息:每个函数定义、每个类、每个方法、每个变量、每个导入导出语句、每个函数调用。
第二步:关系构建
把这些结构连成图。节点是:文件、函数、类、接口、变量。边是:定义关系(文件定义了函数)、调用关系(函数A调用了函数B)、继承关系(类A extends类B)、依赖关系(文件import了另一个文件)、类型引用关系等。
例如一个简单的文件:
// auth.ts
export function login(username: string, password: string): User {
const user = findUserByUsername(username);
return authenticate(user, password);
}
会生成节点:[auth.ts, login, findUserByUsername, authenticate, User, username, password] 和边:[auth.ts defines login, login calls findUserByUsername, login calls authenticate, login uses User] 等等。
第三步:索引与查询
构建好的图被序列化成一种高效的本地存储格式(默认用LevelDB或SQLite)。查询时,给定一个自然语言问题,CodeGraph不会直接做语义搜索——它用关键词提取+图遍历。比如问“怎么重置用户密码”,它会提取“重置”“用户”“密码”这些关键词,映射到相关代码节点(比如User类、resetPassword函数、password字段),然后返回一个以这些节点为中心、向外扩散两层的关系子图。
这个子图比你直接给AI看整个文件要小得多,且保留了关键依赖关系。AI看到的不再是零散的代码片段,而是“resetPassword调用了hashPassword和updateUser,其中updateUser在userService.ts中,而User类在models/User.ts中”这种有结构的信息。

实战:5分钟跑通CodeGraph + Claude Code
目前CodeGraph支持接入:Claude Code、Codex、Cursor、OpenCode、Hermes Agent。我用Claude Code演示,因为这是最常用的场景。
1. 安装
# 使用npm全局安装
npm install -g @colbymchenry/codegraph
# 或者用npx直接运行
npx @colbymchenry/codegraph init
2. 在你的项目根目录初始化
cd your-project/
codegraph init
这会生成一个codegraph.yml配置文件,内容类似:
# codegraph.yml
language: typescript
sourceDirs:
- src/
excludePatterns:
- node_modules
- dist
- *.test.ts
- *.spec.ts
buildOptions:
granularity: function # 可选:file, class, function
includeComments: true
maxGraphSize: 5000 # 最大节点数,超出则分片
storage:
type: leveldb # 或 sqlite
path: .codegraph/cache
可以根据项目调整granularity。如果项目超大(比如几百个文件),建议用file级别,否则构建时间太长;中小型项目用function最精细。
3. 构建图谱
codegraph build
第一次构建会比较慢(我那个150文件的项目用了大约12秒)。之后增量更新时,只重新解析变更的文件,很快。
4. 启动本地服务
codegraph serve --port 8942
这会启动一个HTTP服务,提供RESTful API:/query用于传入问题返回子图,/docs用于返回API文档。
5. 配置Claude Code使用CodeGraph
Claude Code可通过工具调用(MCP)的方式接入。在Claude Code的配置文件中(通常是~/.claude/agent.json或项目中的.clauderc.json),添加一个MCP工具:
{
"mcpServers": [
{
"name": "codegraph",
"command": "node",
"args": ["/path/to/codegraph-server.mjs"],
"env": {
"CODEGRAPH_PORT": "8942"
}
}
]
}
或者更简单的办法:直接在对话前把CodeGraph查询结果的子图注入到系统提示中。我写了一个包装脚本,每次提问前自动调一次CodeGraph API,把子图文本附加到用户消息后。下面给你这个模板:
# 伪代码,你可以改成脚本或VSCode任务
import requests
import json
def query_codegraph(question, project_dir):
resp = requests.post(
"http://localhost:8942/query",
json={"question": question, "depth": 2, "max_nodes": 30}
)
subgraph = resp.json()
# 格式化为AI友好的文本
text = "<code_knowledge_graph>\n"
for node in subgraph["nodes"]:
text += f"Node: {node['type']} {node['name']} in {node['file']}:{node['line']}\n"
for edge in subgraph["edges"]:
text += f"Edge: {edge['source']} --{edge['relation']}--> {edge['target']}\n"
text += "</code_knowledge_graph>\n"
return text
然后你在发给Claude Code的消息前,先调用这个函数把结果拼进去。比如问“帮我重构auth模块的登录逻辑”:
[知识图谱:登录相关函数、调用链、文件位置]...
问题:帮我重构auth模块的登录逻辑,保持对外接口不变。
效果对比:用CodeGraph之前,Claude Code可能会问“请提供auth.ts文件内容”,然后你给了它,它修改时可能漏掉authenticate函数中的依赖。用CodeGraph之后,它直接知道login调用了findUserByUsername和authenticate,还会关注User类型定义在哪,避免了重复询问。
CodeGraph vs 传统RAG:为什么图结构更优
很多人第一反应:这和用向量数据库做代码RAG有什么区别?我两个都深度用过,给你拆开说。
召回粒度不同
- 向量RAG:按固定窗口(比如每200行)切块,向量化。查询时按余弦相似度召回top-k块。缺点是:同一个函数的定义和调用可能被切到不同块里,AI拿到的是碎片。
- CodeGraph:以代码实体(函数、类)为基本单位,保留调用关系。AI拿到的是一张关系网,而不是一堆散落的句子。
上下文压缩比不同
- 向量RAG:为了覆盖可能相关的地方,需要召回5-10个块,大约1000-2000行代码,token量约4000-8000。
- CodeGraph:只返回子图文本(节点描述+关系边),不包含函数体。如果需要函数体,可以懒加载:AI先看子图,再按需请求具体文件内容。实际token消耗只有300-500。
对动态语言的支持
向量RAG对JavaScript这种动态类型语言几乎无法区分变量在不同情境下的类型。CodeGraph基于语法解析,虽然静态分析也有限制(比如高阶函数、运行时动态绑定),但大多数显式调用都能准确捕获。
我测试了一个案例:一个Redux store中,多个reducer监听同一个action。向量RAG返回的片段里,action type字符串散落在各处,AI经常混淆哪个reducer处理哪个action。CodeGraph直接给出actionCreators/createUser --> type 'CREATE_USER',被 reducers/user.ts 和 reducers/audit.ts 共同订阅这样的关系,AI一目了然。
完整模板:你可以直接用的配置和脚本
下面是我整理的最小可用配置,你可以直接复制到项目中使用。
配置模板
# codegraph.yml
language: typescript
sourceDirs:
- src/
- lib/
excludePatterns:
- node_modules
- __tests__
- "*.d.ts"
buildOptions:
granularity: function
includeComments: true
maxGraphSize: 3000
followImports: true
storage:
type: leveldb
path: .codegraph/cache
queryOptions:
depth: 2
maxNodes: 40
includeFileContent: false
快速查询脚本(Node.js)
// codegraph-query.js
const http = require('http');
async function query(question) {
const data = JSON.stringify({
question,
depth: 2,
max_nodes: 40
});
const options = {
hostname: 'localhost',
port: 8942,
path: '/query',
method: 'POST',
headers: { 'Content-Type': 'application/json' }
};
return new Promise((resolve, reject) => {
const req = http.request(options, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => resolve(JSON.parse(body)));
});
req.on('error', reject);
req.write(data);
req.end();
});
}
const question = process.argv[2];
if (!question) { console.error('Usage: node query.js "your question"'); process.exit(1); }
query(question).then(result => {
console.log(JSON.stringify(result, null, 2));
});
集成到Cursor的提示词模板
在Cursor的rules或.cursorrules文件中,添加一段让Cursor主动使用CodeGraph的规则:
You have access to a local CodeGraph server at http://localhost:8942.
Whenever you need to understand code dependencies or find where something is defined/used,
call the /query API with a brief question about the code.
Use the returned subgraph as context before generating any code changes.
变体与注意事项
变体1:针对大型项目(500+文件)
建议将granularity设为file,并且开启followImports: false(只索引直接导入的文件,不深入传递)。另外可以用maxGraphSize分片,每个分片约5000节点,服务会自动合并相关分片的结果。
变体2:与Git工作流结合
我写了一个pre-commit钩子,在提交前自动更新CodeGraph索引,保证图谱与代码同步。如果检测到某个文件修改,只重建该文件及其依赖的子图,耗时不到1秒。
变体3:自定义图谱内容排除测试代码
测试代码往往大量使用mock和stub,这些虚假关系会让图谱变脏。在excludePatterns中加入*.test.*、__mocks__/等。如果需要测试覆盖报告,可以单独建一个测试图谱。
注意事项
- 只适用于静态代码分析。动态创建的函数、eval、decorator等无法被Tree-sitter捕获,需要你手动在配置文件里添加
extraRelations字段补充。 - 首次构建性能。超过10万行的项目首次构建可能需要30秒以上,但增量更新很快。建议在CI/CD中定期全量重建,本地开发时用增量模式。
- 不要完全依赖它。CodeGraph给出的子图可能遗漏某些运行时确认的调用关系(例如通过事件订阅回调),你仍然需要让AI具备读源码的能力,CodeGraph只是减少它盲目搜索的步骤。
我的感受与建议
CodeGraph不是第一个做代码知识图谱的项目(之前有sourcegraph、CodeQL、ast-grep等),但它专门为AI编码助手优化了数据格式和查询接口,这很聪明。它把RAG中的“检索+阅读”模式变成了“预索引+子图注入”,在token效率和准确性之间找到了一个很好的平衡点。
如果你已经在用AI编码助手做日常开发,我强烈建议花半小时跑通CodeGraph。效果最明显的场景是:
- 你让AI修改跨多个文件的逻辑(比如添加一个新功能,影响5个以上文件)
- 你让AI分析代码库中的依赖关系(比如某个公共函数的调用者有哪些)
- 你让AI做重构,需要理解现有架构
对于简单的单文件问答(比如“这个函数的返回值是什么”),CodeGraph带来的提升不大,因为直接用grep就行。
最后提醒一点:代码知识图谱的质量取决于你项目代码的规范性。如果代码中大量使用any类型、隐式全局变量、动态require,图谱会变得稀疏。反过来,如果代码本身结构清晰、类型完整,CodeGraph的效果会让你惊喜。
试试看,有任何问题欢迎在评论区交流。