深入Microsoft GraphRAG之索引阶段:原理、测试及如何集成到Neo4j图数据库
我们已经了解了基于知识图谱的RAG应用原理,之前的文章里也演示过怎么用LangChain或LlamaIndex这类框架构建简易的GraphRAG原型。但话说回来,要把GraphRAG应用真正投入生产,中间还有一大堆优化工作要做。也正因为如此,一些更专业的工具应运而生——微软最近开源的GraphRAG,就迅速成了圈里的焦点。
不少朋友可能已经在微软那篇论文里见过GraphRAG的基本思路了。不过,我们还是打算结合一个实际案例,把GraphRAG的内部原理拆开揉碎了讲清楚,顺带演示一下怎么跟Neo4j图数据库集成——这样一来,灵活性和应用场景都会大不一样。
我们准备分两篇文章来聊,分别侧重索引阶段(Index)和查询阶段(Query)。本篇的内容包括:
GraphRAG原理
GraphRAG索引构建与源码分析
GraphRAG索引集成到Neo4j
GraphRAG原理
Microsoft GraphRAG的源头,是自家那篇论文《From Local to Global: A Graph RAG Approach to Query-Focused Summarization》。论文里说得很清楚,它要解决的,是传统RAG的一个老大难问题:
没法回答那些需要高层语义理解的总结性查询——比如“这些数据集表达了什么主题”。这类任务,学术上叫QFS(Query-Focused Summarization)型任务。
论文里给出的解法是这样的:
先从多个原始文档构建知识图谱(这一步跟之前介绍的Graph RAG差别不大);然后用社区检测算法(比如leiden算法)把知识图谱划分成多个社区/聚簇,再用大模型给这些社区生成自然语言摘要。
可以把社区理解成
围绕某个主题的一组紧密相关的实体与关系信息
这个过程用下图表示:

图片来自微软论文
这个流程的妙处在于:
它把原始的自然语言文本转化并压缩成图谱,然后又把这些图谱总结回自然语言。说白了,就是从自然语言文本→结构化的知识图谱→自然语言摘要。
Microsoft GraphRAG对这套流程的实现,可以参考论文中的描述:

图片来自微软论文
这里得说明一下,查询阶段(Query Time)相对简单,真正复杂的是索引阶段(Indexing Time)。我们用尽量简洁的方式把处理过程梳理一下:
1. 文本块拆分:
2. 实体与关系提取:
3. 生成实体与关系摘要:

这种摘要的好处是:可以借助嵌入向量更有效、更准确地对这些实体与关系进行检索——这也就是上图中description_embedding属性的意义所在。
当然,好处背后也有代价。因为需要为大量的实体与关系生成描述信息,所以会触发非常多的LLM调用,这意味着漫长的耗时和昂贵的大模型API开销!我们建议在测试阶段优先用GPT-4o-mini模型。
4. 检测与识别社区:
5. 生成社区摘要:
GraphRAG索引构建与源码分析
现在我们用一个文档来构建基于MS GraphRAG的Demo应用,重点放在索引阶段。我们准备了一个自然语言描述漫威漫画世界的文本文件用于测试,内容大致如下(全文约2万汉字):

构建GraphRAG索引的过程其实不复杂(详细步骤可以看官方文档):
1.
准备。
2.
初始化。
python -m graphrag.index --init --root ./msgraphrag
初始化完成以后,会在指定的根目录下生成基本的文件与目录结构。重要的包括:
- 用来存放输入的原始文档(txt或者csv)。我们把测试用的txt文件放到这个目录下。
input目录:
- 你可以在.env或settings.yaml里修改全部配置项。默认情况下只需要改LLM相关的配置——注意,目前只支持OpenAI或者Azure OpenAI的模型:
.env与settings.yaml配置文件:

- 这里存放了自动生成的LLM提示模板文件,一共四个,分别在流程的不同处理阶段使用:
prompts目录:
- 用于从自然语言文本中抽取实体与关系。
entity_extraction:
- 用于生成实体与关系的描述性文本。
summarize_descriptions:
- 用于生成社区的摘要等报告信息。
community_report:
- 这是一个可选动作,用来生成一些实体的辅助声明(由GRAPHRAG_CLAIM_EXTRACTION_ENABLED参数控制)。这里先跳过它。
claim_extraction:
虽然可以直接用初始化时生成的默认提示模板,但强烈建议通过GraphRAG提供的命令来创建
自适应提示模板
GraphRAG会提取输入数据的信息,然后借助大模型分析并生成更有针对性的提示模板。
python -m graphrag.prompt_tune --language Chinese
执行成功后,我们来观察一下prompts目录下新的提示模板文件内容(为了方便理解,这里翻译成中文):
先看用于实体/关系摘要生成的summarize_descriptions提示。

再观察用于生成社区摘要的community_report提示

3.
创建索引。
python -m graphrag.index --root ./msgraphrag
之后会进入一系列工作流程。当看到如下输出时,说明索引阶段的工作已经完成。

从最后输出的信息里,可以大致了解到它的基本处理过程:从拆分输入文本开始,到提取实体与关系、生成摘要信息、构建内存中的Graph结构、从Graph中识别社区、创建社区报告、创建Graph中的文本块节点和文档节点,等等。当然,除了上面介绍的几个核心步骤,还涉及到大量中间处理细节,比如embedding生成、持久化到存储、不同的算法策略等。如果有兴趣深入了解具体的实现,那还是得去啃GraphRAG的源代码。这里提供几个发现和指南:
Microsoft GraphRAG内部借助了DataShaper来实现灵活的工作流与处理动作的“装配”。
是微软开源的一个用来DataShaper
。通过定义一个数据处理工作流,你可以对输入的数据(比如Pandas的DataFrame)定义一系列数据操作的定义和执行数据处理工作流的库
(DataShaper里叫动作
)、Verb
,执行这个工作流就能完成数据处理。DataShaper里提供了很多开箱即用的Verb,你也可以自定义Verb。多个子工作流还能组合定义成一个更大的工作流。参数和步骤
一种简单的阅读方式:你可以在index/workflows/v1目录下找到基本的工作流定义,比如上面的create_base_extracted_entities;再根据工作流中的步骤(steps)找到对应的verb,然后在index/verbs里找到verb的实现,就能大致了解这个工作流的内部逻辑了。
可以学习代码目录中examples目录下的例子,用GraphRAG的索引引擎来构建自己的数据处理管道——这对理解DataShaper和GraphRAG的内部原理非常有帮助。
值得注意的一点是:Microsoft GraphRAG在索引构建过程中目前并不支持使用图数据库。中间数据主要用Pandas
这类结构化类型进行交换;Graph的构建与分析主要借助DataFrame
这个图计算库;Graph数据的交换使用Networkx
(一种基于XML的Graph表示);在社区识别时,则借助了Graphml
实现的leiden算法。Graspologic库
GraphRAG索引集成到Neo4j
索引构建完成后,默认情况下,GraphRAG会把构建整个知识图谱所需的数据持久化到output目录下,以parquet格式文件存放(
parquet

但parquet是一种底层文件格式,光靠它没法直观地观察上面构建的知识图谱索引的细节。那有没有办法做更直观的可视化、分析和检索呢?
其实parquet文件可以通过pandas库很方便地读取成DataFrame表,所以只要了解了它的结构,就能用Cypher语句把它导入到Neo4j图数据库中,变成节点和关系。

用他提供的笔记本文件在本地运行,就能成功把上面构建的知识图谱数据全部导入到Neo4j数据库。现在,我们可以通过Neo4j管理台看到完整的可视化知识图谱(部分):

在这个Demo的图谱里,看到的节点包括上面提取的实体(
entity
community
chunk
document
RELATED
PART_OF
HAS_ENTITY
IN_COMMUNITY

有了Neo4j的Cypher语言,你可以查清楚任何你想知道的图谱信息,或者直接点击某个节点查看详情。来看一个社区的信息——比如“蜘蛛侠与反派角色的关系”这个社区的图谱:

这个社区的报告信息(节点属性):

为了更深入地研究GraphRAG生成的数据,还可以用Cypher配合可视化库对知识图谱做进一步分析。比如,通过不同节点的关系数量(Node Degree)来了解节点的重要性:

这里最高的节点度接近30,来看看是哪个节点:
MATCH (n:__Entity__)
RETURN n.name AS name, count{(n)-[:RELATED]-()} AS degree
ORDER BY degree DESC LIMIT 10
执行结果如下(钢铁侠永远的神?):

除了数据分析,你还可以在此基础上做增强,比如联合导入其他已有的知识图谱数据。当然,更关键的是,你可以在自己的Neo4j图数据库上定义专属于你自己的RAG应用检索与生成器,不再依赖GraphRAG项目自带的Query功能——这带来的灵活性,可不是一星半点。
下一篇,我们将分析Microsoft GraphRAG中Query功能的实现,并探讨如何基于导入的Neo4j库来自定义实现RAG检索器。
-
- 关于宇宙的好的网名有哪些
- 角色扮演 | 1
- 网名