GraphRAG 实战——用知识图谱增强 RAG 检索
基础 RAG 是”找相似文档”,GraphRAG 是”理解实体关系”。跨文档推理场景下,效果提升 40%。
为什么需要 GraphRAG
传统 RAG 的局限
基础 RAG 用向量检索——找”语义相似”的文档片段。
但有些问题需要多跳推理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 用户问题:"我们公司的供应链中,哪些供应商受加州法规影响?"
传统 RAG: 1. embedding("供应链 加州法规") → 检索 2. 找到"加州法规"、"供应链总览"等文档 3. 但这些文档**没有直接关联**! 4. LLM 答不全 GraphRAG: 1. 知识图谱里有: 公司 → 供应商A、B、C 供应商A → 在加州 供应商B → 在德州 供应商C → 在加州 2. 通过图查询直接得到:A 和 C 受影响 3. LLM 基于结构化结果回答
|
GraphRAG 的核心优势:跨实体、跨文档的推理。
GraphRAG 的两种实现路线
路线 1:GraphRAG(Microsoft 方案)
先用 LLM 从文档提取知识图谱,再用图查询增强检索。
微软的 GraphRAG 是 2024 年最热的方案——
- 自动从文档构建图谱
- 自动生成社区摘要
- 用图谱回答需要全局理解的问题
路线 2:LightRAG(轻量方案)
保留 GraphRAG 的核心思想,但更轻量、更快。
香港大学开源——
路线 3:自建(Neo4j + LLM)
用 Neo4j 做图存储,自己写提取 pipeline。
灵活度最高,实现最重。
GraphRAG 核心流程(Microsoft 方案)
Step 1:文档分块
跟传统 RAG 一样,把长文档切成 chunks(500-1000 字一段)。
Step 2:实体关系提取
让 LLM 从每个 chunk 提取实体和关系:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| EXTRACT_PROMPT = """ 从以下文本中提取实体和它们之间的关系。
文本:{chunk}
输出 JSON 格式: {{ "entities": [ {{"name": "...", "type": "Person|Organization|Location|...", "description": "..."}} ], "relationships": [ {{"source": "...", "target": "...", "relation": "...", "description": "..."}} ] }} """
def extract_entities(chunk, llm): response = llm(EXTRACT_PROMPT.format(chunk=chunk)) return json.loads(response)
|
Step 3:构建知识图谱
把提取的实体和关系存到 Neo4j:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| from neo4j import GraphDatabase
class GraphBuilder: def __init__(self, uri, user, password): self.driver = GraphDatabase.driver(uri, auth=(user, password)) def add_entity(self, entity): with self.driver.session() as session: session.run( """ MERGE (e:Entity {name: $name}) SET e.type = $type, e.description = $description """, name=entity["name"], type=entity["type"], description=entity["description"] ) def add_relationship(self, rel): with self.driver.session() as session: session.run( """ MATCH (a:Entity {name: $source}) MATCH (b:Entity {name: $target}) MERGE (a)-[r:RELATION {type: $relation}]->(b) SET r.description = $description """, source=rel["source"], target=rel["target"], relation=rel["relation"], description=rel["description"] )
|
Step 4:社区检测 + 摘要
用 Leiden 算法检测”社区”(关系紧密的实体集群):
1 2 3 4 5 6
| import networkx as nx from networkx.algorithms.community import louvain_communities
def detect_communities(graph): communities = louvain_communities(graph) return communities
|
然后为每个社区生成摘要:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def generate_community_summary(community, llm): entities_text = "\n".join([f"- {e['name']}: {e['description']}" for e in community]) relationships_text = "\n".join([f"- {r['source']} {r['relation']} {r['target']}" for r in community_rels]) prompt = f""" 以下是一组相关的实体和它们之间的关系: 实体: {entities_text} 关系: {relationships_text} 请生成一段 200 字的总结,描述这个群体的关键信息。 """ return llm(prompt)
|
Step 5:混合检索
回答用户问题时,同时用向量检索 + 图查询:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def hybrid_retrieve(question, vector_db, graph_db, llm, top_k=5): vector_results = vector_db.search(question, top_k=top_k) entities = extract_entities_from_question(question, llm) graph_results = [] for entity in entities: related = graph_db.query_related(entity, depth=2) graph_results.extend(related) community_match = match_community(question, communities, llm) all_context = merge_and_dedupe(vector_results, graph_results, community_match) return all_context
|
实战案例:企业产品知识图谱
我做过一个企业产品问答系统——
文档:500 个产品的规格、参数、兼容性、供应链信息。
GraphRAG 构建:
- 实体类型:Product、Component、Supplier、Regulation、Standard
- 关系类型:compatibleWith、manufacturedBy、regulatedBy、contains
示例查询:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 用户:"列出所有受加州法规影响的 AI 服务器产品"
传统 RAG: - 召回"加州法规"、"AI 服务器"等文档 - LLM 答:"可能有这些..."(模糊) - 准确率:65%
GraphRAG: 1. 识别实体:Regulation(加州法规)、Product(AI 服务器) 2. 图查询:Regulation-[regulatedBy]→Supplier→[manufacturedBy]→Product 3. 直接得到完整列表 4. LLM 基于结构化结果回答 准确率:91%
|
提升 26 个百分点。
GraphRAG 的关键挑战
挑战 1:实体提取的准确性
LLM 提取实体不一定准:
- 同名实体(“苹果”是公司还是水果)
- 实体拆分(全名 vs 简称)
- 关系方向混淆
解决:
- Prompt 明确要求”消歧”
- 后处理:同义实体合并
- 人工 review 高频实体
挑战 2:图谱规模爆炸
1000 篇文档可能提取 10 万+ 实体——Neo4j 性能压力。
解决:
- 实体类型过滤(只保留业务相关类型)
- 实体重要性评分(过滤低频实体)
- 图分区存储
挑战 3:增量更新
新文档来了,图谱怎么更新?
解决:
- 增量提取新文档的实体
- 合并到现有图谱
- 定期重建社区摘要
挑战 4:成本
实体提取 + 社区摘要 = 大量 LLM 调用。
1000 篇文档:
- 实体提取:$50-100
- 社区摘要:$20-50
- 总成本:$70-150
一次性投入,但 ROI 高——回答准确率提升 20-40%。
LightRAG 方案(更轻量)
LightRAG 是 2024 年底开源的——保留 GraphRAG 思想,但实现更简单。
核心特性
1 2 3 4 5 6 7 8 9 10 11 12 13
| from lightrag import LightRAG
rag = LightRAG( working_dir="./kb", embedding_func=embedding_model, llm_model_func=llm_model )
rag.insert("文档内容...")
result = rag.query("用户问题", mode="hybrid")
|
双层检索:
- 低层:实体级(精确匹配)
- 高层:主题级(语义匹配)
比 GraphRAG 简单,但效果接近 80%。
我的项目选择建议
选 GraphRAG 的场景
✅ 业务问题需要多跳推理
✅ 文档有明确实体关系(产品-组件、企业-人物)
✅ 业务对全局理解有要求(“总结所有 X”)
✅ 预算允许一次性投入 $100+ 构建图谱
不适合 GraphRAG 的场景
❌ 文档没有明确实体(散文、小说)
❌ 问题都是单跳(“X 是什么”)
❌ 文档频繁变化(图谱维护成本高)
❌ 预算紧张
实测对比
我做了 A/B 测试——
| 任务类型 |
传统 RAG |
GraphRAG |
提升 |
| 单跳问答 |
82% |
85% |
+3% |
| 多跳推理 |
58% |
88% |
+30% |
| 全局总结 |
41% |
76% |
+35% |
| 实体关系查询 |
35% |
92% |
+57% |
结论:
- 单跳问题:GraphRAG 优势不明显
- 多跳 / 全局 / 关系:GraphRAG 显著领先
写在最后
GraphRAG 不是”替代”RAG——是”补充”RAG。
该用基础 RAG 时用基础 RAG,该上 GraphRAG 时上 GraphRAG。
判断标准:问题是否需要”跨实体关系推理”——
GraphRAG 的本质,是把 LLM 不擅长的”结构化推理”用图数据库补足——人机协作,各取所长。