GraphRAG:知识图谱增强检索的原理与实践——从实体抽取到图查询的完整链路

为什么向量检索撑不起「全局性」问题

GraphRAG 知识图谱增强检索的原理与实践

一个真实的问题场景

我们在给一家制造企业做内部知识库时,遇到一个看似平常的提问:「目前公司主要供应商的风险敞口集中在哪些领域?」。这个问题在向量检索面前几乎全军覆没——答案散落在几十份合同评审纪要、供应商年报和审计报告里,没有任何一个 chunk 的嵌入向量会与这句查询在语义上接近。每个 chunk 都只讲自己那家供应商的故事,而问题问的是全局的结构:哪些领域、集中度如何、风险何在。

这类问题有一个共同特征:答案不是某段文字,而是散布在语料中的实体与关系拼起来的整体图景。用户问的是「A 公司和 B 项目是什么关系」「这几个部门在哪些政策上立场冲突」「行业里的主要技术路线有哪几条、各自的拥趸是谁」。向量检索的每一跳都只能在「语义相似的段落」里打转,永远没有机会把这些散点连成一张网。

传统 RAG 社区对这类问题的标准答案曾经是「多检索一些,让模型自己总结」。实践里这条路很快撞墙:Top-K 取到 50、100 个 chunk,上下文塞满无关细节,模型的注意力被稀释,关键线索反而被淹没;而且无论取多少,取的都是「与查询相似」的段落,全局结构并不会因为多取几段而浮现出来。

向量检索的结构性盲区

把向量检索的失效模式拆开看,有两类问题是结构性的:

第一类是跨文档的实体关系问题。「张三和李四共同参与过哪些项目」这样的查询,答案分布在他俩各自出现的所有段落里。嵌入模型对「张三」这个词本身的语义并不敏感——嵌入捕捉的是上下文主题相似度,而不是实体的身份等价。不同文档里「张三」「张某」「张总」三个写法在向量空间里可能相距甚远,检索系统根本没有把它们当成同一个人。

第二类是全局主题归纳问题。「这批文档讨论的主要争议点是什么」需要对整个语料做归纳。向量检索的检索单元是段落,全局归纳的单元是语料全集——粒度错配。你可以把所有段落塞给模型做归纳,但语料一旦超过几百份文档,这个方案的成本和效果都不成立了。

微软研究院 2024 年提出的 GraphRAG(Edge 等,论文《From Local to Global: A GraphRAG Approach to Query-Focused Summarization》)正是冲着这两类问题去的。它的核心思想一句话可以说完:用一次性的离线索引成本,把语料中的实体、关系和主题结构显式提炼成一张图,查询时按问题的类型走不同的图查询路径。索引贵,但查询时可以便宜且准。

GraphRAG 的完整链路:从文档到知识图谱

GraphRAG 的流水线可以分为四个阶段:实体与关系抽取、图谱清洗消歧、社区检测、社区摘要生成。每一步都有工程上的坑,我们逐一拆解。

flowchart TD
    A["原始文档"] --> B["LLM 实体/关系抽取"]
    B --> C["图谱清洗与实体消歧"]
    C --> D["知识图谱"]
    D --> E["Leiden 社区检测"]
    E --> F["逐层社区摘要"]
    F --> G["Local Search:实体邻域检索"]
    F --> H["Global Search:社区摘要 Map-Reduce"]
    D --> G

实体与关系抽取

抽取是整条链路的根基,也是成本大头。GraphRAG 原论文的做法是用 LLM 对每个文本块跑一次结构化抽取,产出三元组形式的实体列表和关系列表。微软官方实现(graphrag 库)的抽取提示词要求模型输出 JSON,包含实体名、类型、描述,以及关系(源实体、目标实体、关系描述、强度评分)。

工程上有几个直接影响质量的细节:

多轮抽取(gleaning)。LLM 单次抽取的召回率并不高,尤其是嵌在长段落里的隐式关系。GraphRAG 的做法是让模型对同一文本做第二轮、第三轮「补充抽取」,每轮显式提示「上一轮漏掉了什么」。实测开启两轮 gleaning,实体召回能提升明显,但 token 成本接近翻倍。我们的取舍是:高价值语料(年报、合同)开两轮,普通文档开一轮。

切块粒度影响抽取质量。抽取用的 chunk 不能沿用检索用的切分——检索 chunk 追求语义独立,抽取 chunk 更希望保留上下文连贯。GraphRAG 默认用 1200 token 的较大块做抽取,就是为了给实体识别留足上下文。同一个实体在不同块里被抽到,靠后面的消歧合并。

类型体系要收窄。让模型自由发挥实体类型,你会得到「组织」「机构」「公司」「法人实体」四种同义类型。上线前必须固定一个封闭的类型枚举(人物、组织、地点、产品、事件、政策等),在提示词里明确列出,并且给出边界定义。类型体系的宽窄直接影响后面社区检测的语义纯度。

图谱的清洗与消歧

LLM 抽出的图是脏的。同名不同指(两个「华为」:一个是公司、一个是人名)和异名同指(「OpenAI」「OpenAI 公司」「OpenAI, Inc.」)都会出现。消歧没有银弹,工程上的组合拳是:

  • 名字归一化:大小写、标点、常见后缀(Inc、Ltd、公司)的规范化合并,规则可解释、成本低,处理掉大部分异名同指。
  • 嵌入聚类辅助:对实体名和描述做嵌入,高相似度的候选对交给 LLM 做最终裁决(「这两条记录是同一实体吗」)。这一步贵,只对候选对跑。
  • 人工审核高价值实体:财务、合规场景里,对度数最高的头部实体(出现在大量关系里的核心节点)抽检一遍,性价比极高——头部实体决定图的主干结构。

另一个常被忽视的步骤是给每个实体挂上来源:出现在哪些文档、哪些段落。这不只是为了溯源引用,更是后面查询时回原文取证的通道——图谱负责找到路,原文负责给出证据。

社区检测与分层摘要

图谱建好之后,GraphRAG 最有辨识度的一步来了:用 Leiden 算法(Traag 等,2019)在图上做社区检测,把连接紧密的实体聚成一簇一簇的社区。Leiden 是模块度优化的改进版算法,比经典的 Louvain 更稳(能避免社区内部不连通的问题),NetworkX 和 igraph 里都有现成实现。

社区划分天然是分层的:Leiden 的每一轮迭代会把大社区切成更小的子社区,GraphRAG 保留了这个层次结构。然后对每个社区,让 LLM 阅读该社区全部实体与关系的文本化描述,生成一份社区摘要。大社区有大摘要,子社区有小摘要——这棵摘要树是后面 Global Search 的弹药库。

这一步的设计妙处在于:社区是数据驱动的主题聚类,而不是人为预设的分类体系。语料自己会告诉你它包含哪些主题社区,摘要则把每个主题的「集体观点」压缩成几千字。全局性问题的答案,就在这些摘要里。

Local Search:实体锚定的邻域检索

局部性查询(「A 公司和 B 项目是什么关系」)走 Local Search,流程是:先从查询中识别出目标实体(可以用轻量的实体链接:嵌入匹配 + 精确匹配兜底),然后在图上取该实体的邻域——直接关系、二度关系、实体所在社区的相关摘要——按相关性重排后塞进上下文,交给 LLM 生成答案。

邻域检索的好处是召回的上下文结构化程度极高:进上下文的不是一堆主题沾边的段落,而是一个以实体为中心的关系网,每条关系自带描述和来源。模型要做的工作从「在一堆文本里找关系」退化成「读懂一张已经画好的关系图」,幻觉率自然下降。

Local Search 的薄弱点在实体链接环节:查询里的实体叫法和图里的名字对不上(缩写、别名、错别字)时,整个查询就哑火了。工程上必须做别名表 + 模糊匹配 + 澄清反问的三层兜底,宁可反问用户「你说的是哪个 XX」,也不要静默地锚定到错误实体上。

Global Search:社区摘要的 Map-Reduce

全局性查询(「主要争议点是什么」「技术路线有哪几条」)走 Global Search:把查询连同每个社区摘要一起过一遍,让 LLM 从每份摘要里抽取与查询相关的要点(Map 阶段),再把所有要点汇总成最终答案(Reduce 阶段)。

关键的成本优化在于分层:社区摘要树有大有小,先在高层级(少量大摘要)做 Map-Reduce,答案粒度不够时再下钻到子社区。一份语料有一百个叶子社区,但顶层可能只有七八个大社区——顶层走一遍的成本只有叶子层的十分之一。

LightRAG(2024 年,港大团队)在这条路上做了简化:它把图检索和向量检索直接融合成「双层检索」(实体层 + 关系层),省掉了昂贵的社区摘要构建,在部分基准上以低得多的索引成本拿到接近的效果。这个方向值得跟进,但我们的实测感受是:LightRAG 在纯事实查询上不吃亏,而在「总结全局争议」这类需要真正归纳的问题上,社区摘要的归纳质量仍然更好。两种方案的取舍本质是「索引时贵」与「查询时糙」之间的再平衡。

工程实践:成本、增量与图谱维护

索引成本的真实账

GraphRAG 的索引成本是「每篇文档过 2-3 次 LLM」量级:抽取(含 gleaning)、社区摘要、可能的消歧裁决。以官方库在播客数据集上的公开基准做参考,一千个文本块的索引大约消耗百万级 token。用便宜的模型(如 glm-5.3-flash 这类轻量模型)跑抽取、把贵模型留给摘要生成,可以把成本压到三分之一左右,代价是抽取召回略降——实测这个代价用 gleaning 补回来是划算的。

所以 GraphRAG 的适用性判断,本质是一道 ROI 题:语料是否稳定、查询中全局性问题的占比是否值得这笔一次性成本。语料天天变、问题全是「XX 系统怎么配置」这类局部查询的场景,GraphRAG 是负资产。

增量更新与图合并

增量更新是 GraphRAG 生产化最疼的环节。新增文档会引入新实体和新关系,但社区检测是全图算法——新节点加入后,社区划分和所有社区摘要理论上都要重算。全量重跑显然不经济,工程上的折中方案:

  • 局部增量:新文档的实体先合并进图,只在受影响的社区内重新检测和重新生成摘要。受影响社区的判定用「新实体的邻居所在的社区」近似,绝大多数增量只波及一两个社区。
  • 定期全量:低峰期(比如每月)全量重跑一次社区检测,纠正增量过程中积累的偏差。
  • 版本化:图和摘要都带版本号,查询层可以灰度切换新旧索引,避免更新期间查询抖动。

什么场景该上 GraphRAG

总结我们的落地经验,GraphRAG 值得投入的信号:语料是「实体密集型」的(人物、组织、项目、事件反复出现);查询日志里全局归纳类问题占比超过两成;语料更新频率是周级或更低。三个信号占齐两个,就可以认真评估。反面信号同样明确:语料是流水式新闻(时效性强、实体关系浅)、查询以操作手册式问题为主——这些场景,把 GraphRAG 的预算花在提升解析质量和重排上,收益大得多。

还有一条务实建议:GraphRAG 不是替代向量检索,而是叠加。生产系统里保留向量混合检索处理大量日常查询,图查询路径只承接被路由器识别出的实体关系类和全局归纳类问题。让每种检索方式干它最擅长的事,才是这套架构的正确打开方式。

小结

GraphRAG 解决的是向量检索的两个结构性盲区:跨文档实体关系问题和全局主题归纳问题。它的完整链路是「LLM 抽取实体与关系 → 清洗消歧 → Leiden 社区检测 → 分层社区摘要」,查询时按问题类型走 Local Search(实体邻域)或 Global Search(社区摘要 Map-Reduce)。

它不是免费的:索引成本是普通 RAG 的数倍,增量更新需要精心的工程设计,实体消歧是决定图质量的隐形地基。落地判断只需要回答一个问题——你的查询里,「需要把散落的点连成线」的问题占比有多高。占比高,GraphRAG 是目前工程上最成熟的答案;占比低,省下这笔钱去打磨解析与重排。

← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?