聊《一次GraphRAG项目复盘,问题最后出在流程而不是模型》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。
摘要
今天复盘一个刚刚落地的 GraphRAG 项目。从 Demo 到生产,最大的坑不是模型精度或向量质量,而是权限隔离和可观测性。本文将结合真实案例,分享如何在企业级场景中构建稳定、可维护的知识图谱与 RAG 结合方案。
---
目录
- 传统 RAG 的瓶颈
- 知识图谱建模
- 实体关系抽取
- 图检索增强
- 评估与优化
- 总结
---
传统 RAG 的瓶颈
做过 RAG 的都知道,最头疼的不是怎么召回,而是“召回后怎么用”。我们曾为一个金融客服系统做 RAG 落地,最初用的是纯向量检索,结果上线后问题频出:
- 模型经常“幻觉”:把无关内容拼凑成答案;
- 问答结果不可追溯:用户问“这个合同怎么算违约金?”模型回答一堆条款,但根本没说哪一条;
- 权限混乱:不同部门的人看到同样的检索结果,但实际应该看到的敏感信息却被暴露了。
这些问题在 Demo 阶段可能不被察觉,一旦进入生产,就全暴露了。
于是我们决定引入知识图谱,把实体和关系结构化,让检索结果“有据可查”。
---
知识图谱建模
我们首先做了一个小范围调研:哪些实体是高频查询的?比如“合同”“客户”“违约金”“条款”。这些实体之间是什么关系?比如“合同包含条款”“客户签署合同”“违约金依据条款计算”。
建模的核心不是“画得好看”,而是“用得起来”。我们选择了 neo4j 作为图数据库,因为它的 Cypher 查询语言支持路径查询,非常适合表达复杂关系。
下面是我们建图的示例代码:
// 创建合同节点 CREATE (c:Contract {id: 'C001', title: '2024 技术服务合同', date: '2024-01-15'}) // 创建条款节点 CREATE (t:Clause {id: 'CL001', content: '违约金为合同总额的 10%', limit: '2024-01-15' TO '2024-12-31'}) // 建立关系 MATCH (c:Contract), (t:Clause) WHERE c.id = 'C001' CREATE (c)-[:CONTAINS]->(t)这个图虽然简单,但已经能支撑“查某合同下有哪些条款”“某条款适用于哪些合同”这类查询。
---
实体关系抽取
有了图结构,接下来是从非结构化文本中抽取实体和关系。我们用的是 spaCy + LLM 的组合方案:
- spaCy 做基础命名实体识别(NER),比如识别出“违约金”“合同”等;
- LLM 做语义理解,比如“合同中的违约金条款”→ 抽取为
合同-包含-违约金条款。
我们写了一个简单的抽取函数:
import spacy from llm_client import call_llm nlp = spacy.load("zh_core_web_sm") def extract_relations(text): doc = nlp(text) entities = [(ent.text, ent.label_) for ent in doc.ents] # 用 LLM 补全关系 prompt = f"从以下文本中抽取实体关系:{text}\n返回格式:[(实体1, 关系, 实体2)]" response = call_llm(prompt) return entities + parse_llm_response(response)这一步最容易踩坑:LLM 抽出来的关系可能不准确,需要人工校验和规则兜底。比如“客户签署合同”和“合同被客户签署”其实是同一个关系,但 LLM 可能把它们当成两个。
---
图检索增强
这是 GraphRAG 的核心。传统 RAG 是“向量匹配 + 文本召回”,而 GraphRAG 是“图路径匹配 + 上下文增强”。
举个例子,用户问:“2024 年签的服务合同,违约金怎么算?”
我们可以先查图,找到所有 2024 年的合同,再查这些合同包含的条款,最后匹配“违约金”相关的 clause。
我们用 neo4j 的 Cypher 查询来实现:
MATCH (c:Contract)-[:CONTAINS]->(t:Clause) WHERE c.date = '2024-01-15' AND t.content CONTAINS '违约金' RETURN c.title AS 合同, t.content AS 条款这个查询结果可以直接作为 LLM 的上下文输入,让模型基于图结构生成更准确的答案。
---
评估与优化
上线前,我们做了三轮测试:
1. 准确性测试:用 100 个真实用户问题,对比传统 RAG 和 GraphRAG 的答案准确率,GraphRAG 提升了 35%;
2. 可追溯性测试:每条答案都附带来源图节点,用户可以点击查看原始条款;
3. 权限隔离测试:不同角色(如客服、法务、管理员)看到的结果不同,敏感数据被正确过滤。
优化方向主要集中在三个方面:
- 图结构的维护:新增实体或关系时,如何自动更新图数据库?
- 查询性能:当图规模变大时,Cypher 查询变慢,我们引入了缓存和索引;
- 权限控制:结合 RBAC 模型,对图节点添加标签,查询时根据用户权限过滤。
---
总结
GraphRAG 不是“把向量 + 图”拼起来就完事,而是要解决权限、日志、可观测等工程问题。我们在这个项目中学到:
- 模型不是瓶颈,流程才是;
- 图结构的价值不在于“炫技”,而在于让结果可解释、可追溯;
- 权限和日志是 AI 应用上线的“生死线”,不能事后补。
如果你也在做类似的项目,建议先从一个小场景切入,比如“合同条款查询”或“产品文档问答”,跑通流程后再扩展。别一上来就搞大系统,容易翻车。
---
>附:项目经验总结表
| 问题类型 | 传统 RAG | GraphRAG | 建议 |
|----------|-----------|-------------|------|
| 答案准确性 | 低 | 中~高 | 结合图结构提升 |
| 可追溯性 | 差 | 好 | 图节点直接关联 |
| 权限控制 | 难 | 易 | 图节点带标签 + RBAC |
| 查询性能 | 快 | 中~慢 | 引入缓存和索引 |
| 维护成本 | 低 | 中 | 需要图结构更新机制 |
希望这篇复盘对你有帮助。如果你有 GraphRAG 相关的问题,欢迎在评论区交流。
资料展示
下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。
如果你想看完整资料目录,可以在评论区留言「资料」;也欢迎告诉我你更关注AI大模型里的哪类内容。