引言
传统RAG基于向量相似度检索文本块,在处理需要跨文档推理、全局性总结和多跳关系分析的任务时存在明显局限。GraphRAG将知识图谱与RAG结合,通过图结构组织信息,支持基于关系的检索和推理。本文深入GraphRAG的架构设计、构建流程和工程实践。
传统RAG的局限
局部检索的困境
传统RAG将文档切分为文本块,用向量相似度检索最相关的Top-K块。这种方式存在根本局限:
多跳推理失效:问题"A公司的CEO在B公司担任什么职务?“需要先找到A公司的CEO是谁,再查找此人在B公司的职务。向量检索可能只检索到A公司或B公司中的一个文档块,无法建立跨文档的连接。
全局信息缺失:问题"这个行业的主要趋势是什么?“需要综合所有文档的全局信息,但向量检索只能返回局部相似的文本块,无法提供全局视角。
关系信息丢失:文档切分时,实体间的关系可能被分散到不同文本块中,向量检索难以捕获这些结构化关系。
GraphRAG架构
整体架构
GraphRAG在传统RAG基础上增加知识图谱层:
文档 → 文本块提取 → 实体抽取 → 关系抽取 → 知识图谱构建
↓
查询 → 查询理解 → 图检索(子图提取)→ 上下文组装 → LLM生成
↑
向量检索(补充)
知识图谱构建
实体抽取:使用LLM从文本中提取实体(人物、组织、地点、概念等):
def extract_entities(text, llm):
prompt = f"""
从以下文本中提取实体,按类型分类。
文本:{text}
输出JSON格式:
{{
"persons": ["..."],
"organizations": ["..."],
"locations": ["..."],
"concepts": ["..."],
"events": ["..."]
}}
"""
return json.loads(llm.generate(prompt))
关系抽取:识别实体间的关系:
def extract_relations(text, entities, llm):
prompt = f"""
识别以下文本中实体间的关系。
文本:{text}
实体:{entities}
输出三元组列表:
[(主体, 关系, 客体), ...]
例如:(苹果公司, 收购, NeXT)
"""
return eval(llm.generate(prompt))
图谱存储:将实体和关系存入图数据库(如Neo4j):
// 创建实体节点
CREATE (n:Person {name: "张三", type: "person"})
CREATE (n:Organization {name: "ABC公司", type: "organization"})
// 创建关系
MATCH (a:Person {name: "张三"}), (b:Organization {name: "ABC公司"})
CREATE (a)-[:WORKS_AT {since: "2020"}]->(b)
图检索策略
邻居扩展检索:从查询中的关键实体出发,扩展N跳邻居:
def graph_search(query_entities, graph_db, max_hops=2):
"""从查询实体出发,检索N跳邻居子图"""
subgraph = set()
for entity in query_entities:
# 1跳邻居
neighbors = graph_db.query(f"""
MATCH (n)-[r]-(m)
WHERE n.name = '{entity}'
RETURN n, r, m
""")
subgraph.update(neighbors)
# 2跳邻居(可选)
if max_hops > 1:
neighbors_2 = graph_db.query(f"""
MATCH (n)-[r1]-(m)-[r2]-(l)
WHERE n.name = '{entity}'
RETURN n, r1, m, r2, l
""")
subgraph.update(neighbors_2)
return subgraph
路径检索:查找两个实体间的最短路径,用于多跳推理:
MATCH p = shortestPath(
(a:Entity {name: "苹果公司"})-[*..5]-(b:Entity {name: "OpenAI"})
)
RETURN p
社区检索:对图谱进行社区检测,在社区层面进行摘要和检索:
def build_communities(graph_db):
"""使用Louvain算法进行社区检测"""
graph_db.query("""
CALL gds.louvain.write('entityGraph', {
writeProperty: 'community'
})
""")
def get_community_summary(graph_db, entity):
"""获取实体所在社区的摘要"""
community_id = graph_db.query(f"""
MATCH (n {{name: '{entity}'}})
RETURN n.community
""")[0]['community']
members = graph_db.query(f"""
MATCH (n {{community: {community_id}}})
RETURN n.name, n.type
""")
# 使用LLM生成社区摘要
summary = llm.summarize(members)
return summary
混合检索策略
GraphRAG不替代向量检索,而是与之互补:
def hybrid_retrieval(query, vector_db, graph_db, llm):
"""混合检索:图检索 + 向量检索"""
# 1. 从查询中提取实体
entities = extract_entities(query, llm)
# 2. 图检索:获取相关子图
graph_context = graph_search(entities, graph_db)
graph_text = subgraph_to_text(graph_context)
# 3. 向量检索:获取相关文本块
vector_results = vector_db.search(query, top_k=5)
vector_text = "\n".join([r['text'] for r in vector_results])
# 4. 组装上下文
context = f"""
# 相关关系信息
{graph_text}
# 相关文档内容
{vector_text}
"""
return context
工程实践
图谱构建质量控制
实体消歧:同一实体可能有不同名称(“北大"和"北京大学”),需要实体消歧机制:
def entity_resolution(entities, llm):
"""实体消歧:合并指向同一实体的不同名称"""
prompt = f"""
以下实体列表中,哪些指向同一实体?请给出合并建议。
实体列表:{entities}
输出JSON:
{{
"merged": [
{{"canonical": "北京大学", "aliases": ["北大", "PKU"]}}
],
"unique": ["清华大学", "复旦大学"]
}}
"""
return json.loads(llm.generate(prompt))
增量更新:当新文档到达时,增量更新图谱而非重建:
def incremental_update(new_docs, graph_db):
for doc in new_docs:
entities = extract_entities(doc, llm)
relations = extract_relations(doc, entities, llm)
for entity in entities:
# 检查是否已存在
existing = graph_db.find_entity(entity)
if not existing:
graph_db.create_entity(entity)
for subject, relation, obj in relations:
graph_db.create_or_update_relation(subject, relation, obj)
查询路由
根据查询类型选择检索策略:
def route_query(query, llm):
"""根据查询类型选择检索策略"""
prompt = f"""
判断以下查询适合哪种检索策略:
A. 向量检索(事实查询、关键词匹配)
B. 图检索(关系查询、多跳推理)
C. 混合检索(综合分析、复杂问题)
查询:{query}
答案(A/B/C):
"""
strategy = llm.generate(prompt).strip()
return strategy
查询示例
不同类型查询的检索策略:
| 查询类型 | 示例 | 检索策略 |
|---|---|---|
| 事实查询 | “RAG是什么?” | 向量检索 |
| 关系查询 | “张三和李四什么关系?” | 图检索(路径查找) |
| 多跳推理 | “A公司CEO的母校在哪?” | 图检索(邻居扩展) |
| 全局总结 | “这个领域的主要趋势?” | 图检索(社区摘要) |
| 综合分析 | “分析A公司的竞争优势” | 混合检索 |
性能优化
图谱规模控制
大图谱会导致检索慢和上下文膨胀。控制策略:限制每个实体的最大关系数、定期修剪低权重关系、对图谱进行分层摘要。
缓存策略
对频繁查询的子图进行缓存:热门实体的邻居子图缓存、社区摘要预计算、常见查询模式的结果缓存。
结语
GraphRAG通过引入知识图谱,突破了传统向量检索在多跳推理和全局分析上的局限。它不是对传统RAG的替代,而是补充——混合检索策略能同时发挥两者的优势。随着LLM实体抽取和关系抽取能力的提升,GraphRAG的构建成本正在降低,使其在更多场景中变得可行。
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
