跳到主要内容

GraphRAG本地部署与调用流程

课程说明:

  体验课时间有限,若想深度学习大模型技术,欢迎大家报名由我主讲的《2025大模型Agent智能体开发实战》(7月班)

06661cb459aa3e4b655aface404435d

《2025大模型Agent智能体开发实战》(7月班) 为【100+小时】体系大课,总共20大模块精讲精析,零基础直达大模型企业级应用!

a55d48e952ed59f8d93e050594843bc

部分项目成果演示

from IPython.display import Video
  • MateGen项目演示
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/MG%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91.mp4", width=800, height=400)
  • 智能客服项目演示
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/%E6%99%BA%E8%83%BD%E5%AE%A2%E6%9C%8D%E6%A1%88%E4%BE%8B%E8%A7%86%E9%A2%91.mp4", width=800, height=400)
  • Dify项目演示
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/2f1b47f42c65fd59e8d3a83e6cb9f13b_raw.mp4", width=800, height=400)
  • LangChain&LangGraph搭建Multi-Agnet
Video("https://ml2022.oss-cn-hangzhou.aliyuncs.com/%E5%8F%AF%E8%A7%86%E5%8C%96%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90Multi-Agent%E6%95%88%E6%9E%9C%E6%BC%94%E7%A4%BA%E6%95%88%E6%9E%9C.mp4", width=800, height=400)

此外,若是对大模型底层原理感兴趣,也欢迎报名由我和菜菜老师共同主讲的《2025大模型原理与实战课程》(夏季班)

4a11b7807056e9f5b281278c0e37dad

两门大模型课程夏季班目前上新特惠,直播间下单可享618平价钜惠,合购还有更多优惠哦~详细信息扫码添加助教,回复“大模型”,即可领取课程大纲&查看课程详情👇

d490904dc5d491768ed1ea938fdf5ef e5b5013521acbcafd29af716aa4a83e

GraphRAG技术实战公开课

Part 2.GraphRAG本地部署与调用流程

一、微软GraphRAG项目介绍与GraphRAG流程回顾

image-20250715162536122

项目地址:https://github.com/microsoft/graphrag/

  检索增强生成(RAG) 是一种通过结合真实世界的信息来提升大型语言模型(LLM)输出质量的技术。RAG 技术是大多数基于 LLM 的工具中的一个重要组成部分。大多数 RAG 方法使用 向量相似性 作为检索技术,我们将其称为 基线 RAG(Baseline RAG)

GraphRAG 则使用 知识图谱 来在推理复杂信息时显著提升问答性能。当需要对复杂数据进行推理时,GraphRAG 展示了优于基线 RAG 的性能,特别是在 知识图谱 的帮助下。

  RAG 技术在帮助 LLM 推理私有数据集方面显示了很大的潜力——例如,LLM 没有在训练时接触过的、企业的专有研究、业务文档或通信数据。基线 RAG 技术最初是为了解决这个问题而提出的,但我们观察到,在某些情况下,基线 RAG 的表现并不理想。以下是几个典型的场景:

  1. Native RAG 很难将信息串联起来:当一个问题的答案需要通过多个不同的信息片段,并通过它们共享的属性来连接,进而提供新的综合见解时,基线 RAG 表现得很差。

    例如,在回答类似“如何通过现有的数据推断出新结论”这种问题时,基线 RAG 无法很好地处理这些散布在不同文档中的相关信息,它可能会遗漏一些关键联系点。

  2. Native RAG 无法有效理解大型数据集或单一大文档的整体语义概念:当被要求在大量数据或复杂文档中进行总结、提炼和理解时,基线 RAG 往往表现不佳。

    例如,如果问题要求对整个文档或多篇文档的主题进行总结和理解,基线 RAG 的简单向量检索方法可能无法处理文档间的复杂关系,导致对全局语义的理解不完整。

  为了应对这些挑战,技术社区正在努力开发扩展和增强 RAG 的方法。微软研究院(Microsoft Research)提出的 GraphRAG 方法,使用 LLM 基于输入语料库构建 知识图谱。这个图谱与社区总结和图谱机器学习输出结合,能够在查询时增强提示(prompt)。GraphRAG 在回答以上两类问题时,展示了 显著的改进,尤其是在 复杂信息的推理能力智能性 上,超越了基线 RAG 之前应用于私有数据集的其他方法。

1.GraphRAG项目简介

  GraphRAG 是微软研究院开发的一种先进的增强检索生成(RAG)框架,旨在提升语言模型(LLM)在处理复杂数据时的性能。与传统的 RAG 方法依赖向量相似性检索不同,GraphRAG 利用 知识图谱 来显著增强语言模型的问答能力,特别是在处理私有数据集或大型、复杂数据集时表现尤为出色。

2.GraphRAG核心特点

  传统的 Baseline RAG 方法在某些情况下表现不佳,尤其是当查询需要在不同信息片段之间建立联系时,或是当需要对大规模数据集进行整体理解时。GraphRAG 通过以下方式克服了这些问题:

  • 更好的连接信息点:GraphRAG 能够处理那些需要从多个数据点合成新见解的任务。
  • 更全面的理解能力:GraphRAG 更擅长对大型数据集进行全面理解,能够更好地处理复杂的抽象问题。

  而借助微软开源的GeaphRAG项目,我们可以快速做到以下事项:

  • 基于图的检索:传统的 RAG 方法使用向量相似性进行检索,而 GraphRAG 引入了知识图谱来捕捉实体、关系及其他重要元数据,从而更有效地进行推理。
  • 层次聚类:GraphRAG 使用 Leiden 技术进行层次聚类,将实体及其关系进行组织,提供更丰富的上下文信息来处理复杂的查询。
  • 多模式查询:支持多种查询模式:
    • 全局搜索:通过利用社区总结来进行全局性推理。
    • 局部搜索:通过扩展相关实体的邻居和关联概念来进行具体实体的推理。
    • DRIFT 搜索:结合局部搜索和社区信息,提供更准确和相关的答案。
  • 图机器学习:集成了图机器学习技术,提升查询响应质量,并提供来自结构化和非结构化数据的深度洞察。
  • Prompt 调优:提供调优工具,帮助根据特定数据和需求调整查询提示,从而提高结果质量。

3.GraphRAG运行流程

索引(Indexing)过程

  1. 文本单元切分:将输入文本分割成 TextUnits,每个 TextUnit 是一个可分析的单元,用于提取关键信息。
  2. 实体和关系提取:使用 LLM 从 TextUnits 中提取实体、关系和关键声明。
  3. 图构建:构建知识图谱,使用 Leiden 算法进行实体的层次聚类。每个实体用节点表示,节点的大小和颜色分别代表实体的度数和所属社区。
  4. 社区总结:从下到上生成每个社区及其成员的总结,帮助全局理解数据集。

查询(Query)过程
索引完成后,用户可以通过不同的搜索模式进行查询:

  • 全局搜索:当我们想了解整个语料库或数据集的整体概况时,GraphRAG 可以利用 社区总结 来快速推理和获取信息。这种方式适用于大范围问题,如某个主题的总体理解。
  • 局部搜索:如果问题关注于某个特定的实体,GraphRAG 会向该实体的 邻居(即相关实体)扩展搜索,以获得更详细和精准的答案。
  • DRIFT 搜索:这是对局部搜索的增强,除了获取邻居和相关概念,还引入了 社区信息 的上下文,从而提供更深入的推理和连接。

Prompt 调优
为了获得最佳性能,GraphRAG 强烈建议进行 Prompt 调优,确保模型可以根据你的特定数据和查询需求进行优化,从而提供更准确和相关的答案。

4.GraphRAG核心原理回顾

GraphRAG导图

二、本地部署GraphRAG

  首先要清楚的是,Microsoft GraphRAG 工具的本质是:假设我们有一些文本数据,想要将这些数据转换为知识图谱,并且希望图谱能够被大模型所理解,以至于大模型在回答问题时能够利用图谱中的信息进行推理,这个过程就完全可以借助Microsoft GraphRAG 工具来实现。因此,我们需要学习和关注的就只有以下两个问题:

  1. Microsoft GraphRAG 的使用方法;
  2. 如何准备需要检索的文本数据;

  我们先来看第一个要解决的问题:如何使用 Microsoft GraphRAG。作为一个完全的开源项目,Microsoft GraphRAG 提供两种使用方式:

  1. pypi 安装: 最简单的使用方式,只需要在终端中借助 graphrag cli 即可无需编写任何代码实现GraphRAG的构建和检索功能。适合初学者和个人使用。
  2. 源码安装: 最灵活的使用方式,可以完全自定义GraphRAG的构建流程,高度可扩展性和控制度,适合真实企业级场景开发使用,但对代码能力要求较高。

  公开课作为快速入门,我们接下来详细介绍更低门槛的Pypi的安装和使用方法。仅仅通过几行命令即可实现基于私有的数据GraphRAG问答。

  微软的graphrag开源项目库中包含一个CLI工具,所谓的CLI工具,其实就是命令行工具,通过在终端中输入命令即可实现GraphRAG的构建和检索功能。在Python中封装一个CLI工具,其实并不复杂,只需要在一个普通的Python文件中,然后通过argparse模块来解析命令行参数即可。比如如下示例:

FENCE0

  然后打开终端,在脚本(test_cli.py)所在目录下输入命令:

FENCE0

  这个很好理解,Pythonargparse模块可以非常方便的解析命令行参数,然后根据参数执行不同的功能。除此以外,还有像ClickTyper等模块,也可以非常方便的实现CLI工具的构建。 Microsoft GraphRAGCLI工具就是基于 Typer 模块实现的。(我们将在接下来的源码安装课程中进行说明,这里大家只需要知道Microsoft GraphRAGCLI工具就是基于 Typer 模块实现的即可。)

  除此之外,为了能让用户更方便的安装和使用Microsoft GraphRAGCLI工具,微软还提供了一个pip 安装包将其发布在PyPI上,地址如下:https://pypi.org/project/graphrag/

  基于这两点,我们只需要在本地的Python环境中安装graphrag包,即可借助graphrag cli命令行工具来实现GraphRAG的构建和检索功能。接下来我们就逐步的来实现这个流程。

  这里我们以Linux系统为例进行流程的实操。(建议大家使用Linux系统进行实操,如果使用Windows系统,则直接在WindowsCMD(命令提示符)中执行命令即可。)

  • Step 1. Python 环境安装及版本要求

  使用 Microsoft GraphRAGCLI,官方建议的Python版本在3.10 ~ 3.12之间,所以大家需要先确保当前开发环境中已经安装了Python,并且版本在3.10 ~ 3.12之间。这里我们以PythonAnaconda版本为例进行安装。首先检查系统是否安装了anaconda,执行命令如下:

FENCE0

  • Step 2. 使用 conda 创建指定 Python 版本的虚拟环境

  conda包版本管理工具的好处就是可以在创建虚拟环境时,指定Python版本。所以接下来我们就可以创建一个指定Python版本的虚拟环境,并安装Microsoft GraphRAGCLI工具。执行命令如下:

FENCE0   这里的 --name 参数用于指定虚拟环境的名称,python=3.11 参数用于指定Python版本。

image-20250715163142882
  • Step 3. 安装Microsoft GraphRAGCLI工具

  进入到虚拟环境后,接下来我们就可以安装Microsoft GraphRAGCLI工具了。执行命令如下:

FENCE0

image-20250715163338228
  • Step 4. 验证Microsoft GraphRAGCLI工具是否安装成功

  安装完成后,接下来我们就可以验证Microsoft GraphRAGCLI工具是否安装成功了。执行命令如下:

FENCE0

image-20250715164307501

  可以看到这里我们安装的Microsoft GraphRAG 的版本为最新版2.4.0

  • Step 5. 使用Microsoft GraphRAGCLI基本使用方法

  作为命令行工具,一定是涉及到一些命令参数的,这可以通过graphrag --help 命令来查看。执行命令如下:

FENCE0

image-20250715170421643

  通过graphrag --help 命令返回的参数信息主要设计的就是GraphRAG的构建和检索功能,具体来看:

  • init: 初始化GraphRAG 的配置文件;
  • index: 构建GraphRAG 索引,即Indexing过程;
  • query: 检索GraphRAG 的查询,即Querying过程;
  • update: 更新GraphRAG 的索引,即增量更新;

  通过graphrag --help 命令返回的参数信息,我们就可以知道Microsoft GraphRAGCLI工具的基本使用方法了。但核心并不在这里,而是在于构建索引或者检索流程中的配置文件参数,这些参数才是真正决定最终效果好坏的关键。因此,接下来我们就借助一个示例文本来详细介绍GraphRAG 的索引构建过程中涉及的配置文件参数及优化技巧。

三、GraphRAG构建索引完整流程

  GraphRAGCli工具可以通过 graphrag index 启动构建索引流程,但并无法控制构建索引过程中的技术细节,比如下图所示的GraphRAG 构建索引的完整流程:

  GraphRAG 整个Indexing过程可以通过以下简单的方式来理解:

  1. 类似于 Native RAG,将源文档分块为较小的子文档;
  2. 执行两个并行提取:实体提取用于识别人名、地名、组织名等实体,关系提取:查找不同数据块中实体之间的关系,比如朋友、同事,员工等;
  3. 创建知识图谱,其中节点表示实体,边表示它们之间的关系,比如张三是李四的朋友, 张三是王五的同事;
  4. 通过识别密切相关的实体来构建社区;
  5. 生成不同社区级别的分层摘要;
  6. 使用 reduce-map 方法通过逐步组合块来创建摘要,直到实现整体概览;

  这个过程非常复杂,因此是需要一些配置文件来控制整个流程的。Microsoft GraphRAG 实现的是完整的索引构建流程逻辑,但具体到每个环节的一些关键参数,比如:文本分块的大小,实体提取、关系提取的粒度,选择使用的大模型,Embedding模型等,都是需要通过配置文件来控制的。

  那么这个配置文件来源于哪里呢? 其实就是 graphrag --init 命令的作用。

1. 初始化配置文件

  所谓的graphrag 初始化,其实就是生成一个默认的配置文件,然后我们就可以根据这个配置文件来控制GraphRAG 的索引构建流程。因此,构建索引的第一步,就是先执行graphrag --init 命令来生成默认的配置文件。即执行命令如下:

FENCE0

  其中 --root 参数用于指定生成的配置文件的存储路径,./ 表示当前目录。

  当执行graphrag --init --root ./ 命令后,会生成两个配置文件及一个文件夹,分别是:

  • settings.yaml: 主配置文件,包含 GraphRAG 从索引构建到检索的设置;
  • .env: 环境变量文件。里面主要存储的是API_KEY密钥等敏感信息,在settings.yaml文件中引用;
  • prompts/: 提示词文件夹。它包含 GraphRAG 使用的默认提示;
image-20250715170516513

  接下来,我们就需要重点的关注这三个配置文件,因为这三个配置文件是唯一我们可以控制GraphRAG 索引构建流程的方法。首先看.env文件。

2. 配置文件基本参数解释

  • .env文件配置说明

  .env文件中主要存储的是API_KEY密钥等敏感信息,作为环境变量会在settings.yaml文件中被引用。默认的.env文件中只有一个GRAPHRA_API_KEY,用来存储用于GraphRAG 构建过程中使用的大模型的有效API_KEY。 修改的方法如下:

  在Linux系统中,修改.env文件的内容可以使用vim命令,执行命令如下:

FENCE0

  然后输入i进入编辑模式,填写.env文件中的GRAPHRA_API_KEY,这里我们使用DeepSeekAPI_KEY,大家可以根据自己的需求选择不同的模型。

  填写完成后按Esc键退出编辑模式,输入:wq保存并退出即可。

  • settings.yaml文件配置说明

  settings.yaml文件是GraphRAGCLI工具的主配置文件,里面主要存储的是GraphRAG 的索引构建流程的配置信息。默认的settings.yaml文件中的配置信息非常多,涉及到了GraphRAG 的索引构建Pipeline的各个环节中策略的控制,首先我们来看最简配置。即必须修改的参数:

  同样,我们还是需要用vim命令来修改settings.yaml文件,执行命令如下:

FENCE0

  然后输入i进入编辑模式,修改settings.yaml文件中的配置信息。这里如下几个配置需要大家根据自己的实际情况进行修改:

  1. default_chat_model:构建GraphRAG时使用的文本大模型,其加载的就是.env文件中的GRAPHRA_API_KEY,比如我们填写的DeepSeekAPI_KEY,那么这里就要根据deepseekAPI_KEY的请求配置来进行修改,其中以下几个参数是必须进行配置,否则流程无法正常进行,具体参数如下:

基础文本模型配置

参数描述
api_base请求某个模型调用 REST APIEndpoint
api_key作为变量,引用 .env 文件中的 GRAPHRA_API_KEY
encodeing_model设置编码模型。
model请求某个模型调用 REST API对应的模型名称。

基础Embedding模型配置

参数描述
api_base请求某个模型调用 REST APIEndpoint
api_key有效的请求 API_KEY
encodeing_model设置编码模型。
model请求某个模型调用 REST API对应的模型名称。

  这里以DeepSeekAPI_KEY为例,进行配置,具体配置信息如下:

  关于如何使用Ollama启动的本地模型,则一个示例配置如下:

  最后,我们给出一个整体的模型和Embedding模型的配置示例,大家可以根据自己的需求进行灵活组合,如下表所示:

文本与Embedding模型配置组合参考

类型.envsettings.yaml
在线 APIGRAPHRAG_API_KEY=有效API_KEYdefault_chat_model:
在线模型:
api_base: 官方要求的 api_base,
api_key: ${GRAPHRA_API_KEY}
encodeing_model: cl100k_base
model: 官方要求的模型名称
本地模型:
api_base: http://localhost:11434/v1
api_key: 任意填写
encodeing_model: cl100k_base
model: ollama 启动的模型名称
Ollama 启动本地模型GRAPHRAG_API_KEY=任意填写default_embedding_model:
在线模型:
api_base: 官方要求的 api_base
api_key: 官方要求的 api_key
encodeing_model: cl100k_base
model: 官方要求的模型名称
本地模型:
api_base: http://localhost:11434/v1
api_key: 任意填写
encodeing_model: cl100k_base
model: ollama 启动的模型名称

  注意:ollama 启动的Deepseek-r1系列模型均不支持作为文本模型接入GraphRAG,可以尝试使用Qwen2.5llama3.3等系列模型。

关于ollama的Embedding模型选型、ModelScope的Embedding模型接入流程,详见此前《从零到一开发RAG系统》系列公开课。
55bcb98e4dadd0f6777b6c94a5312aa

3. 数据准备

  Microsoft GraphRAG 的索引构建流程中,支持 .txt.csvjson 三种格式的数据文件,因此如何非这三种格式的数据文件,是无法直接进行索引构建的。加载文件的方法也非常简单,只需要在graphrag 初始化配置的同级目录下,新建一个input文件夹,然后把.txt.csv或者.json 文件放入其中即可。在linux系统中,执行命令如下:

FENCE0

  这里为了快速测试流程,我构建了一个实体非常丰富的文本文件-technology_companies.txt。该文本中包含了大量实体,如公司(苹果、谷歌、微软、亚马逊)、人物(史蒂夫·乔布斯、拉里·佩奇、比尔·盖茨、杰夫·贝索斯)、地点(硅谷、库比蒂诺、门洛帕克、雷德蒙德、西雅图)和技术(iPhone、Android、Azure、AWS),并且描述了实体之间的多种关系,如创始人关系(乔布斯创立苹果)、竞争关系(苹果与谷歌在智能手机领域的竞争)、合作关系(谷歌与苹果在搜索引擎上的合作)。该文本文件已经随课件上传至百度网盘,大家可以直接下载后放入input文件夹中,准备进行索引的构建。

image-20250715171007362 image-20250715165527008

4. 执行索引构建

  在配置好了.env文件和settings.yaml文件后,同时又准备好了数据文件,接下来我们就可以执行索引的构建了。通过GraphRAGCLI工具,执行命令如下:

FENCE0

  这条命令指的是在当前目录下执行索引的构建。当执行后,会看到GraphRAG 的索引构建流程开始执行,具体如下:

image-20250715174745137

  正常来说,如果对话模型和Embedding模型都配置正确,且数据文件也符合txt或者csv格式要求,那么构建索引的流程会顺利执行,并最终看到ALL Workflows Completed Successfully的提示。

image-20250715174810462

  同时,在构建索引结束后会分别生成cachelogsoutput三个文件夹,分别存储了构建索引过程中的缓存文件、日志文件和输出文件。

image-20250715174838051

  其中,output文件夹中会生成很多个xxx.parquet文件,这些文件就是GraphRAG 的索引文件,也是我们后续进行检索的依据。

image-20250715174658799

  最后,总结一下GraphRAG 的索引构建流程,具体如下:

  1. 配置Python运行的虚拟环境
  2. 安装Microsoft GraphRAGCLI工具
  3. 初始化配置文件
  4. 配置.env文件
  5. 配置settings.yaml文件
  6. 准备数据文件
  7. 执行索引构建

  这个执行过程并不是很复杂,但需要大家注意的是,在执行索引构建的过程中,会涉及到多次大模型的调用,因此需要大家确保当前的网络环境是通畅的,否则可能会导致索引构建失败。同时,如果大家使用的是ollama启动的本地模型,那么需要确保本地模型是正常启动的,否则也会导致索引构建失败。

  Microsoft GraphRAG 的索引构建流程,核心实现的是:利用大模型从传入的文档内容中提取出节点(实体)和边(关系),然后利用社区检测算法对整个知识图谱进行划分,划分成多个包含了相关性较高的节点和边的子图,然后利用大模型对每个子图进行总结,生成社区报告(摘要)(该社区报告(摘要)用来描述每个子图的概况)。当进行问答检索的时候,每个社区会依次执行Query的检索,最终将每个社区的结果进行汇总,从而生成全局性的完整答案。

  自然,这样的流程究竟涉及哪些技术细节,又是如何实现的呢?以及生成的这些文件又有什么用处,该如何使用呢?

  我们接下来就进行详细的讲解。

from tabulate import tabulate

# 其中,headers='keys' 表示使用列名作为表头,tablefmt='pretty' 表示使用 pretty 格式化输出,showindex=False 表示不显示行索引,stralign='left' 表示左对齐,maxcolwidths=[20, 20, 20, 20, 20] 表示每列的最大宽度为20
print(tabulate(df_text_units, headers='keys', tablefmt='pretty', showindex=False, stralign='left', maxcolwidths=[20, 20, 20, 20, 20]))

  在对文档进行分块成TextUnit以后,接下来就要对每个TextUnit中的内容进行图元素的提取。 元素主要包括:实体、关系。

  主要有两种提取策略:

  • 默认的提取策略是:graph_intelligence,其实就是编写提示词让大模型来提取出实体和关系。
  • 另一种是使用NLTK进行实体和关系的提取。

  这里建议大家还是选择使用大模型来进行实体和关系的提取,因为大模型提取的效果会更好。自然,这个环节需要加载我们在settings.yml文件中配置的对话模型接口服务。

  同时,在settings.yml文件中,我们还可以配置实体的类型和提示词,位置如下图所示:

  默认的实体类型是:"organization", "person", "geo", "event"

  默认的实体类型是:"organization", "person", "event", 而提示词内容就是在初始化graphrag项目时,在promots文件夹下的extract_graph.txt文件中定义的。

  这里的问题是:不同的数据块(chunks)可能会抽取出相同的实体。Microsoft GraphRAG会采用merge操作,如果遇到相同的节点,那么GraphRAG就会执行concat操作,也就是将对应的属性和关系进行合并。

  同时,对节点和关系分别基于TextUnit的原始文本进行摘要。简单理解就是给出一个解释:为什么这个节点和关系会被提取出来。

  这就是第三个阶段的完整流程,即从TextUnit中提取出实体和关系以及生成对应的摘要。

  执行extract_graphworkflow后,在output文件夹下会生成entities.parquet文件和relations.parquet文件,同样,这两个文件也涉及二次更新,即在提取出实体和关系后,会执行finalize_graphworkflow,分别对entities.parquet文件和relations.parquet文件进行进一步处理。在这个过程中,将执行图节点和关系的聚合,并生成图的向量表示。

# 使用绝对路径读取 Parquet 文件
df_entities = pd.read_parquet('output/entities.parquet') # 替换为实际路径
df_relations = pd.read_parquet('output/relationships.parquet') # 替换为实际路径
print(tabulate(df_entities, headers='keys', tablefmt='pretty', showindex=False, stralign='left', maxcolwidths=[20, 20, 20, 20, 20]))
print(tabulate(df_relations, headers='keys', tablefmt='pretty', showindex=False, stralign='left', maxcolwidths=[20, 20, 20, 20, 20]))

  现在有了可用的实体和关系图,但是这些实体和关系都是孤立的,没有形成一个完整的图谱。因此需要做的就是将这些实体和关系进行聚合,形成一个完整的图谱。所以接下来的任务就是要将识别出来的实体和关系分组成相关关联的子集。

  要实现这个目标,就需要大家理解社区检测这个概念。

  社区检索是图论中的一个重要任务,旨在识别图中节点的聚集结构。其中社区是指在图中,节点之间的连接比与其他节点的连接更为密切的子集。通过识别社区,我们就可以理解数据的内在结构,发现潜在的模式和关系。其中莱顿算法(Leiden Algorithm)是一种用于社区检测的高效算法,旨在优化社区结构的识别过程。它是基于 Louvain 算法的改进,具有更好的性能和准确性。

  微软实现的就是分层的莱顿算法(Hierarchical Leiden Algorithm),它将图中的节点分成多个层次的社区,从而形成一个层次化的社区结构。

# 使用绝对路径读取 Parquet 文件
df_communities = pd.read_parquet('output/communities.parquet') # 替换为实际路径
print(tabulate(df_communities, headers='keys', tablefmt='pretty', showindex=False, stralign='left', maxcolwidths=[20, 20, 20, 20, 20]))

  莱顿算法(Louvain Method)通过优化模块度(modularity)来划分图中的节点,并没有固定的默认划分数量。它的目标是根据图的结构自动识别社区的数量。算法会在每个 level 中优化社区划分,直到达到局部最优。每个 level 代表一个图的状态,随着算法的迭代,图的结构会逐渐简化,节点会被聚合成更大的社区。

  在生成社区后,执行的workflowcreate_final_text_units,其实就是把之前处理的实体、关系等关联起来,形成最终的文本单元。形成一个完整的知识图谱表示,这样,每个文本单元不仅包含原始文本,还包含了与之相关的所有结构化信息(实体、关系)的引用,可以用于进一步 Embedding 和 后续的Query操作。

df_text_units = pd.read_parquet('output/text_units.parquet') # 替换为实际路径


print(tabulate(df_text_units, headers='keys', tablefmt='pretty', showindex=False, stralign='left', maxcolwidths=[20, 20, 20, 20, 20]))

  接下来,要做的就是对每个社区中的节点、关系和摘要的定义进行总结。这样做的目的是为了方便查询,当查询时需要根据问题匹配知识库中的实体信息和关系信息时,只需要根据总结后的实体描述和关系描述就可以进行匹配了。不然遍历所有的Description进行匹配,效率会非常低下。

  同时,生成报告的策略也是借助提示工程 + 大模型实现,同时复用 实体、关系提取的部分子逻辑,因此,我们也可以在setting.yml 文件中进行相关提示词的配置更改:

df_community_reports = pd.read_parquet('output/community_reports.parquet') # 替换为实际路径

print(tabulate(df_community_reports, headers='keys', tablefmt='pretty', showindex=False, stralign='left', maxcolwidths=[20, 20, 20, 20, 20]))

  最后,在最新版本的代码实现中,对各个阶段不在单独生成Embedding向量,而是在完成所有的索引构建流程且得到索引文件后,一次性的将实体、关系、社区报告等关键信息的Embedding向量表示生成,并在本地生成Lancedb存储,用于接下来的Query流程。

  至此,这就是完成的Microsoft GraphRAG构建索引的内部细节。而关于Query阶段,我们将在接下来的课程中进行详细的讲解,从而构建出完整的基于GraphRAG的问答流程。

注,公开课中索引构建只是最简单的实现方法,在付费课程《2025大模型Agent智能体开发实战》(7月班) 中,还会实现更多工业级功能,包括:

  1. 默认类型 txt、csv和json 的默认加载模式,根据接入规范,二次开发了针对 pdf、图片、word、ppt、markdown 的独立解析模式,仅需要修改 settings.yaml 中的配置即可。
  2. 默认的切分策略是简单的按照token或者sentence进行切分,我们完全重写了 PDF 和 Markdown 等复杂文件的切分策略以及数据预处理策略
  3. 在图提取阶段,我们讲解了基于不同数据如何动态的调整提示词,从而适配不同的实体和关系的构建差异
  4. 对于像PDF这种多模态数据,课程重点讲解了 MinerU项目,并基于这个项目做了二次开发,通过外放 FastAPI 接口的形式接入到 GraphRAG 中,并且做了并行处理,提升索引效率 感兴趣的同学扫码即可咨询: 06661cb459aa3e4b655aface404435d
e5b5013521acbcafd29af716aa4a83e

四、GraphRAG查询(Query)构建流程详解

  在完成了Microsoft GraphRAG的索引构建后,Microsoft GraphRAG提供了一种更为直观、易用的查询方式,我们只需要输入自然语言查询,即可获得结构化的查询结果。

  索引阶段我们利用大语言模型结合提示工程,从非结构化文本(.txt.csvJson)中提取出实体(Entities)与关系(Relationships),构建出了基础的Knowledge Graph,并且通过建立层次化的community 结构,community 以及community_report 的丰富语义,相较于传统基于Cypher的查询方式可以提供更多灵活性的Query操作,Microsoft GraphRAG 在项目开源之初是提供了localglobal 两种查询方式,分别对应了local searchglobal search,而后在不断的迭代更新过程中,除了优化了local searchglobal search 的效果,还新增了DRIFT SearchMulti Index Search 作为扩展优化的可选项,以进一步丰富Query操作的多样性。

  如下图所以,原图来源于Microsoft GraphRAG 的官方论文:https://arxiv.org/pdf/2404.16130

  Microsoft GraphRAG 在查询阶段构建的流程,相较于构建索引阶段会更为直观,核心的具体步骤包括:

  1. 接收用户的查询请求。
  2. 根据查询所需的详细程度,选择合适的社区级别进行分析。
  3. 在选定的社区级别进行信息检索。
  4. 依据社区摘要生成初步的响应。
  5. 将多个相关社区的初步响应进行整合,形成一个全面的最终答案。

  通过学习Microsoft GraphRAG索引构建的源码大家应该已经能够清晰的知道,Indexing 过程中并不是在创建完第一层社区后就停止了,而是是分层的。也就是说,当创建第一层社区(即基础社区)后,会将这些社区视为节点,进一步构建更高层级的社区。这种方法就实现在知识图谱中可以以不同的粒度级别上组织和表示数据。比如第一层社区可以包含具体的实体或数据,而更高层级的社区则可以聚合这些基础社区,形成更广泛的概览。

  因此最核心的Local SearchGlobal Search 的实现,就是源于不同的粒度级别而构建出来用于处理不同类型问题的Pipeline, 其中:

  • Local Search 是基于实体的检索。
  • Global Search 则是基于社区的检索。

  因此接下来,我们就分别从源码层面,来详细介绍Local SearchGlobal Search 的实现原理,并实际操作不同检索方式的查询操作。

模式核心思路场景举例
local只查询与“当前节点”邻居相关的子图“围绕某个主题节点的局部信息”
global全局搜索,忽略当前节点,直接在所有节点里找“在整个图中检索最相关的节点”
hybrid先局部查询,再全局补充“先看局部,再回溯全局补充背景”
contextual根据当前上下文,动态选择检索区域“根据问题类型或语境决定局部/全局混合策略”

1. Local Search 实现原理

  首先来介绍Local Search, 即本地检索。

   Local Search 即本地检索,是基于实体的检索。本地搜索从相关实体开始,使用知识图谱来查找最相关的信息。例如,给定查询中的实体,使用的是连接节点的信息,通过辨识与查询相关的实体与关系,检索特定文本片段、摘要和关联性资料。

  所以Local Search 本质上是基于实体的推理。特别适合回答“who”、“what”、“when” 类型的问题。

  在Microsoft GraphRAG 源码中实现的内部原理如下图所示:

  我们可以通过graphrag query --help 命令来查看,如下图所示:

  各个字段参数的含义如下表所示:

graphrag query 命令参数说明

参数名称类型描述默认值是否必需
--methodTpye可以选择local、global、drift或basic算法。None
--queryTEXT要执行的查询,即提出的问题。None
--configPATH要使用的配置文件路径。None
--dataPATH索引管道输出目录(即包含 parquet 文件的目录)。None
--rootPATH项目根目录的路径。.
--community-levelINTEGER从中加载社区报告的 Leiden 社区层级。较高的值表示来自较小社区的报告。2
--dynamic-community-selection使用动态社区选择的全局搜索。no-dynamic-community-selection
--response-typeTEXT描述响应类型和格式的自由文本,可以是任何内容,例如多个段落、单个段落、单句、3-7点列表、单页、多页报告。Multiple Paragraphs
--streaming以流式方式打印响应。no-streaming
--help显示帮助信息并退出。

  其中,在执行查询时必须指定的参数是--method--query,其他参数为可选参数。其中:

  • --method 参数可以选择localglobaldriftbasic算法。(接下来我们会依次介绍这几种算法)
  • --query 参数是要执行的查询,即提出的问题。

  了解到这里,就可以通过命令行快速启动问答检索了。这里我们先来看local 本地搜索。输入如下命令:

FENCE0

image-20250715175213316

  最终会显示SUCCESS: Local Search Response 成功提示,并会显示最终的问答结果。整个过程使用起来非常简单,但是简单并不意味着可以直接使用,大多数情况下基于通用流程的问答检索,并不能满足实际业务需求。比如检索的效果不准确,效率不高,检索结果不全面等,因此,我们需要进一步掌握Microsoft GraphRAG 的检索原理,并根据实际业务需求,进行针对性的优化和调整。

  而对于 Local Search 的完整实现过程,其实是这样的:

  1. 依次读取text_units.parententities.parentrelationships.parent communities.parentcommunity_reports.parent 的索引文件,并将其加载到内存中。
  2. 加载Lancedb 中的词向量,准备用于后续的相似度计算。
  3. 根据社区的community_level 参数的值,对实体进行第一轮的过滤,过滤的规则是:如果实体的community_level 小于等于community_level 参数的值,则保留该实体,否则丢弃。
  4. 基于输入的问题,进行实体的匹配,并构建完整的上下文。
    • 处理输入问题,如果存在对话历史记录,则将之前的用户问题附加到当前查询。
    • 将输入的问题转化为词向量,然后和lancedb中的实体词向量进行相似度计算,得到与查询最相关的实体,这个过程中会采用两个策略:
      • 过采样 (Oversampling) 策略,即最终检索的实体数量是 k * oversample_scaler。
      • 如果提供了exclude_entity_names列表,则过滤掉这些实体。
    • 根据匹配到的实体,读取该实体所属的社区报告,这个过程会采用的策略是:
    • 统计每个社区被多少个选中实体引用(一个实体可能属于多个社区),做基于实体归属的社区投票排序
    • 按匹配度和社区自身排名双重排序
      • 主要排序标准:被实体引用的频次(匹配度)
      • 次要排序标准:社区自身的重要性排名
    • 在 2,3 的基础上,提取出文本单元、关系的附件属性
    • 生成完整的数据表格
  5. 构建本地搜索的系统提示词,将数据表格填充到系统提示词中,引导大模型生成最终的回答。其提示词设置在settings.yaml 文件的local_search

  以上就是Local Search 的完整实现过程,至此,大家再理解Microsoft GraphRAG 给出的Local Search 原理图,就可以非常清晰的理解到其中各个阶段的工作原理了。

  好,Local Search 的源码解析到这里就全部结束了。所以的细节均给大家介绍完毕。接下来我们在关注Global Search 的实现过程。

2. Global Search 实现原理

  Microsoft GraphRAG 中的全局搜索算法旨在回答需要了解整个数据集的抽象问题,即借助社区摘要来获取全局的答案。实现思路是通过 map-reduce 流程总结知识图谱中的社群摘要,汇总社区摘要中的见解,尝试生成文档中元素的概述,聚合相关资料并生成针对整体数据集的高层次回答。因此全局搜索更侧重于为需要更高层次理解的问题提供答案。比如数据中的前5个主题是什么?这类问题。

  传统的 Map-Reduce 中,Map阶段会将输入数据分解为独立的块,每个块可以并行处理,然后Reduce 阶段会汇总所有映射操作的结果,生成最终输出。而在Microsoft GraphRAG 中,Map 阶段会使用大模型对多个文档或信息片段并行处理,从每个片段中提取相关信息,然后Reduce 阶段会汇总所有映射操作的结果,生成最终输出。

  Global SearchMicrosoft GraphRAG 源码中的实现原理图如下所示:

  注意,当使用Global Search 时,需要指定--method global 参数,如下所示:

FENCE0

image-20250715175521079

  如果大家理解了Local Search 的检索过程,那么Global Search 理解起来就非常简单了。按照相同的思路,逐步进入到各个阶段的内部细节即可清晰的了解其实现的原理。接下来我们就分步骤给大家介绍Global Search 的实现过程。具体如下:

  1. 依次读取entities.parentcommunities.parentcommunity_reports.parent 的索引文件,并将其加载到内存中;
  2. 依次创建 entities.parentcommunities.parentcommunity_reports.parent 的实体对象,并进行格式化处理;
  3. 进入到构建上下文阶段。在这个阶段,最关键的一个核心概念是:静态与动态全局搜索策略的选择。
    • 静态策略方法指的是知识图谱中预定级别的社区中进行搜索来生成答案。然后,大模型合并并总结此抽象级别的所有社区报告。最后,摘要用作 大模型的附加上下文,以生成对用户问题的响应。此为静态方法。它存在的问题是既昂贵又低效,因为包含许多对用户查询没有帮助的低级报告。
    • 动态社区选择算法dynamic_community_selection。该算法利用索引数据集的知识图谱结构。从知识图谱的根开始,我们使用提示工程 + 大模型来评估社区报告在回答用户问题方面的相关性。如果报告被视为不相关,则将其及其节点(或子社区)从搜索过程中删除。另一方面,如果报告被视为相关,将遍历其子节点并重复该操作。最后,只有相关的报告才会传递给 map-reduce 操作以生成对用户的响应。如下图所示:

  该算法类实现的核心机制并不是简单地评估所有社区,而是采用启发式遍历,具体体现在:

  1. 选择性探索: 并不是简单地评估所有社区,而是根据当前社区的相关性决定是否探索其子社区。只有当一个社区的评分大于或等于阈值时,才会将其子社区添加到下一轮评估中。
  2. 动态队列构建: queue = communities_to_rate 表明下一轮要评估的社区完全取决于当前轮次中哪些社区被认为是相关的。这不是一个固定的或预先确定的遍历顺序。
  3. 剪枝机制: 如果一个社区的评分低于阈值,其所有子社区都会被"剪枝",不会被进一步探索。这是启发式算法的典型特征。
  4. 自适应性: 算法的路径会根据不同的查询而变化,因为相关性评分依赖于具体的查询内容。
  5. 回退策略: 如果在当前路径上找不到相关社区,算法会尝试探索下一个层级的所有社区,这也是一种启发式决策。

  其中,用于评估社区相关性的提示词是这样的,其对应的中文提示如下所示:

FENCE0

  其响应的结果如下所示:

  然后,该输出的结果会作为变量context_data 传递给global_search_reduce_system_prompt.txt 中定义的提示,并调用大模型生成最终的 Reduce 响应,同时,Reduce 响应的结果会作为变量context_text 传递给global_search_knowledge_system_prompt.txt 中定义的提示,引导大模型生成最终的 Knowledge 响应。

  至此,Global Search 的实现原理就全部介绍完毕了。而现在大家在看Microsoft GraphRAG 官方提供的流程图,自然也能够非常清晰的理解其背后的实现原理。如下图所示:

  以上就是我们对Microsoft GraphRAG 的检索流程中最关键的Local SearchGlobal Search的完整流程解读,而关于basic searchdrift search,大家可以按照相同的思路进行扩展学习。

五、GraphRAG Python API使用方法

from pathlib import Path
from pprint import pprint

import pandas as pd

import graphrag.api as api
from graphrag.config.load_config import load_config
from graphrag.index.typing.pipeline_run_result import PipelineRunResult
  • Index过程
PROJECT_DIRECTORY = "./graphrag_course"
graphrag_config = load_config(Path(PROJECT_DIRECTORY))
index_result: list[PipelineRunResult] = await api.build_index(config=graphrag_config)

# index_result is a list of workflows that make up the indexing pipeline that was run
for workflow_result in index_result:
status = f"error\n{workflow_result.errors}" if workflow_result.errors else "success"
print(f"Workflow Name: {workflow_result.workflow}\tStatus: {status}")
  • Query过程
entities = pd.read_parquet(f"{PROJECT_DIRECTORY}/output/entities.parquet")
communities = pd.read_parquet(f"{PROJECT_DIRECTORY}/output/communities.parquet")
community_reports = pd.read_parquet(
f"{PROJECT_DIRECTORY}/output/community_reports.parquet"
)

response, context = await api.global_search(
config=graphrag_config,
entities=entities,
communities=communities,
community_reports=community_reports,
community_level=1,
dynamic_community_selection=False,
response_type="Multiple Paragraphs",
query="请帮我介绍下亚马逊公司?",
)
print(response)

需要注意的是,以上是GraphRAG高层API,更加底层的面向开发端的API,我们将在后续的课程中进行介绍。