概述

GraphRAG(Graph Retrieval-Augmented Generation)是微软研究院提出的基于知识图谱的检索增强生成框架,旨在解决传统RAG在处理复杂关系和全局性问题时的局限性。1

传统Naive RAG依赖于向量相似性检索,只能找到与查询语义相近的文本片段,但在以下场景表现不佳:

  • 需要理解实体间复杂关系的查询
  • 需要综合全文信息才能回答的全局性问题
  • 需要推理跨文档关联的场景

GraphRAG通过构建知识图谱,将文本中的实体和关系结构化,从而支持更深层的语义理解和推理。


1. 为什么需要GraphRAG?

1.1 传统RAG的局限性

问题类型Naive RAG表现GraphRAG优势
简单实体查询✓ 高效✓ 同样高效
关系推理查询✗ 困难✓ 擅长
全局性总结✗ 碎片化✓ 层次化
多跳推理✗ 难以保证✓ 结构化支持
主题理解✗ 仅局部✓ 全局语义

1.2 知识图谱的优势

文本语料库                    知识图谱
┌─────────────────┐          ┌─────────────────┐
│ 实体A出现在文档1 │          │      实体A       │
│ 实体A出现在文档3 │    →     │    ↗      ↘     │
│ 实体B出现在文档2 │          │  实体B    实体C  │
│ 实体C出现在文档1 │          │      ↘      ↙    │
│ 实体A与B有引用   │          │      实体D       │
└─────────────────┘          └─────────────────┘

知识图谱将分散的文本信息转化为结构化的实体-关系网络,保留了语义关联。


2. GraphRAG核心架构

2.1 系统流程

┌──────────────────────────────────────────────────────────────────┐
│                        GraphRAG Pipeline                         │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐ │
│  │   源文档    │ →  │   文本分割   │ →  │   实体/关系抽取    │ │
│  │  (Documents)│    │  (Chunking) │    │  (Entity Extraction)│ │
│  └─────────────┘    └─────────────┘    └──────────┬──────────┘ │
│                                                    │            │
│                                                    ↓            │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐ │
│  │   查询处理  │ ←  │   社区摘要   │ ←  │    社区检测         │ │
│  │(Query Proc.)│    │(Community   │    │(Community Detection)│ │
│  │             │    │  Summary)   │    │                     │ │
│  └──────┬──────┘    └─────────────┘    └──────────┬──────────┘ │
│         │                                          │            │
│         ↓                                          ↓            │
│  ┌─────────────┐                          ┌─────────────────────┐ │
│  │   图谱检索  │ ← ──────────────────────  │    知识图谱        │ │
│  │(Graph Search│                          │  (Knowledge Graph)  │ │
│  └──────┬──────┘                          └─────────────────────┘ │
│         │                                                         │
│         ↓                                                         │
│  ┌─────────────┐                                                  │
│  │   LLM生成   │                                                  │
│  │(LLM Generate)                                                 │
│  └─────────────┘                                                  │
└──────────────────────────────────────────────────────────────────┘

2.2 索引阶段(Indexing Pipeline)

步骤1:文本分割(Text Chunking)

# GraphRAG使用多级分块策略
def graphrag_chunking(document, chunk_size=300):
    """
    将文档分割成适合实体抽取的块
    - 块大小:300 tokens(可调整)
    - 相邻块有50 token重叠
    """
    chunks = []
    for i in range(0, len(document), chunk_size - 50):
        chunks.append(document[i:i + chunk_size])
    return chunks

步骤2:实体与关系抽取(Entity & Relation Extraction)

# 使用LLM进行实体抽取
ENTITY_EXTRACTION_PROMPT = """
从以下文本中抽取所有实体和它们之间的关系。
 
输出格式(JSON):
{{
    "entities": [
        {{"name": "实体名", "type": "实体类型", "description": "描述"}},
        ...
    ],
    "relationships": [
        {{"source": "实体A", "target": "实体B", "description": "关系描述"}},
        ...
    ]
}}
 
文本:{chunk_text}
"""
 
def extract_entities_relations(chunk, llm):
    """使用LLM抽取实体和关系"""
    prompt = ENTITY_EXTRACTION_PROMPT.format(chunk_text=chunk)
    response = llm.generate(prompt)
    return parse_json_response(response)

步骤3:知识图谱构建(Graph Construction)

def build_knowledge_graph(entities, relationships):
    """
    构建知识图谱
    - 实体节点:包含名称、类型、描述
    - 关系边:包含源实体、目标实体、关系描述
    """
    graph = {
        "nodes": [],  # 实体列表
        "edges": []    # 关系列表
    }
    
    # 添加节点
    for entity in entities:
        graph["nodes"].append({
            "id": generate_node_id(entity["name"]),
            "label": entity["name"],
            "type": entity["type"],
            "description": entity["description"]
        })
    
    # 添加边
    for rel in relationships:
        graph["edges"].append({
            "source": get_node_id(rel["source"]),
            "target": get_node_id(rel["target"]),
            "description": rel["description"]
        })
    
    return graph

步骤4:社区检测(Community Detection)

使用Leiden算法对图谱进行社区检测,将实体组织成层次化社区结构:

import networkx as nx
from networkx.algorithms.community import leiden
 
def detect_communities(graph):
    """
    使用Leiden算法检测社区
    返回层次化的社区结构
    """
    # 构建NetworkX图
    G = nx.Graph()
    G.add_nodes_from([n["id"] for n in graph["nodes"]])
    G.add_edges_from([
        (e["source"], e["target"]) for e in graph["edges"]
    ])
    
    # Leiden社区检测
    communities = leiden(G, resolution=1.0)
    
    # 构建层次化结构
    community_hierarchy = build_hierarchy(communities)
    
    return community_hierarchy

步骤5:社区摘要生成(Community Summarization)

COMMUNITY_SUMMARY_PROMPT = """
给定以下社区中的实体和关系,生成一个全面的社区摘要。
 
社区成员:
{community_members}
 
关系:
{relationships}
 
请生成:
1. 社区核心主题(1-2句话)
2. 关键实体列表
3. 主要关系模式
4. 社区内重要事件/事实
 
摘要:
"""
 
def generate_community_summary(community, llm):
    """为每个社区生成LLM摘要"""
    prompt = COMMUNITY_SUMMARY_PROMPT.format(
        community_members=community["entities"],
        relationships=community["relationships"]
    )
    summary = llm.generate(prompt)
    return {
        "community_id": community["id"],
        "summary": summary,
        "level": community["level"]
    }

3. 查询阶段(Query Pipeline)

GraphRAG支持两种主要查询模式:

适用于需要特定实体相关信息的查询:

def local_search(query, graph, entities, llm):
    """
    本地搜索:聚焦于查询相关的实体及其邻域
    
    流程:
    1. 识别查询中的实体
    2. 在图谱中定位这些实体
    3. 收集实体的邻居和关系
    4. 结合上下文生成答案
    """
    # 步骤1-2:实体匹配
    matched_entities = match_entities(query, graph)
    
    # 步骤3:收集邻域信息
    neighborhood = collect_neighborhood(
        graph, 
        matched_entities,
        depth=2  # 收集2跳邻居
    )
    
    # 步骤4:上下文增强生成
    context = build_context(neighborhood)
    answer = llm.generate(
        f"基于以下信息回答问题:\n\n{context}\n\n问题:{query}"
    )
    
    return answer

适用于需要综合全文信息的主题性查询:

def global_search(query, community_summaries, llm):
    """
    全局搜索:通过社区层次结构综合回答
    
    流程:
    1. 根据查询确定相关社区
    2. 从最顶层开始,收集社区摘要
    3. 中间层社区补充细节
    4. 必要时深入底层社区
    5. 综合所有摘要生成最终答案
    """
    # 步骤1:社区优先级排序
    ranked_communities = rank_communities(
        query, 
        community_summaries,
        top_k=10
    )
    
    # 步骤2-4:收集摘要直到达到token限制
    collected_summaries = []
    total_tokens = 0
    max_tokens = 6000
    
    for community in ranked_communities:
        summary_tokens = count_tokens(community["summary"])
        if total_tokens + summary_tokens > max_tokens:
            break
        collected_summaries.append(community)
        total_tokens += summary_tokens
    
    # 步骤5:Map-Reduce生成
    intermediate_answers = map_phase(collected_summaries, query, llm)
    final_answer = reduce_phase(intermediate_answers, query, llm)
    
    return final_answer
 
def map_phase(summaries, query, llm):
    """Map阶段:每个社区摘要独立生成中间答案"""
    answers = []
    for summary in summaries:
        prompt = f"""
社区摘要:{summary['summary']}
 
基于以上摘要,回答问题:{query}
 
如果摘要包含相关信息,给出简短答案(2-3句话)。
如果摘要不包含相关信息,回答"此摘要不包含相关信息"。
"""
        answer = llm.generate(prompt)
        answers.append({"community": summary["id"], "answer": answer})
    return answers
 
def reduce_phase(intermediate_answers, query, llm):
    """Reduce阶段:综合所有中间答案生成最终答案"""
    combined = "\n\n".join([
        f"社区{i+1}的答案:{a['answer']}" 
        for i, a in enumerate(intermediate_answers)
    ])
    
    prompt = f"""
以下是各个社区对问题的回答:
 
{combined}
 
问题:{query}
 
请综合以上所有答案,给出一个全面、连贯的最终回答。
"""
    return llm.generate(prompt)

4. 与传统RAG的对比

4.1 核心差异

维度Naive RAGGraphRAG
检索单元文本块实体+关系+社区
语义理解局部相似性全局结构化
关系建模显式关系
索引成本中等(需要LLM调用)
查询复杂度简单查询简单+复杂推理
可解释性中等高(图谱可视化)

4.2 性能对比

任务类型Naive RAGGraphRAG提升
实体查询-
关系推理+40%
全局总结+60%
多跳问答+50%

5. 应用场景

5.1 私有文档分析

场景:分析公司内部文档库

GraphRAG优势:
- 跨部门信息关联
- 人员-项目-成果关系追踪
- 政策沿革追溯

5.2 科学研究

场景:分析大量学术论文

GraphRAG优势:
- 作者合作关系网络
- 引用关系追踪
- 跨领域知识关联

5.3 客户支持

场景:企业知识库问答

GraphRAG优势:
- 产品-问题-解决方案映射
- 相似问题关联
- 上下文理解

6. 局限性

局限性说明缓解方法
索引成本LLM抽取实体消耗大量token使用小模型+规则混合
图谱规模大规模文档可能导致图谱过大分层索引、增量更新
实体消歧同一实体可能有不同表述实体链接、实体融合
更新维护动态文档需要持续更新增量索引策略

7. 实践建议

7.1 何时使用GraphRAG

适合使用GraphRAG的场景

  • 需要理解实体间关系的查询
  • 需要全局性总结或主题分析
  • 文档之间存在明确的实体关联
  • 查询涉及多跳推理

不适合使用GraphRAG的场景

  • 简单的事实查询
  • 高度独立的短文档集合
  • 实时性要求极高的场景
  • 索引成本受限的情况

7.2 最佳实践

# GraphRAG配置建议
GRAPH_RAG_CONFIG = {
    # 分块策略
    "chunk_size": 300,           # 较小块便于实体抽取
    "chunk_overlap": 50,
    
    # 实体抽取
    "entity_types": ["PERSON", "ORG", "PRODUCT", "EVENT", "CONCEPT"],
    "extraction_model": "gpt-4-turbo",
    
    # 社区检测
    "community_resolution": 1.0,  # 影响社区粒度
    "max社区层级": 3,
    
    # 查询策略
    "local_search_neighbors": 2,
    "global_search_top_k": 10,
    
    # 摘要长度
    "max_summary_tokens": 500,
    "max_context_tokens": 6000
}

8. 相关资源

资源链接
Microsoft GraphRAGGitHub
官方文档GraphRAG Docs
论文arXiv:2404.16130

参考资料

Footnotes

  1. Edge, D., et al. “From Local to Global: A GraphRAG Approach to Query-Focused Summarization.” Microsoft Research, 2024.