源码解析(一):GraphRAG

原文 技术博客
| 😀 GraphRAG 是一种结构化的、分层的检索增强生成 (RAG) 方法,它利用知识图谱来增强 LLM 的输出,用于推理私有数据集中的复杂信息。本文档对 GraphRAG 系统、其架构和关键组件进行了概述。

GraphRAG 通过从非结构化文本构建知识图谱并将其用于检索,增强了传统的 RAG 系统。与仅依赖向量相似度的标准 RAG 方法不同,GraphRAG 提取实体和关系,执行社区检测,并生成不同层级的报告。这种结构化方法为语言模型提供了更多上下文和关系信息,从而产生更全面、更准确的响应。

系统框架

  1. 实体提取 (Entity Extraction)

    从非结构化或半结构化数据(如文本、表格)中识别并抽取出具有特定语义的独立对象(如人名、地点、机构、时间等)。

  2. 图谱构建 (Knowledge Graph Construction)

    将提取的实体和它们之间的关系组织成结构化网络的过程,形成"节点-边-属性"三元组(如**<人物, 就职于, 公司>**)。

  3. 社区检测 (Community Detection)

    在图结构中自动发现紧密连接的子图(社区),使社区内部连接密集,社区之间连接稀疏。

  4. 社区报告 (Community Reporting)

    对检测到的社区进行统计、分析和可视化,描述其规模、关键节点、语义特征及与其他社区的关系。

  5. 向量化 (Embedding)

    将知识图谱中的实体和关系映射为低维数值向量(如用[0.2, -0.5, 1.3]表示"北京"),以便机器学习模型处理语义和相似性计算。

安装与使用

软件要求

  • Python 3.10-3.12
  • OpenAI API 密钥或 Azure OpenAI 访问权限(或者其他大模型的接口API)

pip直接安装

python 复制代码
pip install graphrag

快速使用

项目初始化

python 复制代码
graphrag init --root ./myproject

上述指令将创建下面3个配置文件:

  • settings.yaml:基础配置文件
  • .env:环境配置文件
  • prompts/:提示模板

相关配置的设置

可以在.env 文件中配置大模型的API密钥

对于 Azure OpenAI 用户,您还需要**settings.yaml**使用 Azure 详细信息更新文件:

python 复制代码
models:
  default_chat_model:
    type: azure_openai_chat
    api_base: https://<instance>.openai.azure.com
    api_version: 2024-02-15-preview
    deployment_name: <model_deployment_name>
  default_embedding_model:
    type: azure_openai_embedding
    api_base: https://<instance>.openai.azure.com
    api_version: 2024-02-15-preview
    deployment_name: <embedding_model_deployment_name>

用户数据准备

将自己的数据放在输入目录中:

python 复制代码
mkdir -p ./myproject/input

GraphRAG 支持以下输入格式:

  • 文本文件(.txt
  • **text**带有列的 CSV 文件
  • **text**带有字段的 JSON 文件

自动化构建知识图谱

python 复制代码
graphrag index --root ./myproject

这个过程:

  1. 将文档分成文本单元
  2. 提取实体和关系
  3. 构建知识图谱
  4. 创建社区集群
  5. 生成社区报告
  6. 嵌入文本以进行矢量搜索

查询知识图谱

索引完成后,使用以下几种搜索方法之一查询数据:

python 复制代码
graphrag query --root ./myproject --method global --query "What are the main themes in this dataset?"

多种查询方法

python 复制代码
#全局搜索
graphrag query --method global --query "What are the primary themes?"
#本地搜索
graphrag query --method local --query "Tell me about Entity X and its relationships"
#DRIFT搜索
graphrag query --method drift --query "What is the significance of Entity X in the broader context?"
#基本搜索
graphrag query --method basic --query "Find information about X"

核心模块代码解读

图谱构建

实体和关系提取是 GraphRAG 索引流程中的关键组件,它将纯文本转换为结构化知识图谱。此过程从文本文档中识别关键概念(实体)并确定它们之间的关系,从而实现比传统 RAG 系统更复杂的信息检索和推理能力。

GraphRAG 使用自然语言处理技术从文本单元(文档块)中提取实体和关系。这构成了知识图谱的基础,并支持高级查询功能。

主要代码文件:

python 复制代码
graphrag/index/workflows/extract_graph_nlp.py
graphrag/index/operations/build_noun_graph/build_noun_graph.py

实体提取

GraphRAG 提供了多个提取器来从文本中识别实体,每个提取器在准确性、语言支持和性能方面都有不同的权衡。

python 复制代码
#graphrag/index/operations/build_noun_graph/build_noun_graph.py
async def _extract_nodes(
    text_unit_df: pd.DataFrame,
    text_analyzer: BaseNounPhraseExtractor,
    num_threads: int = 4,
    cache: PipelineCache | None = None,
) -> pd.DataFrame:

名词短语提取

可用的提取器有:

  1. 句法分析提取器:通过 SpaCy 进行依赖项分析和命名实体识别 (NER)。此提取器结果准确,支持多种语言,但速度比其他选项慢。
python 复制代码
graphrag/index/operations/build_noun_graph/np_extractors/syntactic_parsing_extractor.py
  1. 上下文无关语法 (CFG) 提取器:使用上下文无关语法规则来识别名词短语。这在速度和准确性之间取得了平衡。
python 复制代码
graphrag/index/operations/build_noun_graph/np_extractors/cfg_extractor.py
  1. 正则表达式提取器:使用专门针对英文文本的正则表达式。这是最快的选项,但仅适用于英文内容。
python 复制代码
graphrag/index/operations/build_noun_graph/np_extractors/regex_extractor.py

实体提取过程遵循以下步骤:

  1. 文本分析:使用配置的名词短语提取器分析每个文本单元
  2. 名词短语识别:提取器识别潜在的名词短语
  3. 过滤 :短语根据启发式方法进行过滤,例如:
    • 排除特定的词性标记或实体类型
    • 验证令牌长度
    • 识别复合词或专有名词
  4. 聚合:合并相似的名词短语,并生成频率计数
python 复制代码
graphrag/index/operations/build_noun_graph/build_noun_graph.py

关系提取

实体之间的关系是根据同一文本单元内的共现情况来识别的。具体流程如下:

  1. 对于每个文本单元,在其中提到的所有实体之间创建连接
  2. 计算每个实体对在所有文本单元中同时出现的次数
  3. 可选地使用逐点互信息 (PMI) 对权重进行归一化
python 复制代码
#graphrag/index/operations/build_noun_graph/build_noun_graph.py
def _extract_edges(
    nodes_df: pd.DataFrame,
    normalize_edge_weights: bool = True,
) -> pd.DataFrame:

使用 PMI 进行权重归一化

PMI 权重计算通过将观察到的共现频率与实体独立出现时的预期频率进行比较来突出显示重要的关系:

python 复制代码
PMI(x,y) = log2(p(x,y) / (p(x) * p(y)))

其中:

  • p(x,y) = 实体 x 和 y 共现的频率
  • p(x) = 实体 x 的频率
  • p(y) = 实体 y 的频率

这种规范化对于区分有意义的关系和巧合的共现尤为重要。

图谱配置

实体和关系提取通过**ExtractGraphNLPConfig**GraphRAG 配置中的部分进行配置:

名称 描述 默认
normalize_edge_weights 是否使用 PMI 作为边权重 True
concurrent_requests 提取线程数 4
text_analyzer.extractor_type 提取器的类型:语法、cfg 或正则表达式 'syntactic'
text_analyzer.model_name SpaCy 模型名称 'en_core_web_sm'
text_analyzer.max_word_length 最大字长 15
text_analyzer.include_named_entities 包括命名实体 True
text_analyzer.exclude_nouns 要排除的停用词 (常见停用词列表)
text_analyzer.exclude_entity_tags 要排除的实体类型 []
text_analyzer.exclude_pos_tags 要排除的 POS 标签 ['DET', 'PUNCT', 'ADP']

输出格式

实体和关系提取的输出由两个数据框组成:

实体数据框

  • title:实体文本(名词短语)
  • frequency:实体出现的频率
  • text_unit_ids:实体出现的文本单元的 ID
  • type:实体类型(默认:"名词短语")
  • description:实体描述(初始为空)

关系数据框

  • source:源实体
  • target:目标实体
  • weight:关系强度(共现或 PMI)
  • text_unit_ids:出现关系的文本单元的 ID
  • description:关系描述(初始为空)

社区检测

GraphRAG 中的社群检测功能将知识图谱划分为相关实体的层次化集群。这些社群构成了全局搜索功能的基础,并为检索和查询解答提供了结构化的上下文。

代码文件位置:

该**create_communities**函数实现了社区检测工作流程,以实体和关系表作为输入,并生成具有层次结构的社区表。

python 复制代码
graphrag/index/workflows/create_communities.py

参数配置

社区检测过程可以通过几个参数进行定制:

范围 描述 默认
max_cluster_size 集群的最大大小(实体数量) 在设置中配置
use_lcc 是否仅使用最大的连通分量 在设置中配置
seed 随机种子用于重复性 无(系统定义)

这些参数可以在配置文件中设置,如测试装置所示:

python 复制代码
#tests/fixtures/text/config.json

"create_communities": {
    "row_range": [1, 30],
    "max_runtime": 30,
    "expected_artifacts": ["communities.parquet"]
}

社区检测算法

实际的社区检测由函数执行**cluster_graph**。该函数根据网络连接模式将图划分为多个聚类。

代码文件位置:

python 复制代码
graphrag/index/workflows/create_communities.py

聚类受以下配置参数的影响:

  • max_cluster_size:限制任何单个社区的规模,迫使较大的自然社区分裂成较小的社区
  • use_lcc:设置为 true 时,仅考虑图中最大的连通分量
  • 种子:为具有随机组件的算法提供可重复性

社区结构

GraphRAG 中的社区采用分层结构组织,允许多层次地组织知识。

每个社区都具有定义其与其他社区关系的属性:

  • 级别:层次结构级别(0 = 顶级)
  • Parent:父社区的 ID
  • Children:子社区的 ID

其具体结构模型参数如下:

colum desc
id 唯一标识符 (UUID)
human_readable_id 与社区号码匹配的数字标识符
title 人类可读的标题(例如"社区 1")
level 层级(0 = 顶部)
parent 家长社区ID
children 子社区 ID
entity_ids 此社区中的实体 ID 列表
relationship_ids 两个端点都属于此社区的关系 ID 列表
text_unit_ids 与此社区关联的文本单元 ID 列表
period 社区创建的 ISO 日期(用于增量更新)
size 社区实体数量

图谱存储

存储系统负责在整个索引管道中持久保存所有数据工件,并存储搜索操作中使用的向量嵌入。

存储架构

存储系统负责在整个索引管道中持久保存所有数据工件,并存储搜索操作中使用的向量嵌入。

GraphRAG 采用双层存储架构,包括:

  1. **管道存储:**将结构化数据存储为代表知识图谱组件(文档、文本单元、实体、关系、社区等)的 Parquet 文件。
  2. **向量存储:**用于向量嵌入的专用存储,以实现语义搜索

代码文件位置:

python 复制代码
graphrag/utils/storage.py
graphrag/index/update/incremental_index.py
graphrag/vector_stores/azure_ai_search.py

图谱检索

GraphRAG 查询系统提供先进的搜索功能,用于从索引过程中创建的知识图谱中检索和生成答案。与传统的基于向量的 RAG 方法不同,GraphRAG 提供了多种针对不同类型问题优化的搜索策略,充分利用了知识图谱、实体关系和社区层级的丰富结构。

代码文件位置:

python 复制代码
#文件夹:graphrag/query/structured_search/
graphrag/query/structured_search/base.py
graphrag/query/factory.py

分为下面四种检索方法:

搜索方法 类名 目的 适合场景
全局搜索 GlobalSearch 利用社区报告提供整体理解 关于主题、主题和模式的高级问题
本地搜索 LocalSearch 专注于以实体为中心的探索 关于具体实体及其关系的详细问题
DRIFT 搜索 DRIFTSearch 灵活遍历的动态推理 复杂的问题需要广泛的背景和具体的细节
基本搜索 BasicSearch 传统向量相似性搜索 不需要图形上下文时的简单事实问题

全局搜索

全局搜索旨在解决需要了解整体数据集的广泛、高层次问题。它利用索引过程中生成的社区报告,其中包含不同主题集群的摘要。

全局搜索采用 map-reduce 方法:

  1. 上下文构建:根据语义相似性或社区级别选择相关的社区报告
  2. 映射阶段:分别处理每个报告块,提取关键点
  3. 减少阶段:结合所有报告块的见解来生成全面的答案

该实现支持可选的动态社区选择,它使用 LLM 来识别给定查询最相关的社区报告,而不是使用固定社区级别的所有报告。

本地搜索

本地搜索专注于实体相关的问题,通过检查与查询主题相关的实体、关系和文本单元来解决问题。它旨在提供有关特定实体及其联系的详细答案。

本地搜索过程包括:

  1. 实体识别:使用向量相似度查找与查询相关的实体
  2. 语境构建:收集与这些实体相关的关系、文本单元以及可选的社区报告
  3. 混合上下文创建:结合实体信息、关系和文本证据
  4. 响应生成:使用 LLM 根据此焦点上下文创建响应

本地搜索对于有关实体、其属性以及它们与知识图谱中其他实体的关系的特定问题最有效。

DRIFT 搜索

DRIFT(动态推理与灵活遍历)搜索结合了全局搜索和局部搜索的优势,能够为复杂问题提供全面的答案。它采用一种新颖的方法来动态生成和跟踪问题,从而探索知识图谱。

DRIFT Search 主要分为三个阶段:

  1. 启动:利用社区报告获得高层次的理解并生成初步的后续问题
  2. 探索:对每个后续问题执行本地搜索,并根据发现生成新问题
  3. 缩减:将所有收集到的信息合并成一个综合的响应

这种方法创建了知识图谱的动态、迭代探索,允许系统在保持整体背景的同时"深入"到特定领域。

基本搜索

基本搜索提供类似于标准 RAG 系统的传统基于向量的检索方法。它比其他方法更简单,并且没有利用完整的知识图谱结构。

基本搜索流程:

  1. 向量搜索:将查询转换为向量并查找相似的文本单元
  2. 上下文构建:将这些文本单元组装成提示上下文
  3. 响应生成:使用 LLM 根据检索到的文本生成答案

基本搜索对于比较简单的问题或当您想要绕过知识图结构并执行直接文本检索时很有用。

搜索接口使用

API接口

python 复制代码
response, context_data = await global_search(
    config=config,
    entities=entities,
    communities=communities,
    community_reports=community_reports,
    community_level=2,
    dynamic_community_selection=True,
    response_type="multiple paragraphs",
    query="What are the main themes in the dataset?"
)

# Streaming API example
async for chunk in global_search_streaming(
    config=config,
    entities=entities,
    communities=communities,
    community_reports=community_reports,
    community_level=2,
    dynamic_community_selection=True,
    response_type="multiple paragraphs",
    query="What are the main themes in the dataset?"
):
    print(chunk, end="")

CLI界面

python 复制代码
# Global Search
graphrag query --root ./project --method global --query "What are the main themes in the dataset?"

# Local Search with specific community level
graphrag query --root ./project --method local --community-level 2 --query "Tell me about Entity X"

# DRIFT Search with streaming
graphrag query --root ./project --method drift --streaming --query "What insights can be derived?"

# Basic Search
graphrag query --root ./project --method basic --query "What does the text say about topic Y?"
相关推荐
燃于AC之乐4 小时前
《算法实战笔记》第10期:六大算法实战——枚举、贪心、并查集、Kruskal、双指针、区间DP
算法·贪心算法·图论·双指针·区间dp·二进制枚举
diediedei4 小时前
高性能计算通信库
开发语言·c++·算法
蒸蒸yyyyzwd4 小时前
算法学习笔记
笔记·算法
kogorou0105-bit4 小时前
前端设计模式:发布订阅与依赖倒置的解耦之道
前端·设计模式·面试·状态模式
练习时长一年4 小时前
LeetCode热题100(颜色分类)
算法·leetcode·职场和发展
说文科技4 小时前
大模型项目实战之dpo微调
人工智能·算法
闻哥4 小时前
深入理解 ES 词库与 Lucene 倒排索引底层实现
java·大数据·jvm·elasticsearch·面试·springboot·lucene
睡一觉就好了。5 小时前
归并排序——递归与非递归的双重实现
数据结构·算法·排序算法
酉鬼女又兒5 小时前
SQL23 统计每个学校各难度的用户平均刷题数
数据库·sql·算法
爱学习的阿磊5 小时前
模板代码跨编译器兼容
开发语言·c++·算法