CodeGraphWiki 深度解析 — 把代码变成知识图谱

🔬

# 把代码变成知识图谱

深入了解 CodeGraphWiki 如何将一堆源代码文件，变成 AI 助手能理解和搜索的结构化知识。

1

源代码

→
2

语法树解析

→
3

知识图谱

→
4

AI 可搜索

向下滚动开始学习 ↓

01

# 这东西到底干嘛的？

想象你有一个巨大的代码仓库，里面有成千上万个函数——CodeGraphWiki 能让 AI 真正"读懂"它们

## 问题：AI 看代码就像大海捞针

你让 AI 助手帮你改一个 bug，但它不知道你的项目里有哪些函数、它们之间怎么调用、谁依赖谁。它只能一个文件一个文件地"扫"，效率很低，还经常遗漏关键信息。

CodeGraphWiki 解决的就是这个问题：它给代码仓库做一次彻底的"体检"，把所有函数、类、调用关系整理成一张关系网络——然后 AI 助手就能在这张网上精准搜索。

## 它做了什么：从源码到智能搜索的四步

1
解剖代码结构

用 Tree-sitter 把每个文件的函数、类、调用关系提取出来，存入图数据库

2
生成 API 文档

查询图数据库，为每个函数自动生成文档——包含签名、调用关系树、参数说明

3
创建语义搜索索引

把函数文档转化为向量嵌入，让你用自然语言搜索代码——比如问"怎么解析类型"就能找到 parse_btype 函数

4
生成 Wiki 百科

用 LLM 自动写一套多页技术文档，解释整个项目的架构和设计思路

## 打个比方

想象一个巨大的图书馆，几十万本书（代码文件）杂乱无章地堆在地上。

💡
核心洞察

CodeGraphWiki 就像一个图书管理员：它先给每本书编号（解析），然后制作一套卡片目录记录"哪本书引用了哪本书"（知识图谱），再写一本使用指南（Wiki），最后装上一个智能搜索终端，让你用普通话就能找到想要的书（语义搜索）。

## 真实场景：你在 Claude Code 里问了一个问题

假设你在用 Claude Code，对一个已经被 CodeGraphWiki 索引过的项目说：

"这个项目里怎么处理函数调用关系的？"

1
Claude Code 调用 find_api 工具

把你的问题发给 CodeGraphWiki 的 MCP 服务器

2
语义搜索启动

把问题转化为向量，在索引里找到最相关的函数——比如 CallProcessor、call_resolver

3
返回完整上下文

不仅返回函数名，还附带完整的 API 文档、调用关系树、源代码位置

4
Claude 给出精准回答

有了这些上下文，Claude 能告诉你具体哪个文件、哪一行在处理调用关系

## 检验一下

### 你的 AI 助手在大项目里总是找不到关键函数。根据刚才学到的，CodeGraphWiki 主要通过什么方式解决这个问题？

### 如果你想让 AI 更好地理解一个新项目，你应该先做什么？

02

# 认识主角们

五个核心组件，各司其职，像一条精密的流水线

## 五大角色一览

这个项目的所有功能，归根结底由五个"角色"完成。想象一个快递分拣中心：每个角色负责流水线上的一个环节。

🔍
Tree-sitter 解析器

"验货员"——把源代码文件拆解成结构化的语法树，提取出函数、类、调用关系

🗄️
Kuzu 图数据库

"档案馆"——把所有代码实体和它们的关系存成一张巨大的网络图

📝
API 文档生成器

"文书"——查询图数据库，为每个函数写出详细的技术文档

🧠
向量嵌入引擎

"翻译官"——把文档变成数字向量，让计算机能通过"比较数字"来理解"意思相近"

🔌
MCP 服务器

"前台接待"——对外暴露 19 个工具，让 Claude Code 等 AI 助手随时查询

## 它们住在哪里

每个角色对应项目中特定的文件和文件夹：

code_graph_builder/ Python 主包——所有核心逻辑都在这里
📄 builder.py 核心入口——CodeGraphBuilder 类，启动整个图构建流程
📁 parsers/ Tree-sitter 解析器——拆解代码的"验货员"
📄 definition_processor.py 提取函数、类的定义
📄 call_processor.py 提取函数调用关系
📄 call_resolver.py 解析函数名到完整限定名
📁 services/ 数据库服务——"档案馆"的管理层
📄 kuzu_service.py Kuzu 图数据库的读写操作
📁 embeddings/ 向量嵌入——"翻译官"的工作间
📄 qwen3_embedder.py 调用 Qwen3 API 生成嵌入向量
📄 vector_store.py 存储和搜索向量
📁 mcp/ MCP 服务器——"前台接待"所在地
📄 server.py 服务器启动入口
📄 tools.py 19 个 MCP 工具的定义
📄 pipeline.py 四步流水线的编排
💡
关键洞察：分而治之

注意每个文件夹只负责一件事。这种"把大问题拆成小问题"的策略，工程师叫它关注点分离。下次你让 AI 搭建新项目时，可以明确要求："把解析逻辑、数据库操作、对外接口分开放在不同的文件夹里。"

## 看看核心入口长什么样

builder.py 里的 CodeGraphBuilder 类是整个项目的起点：

CODE

    class CodeGraphBuilder:
        def __init__(self,
            repo_path: str | Path,
            backend: str = "kuzu",
            backend_config: dict | None = None,
            scan_config: dict | None = None,
        ) -> None:

PLAIN ENGLISH

定义一个叫 CodeGraphBuilder 的"蓝图"（类）

它的初始化需要以下材料：

repo_path——你想分析的代码仓库在哪个文件夹

backend——用什么数据库存储，默认是 "kuzu"（一个不需要安装服务器的轻量数据库）

backend_config——数据库的配置细节（可选）

scan_config——扫描时要排除哪些文件夹（可选）

## 检验一下

场景

你想给 CodeGraphWiki 换一个不同的向量搜索引擎（比如从内存搜索换成 Qdrant 云服务），你应该主要修改哪个目录？

03

# 数据如何流动

跟踪一次完整的代码索引过程——从"一堆文件"到"AI 能搜索的知识"

## 组件之间的"群聊"

当你执行 `initialize_repository` 时，幕后发生的事就像这段对话：

MCP
MCP 服务器

收到用户请求——要索引 /path/to/repo。Pipeline，你来编排整个流程吧！

PL
Pipeline 编排器

收到！先让 Tree-sitter 上场。嘿 Parser，先把这个仓库的代码全部拆解一遍！

TS
Tree-sitter

正在解析... 发现 42 个 Python 文件，提取了 156 个函数、23 个类、89 条调用关系。全部写入 Kuzu 了！

KZ
Kuzu 数据库

数据全部入库。现在有 156 个 Function 节点、23 个 Class 节点、89 条 CALLS 边。图谱构建完成！

PL
Pipeline 编排器

好的，Step 1 完成 (15%)。现在开始生成 API 文档... Doc Generator，轮到你了！

DOC
API 文档生成器

查询图数据库中... 为每个函数生成了三级文档：索引页 → 模块详情 → 函数详情。写入 api_docs/ 目录了。

PL
Pipeline 编排器

文档 OK。现在 Embedder，把这些文档全部向量化！

EM
向量嵌入引擎

正在调用 Qwen3 API... 每批 10 个函数... 156 个函数全部转成 1536 维向量了。保存到 vectors.pkl。

PL
Pipeline 编排器

进度 40%。最后一步——Wiki 生成器，请用 LLM 写一套项目百科！

WK
Wiki 生成器

规划了 8 个页面... 正在逐页生成... 完成！所有 Wiki 页面已写入 wiki/ 目录。整个流水线 100% 完成！🎉

?
0 / 10 条消息

## 数据流动路径

📂
源代码
🔍
Tree-sitter
🗄️
Kuzu DB
🧠
Embedder
🔌
MCP Server
点击"下一步"开始
步骤 0 / 6

## 进度条背后的秘密

当 AI 助手显示"索引中... 35%"时，这个数字是怎么算出来的？看看 pipeline.py 里的权重分配：

CODE

    ProgressCb = Callable[[str, float], None] | None
    """Progress callback: (message, percentage_0_to_100)

    Pipeline weight allocation:
        Step 1 (graph + API docs):  0 – 15 %
        Step 2 (embeddings):       15 – 40 %
        Step 3 (wiki generation):  40 – 100 %
    """

PLAIN ENGLISH

定义一个"进度回调"——用来向外界报告"做到哪了"

它接收两个参数：一条消息描述和一个 0-100 的百分比

权重怎么分：

图谱构建 + 文档生成 = 0% 到 15%（最快的步骤）

向量嵌入 = 15% 到 40%（需要调 API，比较慢）

Wiki 生成 = 40% 到 100%（需要 LLM 逐页生成，最耗时）

📌
为什么这样分配？

图谱构建是纯本地计算（快），向量嵌入要调外部 API（中等），Wiki 生成要让 LLM 逐页思考并写长文（慢）。所以 Wiki 占了 60% 的进度权重。下次你看到进度条前 40% 跑得飞快、后面慢下来，就知道原因了！

## 检验一下

场景

索引一个大项目时，进度条卡在 42% 很长时间不动。根据你了解的进度权重分配，最可能是哪个步骤正在运行？

04

# 给代码做 X 光

Tree-sitter 是怎么把一段看似普通的代码文本，变成结构化数据的

## 代码的"骨骼扫描"

人类读代码时，自然而然能看出"这是一个函数"、"这里调用了另一个函数"。但对计算机来说，代码只是一长串字符。

AST（抽象语法树）就是让计算机"读懂"代码结构的方式——把平面文本变成一棵有层次的树。

📄

#### 源代码文本

def add(a, b): return a + b

🌳

#### 语法树

function_definition → name: "add" → params: ["a", "b"] → body: binary_op(a + b)

📊

#### 结构化数据

{name: "add", params: 2, return_type: "inferred", line: 1}

## Tree-sitter 的"搜索模式"

Tree-sitter 不只是生成语法树——它还支持查询模式，让你可以精确地说"我要找所有函数定义"。

CODE

    # Python 函数查询模式
    (function_definition
      name: (identifier) @func_name
      parameters: (parameters) @params
      body: (block) @body
    )

PLAIN ENGLISH

在语法树里寻找所有"函数定义"节点

把函数名捕获到变量 @func_name 里

把参数列表捕获到变量 @params 里

把函数体捕获到变量 @body 里

就像一个模板——"找到所有长这个样子的东西"

## 一个工具，十种语言

CodeGraphWiki 支持从 Python 到 Rust 的 10+ 种编程语言。每种语言有自己的查询模式，因为语法不同：

`Python` function_definition → 直接匹配 def 关键字
`C/C++` function_definition → 还要检查 storage_class_specifier (static 等)
`JavaScript` function_declaration + arrow_function → 两种函数写法都要匹配
`Rust` function_item → 还要提取 trait、impl 块
`Go` function_declaration + method_declaration → 区分普通函数和方法
💡
为什么不用正则表达式？

你可能想："直接用正则表达式匹配 'def' 不就行了？"问题是正则不理解嵌套——它分不清一个 def 是顶层函数还是嵌套在 if 块里的。Tree-sitter 理解整个语法结构，所以永远不会搞混。

## DefinitionProcessor：提取定义的工人

CODE

    class DefinitionProcessor:
        def __init__(self,
            ingestor: IngestorProtocol,
            repo_path: Path,
            project_name: str,
            function_registry: FunctionRegistryTrieProtocol,
            simple_name_lookup: SimpleNameLookup,
            import_processor: ImportProcessor,
        ):

PLAIN ENGLISH

定义"定义处理器"——它的工作是从语法树中提取函数和类

它需要这些"工具"才能工作：

ingestor——用来把结果写入数据库的接口

repo_path——代码仓库的路径

function_registry——一个"电话簿"，记录所有已知函数的完整名称

simple_name_lookup——一个快速查找表，函数简称→完整名

import_processor——处理 import 语句的伙伴，帮助解析跨模块调用

## 检验一下

场景

你想让 CodeGraphWiki 支持一门新的编程语言（比如 Kotlin）。你需要添加什么？

05

# 记忆宫殿

图数据库和向量搜索——两种截然不同但互补的记忆方式

## 两套记忆系统

CodeGraphWiki 用两种完全不同的方式存储知识，就像人脑的两种记忆方式：

🗺️

#### Kuzu 图数据库

像一张城市地图——记录"A 调用 B"、"C 继承 D"这样的精确关系。适合回答"谁调用了这个函数？"

🧭

#### 向量存储

像一个"意思相似度"引擎——你说"处理类型"，它就能找到"parse_btype"。适合回答"哪个函数做了类似的事？"

## 图谱里有什么

图数据库用Cypher 语言查询。节点是代码实体，边是它们之间的关系：

### 节点类型

`Function` 函数
`Class` 类
`Module` 模块/文件
`Type` 类型定义

### 关系类型

`CALLS` 函数 A 调用了函数 B
`DEFINES` 模块定义了某个函数
`INHERITS` 类继承自另一个类
`IMPORTS` 模块导入了另一个模块

## 向量搜索的核心魔法

向量搜索的关键是余弦相似度——比较两个向量的"方向"是否接近：

CODE

    def cosine_similarity(a: list[float], b: list[float]) -> float:
        dot_product = sum(x * y for x, y in zip(a, b))
        norm_a = math.sqrt(sum(x * x for x in a))
        norm_b = math.sqrt(sum(x * x for x in b))
        return dot_product / (norm_a * norm_b)

PLAIN ENGLISH

比较两个向量（两列数字）有多"相似"

第一步：把两列数字对应相乘再加起来（点积——衡量方向一致性）

第二步：计算每个向量的"长度"（就像测量箭头有多长）

第三步：用同样的方法算另一个向量的长度

最后：点积除以两个长度的乘积——结果越接近 1，两段文字的"意思"越接近

## 每个函数的"简历"

向量嵌入并不只看函数名——它为每个函数构建一份丰富的上下文"简历"：

1
函数名 + 文件位置

比如：parse_btype，位于 tccgen.c

2
文档字符串

"Parse base type declaration including struct/union/enum specifiers"

3
调用者和被调用者

谁在调用我？我又调用了谁？最多各 10 个名字

4
前 2000 字符源代码

函数的实际代码——让嵌入能理解"这个函数具体在做什么"

💡
上下文决定精度

如果只用函数名去生成向量，"parse_btype" 和 "parse_string" 看起来很像（都有 parse）。但加上调用关系和源代码后，嵌入能区分一个是处理类型，一个是处理字符串。信息越丰富，搜索越精准。

## 检验一下

场景

用户在 AI 助手里问"找出所有调用了 database_connect 的函数"。这个查询更适合用哪种方式处理？

06

# AI 的接口

MCP 服务器如何把所有能力包装成 AI 助手能调用的"工具"

## 什么是 MCP？

你有没有用过万能充电器？不管是 iPhone 还是安卓，插上同一个USB-C 就能充电。

MCP 对 AI 工具的作用是一样的：它是一个标准协议，让任何 AI 助手（Claude Code、Cursor、OpenCode）都能调用 CodeGraphWiki 的能力，不需要各写一套适配器。

## 19 个"超能力"

MCP 服务器对外暴露了 19 个工具，分为四大类：

🏗️

#### 仓库管理 (4个)

initialize_repository、get_repository_info、list_repositories、switch_repository

🔍

#### 代码搜索 (5个)

find_api、semantic_search、query_code_graph、get_code_snippet、locate_function

📖

#### API 文档 (4个)

list_api_docs、get_api_doc、list_api_interfaces、generate_api_docs

📚

#### Wiki 与构建 (6个)

list_wiki_pages、get_wiki_page、generate_wiki、rebuild_embeddings、build_graph、prepare_guidance

## 服务器是怎么启动的

CODE

    async def main() -> None:
        workspace = Path(
            os.environ.get("CGB_WORKSPACE",
                Path.home() / ".code-graph-builder")
        ).expanduser().resolve()

        registry = MCPToolsRegistry(workspace=workspace)
        server = Server("code-graph-builder")

PLAIN ENGLISH

定义一个异步的启动函数（异步 = 能同时处理多件事）

先确定工作空间在哪——默认是你电脑的 ~/.code-graph-builder/ 文件夹

也可以通过环境变量 CGB_WORKSPACE 自定义位置

创建工具注册表——它管理所有 19 个工具和已索引的仓库

创建 MCP 服务器实例，给它起名 "code-graph-builder"

## 通信方式：标准输入/输出

MCP 服务器使用 stdio 通信——不需要网络端口，直接通过标准输入/输出交换 JSON 消息。

📌
为什么用 stdio 不用 HTTP？

HTTP 需要开端口、处理网络安全。stdio 更简单——AI 助手直接启动服务器进程，通过管道通信。没有端口冲突，没有防火墙问题，也不需要用户做任何网络配置。

## 检验一下

场景

你想让一个不支持 MCP 的 AI 助手（比如一个自定义的 AI 工具）也能使用 CodeGraphWiki 的能力。你需要做什么？

07

# 全局视角

把所有线索串起来——完整的架构和调试直觉

## 完整架构一览

#### 对外接口层

🔌 MCP Server (server.py)
⌨️ CLI (cli.py)

#### 编排层

🎯 Pipeline (pipeline.py)
📋 Tools Registry (tools.py)

#### 处理层

🔍 Parsers (parsers/)
📝 Doc Generator
🧩 RAG Engine (rag/)

#### 存储层

🗄️ Kuzu DB (services/)
🧠 Vector Store (embeddings/)
点击任意组件查看详细说明

## 当事情出错时

有了对架构的理解，你可以用"排除法"快速定位问题。以下是最常见的故障场景：

!
索引卡在某个百分比不动

如果 0-15%：图谱构建问题，检查文件权限和 Tree-sitter 语言支持。如果 15-40%：嵌入 API 问题，检查 DASHSCOPE_API_KEY。如果 40-100%：LLM 问题，检查 LLM_API_KEY。

!
搜索结果不相关

向量嵌入可能过期了——代码改了但没重新索引。运行 rebuild_embeddings 重新生成向量。

!
数据库锁定错误

Kuzu 是文件级锁——如果另一个进程在用数据库，会报锁定错误。系统会自动重试最多 5 次，指数退避（1秒、2秒、4秒...）。如果仍然失败，手动关闭其他使用数据库的进程。

## 数据存在哪里

所有索引结果都保存在工作空间目录下：

~/.code-graph-builder/ 工作空间根目录
📄 active.txt 记录当前活跃仓库的名字
📄 .env API 密钥配置
📁 myproject_a1b2c3d4/ 某个仓库的索引数据（名字+哈希防冲突）
📄 meta.json 仓库路径、索引时间、完成状态
📁 graph.db/ Kuzu 图数据库文件
📄 vectors.pkl 向量存储的序列化文件
📁 api_docs/ 三级 API 文档
📁 wiki/ 生成的 Wiki 页面

## 你现在能做什么

学完这七个模块，你现在有了一些新"超能力"：

🎯

#### 更精准地指导 AI

"先用 find_api 搜索相关函数，再用 query_code_graph 看调用关系"——你能给出具体的工具调用建议

🔧

#### 自主排查问题

索引失败？你知道先看哪个步骤、检查哪个 API 密钥、是不是数据库锁冲突

🏛️

#### 理解架构决策

"为什么用嵌入式数据库不用 PostgreSQL？"——因为不需要用户装 Docker，降低使用门槛

🗣️

#### 掌握技术词汇

AST、知识图谱、余弦相似度、MCP 协议、向量嵌入——这些概念你都能用来和工程师沟通了

## 最终挑战

综合场景

你刚用 CodeGraphWiki 索引了一个 TypeScript 项目，但 AI 搜索"用户认证"相关的代码时，结果完全不相关。你会怎么排查？

综合场景

你想给 CodeGraphWiki 添加一个新功能："显示某个函数被修改的 Git 历史"。根据项目的架构，你应该怎么向 AI 助手描述这个需求？