乐于分享
好东西不私藏

GraphRAG v3.0 源码拆解:5 个子包各自管什么,为什么要拆成 Monorepo

GraphRAG v3.0 源码拆解:5 个子包各自管什么,为什么要拆成 Monorepo

一篇帮你快速理解 v3.0 架构全貌、找到源码入口、知道改代码该去哪里的实操指南

阅读提示

  • 适合谁看:准备阅读或修改 GraphRAG 源码的工程师
  • 看完能做什么:知道 5 个子包各自负责什么,找到索引和查询的源码入口,理解 TableProvider 抽象的设计意图
  • 不适合谁:只用 pip install 跑命令、不打算改源码的用户

先给结论

  • v3.0 拆成 5 个子包的核心原因是模块化 + 可插拔:LLM 层、存储层、向量层、切分层都可以替换实现
  • 入口文件就两个:api/index.py(索引)和 api/query.py(查询),其他都是被它们调用的
  • TableProvider 是最关键的抽象:它让"数据存哪里"变成一个可配置的选择,而不是硬编码

很多人第一次打开 GraphRAG v3.0 的源码,看到 packages/ 目录下有 5 个子包,第一反应是"为什么要拆这么散"。

答案很简单:为了让每个层都可以独立替换

你可以换 LLM 提供商(OpenAI → Azure → 本地模型),可以换存储后端(本地文件 → Blob Storage → 数据库),可以换向量引擎(LanceDB → Azure AI Search),可以换切分策略(按句子 → 按 Token → 按语义)。每个替换都不需要改其他层的代码。

这篇文章解决一个问题:v3.0 的 5 个子包各自负责什么,依赖关系是什么样的,改代码该从哪里入手。


01 先说清问题:v2.x 的"大锅饭"有什么问题

GraphRAG v2.x 的代码都放在一个包里。LLM 调用、数据存储、向量检索、文本切分、流程编排全混在一起。

这带来了几个实际问题:

  • 想换 LLM 提供商?得改好几处代码
  • 想换存储后端?得深入内部逻辑
  • 想单独测试某个模块?做不到,因为依赖链太深
  • 想贡献代码?得理解整个大包才能改一小块

v3.0 的 Monorepo 架构就是为了解决这些问题。每个子包有清晰的职责边界和对外接口,互不侵入。

这一节的小结

Monorepo 不是为了"看起来高级",而是为了让每一层都可以独立开发、独立测试、独立替换。


02 先把全局地图摆出来

图 1|GraphRAG v3.0 Monorepo:5 个子包的依赖关系

中心是 graphrag 核心包(编排调度),四周是 4 个工具包。箭头标注依赖方向:核心包依赖其他 4 个,4 个工具包之间互不依赖。

5 个子包的定位:

  • graphrag(核心包):编排调度,包含 Pipeline / Workflow / Step / Config / API 入口
  • graphrag-llm:LLM 调用层,封装 Chat / Embedding / 重试 / 流式 / Token 计数
  • graphrag-input:数据读写抽象,TableProvider / FileStorage / BlobStorage
  • graphrag-vectors:向量索引与检索,支持 LanceDB / Azure AI Search 等后端
  • graphrag-chunking:文本切分策略,按句子 / Token / 语义切分

读者应该先记住的 1 件事

graphrag 核心包是唯一一个依赖其他 4 个包的包。4 个工具包之间互不依赖。这意味着你可以单独替换任何一个工具包,不需要改其他包的代码。


03 关键机制 1:两个入口文件

整个 v3.0 的源码入口就两个文件:

代码 1:索引入口

# packages/graphrag/graphrag/api/index.pyasyncdefbuild_index(config: GraphRAGConfig) -> IndexResult:"""构建知识图谱索引的主入口"""# 1. 创建 Pipeline    pipeline = create_pipeline(config)# 2. 注入依赖(LLM / TableProvider / VectorStore)    pipeline = inject_dependencies(pipeline, config)# 3. 执行    result = await pipeline.run()return result

代码 2:查询入口

# packages/graphrag/graphrag/api/query.pyasyncdefglobal_search(config, query, **kwargs):"""Global Search 查询入口"""# 从 TableProvider 加载 Community Reports    reports = config.table_provider.load("community_reports")# 执行 Map-Reducereturnawait run_map_reduce(query, reports, config.llm)asyncdeflocal_search(config, query, **kwargs):"""Local Search 查询入口"""# 从 TableProvider 加载实体和关系    entities = config.table_provider.load("entities")# Fan-Out 检索 + LLM 生成returnawait run_fan_out(query, entities, config.llm)

所有索引和查询的操作,最终都会走到这两个入口。想找某个功能的源码,从这里顺着调用链往下找就行。


04 关键机制 2:TableProvider 抽象

TableProvider 是 v3.0 最关键的设计。它解决的问题是:中间结果和最终产出存到哪里

代码 3:TableProvider 接口

classTableProvider(Protocol):"""数据读写的统一接口"""defload(self, name: str) -> pd.DataFrame:"""读取一张表"""        ...defwrite(self, name: str, data: pd.DataFrame) -> None:"""写入一张表"""        ...defdelete(self, name: str) -> None:"""删除一张表"""        ...

默认实现是 ParquetTableProvider,把所有数据存为本地 Parquet 文件。但你可以替换为:

  • BlobTableProvider:存到 Azure Blob Storage
  • DataFrameTableProvider:直接在内存中操作
  • 自定义实现:存到数据库、S3、GCS 等

为什么这个抽象重要?

GraphRAG 索引过程中会产生大量中间结果(TextUnit 表、实体表、关系表、社区表等)。如果这些表的存储方式和核心逻辑耦合,你就没法把 GraphRAG 部署到云端(因为本地文件路径硬编码了)。TableProvider 把"存到哪里"变成了一个可注入的依赖,核心逻辑完全不关心数据存在哪。


05 一次索引请求在源码中的完整调用链

图 2|一次索引请求在源码中的调用链

从 api/index.py:build_index() 出发,经过 Pipeline → Workflow 调度器 → 多个 Workflow → 每个 Workflow 内部的 Step → Step 调用 LLM → 结果写入 Storage。橙色标注并发控制(Semaphore),红色标注重试机制。

完整调用链的关键节点:

  1. **build_index()**:用户调用入口,创建 Pipeline
  2. **Pipeline.run()**:启动异步执行引擎
  3. Workflow 调度器:解析 Workflow 依赖图 → 拓扑排序 → 按依赖顺序执行
  4. Workflow 内部:每个 Workflow 包含多个 Step,Step 之间通过 TableProvider 传递中间结果
  5. Step 调用 LLM:通过 graphrag-llm 的 llm.invoke() 封装,自动重试、超时、计数
  6. 结果写入 Storage:通过 graphrag-input 的 table.write() 写入 Parquet 或其他存储

并发控制:Pipeline 使用 asyncio.Semaphore 控制并发 LLM 调用数量,防止触发 API rate limit。

错误恢复:Step 失败后会重试 N 次(指数退避),仍失败则整个 Pipeline 中止并报告错误位置。


06 子包速查表

图 3|5 个子包职责速查表

每列一个包,3 行分别列出核心职责、关键类、对外接口。灰色列是底层工具包(被依赖),蓝色列是核心编排包(依赖其他包)。

改代码时的快速定位

  • 想换 LLM 提供商?→ 改 graphrag-llm,实现 ChatLLM 接口
  • 想换存储后端?→ 改 graphrag-input,实现 TableProvider 接口
  • 想换向量引擎?→ 改 graphrag-vectors,实现 VectorStore 接口
  • 想换切分策略?→ 改 graphrag-chunking,实现 ChunkStrategy 接口
  • 想改索引流程?→ 改 graphrag 核心包的 Pipeline / Workflow
  • 想改查询逻辑?→ 改 graphrag 核心包的 api/query.py

07 为什么 v3.0 要拆成 Monorepo

拆包的 3 个核心收益

  1. 模块化:每个包有清晰的职责边界,改一个不影响其他
  2. 独立版本graphrag-llm 可以单独发版升级,不需要等整个 graphrag 发版
  3. 可插拔:LLM / 存储 / 向量 / 切分 4 个层都可以替换实现,核心逻辑不变

Monorepo vs 多仓库

GraphRAG 团队选择 Monorepo 而不是 5 个独立仓库,原因是:

  • 子包之间的接口还在演进,放在同一个仓库里方便同步修改
  • CI/CD 可以统一管理,确保所有包的兼容性
  • 开发者 clone 一个仓库就能看到全部代码,降低贡献门槛

依赖管理

5 个子包通过 pyproject.toml 的 [project.dependencies] 声明依赖关系。用户只需 pip install graphrag,4 个子包作为传递依赖自动安装。


08 第一次上手怎么试:最小实验

实验条件

  • 环境:已 clone graphrag v3.0 仓库
  • 输入:无
  • 预期观察:理解源码目录结构,找到两个入口文件

代码 4:最小实验步骤

# 1. 查看 packages 目录结构ls packages/# 应该看到:graphrag/  graphrag-input/  graphrag-llm/  graphrag-vectors/  graphrag-chunking/# 2. 找到索引入口cat packages/graphrag/graphrag/api/index.py# 3. 找到查询入口cat packages/graphrag/graphrag/api/query.py# 4. 查看 TableProvider 接口cat packages/graphrag-input/graphrag_input/table_provider.py# 5. 查看 ChatLLM 接口cat packages/graphrag-llm/graphrag_llm/chat_llm.py

你应该观察什么

  • 每个子包的目录结构是否清晰(src / tests / pyproject.toml)
  • 对外接口是否简洁(Protocol 类定义)
  • 核心包是否只做编排,不直接实现 LLM / 存储 / 向量逻辑

09 什么时候该改源码,什么时候别动

适合改源码的场景:

  • 你需要接入一个 GraphRAG 不支持的 LLM 提供商(改 graphrag-llm)
  • 你需要把数据存到自定义存储(改 graphrag-input)
  • 你需要实现一个自定义的切分策略(改 graphrag-chunking)

不适合改源码的场景:

  • 只是想调参数(改 settings.yaml 就够了)
  • 只是想换模型名(改 .env 就够了)
  • 只是想修改 prompt(改 prompts/ 目录下的模板就够了)

10 给读者一个真正能用来做决策的结论

决策帮助

  • 如果你只是用 GraphRAG:不需要读源码,settings.yaml + .env + prompts/ 覆盖 90% 的配置需求
  • 如果你需要扩展 GraphRAG:先读 TableProvider 和 ChatLLM 的接口定义,再决定改哪个包
  • 如果你要贡献代码:从 api/index.py 和 api/query.py 出发,顺着调用链往下读

v3.0 的 Monorepo 架构是"先拆清楚,再各自演进"的设计。理解了 5 个子包的职责边界,改代码就不会迷路。

如果你在阅读源码时遇到了具体的定位问题,欢迎在评论区写下你想改的功能,我帮你指出该看哪个包的哪个文件。

下一篇我们进入 Day 12:核心流程源码阅读。从 build_index() 出发,逐行跟踪 Pipeline 是怎么执行的。


如果这篇帮你搞清楚了 v3.0 的架构全貌,欢迎点个赞。

如果你正在改某个子包的代码但不确定该从哪里入手,欢迎在评论区写下你的需求。

参考链接

  • [GraphRAG GitHub 仓库] (https://github.com/microsoft/graphrag)
  • [DEVELOPING.md - 开发指南] (https://github.com/microsoft/graphrag/blob/main/DEVELOPING.md)
  • [GraphRAG 官方文档] (https://microsoft.github.io/graphrag/)