日习一技 - GraphRAG
type: channel
link: https://i-study-everyday.online/category/GraphRAG
description: GraphRAG 的学习
items: 学习 GraphRAG 四大搜索策略
items: 详解 GraphRAG 索引构建的输出文件
items: GraphRAG 索引构建之图谱增强
items: GraphRAG 索引构建之知识提取（四）
items: GraphRAG 索引构建之知识提取（三）
items: GraphRAG 索引构建之知识提取（二）
items: GraphRAG 索引构建之知识提取
items: GraphRAG 索引构建之文档处理
items: GraphRAG 索引构建概述
items: 剖析 GraphRAG 的项目结构

学习 GraphRAG 四大搜索策略
type: item
date: 2025-09-05T00:51:00+00:00
description: 在前面的系列文章中，我们深入学习了 GraphRAG 索引构建的完整流程，从文档加载、文本分片，到实体关系提取、社区检测，最终生成了包括实体表、关系表、社区报告等在内的结构化输出文件。这些文件构成了 GraphRAG 的知识库基础，为查询阶段提供了丰富的数据源。现在，让我们转入查询阶段的学习，探索 GraphRAG 如何基于这些数据实现智能问答。在之前的入门篇中，我们已经体验了通过 query 命令来查询，并通过 --method 参数指定搜索策略：$ uv run poe query \ --root ./ragtest \ --method global \ --query "What are the top themes in this story?"GraphRAG 提供了四种不同的搜索策略，按照复杂程度递增的顺序，它们分别是：基础搜索（Basic Search）、本地搜索（Local Search）、全局搜索（Global Search） 和 漂移搜索（DRIFT Search）。本文将由浅入深地剖析这四种搜索策略的工作原理和使用场景。基础搜索（Basic Search）基础搜索是 GraphRAG 中最简单的查询方式，本质上是传统向量 RAG 的实现。它主要用于与其他搜索策略进行对比，帮助用户了解 GraphRAG 相对于传统方法的优势。基础搜索的核心思想非常直接：对用户查询进行向量化，然后在文本单元的向量数据库中进行相似性搜索，找到最相关的前 K 个文本片段，最后使用这些片段作为上下文，连同原始问题一起提交给大语言模型，生成最终答案。基础搜索适用于简单的事实性问题，特别是答案可以直接从单个或少数几个文档片段中获得的情况，比如：什么是机器学习？Python 中如何定义函数？苹果公司的总部在哪里？由于基础搜索仅依赖向量相似性，它无法处理需要多步推理或全局理解的复杂问题。这正是 GraphRAG 引入图结构和社区检测的动机。本地搜索（Local Search）本地搜索，或者叫 局部搜索，是 GraphRAG 的核心创新之一，它利用知识图谱的实体关系结构来增强传统 RAG 的检索能力。相比基础搜索，本地搜索能够理解查询中的实体，并利用这些实体在知识图谱中的连接关系来查找更丰富、更相关的上下文信息。本地搜索的流程分为三个主要阶段：实体识别、上下文扩展和答案生成。这个过程的详细步骤如下：实体识别阶段：对用户查询进行向量化，在实体描述向量数据库中进行相似性搜索，获取语义相关的候选实体集合；上下文扩展阶段：文本单元扩展：根据实体和文本单元映射关系，找到包含这些实体的原始文本片段；社区报告扩展：根据实体和社区映射关系，获取相关的社区摘要报告；实体关系扩展：使用实体名称和描述等信息构建实体上下文，然后再依次查找与实体相连的关系构建关系上下文；协变量扩展：如果配置了协变量提取，还会包含相关的声明信息；排序过滤阶段：排序：对每类候选数据进行重要性排序，比如对于文本单元来说，关系数量更多优先级更高，对于社区来说，包含的选中实体数量更多的优先级更高；过滤：根据 token 预算进行过滤，确保上下文适合大语言模型的输入窗口；答案生成阶段：将过滤后的多源信息整合成结构化上下文，调用大模型生成最终答案；本地搜索的过程就像是一次从图谱中的特定节点出发，向外探索和收集信息的侦察任务，它的关键优势在于 多源信息融合 能力：通过文本单元保留原始文档的详细信息，通过知识图谱揭示实体间的复杂关系，通过社区报告提供结构化的主题总结。它特别适合需要理解特定实体及其关系的问题，比如：洋甘菊有什么治疗功效？（需要理解洋甘菊这个实体的属性）苹果公司和微软公司有什么合作关系？（需要理解两个实体间的关系）机器学习领域的主要算法有哪些？（需要找到与机器学习相关的算法实体）全局搜索（Global Search）全局搜索解决了传统 RAG 的一个根本性问题：无法处理需要理解整个数据集的查询。当用户问 数据中的主要主题是什么？ 或 最重要的趋势有哪些？ 这种需要全局视角和高度概括性的问题时，传统的向量检索往往无法给出满意的答案，因为这类问题需要对整个数据集进行宏观理解和总结。全局搜索采用了 Map-Reduce 架构，分为两个核心阶段：首先是 Map 阶段，收集指定层级的社区报告，并行处理：报告收集：从指定层级的社区层次结构中收集所有的社区报告；如果开启了动态社区选择，则使用大模型根据用户问题对社区报告进行打分，选择得分大于阈值的社区报告；分批处理：将社区报告按照 token 预算随机分成多个批次；并行分析：对于每个批次，将其中的社区报告作为上下文，连同用户查询一起发送给大模型，使用 Map 系统提示词生成一个中间响应；这个响应包含一系列观点，每个观点都有一个重要性评分（1-10…

详解 GraphRAG 索引构建的输出文件
type: item
date: 2025-09-04T01:12:00+00:00
description: 在前面的系列文章中，我们深入学习了 GraphRAG 索引构建的完整流程，从文档加载、文本分片，到实体关系提取、社区检测和向量化。经过这些复杂的处理步骤，GraphRAG 最终生成了一系列结构化的输出文件，这些文件就是整个知识图谱的数字化资产。通过这些文件，GraphRAG 实现了不同的检索策略，可以回答用户的各种问题。但是在正式进入检索阶段之前，让我们先来详细剖析下这些输出文件，了解每个文件的格式、字段信息和存储机制。输出文件概览当 GraphRAG 索引构建完成后，所有结果都保存在 output 目录中。让我们先来看看完整的文件结构：output/ ├── documents.parquet # 文档表 ├── text_units.parquet # 文本单元表 ├── entities.parquet # 实体表 ├── relationships.parquet # 关系表 ├── communities.parquet # 社区表 ├── community_reports.parquet # 社区报告表 ├── embeddings.entity.description.parquet # 实体描述向量 ├── embeddings.community.full_content.parquet # 社区内容向量 ├── embeddings.text_unit.text.parquet # 文本单元向量 ├── graph.graphml # 图结构文件 ├── lancedb/ # LanceDB 向量数据库 ├── stats.json # 统计信息 └── context.json # 上下文信息这些文件可以分为三类：核心数据表：存储结构化数据，包括文档、文本单元、实体、关系、社区、社区报告等，使用 Parquet 格式；向量数据：存储嵌入向量，包括文本单元、实体描述、社区内容等，使用 Parquet 和 LanceDB 双重存储；元数据文件：包含图结构、统计信息等辅助数据；其中 graph.graphml 文件在之前学习可视化的时候已经详细介绍过，此处不再赘述；核心数据表详解这一节对所有的核心数据表做个总结。1. documents.parquet - 文档表文档表存储了原始文档的基础信息和预处理后的文本内容：字段描述id文档唯一标识符（SHA-256 哈希）human_readable_id人类可读的递增 IDtitle文档标题（通常是文件名，或 CSV 中的 title 列）text文档的完整文本内容text_unit_ids关联的文本单元 ID 列表creation_date创建时间戳metadata额外的元数据信息文档表是整个知识图谱的源头，每个文档都会被分解成多个文本单元进行后续处理。2. text_units.parquet - 文本单元表文本单元是 GraphRAG 处理的基本单位，通过 tokens 策略将长文档分解成固定长度的片段，或者通过 sentence 策略将其分解成自然语言的句子：字段描述id文本单元唯一标识符human_readable_id人类可读的递增 IDtext文本单元的具体内容n_tokens文本的 token 长度，应该和配置文件中的 chunk_size 相等，除了最后一个分块document_ids所属文档 ID 列表，通常情况下只有一个，但是也可以修改分组策略让一个分块跨多个文档entity_ids包含的实体 ID 列表relationship_ids包含的关系 ID 列表covariate_ids关联的协变量 ID 列表（如果存在）文本单元表是连接文档和知识图谱的桥梁，每个文本单元都详细记录了从中提取的结构化信息。3. entities.parquet - 实体表实体表存储了从文本中识别出的所有命名实体及其详细信息：字段描述id实体唯一标识符human_readable_id人类可读的递增 IDtitle实体名称type实体类型，默认支持 "organization", "person", "geo" 和 "event" 四种description实体详细描述，一个实体可能出现在多个文本单元中，使用大模型生成总结摘要text_unit_ids出现的文本单元 ID 列表frequency出现频次degree图中的度数（连接的边数量）x图布局中的 x 坐标，必须开启图嵌入和 UMAP 配置y图布局中的 y 坐标，必须开启图嵌入和 UMAP 配置实体表是知识图谱的节点集合，每个实体都包含了丰富的语义信息和图结构属性。4. relationships.parquet - 关系表关系表记录了实体之间的连接关系：字段描述id关系唯一标识符human_readable_i…

GraphRAG 索引构建之图谱增强
type: item
date: 2025-09-03T00:20:00+00:00
description: 在前面的文章中，我们已经深入学习了 GraphRAG 索引构建的前两个阶段，从原始文档到文本单元，再从文本单元提取出结构化的知识图谱。现在，我们已经拥有了包含实体和关系的网络图，接下来，我们将进入索引构建的第三阶段 —— 图谱增强，探索 GraphRAG 如何从这张零散的网络图中挖掘出更高层次的结构和洞见。图谱增强阶段包含四个核心工作流：创建社区（create_communities） - 使用 Leiden 算法对知识图谱进行层次化社区检测，返回多层次的社区结构；创建最终文本单元（create_final_text_units） - 负责将基础文本单元与实体、关系和协变量信息进行关联，生成最终的文本单元数据；生成社区报告（create_community_reports） - 为每个社区生成高质量的摘要报告；生成文本嵌入（generate_text_embeddings） - 将各层次文本信息向量化，并存储到外部的向量数据库；其中，创建最终文本单元按理应该放在第二阶段的末尾，当图谱提取结束后就可以创建了，它的作用是将文本单元与提取出来的实体、关系和协变量进行关联并重新保存。这里按照源码中顺序，将其放在第三阶段，这一步也比较简单，本篇不做过多赘述，主要关注另三个工作流的实现。创建社区创建社区是图谱增强阶段的核心步骤，它通过图聚类算法将零散的实体组织成有意义的主题集群。该工作流的实现位于 index/workflows/create_communities.py 文件中：async def run_workflow( config: GraphRagConfig, context: PipelineRunContext, ) -> WorkflowFunctionOutput: # 1. 加载实体和关系数据 entities = await load_table_from_storage("entities", context.output_storage) relationships = await load_table_from_storage("relationships", context.output_storage) # 2. 获取聚类配置 max_cluster_size = config.cluster_graph.max_cluster_size use_lcc = config.cluster_graph.use_lcc seed = config.cluster_graph.seed # 3. 执行社区创建 output = create_communities( entities, relationships, max_cluster_size=max_cluster_size, use_lcc=use_lcc, seed=seed, ) # 4. 保存结果 await write_table_to_storage(output, "communities", context.output_storage)创建社区使用的配置如下：cluster_graph: max_cluster_size: 10 # 最大社区数量 use_lcc: true # 是否使用最大连通分量 seed: 0xDEADBEEF # 随机种子其中 max_cluster_size 表示最多生成 10 个社区；use_lcc 表示是否使用最大连通分量，我们在之前计算图嵌入时也见过这个参数，意味着只有图中最大的连通子图会被用于计算，孤立的节点或较小的连通分量会被过滤掉；seed 表示随机种子，一般保持默认即可，主要用于在多次运行聚类算法时获得一致的结果。核心处理逻辑位于 create_communities() 函数中：def create_communities( entities: pd.DataFrame, relationships: pd.DataFrame, max_cluster_size: int, use_lcc: bool, seed: int | None = None, ) -> pd.DataFrame: # 1. 构建图结构 graph = create_graph(relationships, edge_attr=["weight"]) # 2. 执行层次化聚类 clusters = cluster_graph( graph, max_cluster_size, use_lcc, seed=seed, ) # 3. 格式化聚类结果 communities = pd.DataFrame( clusters, columns=pd.Index(["level", "community", "parent", …

GraphRAG 索引构建之知识提取（四）
type: item
date: 2025-09-02T01:17:00+00:00
description: 我们昨天大概了解了基于 NLP 的知识提取流程，为了更好地学习相关的提取技术，我们简单介绍了 SpaCy 和 TextBlob 这两个 NLP 库的基本使用。有了 SpaCy 和 TextBlob 的基础，我们再回过头来看看 extract_graph_nlp 工作流中的三大名词短语提取器。句法分析提取器（Syntactic）首先是句法分析提取器，其核心实现位于 SyntacticNounPhraseExtractor 类：def __init__( self, model_name: str, max_word_length: int, include_named_entities: bool, exclude_entity_tags: list[str], exclude_pos_tags: list[str], exclude_nouns: list[str], word_delimiter: str, ): # 根据是否需要命名实体识别来决定加载的组件 if not include_named_entities: # 排除命名实体识别器，提升处理速度 self.nlp = self.load_spacy_model(model_name, exclude=["lemmatizer", "ner"]) else: # 保留命名实体识别器，只排除词形还原器 self.nlp = self.load_spacy_model(model_name, exclude=["lemmatizer"])从初始化函数可以看出该提取器有不少配置参数：extract_graph_nlp: text_analyzer: extractor_type: syntactic_parser model_name: en_core_web_md # SpaCy 模式 max_word_length: 15 # 最大单词长度 word_delimiter: " " # 单词分隔符 include_named_entities: true # 是否开启命名实体识别 exclude_nouns: # 排除停用词，大多是日常交流中使用频繁但本身不携带太多关键信息的词汇 - stuff - thing - things - ... exclude_entity_tags: # 排除指定类型的实体 - DATE # 日期 exclude_pos_tags: # 排除特定的词性标签 - DET # 限定词，如 a an the 等 - PRON # 代词，如 he she it 等 - INTJ # 感叹词，如 oh wow hey 等 - X # 其他句法分析提取器根据 include_named_entities 参数加载 SpaCy 模型，默认模型是 en_core_web_md，为提高性能，加载模型时排除了 lemmatizer 模块（词形还原器），如果用户关闭了命名实体识别，还会排除 ner 模块（命名实体识别器）。该提取器的核心实现如下：def extract(self, text: str) -> list[str]: # SpaCy 文本分析 doc = self.nlp(text) if self.include_named_entities: # 命名实体 + 名词块 entities = [ ent for ent in doc.ents if ent.label_ not in self.exclude_entity_tags ] spans = entities + list(doc.noun_chunks) # 根据规则过滤 tagged_noun_phrases = [ self._tag_noun_phrases(span, entities) for span in spans ] else: # 直接获取名词块，根据规则过滤 tagged_noun_phrases = [ self._tag_noun_phrases(chunk, []) for chunk in doc.noun_chunks ]如果开启了命名实体识别，则将 SpaCy 提取的命名实体（ents）和名词块（noun_chunks）合并，然后通过一些规则进行过滤得到结果；如果未开启，则直接获取名词块，根据规则过滤。过滤规则比较细碎，比如根据 exclude_entity_tags 排除特定类型的实体，根据 exclude_pos_tags 排除特定词性，根据 exclude_nouns 排除停用词，排除空格和标点，根据 max_word_length 判断长度是否有效，等等。上下文无关文法提取器（CFG）第二个是上下文无关文法（CFG，Context-Free …

GraphRAG 索引构建之知识提取（三）
type: item
date: 2025-09-01T00:55:00+00:00
description: 今天，我们将继续学习 GraphRAG 中关于知识提取的内容。上周的 extract_graph 工作流，完全基于大语言模型进行实体关系提取，质量高但速度较慢；为此 GraphRAG 还提供了另一种实现，基于传统的自然语言处理（NLP）技术，实现更快速、更低成本的实体关系提取。我们可以通过 Fast 索引方法 开启该功能：$ graphrag index --root ./ragtest --method fast我们重点学习 Fast 方法中的两个核心工作流：基于 NLP 的图谱提取（extract_graph_nlp） - 使用 NLP 技术从文本中提取名词短语作为实体图谱修剪（prune_graph） - 对提取结果进行统计过滤和清理基于 NLP 的图谱提取extract_graph_nlp 工作流的核心实现位于 index/workflows/extract_graph_nlp.py 文件，整个流程相当简洁：async def run_workflow( config: GraphRagConfig, context: PipelineRunContext, ) -> WorkflowFunctionOutput: # 1. 加载文本单元 text_units = await load_table_from_storage("text_units", context.output_storage) # 2. 执行 NLP 图谱提取 entities, relationships = await extract_graph_nlp( text_units, extraction_config=config.extract_graph_nlp, ) # 3. 保存结果 await write_table_to_storage(entities, "entities", context.output_storage) await write_table_to_storage(relationships, "relationships", context.output_storage)与基于大模型的 extract_graph 相比，这个工作流的实现要简单得多，核心逻辑都封装在 extract_graph_nlp() 函数中：async def extract_graph_nlp( text_units: pd.DataFrame, extraction_config: ExtractGraphNLPConfig, ) -> tuple[pd.DataFrame, pd.DataFrame]: # 创建名词短语提取器 text_analyzer = create_noun_phrase_extractor(text_analyzer_config) # 构建名词图谱 extracted_nodes, extracted_edges = await build_noun_graph( text_units, text_analyzer=text_analyzer, normalize_edge_weights=extraction_config.normalize_edge_weights, num_threads=extraction_config.concurrent_requests, ) # 添加下游工作流所需的字段 extracted_nodes["type"] = "NOUN PHRASE" extracted_nodes["description"] = "" extracted_edges["description"] = "" return (extracted_nodes, extracted_edges)整个工作流的执行流程如下：大致可分为三个步骤：首先创建名词短语提取器，然后构建名词图谱，最后为提取的节点和边添加必要的元数据字段。名词短语提取器GraphRAG 提供了三种不同的名词短语提取方法，每种都有其独特的优势和适用场景，通过工厂模式进行统一管理：class NounPhraseExtractorFactory: @classmethod def get_np_extractor(cls, config: TextAnalyzerConfig) -> BaseNounPhraseExtractor: # 根据配置创建名词短语提取器 match np_extractor_type: # 句法分析提取器 case NounPhraseExtractorType.Syntactic: return SyntacticNounPhraseExtractor(...) # 上下文无关文法提取器 case Nou…

GraphRAG 索引构建之知识提取（二）
type: item
date: 2025-08-29T01:07:00+00:00
description: 昨天我们学习了知识提取阶段的提取图谱工作流，今天我们继续学习另外两个：图谱规范化 和 提取事实声明。图谱规范化提取出的原始实体和关系需要进一步处理才能构成完整的知识图谱，finalize_graph 工作流负责这一规范化过程：async def run_workflow( config: GraphRagConfig, context: PipelineRunContext, ) -> WorkflowFunctionOutput: # 1. 加载实体和关系 entities = await load_table_from_storage("entities", context.output_storage) relationships = await load_table_from_storage("relationships", context.output_storage) # 2. 执行图谱规范化 final_entities, final_relationships = finalize_graph( entities, relationships, embed_config=config.embed_graph, layout_enabled=config.umap.enabled, ) # 3. 保存结果 await write_table_to_storage(final_entities, "entities", context.output_storage) await write_table_to_storage(final_relationships, "relationships", context.output_storage) if config.snapshots.graphml: # 生成图描述文件 graph = create_graph(final_relationships, edge_attr=["weight"]) await snapshot_graphml( graph, name="graph", storage=context.output_storage, )处理流程很清晰，首先加载上一步提取的实体和关系，然后调用 finalize_graph() 函数对其进行规范化处理，最后将处理后的数据重新保存，并根据配置生成 GraphML 图描述文件，便于外部工具进行图分析和可视化，这也就是我们之前学习可视化时所导入的文件。其中 finalize_graph() 函数的实现如下：def finalize_graph( entities: pd.DataFrame, relationships: pd.DataFrame, embed_config: EmbedGraphConfig | None = None, layout_enabled: bool = False, ) -> tuple[pd.DataFrame, pd.DataFrame]: # 实体规范化 final_entities = finalize_entities( entities, relationships, embed_config, layout_enabled ) # 关系规范化 final_relationships = finalize_relationships(relationships) return (final_entities, final_relationships)可以看出，它主要包括实体规范化和关系规范化：实体规范化：使用 NetworkX 创建网络图，计算每个节点的度数，使用 Node2Vec 生成图嵌入向量，使用 UMAP 降维算法进行图布局计算，得到 2D 可视化坐标，为每个实体分配唯一的 UUID 和人类可读的 ID 并输出最终规范化的实体对象；关系规范化：基于 source 和 target 去除重复的关系，计算每个关系的组合度数，为每个关系分配唯一的 UUID 和人类可读的 ID 并输出最终规范化的关系对象；下面我们仔细看下这两个部分。实体规范化实体规范化的逻辑位于 finalize_entities() 函数：def finalize_entities( entities: pd.DataFrame, relationships: pd.DataFrame, embed_config: EmbedGraphConfig | None = None, layout_enabled: bool = False, ) -> pd.DataFrame: # 创建网络图 graph = create_graph(relationships, edge_attr=["weigh…

GraphRAG 索引构建之知识提取
type: item
date: 2025-08-28T04:13:00+00:00
description: 在前面的文章中，我们详细学习了 GraphRAG 索引构建的文档处理阶段，了解了如何将各种格式的原始文档转换为标准化的文本单元。今天我们将深入探索整个索引构建流程中最核心的部分 —— 知识提取，看看 GraphRAG 是如何利用大语言模型的力量，从非结构化的文本中挖掘出结构化的实体、关系和声明，并最终构建出完整的知识图谱。知识提取阶段总览让我们回顾一下索引构建的整体流程，知识提取正是连接文本处理和图谱分析的关键桥梁：知识提取阶段包含三个核心工作流：提取图谱（extract_graph） - 从文本中提取实体和关系，对同一个实体和关系的描述进行总结合并；图谱规范化（finalize_graph） - 对提取结果进行规范化处理，输出最终的实体表和关系表；提取事实声明（extract_covariates） - 提取事实性声明，这一步是可选的，声明通常用于识别诸如欺诈等恶意行为，因此并不适用于所有数据集；提取图谱图谱提取的实现位于 index/workflows/extract_graph.py 文件中，整个工作流包含以下关键步骤：async def run_workflow( config: GraphRagConfig, context: PipelineRunContext, ) -> WorkflowFunctionOutput: # 1. 加载文本单元 text_units = await load_table_from_storage("text_units", context.output_storage) # 2. 配置提取策略和摘要策略 extraction_strategy = config.extract_graph.resolved_strategy() summarization_strategy = config.summarize_descriptions.resolved_strategy() # 3. 执行图谱提取 entities, relationships, raw_entities, raw_relationships = await extract_graph( text_units=text_units, extraction_strategy=extraction_strategy, summarization_strategy=summarization_strategy ) # 4. 保存结果 await write_table_to_storage(entities, "entities", context.output_storage) await write_table_to_storage(relationships, "relationships", context.output_storage)这里值得注意是提取策略和摘要策略，它们对应 settings.yaml 文件中的 extract_graph 和 summarize_descriptions 两个配置：extract_graph: model_id: default_chat_model prompt: "prompts/extract_graph.txt" entity_types: [organization,person,geo,event] max_gleanings: 1 summarize_descriptions: model_id: default_chat_model prompt: "prompts/summarize_descriptions.txt" max_length: 500从这里可以看出，整个图谱提取分为两步：首先遍历上一阶段生成的所有文本单元，通过大模型从每个文本片段中识别出实体和关系；然后将相同的实体和关系进行合并，再通过大模型总结合并之后的实体和关系描述；核心提示词第一步所使用的提示词位于 prompts/extract_graph.txt，翻译如下：-目标- 给定一个可能与本活动相关的文本文档和一个实体类型列表，从文本中识别出所有属于这些类型的实体以及已识别实体之间的所有关系。 -步骤- 1. 识别所有实体。对于每个已识别的实体，提取以下信息： - entity_name: 实体名称，首字母大写 - entity_type: 以下类型之一：[{entity_types}] - entity_description: 对实体属性和活动的全面描述 每个实体的格式为（"entity"<|><entity_name><|><entity_type><|><entity_description>） 2. 从步骤1中识别出的实体中，识别所有（源实体，目标实体）对，这些实体对之间存在*…

GraphRAG 索引构建之文档处理
type: item
date: 2025-08-27T00:56:00+00:00
description: 昨天我们对 GraphRAG 的索引构建做了一个基本的概述，了解了其索引构建的整体流程和工作流引擎的设计。今天我们将深入第一个具体阶段 —— 文档处理，这是整个知识图谱构建的起点，负责将各种格式的原始文档转换为标准化的文本单元，为后续的知识提取奠定基础。回顾索引构建流程根据前一篇文章的分析，我们可以将 GraphRAG 的索引构建流程分为三个主要阶段：今天我们重点关注文档处理阶段，它的核心任务是将非结构化的原始数据转换为后续处理流程所需的标准化文本单元。这个阶段包含三个关键工作流：加载原始文档（load_input_documents） - 从各种数据源加载原始文档文本分块处理（create_base_text_units） - 将长文档分割成可处理的文本块文档规范化（create_final_documents） - 对文档进行最终的标准化整理加载原始文档在 GraphRAG 中，所有工作流的入口都是 run_workflow() 方法，加载原始文档也是如此。它的核心逻辑位于 index/workflows/load_input_documents.py 文件：async def run_workflow( config: GraphRagConfig, context: PipelineRunContext, ) -> WorkflowFunctionOutput: # 加载输入文档，转换为标准的 pd.DataFrame 格式 output = await load_input_documents(config.input, context.input_storage) # 将原始文档写入 documents 表中 await write_table_to_storage(output, "documents", context.output_storage) return WorkflowFunctionOutput(result=output)这个工作流首先加载输入文档，将其转换为标准的 pd.DataFrame 格式，然后写入 documents 表中。GraphRAG 通过工厂模式实现了对纯文本、CSV、JSON 三种文件格式的统一处理：loaders: dict[str, Callable[..., Awaitable[pd.DataFrame]]] = { InputFileType.text: load_text, InputFileType.csv: load_csv, InputFileType.json: load_json, }如果你有不同的格式，官方的建议是编写脚本将其转换为其中一种。同时，它也支持 Azure Blob、CosmosDB、本地文件、内存这四种不同的存储类型：StorageFactory.register(StorageType.blob.value, create_blob_storage) StorageFactory.register(StorageType.cosmosdb.value, create_cosmosdb_storage) StorageFactory.register(StorageType.file.value, create_file_storage) StorageFactory.register(StorageType.memory.value, lambda **_: MemoryPipelineStorage())默认情况下是从本地的 input 目录下读取文件，并使用 text 加载器处理。我们可以在 settings.yaml 文件中的 input 部分进行配置：input: storage: type: file # [blob, cosmosdb, file, memory] base_dir: "input" file_type: text # [csv, text, json]文本文件处理对于纯文本文件，处理逻辑相对简单，在 index/input/text.py 中：async def load_file(path: str, group: dict | None = None) -> pd.DataFrame: text = await storage.get(path, encoding=config.encoding) new_item = {**group, "text": text} new_item["id"] = gen_sha512_hash(new_item, new_item.keys()) new_item["title"] = str(Path(path).name) new_item["creation_d…

GraphRAG 索引构建概述
type: item
date: 2025-08-26T04:49:00+00:00
description: 经过前面对 GraphRAG 项目结构的深入了解，我们已经掌握了它的整体架构和技术栈。今天我们将顺着 graphrag index 命令的调用链，深入探索 GraphRAG 索引构建的核心流程，包括命令行入口、配置加载机制、工作流引擎，以及不同索引方法的实现细节。命令行入口当我们执行 graphrag index 命令时，整个调用过程如下：入口点：__main__.py 或 bin/graphrag → graphrag.cli.main:appCLI 解析：cli/main.py → @app.command("index") 装饰器配置加载：cli/index.py → index_cli() 函数API 调用：api.build_index() 函数其中，前两步我们昨天已经学习过了：__main__.py 的作用是让 GraphRAG 能以包的方式运行，pyproject.toml 文件中的 [project.scripts] 配置让 GraphRAG 能以可执行文件的方式运行，运行的入口都是 graphrag.cli.main 包的 app 方法；该方法基于 Typer 这个现代化的 Python CLI 库实现，通过 @app.command 装饰器，定义了 GraphRAG 的 5 个子命令，index 就是其中之一。跟随调用链，我们接着看一下 cli/index.py 文件中 index_cli() 函数的实现：def index_cli(root_dir: Path, method: IndexingMethod, ...): # 配置加载 config = load_config(root_dir, config_filepath, cli_overrides) # 索引构建 _run_index(config=config, method=method, ...)这里我们可以看到两个关键步骤：配置加载：调用 load_config() 函数加载并合并配置，支持通过命令行参数覆盖配置文件中的设置索引执行：调用 _run_index() 执行实际的索引构建配置加载配置加载是 GraphRAG 的核心功能之一，位于 config/load_config.py 文件中，其实现如下：def load_config( root_dir: Path, config_filepath: Path | None = None, cli_overrides: dict[str, Any] | None = None, ) -> GraphRagConfig: # 路径规范化，确保使用绝对路径 root = root_dir.resolve() # 在根目录中搜索配置文件 config_path = _get_config_path(root, config_filepath) # 加载 .env 文件中的环境变量 _load_dotenv(config_path) # 读取配置文件文本内容 config_text = config_path.read_text(encoding="utf-8") # 解析环境变量引用 config_text = _parse_env_variables(config_text) # 根据文件类型解析为字典（支持 YAML 和 JSON） config_extension = config_path.suffix config_data = _parse(config_extension, config_text) # 应用命令行参数覆盖 if cli_overrides: _apply_overrides(config_data, cli_overrides) # 创建并验证最终配置对象 return create_graphrag_config(config_data, root_dir=str(root))这里的 load_config() 函数实现了一个完整的类型安全的配置管理流程，整体流程非常清晰：路径规范化：通过 root_dir.resolve() 确保使用绝对路径，其中 root_dir 是用户通过 --root 或 -r 参数指定配置发现：如果用户指定了 --config 或 -c 参数，则使用用户自定义配置；否则在根目录中搜索默认配置文件，比如 settings.yaml、settings.yml 或 settings.json环境变量加载：加载 .env 文件中的环境变量配置读取：读取配置文件文本内容环境变量替换：解析配置文件中环境变量引用，比如 ${GRAPHRAG_API_KEY} 等格式解析：根据文件类型将配置解析为字典，支持 YAML 和 JSON 两种方式覆盖应用…

剖析 GraphRAG 的项目结构
type: item
date: 2025-08-25T00:08:00+00:00
description: 经过这几天的动手实践和可视化体验，我们已经对 GraphRAG 的核心功能有了一个基本的了解。今天，我们正式开始深入研究它的源码，首先从熟悉项目结构入手，为我们后续学习其核心工作流（比如索引和查询）打下基础。项目概览使用 tree 命令查看 GraphRAG 项目的项目结构如下：$ tree -L 1 graphrag ├── __init__.py ├── __main__.py # 模块入口 ├── api # API 层 ├── cache ├── callbacks ├── cli # CLI 入口 ├── config # 配置管理 ├── data_model # 数据模型 ├── index # 索引系统 ├── language_model # 语言模型 ├── logger ├── prompt_tune # 提示词调优 ├── prompts # 提示词系统 ├── query # 查询系统 ├── storage # 存储抽象层 ├── utils └── vector_stores # 向量数据库其中基础模块包括：API 层（api）：这里提供了高层次的编程接口，是外部调用 GraphRAG 功能的主要入口，包括索引构建 API（index.py）、查询 API（query.py）和提示词调优 API（prompt_tune.py）三大块；CLI 入口（cli）：通过 Typer 装饰器定义命令，解析命令行参数并调用 API 层；配置管理（config）：使用 Pydantic 定义类型安全的配置模型，包括主配置、LLM 配置、向量配置、存储配置等；数据模型（data_model）：定义核心数据结构，包括实体、关系、社区、社区报告、文本单元、文档等；从入口处可以看出 GraphRAG 有三大功能：索引构建、查询、提示词调优，分别位于下面这些模块中：索引系统（index）：这是 GraphRAG 的核心模块，负责从原始文档构建知识图谱，这里的内容也是最丰富的；比如 input 目录用于输入处理，支持 CSV、JSON、纯文本多种格式的文档；workflows 是 GraphRAG 的工作流引擎，定义了标准的数据处理工作流，使用工厂模式动态创建流水线，支持增量更新和全量重建；operations 目录实现了大量的工作流原子操作，包括文本处理、图谱构建、社区识别、总结分析等；下面是一些典型的工作流操作：chunk_text - 文本分块，将长文档切分为可处理的片段；embed_text - 文本向量化，支持多种嵌入模型；extract_graph - 从文本提取实体和关系；build_noun_graph - 构建名词图，识别重要概念；create_graph.py - 创建完整的知识图谱；cluster_graph.py - 图聚类，发现社区结构；embed_graph - 图嵌入，支持 Node2Vec 等算法；layout_graph - 图布局，支持 UMAP 降维可视化；summarize_communities - 社区摘要生成；summarize_descriptions - 实体描述摘要；extract_covariates - 协变量提取（如声明检测）；查询系统（query）：为 GraphRAG 提供了多种检索策略，包括：全局搜索：基于社区报告的高层次查询，适合回答概括性或主题性问题；使用 Map-Reduce 模式处理大规模数据；本地搜索：基于实体和关系的细粒度查询，适合回答具体的事实性问题；混合向量检索和图遍历；漂移搜索：基于动态选择社区查询，在查询过程中调整搜索范围，平衡查询深度和广度；提示词系统（prompts）：包括索引和查询所使用的所有提示词；提示词调优（prompt_tune）：根据具体数据领域自动生成最适合的提示词，提高知识图谱构建质量；此外，为实现索引构建和查询，大模型和存储服务也是必不可少的：语言模型抽象（language_model）：提供统一的 LLM 和 Embedding 接口，主要通过 fnllm 库实现；存储抽象层（storage）：提供统一的存储接口，支持多种后端，包括本地文件系统、Azure Blob、CosmosDB、内存存储等；向量数据库（vector_stores）：支持多种向量数据库，包括：高性能向量数据库 LanceDB、Azure 认知搜索服务 Azure AI Search 以及 Azure 的 NoSQL 数据库 CosmosDB；技术栈分析通过分析 pyproject.toml 文件，我们可以对 GraphRAG 的核心依赖和开发工作链有一个初步了解。大语言模型fnllm[azure,openai] - 统一的大语言模型接口库opena…