微软最近发布了名为 GraphRAG(Graphs + Retrieval Augmented Generation)的创新 RAG 框架,这是一个将文本提取、语义网络分析,与大语言模型(LLM)的提示和总结功能结合在一起的端到端系统,用于深入理解文本数据集。在对私有数据中的复杂文本信息进行文档分析时,GrahRAG 使用 LLM 生成的知识图谱来大幅提高问答性能。这里的私有数据集是指 LLM 没有接受过训练且从未见过的数据,例如企业的专有技术文档、业务文档等。
为什么提出 GraphRAG?
使用检索增强生成从外部知识源中检索相关信息,使大语言模型能够回答关于私有和/或以前未见过的文档集合的问题。然而,RAG 在面对针对整个文本语料库的全局性问题时表现不佳,例如“数据集的主要主题是什么?”因为这本质上是一个面向查询的总结(QFS, Query-Focused Summarization)任务,而不是显式的检索任务。但是,现有的QFS方法无法扩展至典型 RAG 系统索引的海量文本之上。
因此,微软提出了 GraphRAG 方法,代表“基于图谱的检索增强生成”,用于在私有文本语料库上进行问答。GraphRAG 不是简单地查找文本片段,而是构建信息的结构化和层次化关系图谱。它将基于图谱的知识检索与 LLM 相结合,捕获大规模文本信息中的实体、关系和关键声明。与依赖矢量相似性搜索的传统 RAG 方法不同,GraphRAG 可以增强 LLM 理解和综合复杂数据集及其关系的能力,从而产生更准确的响应。
GraphRAG 如何工作?
GraphRAG 的创新之处在于,它使大型语言模型能够基于整个数据集回答问题。从根本上讲,GraphRAG 是一种新的检索方法,它在基本 RAG 架构中使用知识图谱和向量搜索。因此,它可以整合和理解各种知识,从而提供更广泛、更全面的数据视图。
知识图谱是一种强大的信息组织方式,用于表示和存储实体之间的复杂关系,不仅捕捉到实体本身,还包括定义它们的连接和属性。通过以图结构组织信息,知识图谱能够更深入地理解数据中的关系和层次,从而支持更复杂的推理和推断。
GraphRAG 的工作原理是从索引文档中创建一个知识图谱,这些文档也被称为非结构化数据,例如网页。因此,当 GraphRAG 创建知识图谱时,它实际上是在创建一个“结构化”的表示,表示各种“实体”(如人、地点、概念和事物)之间的关系,使得机器就更容易理解这些关系。
GraphRAG 方法使用 LLM 在两个阶段构建基于图谱的文本索引:首先从源文档中推导出实体知识图谱,基于实体群体间的相关程度,创建称之为“社区”的一般主题(高层次)和更细化的主题(低层次);然后,LLM 会对社区中的每一个主题进行总结,形成一个“数据的分层摘要”。回答问题时,则使用每个社区摘要(Community summary)生成部分回应,之后将所有部分回应再次总结为最终的用户回应。这样,聊天机器人就能够更多地基于知识(即社区摘要)来回答问题,而不是依赖嵌入。
- 提取知识图谱:首先从原始文本创建“知识图谱”。知识图谱就像一个相互连接的内容实体网络,其中每个实体(或“节点”)都以有意义的方式与其他实体相连接。
- 建立社区层次结构:接下来,它将这些相互关联的内容实体组织成“社区”,将这些社区视为相关概念的集群。
- 生成摘要:对于每个社区,GraphRAG 都会生成摘要来概括要点。这有助于理解关键内容,而不会迷失在细节中。
- 利用图谱结构:当您需要执行涉及检索和生成信息的任务时,GraphRAG 会使用这种组织良好的图谱结构。
GraphRAG 核心功能组件
与 RAG 系统类似,整个 GraphRAG 管道可以分为两个核心功能组件:索引和查询。索引过程使用 LLM 来提取节点(如实体)、边(如关系)和协变量(如声明)。然后,它使用社区检测技术对整个知识图谱进行分区,并使用 LLM 进一步形成摘要。对于特定查询,它可以汇总所有相关的社区摘要以生成全局答案。
GraphRAG Indexing 索引
GraphRAG 索引包是一个数据管道和转换套件,旨在使用大语言模型从非结构化文本中提取有意义的结构化数据。索引管道是可配置的,由工作流、标准和自定义步骤、提示模板以及输入/输出适配器组成。索引管道设计用于:
- 从原始文本中提取实体、关系和声明
- 在实体中执行社区检测
- 生成多个粒度级别的社区摘要和报告
- 将实体嵌入到图谱向量空间中
- 将文本块嵌入到文本向量空间中
GraphRAG 索引管道建立在开源库 DataShaper 之上。DataShaper 是一个数据处理库,允许用户使用定义良好的模式声明性地表达数据管道、模式和相关资产。DataShaper 中的核心资源类型之一是工作流 Workflow。工作流程以步骤序列表示,我们称之为 Verbs。每个步骤都有一个动词名称(verb)和一个配置对象(configuration object)。
我们能够将数据管道表示为一系列多个相互依赖的工作流。在 GraphRAG 索引管道中,每个工作流可以定义对其他工作流的依赖性,有效地形成工作流的有向无环图(DAG),然后用于调度处理,如下图所示。管道输出可以以多种格式存储,包括 Json 和 Parquet,或者通过 Python APIs 手动处理。
GraphRAG Query 查询引擎
查询引擎是 GraphRAG 库的检索模块,负责以下任务:
- 本地搜索
本地搜索方法通过将模型从知识图谱中提取的相关数据与原始文档的文本块相结合,生成准确的答案。这种方法特别适用于需要深入了解文档中提到的特定实体的问题,例如“洋甘菊的治疗特性是什么?”
具体来说,本地搜索方法在给定用户查询和可选的对话历史记录的情况下,从知识图谱中识别出一组与用户输入语义相关的实体。这些实体作为访问知识图谱的切入点,可以进一步提取相关的细节信息,如关联实体、关系、实体协变量以及社区报告。此外,该方法还从与这些识别出的实体相关的原始文档中提取相关的文本块。接着,将这些候选数据源进行优先级排序和筛选,以适应预定义大小的单个上下文窗口,用于生成对用户查询的最终响应。
- 全局搜索
全局搜索方法通过以 Map-Reduce 方式搜索所有由 LLM 生成的社区报告来生成答案。这是一种资源密集型的方法,但对于需要了解整个数据集的问题,如“数据中排名前五的主题是什么?”,通常能提供较好的结果。
LLM 生成的知识图谱结构揭示了整个数据集的组织方式和主题分布。这使得我们能够将私有数据集组织成预先总结的、有意义的语义集群。通过全局搜索方法,LLM 能够在响应用户查询时,利用这些集群来总结相关主题。
具体而言,当接收到用户查询和(可选的)对话历史记录时,全局搜索方法使用从知识图谱社区层次结构中指定级别获取的社区报告集合作为上下文数据,以 Map-Reduce 方式生成响应。在 Map 步骤中,社区报告被分割成预定义大小的文本块。每个文本块用于生成包含要点列表的中间响应,并为每个要点附加表示其重要性的数字评分。在 Reduce 步骤中,筛选出的最重要要点被聚合,并用作生成最终响应的上下文。
全局搜索的响应质量可能会受到选择的社区层次结构级别的显著影响。较低级别的层次结构及其详细报告往往能够生成更全面的响应,但由于报告量大,也可能增加生成最终响应所需的时间和 LLM 资源。
- 问题生成
基于实体的问题生成方法将知识图谱中的结构化数据与输入文档中的非结构化数据相结合,以生成与特定实体相关的候选问题。
详细来说,给定先前用户问题的列表,问题生成方法使用与本地搜索相同的上下文构建方法,以提取和优先处理相关的结构化和非结构化数据,包括实体、关系、协变量、社区报告和原始文本块。然后,这些数据记录被合并至单个 LLM 提示中,以生成代表数据中最重要或最紧急的信息内容或主题的候选后续问题。这对于在对话中生成后续问题或生成问题列表非常有用,以便调查人员深入研究数据集。
GraphRAG 实践
GraphRAG 项目
基于 Python 的 GraphRAG 开源实现请参考 GitHub 项目:https://github.com/microsoft/graphrag。
安装 GraphRAG
初始化设置
现在我们需要设置数据项目和初始配置。我们使用默认配置模式,您可以根据需要使用配置文件或环境变量进行自定义。
首先,我们需要一个样本数据集:
接下来,我们需要设置工作区环境变量。
运行 graphrag.index --init
命令进行工作区初始化。
这将在 ./ragtest
目录中创建两个文件:.env
和 settings.yaml
。
.env
包含运行 GraphRAG 管道所需的环境变量。如果查看该文件,您将看到定义的单个环境变量,GRAPHRAG_API_KEY=<API_KEY>
。这是 OpenAI API 或 Azure OpenAI 端点借口的 API 密钥。你需要替换为自己的 API 密钥。settings.yaml
包含管道的设置。Azure OpenAI 用户应在settings.yaml
文件中设置以下变量:搜索 “llm:
” 配置,您应该会看到两个部分,一个用于聊天端点,一个用于嵌入端点。以下是如何配置聊天端点的示例:
构建索引
现在,我们将开始运行索引管道。
控制台将打印许多运行时日志,例如完整的索引管道编排工作流:
索引管道执行过程中,运行时日志会打印非常丰富的社区报告、节点信息等内容。
索引过程需要一些时间来运行,具体时间取决于输入数据的大小、所使用的模型以及文本块的大小(这些参数可以在 .env
文件中配置)。一旦索引管道完成,您应该会在 ./ragtest/output/<timestamp>/artifacts
文件夹中看到一系列的 .parquet
文件。
请记住,GraphRAG 在计算上可能非常密集,尤其是在索引阶段。保持输入文档简洁以获得最佳性能。
图谱可视化
修改settings.yaml
,可以将图谱保存成为 GraphML 标准格式文件,例如 ragtest/output/<timestamp>/artifacts/summarized_graph.graphml
。
执行全局查询
索引过程执行完成后,我们就可以使用数据集进行提问了。
以下是使用全局搜索询问高级问题的示例:
执行本地查询
以下是使用本地搜索询问有关特定字符的更具体问题的示例:
GraphRAG + Ollama 本地方案
GraphRAG + Ollama 旨在支持本地模型,使其成为 OpenAI / Azure OpenAI APIs 实现的本地替代方案。通过利用由 Ollama 支持的开源语言模型,我们可以进行具有成本效益的本地推理,而无需承担昂贵的 LLM APIs 调用成本。但是请注意:本地方案的运行时间成本非常高。
创建运行环境
可以使用 conda 创建一个新的运行环境,以确保所有依赖项都安装在一个隔离的 Python 环境中。
安装 Ollama
下载语言模型与嵌入式模型
初始化文件夹
修改配置
我们使用 Ollama 提供对语言模型与嵌入式模型的本地部署支持。其中,LLM 部分可以使用诸如 llama3.1、mistral、phi3 等语言模型,而嵌入模型部分则可以使用诸如 mxbai-embed-large、nomic-embed-text 等模型。默认的 API 地址基址为 LLM 模型的 http://localhost:11434/v1
和嵌入模型的 http://localhost:11434/api
。
将 settings.yaml
文件中的相关配置修改为 Ollama 本地模型与 API 调用接口:
更改源代码
参考 GitHub 项目:https://github.com/karthik-codex/Autogen_GraphRAG_Ollama
,替换 GraphRAG 包中的两个文件:
site-packages/graphrag/llm/openai/openai_embeddings_llm.py
site-packages/graphrag/query/llm/oai/embedding.py
执行索引
执行用户查询
GraphRAG 源代码简析
GraphRAG 项目的源代码结构如下图所示。
索引工作流
索引阶段的工作流程包括以下步骤:
- 初始化:生成必要的配置文件、缓存和目录。
- 索引:使用工作流程模板创建一系列管道,根据依赖关系调整执行顺序,并依次执行这些管道。
这个过程确保了构建知识图谱和为后续查询操作做好准备的系统化和高效性。索引阶段被认为是整个项目的核心,其整体流程相当复杂。执行索引的命令如下:
这些命令调用了 graphrag/index/__main__.py
中的主函数,并使用 argparse
解析输入参数,最终调用 graphrag/index/cli.py
中的 index_cli
函数。
接下来,我们来分析相关函数的调用链,重点关注关键组件:
cli.py::index_cli()
函数首先根据用户输入参数(例如 --init
)决定是否初始化当前文件夹。它会检查目录中是否存在配置文件、提示文件和 .env
文件,如果不存在则创建这些文件,包括 settings.yaml
和各种提示文件。
对于实际的索引操作,它执行了一个内部函数 cli.py::index_cli()._run_workflow_async()
,该函数主要涉及两个函数:cli.py::_create_default_config()
和 run.py::run_pipeline_with_config()
。
- 默认配置生成:
cli.py::_create_default_config()
检查根目录和settings.yaml
文件。- 然后,它执行
cli.py::_read_config_parameters()
来读取系统配置(如 LLM、块大小、缓存、存储等)。 - 关键步骤是根据当前参数创建管道配置,这一步由
create_pipeline_config.py::create_pipeline_config()
实现。该模块是项目中最复杂的模块之一,核心逻辑是:基于不同的函数生成一个完整的工作流程序列,使用的是workflows/v1
目录中的模板。需要注意的是,此阶段不会考虑工作流程之间的依赖关系。 - 管道执行:
run.py::run_pipeline_with_config()
加载现有的管道配置。- 它创建子目录(如缓存、存储、输入、输出等)。
- 然后,它使用
run.py::run_pipeline()
依次执行每个工作流程并返回结果,主要包括两个部分:
- 加载工作流程:
workflows/load.py::load_workflows()
创建常规工作流程并处理拓扑排序。workflows/load.py::create_workflow()
:使用现有模板创建工作流程。graphlib::topological_sort()
:根据工作流程的依赖关系计算有向无环图(DAG)的拓扑排序。 - 执行操作:如
inject_workflow_data_dependencies()
、write_workflow_stats()
和emit_workflow_output
,用于依赖注入、数据写入和保存工作流程输出。
知识图谱构建
知识图谱构建的工作流程 create_final_entities.py
依赖于 workflow:create_base_extracted_entities
,并定义了 cluster_graph
和 embed_graph
等操作。cluster_graph
操作使用了 Leiden 策略,具体实现位于 index/verbs/graph/clustering/cluster_graph.py
:
可以看到这本质上是一个带有 @verb
装饰器的函数。这里使用的 Leiden 算法来自 graspologic
库,一个用于图统计的 Python 包。
全局搜索
GraphRag 提供两种搜索模式:全局搜索和本地搜索。根据参数的不同,主函数会分别调用这两种模式。可以在 graphrag/query/__main__.py
中找到这两个调用:cli::run_local_search()
和 cli::run_global_search()
。
cli::run_global_search()
主要调用 factories.py::get_global_search_engine()
,该函数返回一个 GlobalSearch
类。这个类与 LocalSearch
类类似,都是通过工厂模式创建的。其核心方法 asearch()
采用了 Map-Reduce 方法。该方法使用大型语言模型并行生成每个社区摘要的答案,然后将这些答案汇总成最终结果。这种 Map-Reduce 机制会导致全局搜索消耗大量 tokens。
本地搜索
类似地,cli::run_local_search()
调用了 factories.py::get_local_search_engine()
,返回一个 LocalSearch
类。它的 asearch()
方法更为简单,直接基于上下文提供响应。这种模式更类似于传统的 RAG 语义检索策略,并且消耗的 tokens 较少。
与全局搜索不同,本地搜索模式整合了多个数据源,包括节点、社区报告、文本单元、关系、实体和协变量。
结论
GraphRAG 的核心创新在于其处理查询导向摘要(QFS)任务的方法。QFS 和多跳问答(Multi-Hop Q&A)目前是传统 RAG 系统难以应对的挑战性领域,但它们在数据分析等方面具有广泛的应用前景。尽管 GraphRAG 的当前实现需要大量计算资源,但它为这一领域开辟了新的可能性。
GraphRAG 对知识图谱的细粒度处理尤其值得关注,包括使用 Leiden 算法进行社区检测和集成多源数据的本地搜索。项目中另一个有趣的方面是其实体提取方法,GraphRAG 完全依赖大型语言模型,而不受传统三元组架构的限制。作者指出,由于相似性聚类,模型提取的变化不会显著影响最终的社区生成。
GraphRAG 另一大亮点则是其全面的内置工作流编排系统。该系统基于模板定义工作流程,具有灵活配置和可追溯步骤,这可能为未来发展指明了方向。与完全依赖大型语言模型处理所有任务的系统相比,GraphRAG 提供了更多的控制和透明度。
总之,Microsoft GraphRAG 框架为该领域做出了重要贡献。它为自然语言处理和知识图谱操作中的复杂问题引入了新的解决方案。尽管在某些方面还有改进的空间,但这个项目值得深入研究,它为高级信息检索和摘要领域带来了宝贵的洞见和创新。
References
- Darren Edge, Ha Trinh, Newman Cheng, Joshua Bradley, Alex Chao, Apurva Mody, Steven Truitt, Jonathan Larson. From Local to Global: A Graph RAG Approach to Query-Focused Summarization. Apr 2024. https://doi.org/10.48550/arXiv.2404.16130 https://www.microsoft.com/en-us/research/project/graphrag/ https://microsoft.github.io/graphrag/
- Markus J. Buehler, Accelerating Scientific Discovery with Generative Knowledge Extraction, Graph-Based Representation, and Multimodal Intelligent Graph Reasoning. Jun 2024. https://doi.org/10.48550/arXiv.2403.11996
- rvk. Unlocking Cost-Effective Local Model Inference with GraphRAG and Ollama. Jul 2024. https://medium.com/@vamshirvk/unlocking-cost-effective-local-model-inference-with-graphrag-and-ollama-d9812cc60466
GitHub: https://github.com/TheAiSingularity/graphrag-local-ollama - Ollama. https://ollama.com/
- Saurabh Rajaram Yadav. GraphRAG local setup via vLLM and Ollama : A detailed integration guide. Jul 2024. https://medium.com/@ysaurabh059/graphrag-local-setup-via-vllm-and-ollama-a-detailed-integration-guide-5d85f18f7fec
- Karthik Rajan. Microsoft’s GraphRAG + AutoGen + Ollama + Chainlit = Local & Free Multi-Agent RAG Superbot. Jul 2024. https://ai.gopubby.com/microsofts-graphrag-autogen-ollama-chainlit-fully-local-free-multi-agent-rag-superbot-61ad3759f06f
GitHub: https://github.com/karthik-codex/Autogen_GraphRAG_Ollama - Inside GraphRAG: Analyzing Microsoft’s Innovative Framework for Knowledge Graph Processing. Calvin Ku. Jul 2024. https://medium.com/percena/inside-graphrag-analyzing-microsofts-innovative-framework-for-knowledge-graph-processing1-6f84deec5499
- GraphRAG-Local-UI. GitHub: https://github.com/severian42/GraphRAG-Local-UI
所有评论(0)