概述
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支持两种主要查询模式:
3.1 本地搜索(Local Search)
适用于需要特定实体相关信息的查询:
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 answer3.2 全局搜索(Global Search)
适用于需要综合全文信息的主题性查询:
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 RAG | GraphRAG |
|---|---|---|
| 检索单元 | 文本块 | 实体+关系+社区 |
| 语义理解 | 局部相似性 | 全局结构化 |
| 关系建模 | 无 | 显式关系 |
| 索引成本 | 低 | 中等(需要LLM调用) |
| 查询复杂度 | 简单查询 | 简单+复杂推理 |
| 可解释性 | 中等 | 高(图谱可视化) |
4.2 性能对比
| 任务类型 | Naive RAG | GraphRAG | 提升 |
|---|---|---|---|
| 实体查询 | 高 | 高 | - |
| 关系推理 | 中 | 高 | +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 GraphRAG | GitHub |
| 官方文档 | GraphRAG Docs |
| 论文 | arXiv:2404.16130 |
参考资料
Footnotes
-
Edge, D., et al. “From Local to Global: A GraphRAG Approach to Query-Focused Summarization.” Microsoft Research, 2024. ↩