CodeGraph 技术架构解析:将源代码转化为可查询的知识图谱

什么是 CodeGraph

CodeGraph 是一个将源代码转化为**属性图(Property Graph)**的工具,它通过解析代码的抽象语法树(AST),提取代码中的实体和关系,构建一个可查询的代码知识图谱。

这种架构使得 AI 工具可以基于图查询来理解代码结构、调用链和依赖关系。


整体架构

1
2
3
源代码文件 → 解析器(Tree-sitter) → AST → 提取器 → SQLite数据库
                                                图查询引擎

核心数据模型

CodeGraph 使用三层数据结构来表示代码:

1. Nodes 表 — 代码节点(图的顶点)

字段说明
id唯一标识,格式如 function:hashfile:pathclass:hash
kind节点类型:fileclassfunctionmethodconstantvariableinterfacetype_aliasimport
name / qualified_name名称和全限定名
file_path所在文件路径
language编程语言
start_line/end_line源码位置
docstring/signature文档和函数签名
visibility/is_exported/is_async/is_static/is_abstract修饰符属性
decorators/type_parametersJSON 数组,装饰器和泛型参数

2. Edges 表 — 代码关系(图的边)

字段说明
source/target关联的两个节点 ID
kind关系类型
metadataJSON,含 confidence(置信度)和 resolvedBy(解析方式)
line/col关系发生的源码位置

关系类型

  • contains — 文件包含节点(层级结构)
  • calls — 函数/方法调用
  • references — 变量/类型引用
  • imports — 模块导入
  • instantiates — 类实例化

3. Files 表 — 文件追踪

记录每个文件的 content_hash(内容哈希)、node_countmodified_at 等,用于增量更新——只重新解析变化的文件。


解析流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
1. 扫描项目目录,遍历所有源文件
2. 对每个文件计算 content_hash,与 files 表对比
   → 跳过未修改的文件(增量索引)
3. 对需要更新的文件,使用 Tree-sitter 解析生成 AST
4. 从 AST 中提取:
   - 节点(类、函数、方法、变量、常量、接口等)
   - 边(调用关系、引用关系、包含关系、导入关系)
5. 对未解析的引用存入 unresolved_refs 表
6. 尝试解析 unresolved_refs(跨文件引用解析)
7. 写入 SQLite 数据库

增量更新与删除同步

CodeGraph 支持代码变更的自动同步,包括新增、修改和删除三种场景:

1. 新增代码

当添加新的源文件或代码实体时:

  • 扫描阶段发现新文件 → 创建 file 节点
  • 解析 AST → 提取新的 functionclassvariable 等节点
  • 建立关系 → 生成 containscalls 等边
  • 未解析的跨文件引用存入 unresolved_refs

2. 修改代码

基于内容哈希比对的增量更新:

1
2
3
4
-- files 表记录每个文件的哈希值
content_hash TEXT NOT NULL,  -- 文件内容的 SHA-256 哈希
modified_at INTEGER NOT NULL, -- 文件修改时间
indexed_at INTEGER NOT NULL   -- 最后索引时间

更新流程

1
2
3
4
5
6
1. 计算当前文件的 content_hash
2. 与 files 表中存储的哈希对比
3. 如果哈希不同 → 该文件已被修改
4. 删除该文件旧的 nodes 和 edges(级联删除)
5. 重新解析文件,生成新的 nodes 和 edges
6. 更新 files 表的哈希和时间戳

3. 删除代码

利用 SQLite 的 ON DELETE CASCADE 约束自动清理:

1
2
3
4
5
6
-- edges 表的外键约束
FOREIGN KEY (source) REFERENCES nodes(id) ON DELETE CASCADE
FOREIGN KEY (target) REFERENCES nodes(id) ON DELETE CASCADE

-- unresolved_refs 表的外键约束
FOREIGN KEY (from_node_id) REFERENCES nodes(id) ON DELETE CASCADE

删除流程

1
2
3
4
5
6
1. 扫描发现文件被删除 → 从 files 表移除
2. 删除该文件的所有 nodes(级联删除 edges)
3. 或者:文件中某个函数被删除
   → 删除该 function 节点
   → 自动删除所有包含该节点的 edges
   → 自动删除相关的 unresolved_refs

4. 实际示例

假设项目中有以下代码:

1
2
3
4
5
6
# utils.py (已索引)
def helper():    # node_id: function:abc123
    pass

def main():      # node_id: function:def456
    helper()     # edge: function:def456 → function:abc123 (calls)

场景 A:删除 helper() 函数

1
2
3
# 删除后重新索引
git rm utils.py  # 或手动删除函数
codegraph --update
  • 删除节点 function:abc123
  • 自动删除边 function:def456 → function:abc123
  • main() 函数保留,但缺少对 helper 的调用关系

场景 B:修改 main() 函数

1
2
def main():      # 同一个 node_id: function:def456
    print("updated")
  • content_hash 变化 → 触发重新索引
  • 重新解析生成节点和边
  • 旧的调用关系被新的关系替换

关键技术选型

1. SQLite + FTS5 全文搜索

nodes_fts 虚拟表基于 FTS5,对 namequalified_namedocstringsignature 建立全文索引,支持模糊搜索代码符号。

2. 基于内容哈希的增量更新

files.content_hash 避免重复解析未修改的文件,nodes.updated_at 时间戳追踪节点更新时间。

3. 置信度机制

1
{"confidence": 0.9, "resolvedBy": "exact-match"}

引用解析带置信度分数,exact-match 表示精确匹配,支持不同解析策略的优先级。

4. 节点 ID 生成策略

  • 文件节点:file:相对路径
  • 其他节点:类型:内容哈希(如 function:fcddbf01897d11636307b7ab1f47aa5c
  • 导入节点:import:哈希

查询能力示例

基于这个图结构,可以支持丰富的代码查询:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- 查找某个函数调用了哪些函数
SELECT t.name FROM edges e JOIN nodes t ON e.target = t.id 
WHERE e.source = 'function:xxx' AND e.kind = 'calls'

-- 全文搜索代码符号
SELECT * FROM nodes WHERE nodes MATCH 'search'

-- 查找某个文件包含的所有节点
SELECT n.name, n.kind FROM edges e JOIN nodes n ON e.target = n.id 
WHERE e.source = 'file:xxx' AND e.kind = 'contains'

-- 查找谁调用了某个方法
SELECT s.name FROM edges e JOIN nodes s ON e.source = s.id 
WHERE e.target = 'method:xxx' AND e.kind = 'calls'

实际数据示例

以当前博客项目为例,CodeGraph 生成的数据统计:

指标数值
文件数74
代码节点167
关系边289
未解析引用0

节点类型分布

  • method (50)
  • function (41)
  • file (19)
  • import (16)
  • constant (12)
  • variable (11)
  • interface (9)
  • class (6)
  • type_alias (3)

总结

CodeGraph 的核心思路是:将源代码解析为属性图存储在 SQLite 中,结合 Tree-sitter 进行多语言 AST 解析,通过增量更新和全文索引实现高效的代码理解和检索。

这种架构为 AI 代码助手提供了强大的上下文理解能力,使其能够:

  • 快速定位代码定义和引用
  • 理解函数调用链和依赖关系
  • 支持跨文件的代码导航
  • 基于语义的代码搜索