GraphRAG进阶:用知识图谱提升RAG推理能力
传统的 RAG 是"平面的"——把文档切成块,靠语义相似度检索。它在查事实、找定义这类任务上很好用。但一旦遇到需要"串起来思考"的问题,传统 RAG 就开始吃力了。
比如:“公司去年采购的 A 型传感器出了三次故障,每次都和谁有关?最后是怎么解决的?”
这个问题需要三个文档块的信息串联起来才能回答。向量检索只能找回孤立的块,无法理解块之间的联系。
这就是 GraphRAG 要解决的问题。
大家好,我是黒漂技术佬。
一、GraphRAG 是什么?
GraphRAG = RAG + 知识图谱(Knowledge Graph)。它的核心思路是:在文档之上构建一张"关系网",让检索不再是孤立的"搜相似内容",而是沿着关系走——“顺着这个人找到他的部门,顺着这个项目找到相关的合同,顺着这个故障找到解决方案”。
传统 RAG 的认知:文档是一堆孤立的碎片 [块A] [块B] [块C] [块D] [块E] ↑搜索 ↑搜索 ↑搜索 ↑搜索 用户问题 → 相似度匹配 → 返回Top-K GraphRAG 的认知:文档是一张关系网 [张三] ──属于──→ [技术部] │ │ │负责 │负责 ↓ ↓ [A项目] ──关联──→ [采购合同C-2024-001] │ │产生了 ↓ [故障报告#3] ──解决──→ [解决方案R-042]在 GraphRAG 中,检索不再只是"找相似的文本",而是在图谱中导航——从一个实体出发,沿着关系边找到所有相关信息。
二、知识图谱怎么建?
构建知识图谱分两步:实体与关系抽取、图谱存储与索引。
第一步:从文档中提取实体和关系
用 LLM 自动从文档中抽取"实体"和"关系":
defextract_entities_relations(document_text:str):"""从文档中提取实体和关系"""prompt=f""" 从以下文档中提取所有重要的实体和它们之间的关系。 实体类型包括:人员、部门、项目、产品、合同、事件、日期、金额。 关系类型包括:属于、负责、产生、解决、关联、签署、采购。 请以 JSON 格式输出: {{ "entities": [ {{"name": "张三", "type": "人员"}}, {{"name": "技术部", "type": "部门"}}, ... ], "relations": [ {{"source": "张三", "target": "技术部", "relation": "属于"}}, {{"source": "A型传感器", "target": "故障报告#3", "relation": "产生"}}, ... ] }} 【文档】{document_text}"""returnllm.invoke(prompt)第二步:存入图数据库
图数据库有很多选择,Neo4j是最成熟的关系图数据库:
fromneo4jimportGraphDatabaseclassKnowledgeGraph:def__init__(self,uri,user,password):self.driver=GraphDatabase.driver(uri,auth=(user,password))defadd_entity(self,name,entity_type,doc_source):"""添加实体节点"""withself.driver.session()assession:session.run(""" MERGE (e:Entity {name: $name}) SET e.type = $type, e.source = $source """,name=name,type=entity_type,source=doc_source)defadd_relation(self,source,target,relation):"""添加关系边"""withself.driver.session()assession:session.run(""" MATCH (a:Entity {name: $source}) MATCH (b:Entity {name: $target}) MERGE (a)-[r:RELATION {type: $relation}]->(b) """,source=source,target=target,relation=relation)# 还有一个更轻量的选择:用 NetworkX 做内存图# 适合小规模、不需要持久化的场景importnetworkxasnx G=nx.DiGraph()G.add_node("张三",type="人员")G.add_node("技术部",type="部门")G.add_edge("张三","技术部",relation="属于")第三步:将图谱与向量检索结合
classGraphRAGRetriever:"""图谱 + 向量 混合检索器"""def__init__(self,vectorstore,graph):self.vectorstore=vectorstore self.graph=graphdefretrieve(self,question:str,k=5):# Step 1: 先做向量检索,找到"入口"文档块entry_chunks=self.vectorstore.similarity_search(question,k=k)# Step 2: 从这些文档块中提取实体entities=set()forchunkinentry_chunks:forentityinchunk.metadata.get("entities",[]):entities.add(entity)# Step 3: 在图谱中扩展——找到这些实体关联的其他实体和文档related_chunks=[]forentityinentities:# 在图中找距离 2 跳内的所有关联节点neighbors=self.graph.get_neighbors(entity,hops=2)# 用这些关联的实体名去向量库二次检索forneighborinneighbors:extra=self.vectorstore.similarity_search(neighbor,k=3)related_chunks.extend(extra)# Step 4: 合并所有块,去重,重排序all_chunks=entry_chunks+related_chunks unique_chunks=self._deduplicate(all_chunks)returnself._rerank(question,unique_chunks)[:k]三、GraphRAG 的实际效果
我用同一份企业文档集(包含项目文档、故障报告、采购合同等约 200 份),对比了传统 RAG 和 GraphRAG 在两类问题上的表现:
测试 1:单跳事实查询(传统 RAG 的强项)
问:公司的加班费计算标准是什么? 传统RAG: ✅ 直接搜到《考勤制度》,9 秒出答案 GraphRAG: ✅ 同样准确,但多了实体导航的开销,11 秒测试 2:多跳推理查询(GraphRAG 的强项)
问:去年采购的A型传感器出过几次问题,分别怎么解决的? 传统RAG: ❌ 搜到一堆"传感器"相关的块,但无法串起来 回答碎片化:"好像有一次是……还有一次可能……" GraphRAG: ✅ 从"A型传感器"实体出发,在图谱里沿着"产生故障"的关系 找到 3 个故障报告,再沿着"解决"关系找到对应方案 回答完整:"共3次。第一次因供电不稳定…第二次…第三次…"单跳 vs 多跳:什么时候该上 GraphRAG?
| 你的场景 | 推荐方案 |
|---|---|
| FAQ、员工手册、制度问答 | 传统 RAG 就够了 |
| 项目管理、合同分析、故障追踪 | 上 GraphRAG |
| 法律文档、医疗病历、财报分析 | GraphRAG 几乎是必须 |
| 海量文档且实体关系复杂 | GraphRAG + 混合检索 |
四、GraphRAG 的开源实践:微软的 GraphRAG
微软在 2024 年开源了 GraphRAG 项目(github.com/microsoft/graphrag),它把实体抽取、社区发现、图谱构建、检索增强打包成了一整套流程。
核心创新:社区摘要(Community Summaries)
微软 GraphRAG 不只是在检索时走图谱,还用 Leiden 算法对图谱做社区发现(Community Detection)——把紧密关联的实体聚类成"社区",然后对每个社区生成一段摘要。
原始图谱:几百个实体 + 上千条关系 ↓ Leiden 社区发现 社区1:[张三, 技术部, A项目, 故障#1, 故障#2, 合同C-001] 社区2:[李四, 销售部, B项目, 客户X公司] 社区3:[财务部, 报销制度, 预算审批流程] ↓ LLM 自动生成社区摘要 社区1摘要:"技术部张三负责的A项目,涉及C-001号采购合同。 该项目使用A型传感器,共发生两次故障,均已解决……"检索时,先匹配到相关社区,再在该社区内做细化检索。这样即使用了最简单的向量检索,也能得到"结构化+关联化"的结果。
五、GraphRAG 的成本和取舍
GraphRAG 不是银弹。它有几个显著的代价:
- 构建成本高:实体抽取、关系构建、社区发现……每一步都在调用 LLM。一篇 10 页的文档,传统 RAG 入库可能只要 0.05 元,GraphRAG 加图谱构建可能要到 0.5~2 元。
- 延迟增加:检索时要在图里跳几跳,增加的延迟可能是 200~500ms。
- 维护复杂:文档更新时,图谱需要同步更新——删掉旧实体、添加新关系、重新社区发现。这套维护流水线比纯向量库复杂得多。
我的建议:
- 先用传统 RAG 跑通整体流程,上线后再分析用户提问里"多跳问题"的占比
- 如果多跳问题占比 < 10%,GraphRAG 的 ROI 不高
- 如果多跳问题 > 25%,且错误率高,那就值得投入
- 不要一上来就 GraphRAG——先把基础版做好,再按需升级
💬 你的场景里有没有那种"需要翻好几篇文档才能回答"的问题?占比大概多少?评论区说说你的场景,我帮你判断要不要上图谱!