三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

GraphRAG接入团队项目后,我推翻的四个想当然

GraphRAG接入团队项目后,我推翻的四个想当然

这篇不先堆名词。我们把《我把GraphRAG接进项目后,先推翻了几个想当然》拆成几级台阶,看完至少知道下一步该学什么、该练什么。

摘要

GraphRAG把知识图谱和RAG结合,听起来是个完美的组合。但当我们把这个方案从个人Demo推进到团队协作场景时,才发现很多"理所当然"的判断都需要重新审视。本文记录我们在企业知识库项目中,从需求提出到方案落地的真实过程,以及几个关键的取舍决策。

---

目录

1. 传统RAG的瓶颈
2. 知识图谱建模
3. 实体关系抽取
4. 图检索增强
5. 评估与优化
6. 总结

---

传统RAG的瓶颈

我们团队接到这个需求的时候,业务方原话是:"客户问的问题越来越复杂,光靠向量检索答不上来。"

我第一反应是加更强的embedding模型、调更好的chunk策略。试了一圈,效果提升有限。问题出在哪里?

传统RAG的核心逻辑是:把文档切片、向量化、检索、召回、回答。这个流程在单文档、单主题场景下表现不错,但一旦涉及多实体关联、跨文档推理,就露怯了。

举个例子。我们有份技术文档,讲了A模块和B模块的集成关系,另一份文档讲了B模块和C模块的依赖。当用户问"A如何与C交互"时,基于向量检索的RAG很难把这两份文档关联起来,因为"A与C交互"这个查询在原始文档中根本不存在。

我们做过一个对比实验。用纯向量检索回答一组涉及实体关系的问题,准确率大概60%左右;而这些问题如果用知识图谱来检索,准确率能到85%以上。差距不在于模型能力,而在于检索方式——向量检索找的是"语义相似",知识图谱找的是"结构关联"。

这里有一个判断标准:如果你的知识库中,问题往往涉及多个实体之间的关系,或者需要跨文档综合推理,那就不是简单调RAG参数能解决的,需要引入图谱结构。

---

知识图谱建模

建模是GraphRAG最容易踩坑的环节。我们一开始犯的错误是:把文档里的所有内容都抽成实体和关系。

结果图谱变得又臭又长,查询慢,噪声大。后来我们重新思考:这个图谱到底要解决什么问题?

答案是:支撑复杂问答。

所以我们把建模目标收窄到"问答所需的最小图谱"。具体做法是:

1. 先梳理业务场景,列出典型问题类型
2. 根据问题类型,确定需要哪些实体和关系
3. 只抽取对回答问题有贡献的三元组

我们最终建出的图谱包含三类实体:产品、模块、问题;三类关系:依赖、包含、解决。看起来简单,但覆盖了80%以上的问答场景。

这里有一个取舍:我们主动放弃了"概念"这种抽象实体。因为概念之间的关系很难定义,而且对问答帮助不大。图谱不是越大越好,而是要精准。

建模完成之后,我们用了Neo4j来存储。导入的时候注意两点:一是给节点和关系加上合理的标签,方便查询;二是建索引,否则查询性能会很差。

from neo4j import GraphDatabase class GraphBuilder: def __init__(self, uri, user, password): self.driver = GraphDatabase.driver(uri, auth=(user, password)) def create_schema(self): with self.driver.session() as session: # 创建约束,保证实体唯一性 session.run("CREATE CONSTRAINT FOR (p:Product) REQUIRE p.id IS UNIQUE") session.run("CREATE CONSTRAINT FOR (m:Module) REQUIRE m.id IS UNIQUE") session.run("CREATE CONSTRAINT FOR (q:Question) REQUIRE q.id IS UNIQUE") # 创建索引,加速查询 session.run("CREATE INDEX FOR (m:Module) ON (m.name)") session.run("CREATE INDEX FOR (p:Product) ON (p.name)") def create_relationship(self, source_type, source_id, target_type, target_id, rel_type): with self.driver.session() as session: session.run( f"MATCH (a:{source_type} {{id: $source_id}}), (b:{target_type} {{id: $target_id}}) " f"CREATE (a)-[r:{rel_type}]->(b) RETURN r", source_id=source_id, target_id=target_id )

---

实体关系抽取

抽取环节我们试过几个方案,最后选了LLM+规则的组合。

纯用LLM抽取的问题是不稳定,同一份文档抽两遍结果可能不一样。纯用规则又覆盖不了复杂场景。所以我们的策略是:用LLM做粗抽,用规则做精修。

具体流程:

1. 把文档分段,每段发给LLM,让它提取实体和关系
2. 用正则和词典做后处理,过滤明显错误的结果
3. 对实体做归一化,避免同义词导致的实体分裂

这里有个实际案例。文档里出现"API网关"和"网关",LLM会把它当成两个实体。我们用同义词词典做归一化,把它们合并成一个实体。

抽取prompt的设计也很关键。我们用的是这种格式:

请从以下文本中提取实体和关系,以JSON格式输出: 文本:{text} 要求: 1. 实体类型:Product, Module, Question 2. 关系类型:depends_on, contains, solves 3. 只提取与问答相关的内容 4. 输出格式:{"entities": [...], "relations": [...]}

注意最后一条要求,这是控制图谱规模的关键。我们一开始没加这条,LLM会把文档里的所有名词都当成实体,图谱瞬间膨胀。

---

图检索增强

这是GraphRAG的核心,也是和传统RAG最大的区别。

我们实现的图检索流程是这样的:

1. 用户提问后,先用LLM做意图理解,提取问题中的关键实体
2. 在图谱中定位这些实体
3. 沿关系遍历,找到相关子图
4. 把子图结构转化为文本,作为上下文喂给LLM

这里的关键是第3步:遍历多深?我们试过遍历两层和三层,发现两层效果更好。因为遍历太深会引入噪声,而且查询延迟也会增加。

def graph_query(graph_db, question_entities, hop=2): """在图谱中查询相关子图""" results = [] for entity in question_entities: # 查询实体的直接关系 query = f""" MATCH (e {{name: $entity}}) CALL {{ WITH e MATCH path = (e)-[*1..{hop}]->() RETURN path }} RETURN elements(path) as nodes """ result = graph_db.execute_query(query, entity=entity) results.extend(result) return results

检索到的子图需要转化为LLM能理解的文本。我们用的是邻接表格式,比如:

Product: API平台 - contains -> Module: 网关服务 - depends_on -> Module: 认证服务 - depends_on -> Module: 限流服务 - contains -> Module: 服务注册 - depends_on -> Module: 发现服务

这种格式保留了结构信息,LLM读起来比纯文本更清晰。

---

评估与优化

GraphRAG上线后,我们建立了一套评估体系。

指标主要有三个:

1. 检索准确率:图谱检索召回的相关子图是否覆盖问题所需信息
2. 回答准确率:LLM基于检索结果生成的答案是否正确
3. 端到端延迟:从用户提问到得到答案的总耗时

我们收集了200个真实问题作为测试集,分别用纯RAG和GraphRAG跑了一遍。结果:

  • 检索准确率:纯RAG 65%,GraphRAG 88%
  • 回答准确率:纯RAG 60%,GraphRAG 82%
  • 端到端延迟:纯RAG 1.2秒,GraphRAG 2.8秒

延迟增加是GraphRAG的代价,但换来的是准确率的显著提升。对于企业知识库这种场景,准确性比速度更重要。

优化方面,我们做了两件事:

一是缓存热点查询。同一个问题被多次提问时,直接返回缓存结果。

二是定期更新图谱。文档变更后,重新抽取实体关系,增量更新图谱。

---

总结

GraphRAG不是银弹,但它在处理复杂问答场景时确实有优势。我们的实践经历了几轮迭代,最终确定的方案是:

  • 建模要精准,不要大而全
  • 抽取要稳定,LLM加规则组合
  • 检索要可控,遍历深度有上限
  • 评估要持续,用真实问题验证效果

从Demo到团队协作,最大的挑战不是技术本身,而是如何在一个真实的业务场景中权衡各种因素。GraphRAG给了我们一个更好的答案质量,但也带来了更高的工程复杂度。值不值,取决于你的场景。

如果你的知识库问答涉及大量实体关系推理,GraphRAG值得尝试。如果只是简单的文档检索,传统RAG可能就够了。

资料展示

下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。

如果你想看完整资料目录,可以在评论区留言「资料」;也欢迎告诉我你更关注AI大模型里的哪类内容。

← 返回列表