如果文章中有不准确的地方,欢迎留言指正。
1 说明#
- 知识图谱 用结构化方式表达知识中的实体和关系
- RAG 从外部知识中检索相关内容,补充给大模型回答
- GraphRAG 可以理解为在 RAG 中引入图结构,让检索不只依赖文本相似度,也能利用实体关系和全局结构
- Neo4j 是一种图数据库,可以存储实体、关系和社区等图结构,让后续查询可以沿着节点和关系扩展上下文
普通 RAG 已经能解决很多知识问答问题,但它更擅长的是“从文档里找相关片段”。
如果问题涉及多个实体之间的关系,或者需要从整批文档中总结主题,单纯依赖向量相似度就不一定够用。
GraphRAG 要解决的正是这类问题:先把文本中的实体和关系抽取出来,构建知识图谱,再在查询时结合图结构、社区摘要和原文证据生成答案。
2 知识图谱#
知识图谱的核心不是“图”这个形式本身,而是用结构化方式表达知识。
2.1 实体#
实体是知识图谱中的节点,可以是人、组织、地点、概念、事件、产品等。
例如:
GraphRAG知识图谱向量数据库MicrosoftNeo4j
在文本中,这些实体往往分散在不同段落甚至不同文档里。
如果只把文档看成一组 chunk,这些实体之间的联系就需要在查询时临时推断。
2.2 关系#
关系描述实体之间的连接。
例如:
GraphRAG - 使用 - 知识图谱
RAG - 依赖 - 向量检索
知识图谱 - 包含 - 实体关系
Neo4j - 存储 - 图数据关系的价值在于,它把文本中原本隐含的信息显式表达出来。
当这些关系被保存下来之后,后续检索就不只是“找相似文本”,还可以沿着实体之间的连接继续扩展。
2.3 三元组#
知识图谱里常见的表达方式是三元组:
头实体 - 关系 - 尾实体例如:
GraphRAG - 结合 - RAG
GraphRAG - 引入 - 图结构
实体 - 通过 - 关系连接
社区检测 - 用于 - 发现实体群组三元组看起来很简单,但它能把一段自然语言拆成可以计算、可以查询、可以扩展的结构。
2.4 实体提及和实体消歧#
文本里出现的一次实体名称,可以理解为一次实体提及。
例如:
LLM
Large Language Model
大语言模型这三个说法在不同上下文里可能指向同一个实体。
如果构建图谱时把它们当成三个完全不同的节点,图谱就会被拆散,后续关系查询也会变得不准确。
实体消歧要解决的就是这个问题:判断不同提及是否指向同一个真实实体,并尽量把它们合并到统一节点上。
2.5 邻居节点#
在图里,和某个节点直接相连的节点,就是它的邻居节点。
例如:
GraphRAG
-> RAG
-> 知识图谱
-> 社区摘要
-> 向量检索这些节点都可以看作 GraphRAG 的一跳邻居。
在 GraphRAG 的 Local Search 中,常见做法就是先命中一个种子实体,再沿着它的邻居节点扩展上下文。
2.6 多跳关系#
有些实体之间没有直接关系,但可以通过中间节点连接起来。
例如:
GraphRAG -> 知识图谱 -> Neo4j -> 图数据库这种路径就是多跳关系。
它的价值在于,可以帮助系统发现间接关联,而不是只能依赖两个实体是否同时出现在同一个文本片段里。
2.7 子图#
真实的知识图谱可能很大,查询时通常不会把整张图都交给模型。
更常见的做法是,围绕问题相关的实体和关系截取一小部分图,这部分图可以理解为子图。
例如用户问 GraphRAG 和知识图谱有什么关系,系统只需要取出和这两个实体相关的邻居、关系和原文证据,而不需要遍历整张图。
子图的作用,是在信息量和相关性之间做平衡:
既保留图结构,又避免把无关节点塞进上下文。
2.8 社区发现#
社区发现是图分析中的一个重要概念。
如果一组节点之间连接很密集,而它们和外部节点的连接相对较少,就可以认为它们形成了一个社区。
在知识图谱里,一个社区往往对应某个主题、事件或实体群组。
例如:
社区 A:RAG、向量数据库、Embedding、chunk
社区 B:知识图谱、实体、关系、Neo4j
社区 C:社区发现、社区摘要、Global Search社区发现的作用,是把一张大图拆成更容易理解的主题块。
GraphRAG 之所以能处理全局性问题,很大程度上就依赖这一步。
2.9 社区摘要#
社区发现只是完成了分组,分组本身还不能直接回答问题。
所以 GraphRAG 通常还会为每个社区生成摘要。
社区摘要可以包含:
- 这个社区的主题
- 关键实体
- 关键关系
- 主要事实
- 这组实体共同表达的含义
有了社区摘要,系统在回答全局问题时,就不需要临时扫描所有原文。
它可以先判断哪些社区摘要和问题相关,再把相关社区的信息综合起来。
这也是 Global Search 的基础:
先基于社区摘要做全局聚合,再让模型生成最终答案。
2.10 知识图谱解决什么问题#
知识图谱比较适合表达这些信息:
- 实体之间的直接关系
- 多跳关系
- 跨文档出现的同一实体
- 一组实体形成的主题或社区
它不直接替代文本,而是给文本增加了一层结构。
文本负责保留上下文和细节,图谱负责保存实体之间的连接。
3 RAG#
RAG 是 Retrieval-Augmented Generation,也就是检索增强生成。
3.1 普通 RAG 的流程#
普通 RAG 一般会这样工作:
- 把文档切成 chunk
- 对 chunk 做 embedding
- 把向量写入向量数据库
- 用户提问时,对问题做 embedding
- 从向量数据库中召回 top-k 片段
- 把召回片段交给 LLM 生成答案
这个流程的重点是:把大模型不知道的外部知识,通过检索的方式补充进上下文。
3.2 普通 RAG 擅长什么#
普通 RAG 比较适合局部事实问答。
例如:
- 某个概念是什么意思
- 某段文档里提到了什么
- 某个配置项怎么使用
- 某个问题的直接答案是什么
这类问题通常能在少量相关 chunk 中找到答案。
只要召回质量足够好,LLM 就可以基于这些片段生成比较可靠的回答。
3.3 普通 RAG 的局限#
普通 RAG 的核心依据是向量相似度。
它擅长找到语义相近的文本片段,但不天然擅长处理关系结构。
所以在这些场景里会比较吃力:
- 多个实体之间存在间接关系
- 答案分散在多个 chunk 中
- 问题需要全局总结
- 需要解释一批文档的整体主题
问题不在于向量检索没有价值,而在于它默认把知识组织成“文本片段集合”。
当问题本身更像是在问“这些实体之间有什么关系”时,就需要额外的结构来辅助检索。
4 GraphRAG#
GraphRAG 可以理解为:在普通 RAG 的基础上,引入知识图谱和图分析能力。
4.1 核心思路#
普通 RAG 主要在查询时做检索。
GraphRAG 会把一部分理解和聚合工作提前到索引阶段。
典型流程是:
- 从文档中抽取实体
- 抽取实体之间的关系
- 构建知识图谱
- 对图谱做社区检测
- 为社区生成摘要
- 查询时结合实体、关系、社区摘要和原文证据回答问题
这里最关键的变化,是 GraphRAG 不只索引文本,还会索引文本背后的结构。
4.2 和普通 RAG 的区别#
普通 RAG 更像是在问:
哪些文本片段和这个问题最相似?
GraphRAG 更进一步,会问:
问题涉及哪些实体?
这些实体之间有什么关系?
它们属于哪个主题社区?
相关社区能提供什么全局背景?
所以 GraphRAG 并不是简单地把向量数据库换成图数据库,而是把检索对象扩展了。
普通 RAG 主要检索:
- 文本片段
GraphRAG 还会利用:
- 实体
- 关系
- 邻居节点
- 社区摘要
- 原文证据
4.3 为什么需要社区摘要#
在图谱中,关系密集的一组实体通常可以形成一个社区。
社区可以理解为一组主题上更接近、连接上更紧密的实体集合。
对社区生成摘要之后,查询全局问题时就不需要临时扫描所有原文。
系统可以先看每个社区摘要和问题是否相关,再把相关社区的部分答案合并起来。
这也是 GraphRAG 和普通 RAG 差异比较明显的地方:
普通 RAG 更偏向局部召回,GraphRAG 可以通过社区摘要支持更强的全局聚合。
5 查询方式#
GraphRAG 中常见的查询方式可以分成 Local Search、Global Search 和 DRIFT Search。
实际使用时,可以先判断问题类型,再选择对应的查询方式。
如果问题围绕具体实体或实体关系,更适合 Local Search;如果问题关注整体主题或全局总结,更适合 Global Search。
5.1 Local Search#
Local Search 适合回答和具体实体相关的问题。
例如:
- A 是谁
- A 和 B 是什么关系
- 某个实体关联了哪些事件
它通常会从实体出发,查找实体邻居、关系和相关原文。
这种方式的重点不是全局总结,而是围绕一个或几个实体展开上下文。
大致流程:
问题
↓ embedding → 实体向量库检索 top-K 实体
↓ 对每个实体拉 1~2 跳邻居 + 相关三元组
↓ 查实体所属社区摘要作为背景补充
↓ 根据三元组里的 chunk_id 反查原文 chunk
↓ 组装“实体 + 关系 + 社区报告 + 原文”上下文
↓ LLM 基于上下文生成答案5.2 Global Search#
Global Search 适合回答全局性问题。
例如:
- 这批文档的核心主题是什么
- 整体上有哪些关键矛盾
- 不同社区分别在讲什么
它通常依赖预先生成的社区摘要。
查询时,系统会先判断各个社区摘要对问题的贡献,再综合相关社区的信息生成最终答案。
这种方式更适合“看整体”的问题,而不是只查某一个实体的细节。
大致流程:
问题
↓ 读取所有社区报告
↓ Map:LLM 对每份社区报告打相关度分数 + 生成 partial_answer(局部答案)
↓ 过滤 score < GLOBAL_MIN_SCORE 的低相关社区报告
↓ 按 score 排序,选出高相关 partial_answer
↓ Reduce:LLM 综合这些 partial_answer
↓ 生成全局答案5.3 DRIFT Search#
DRIFT Search 介于 Local Search 和 Global Search 之间。
它可以先获得一个全局视角,再根据全局答案里的关键实体继续深入局部细节。
可以简单理解为:
问题
↓ Global Search 生成全局视角的初步答案
↓ LLM 从初步答案中抽取 2~4 个关键实体
↓ “关键实体 + 原问题”embedding → 实体向量库检索候选实体
↓ 对匹配到的关键实体拉邻居 + 相关三元组
↓ 组装关键实体的局部细节
↓ LLM 综合“全局答案 + 局部细节”生成最终答案如果问题既需要全局判断,又需要具体实体支撑,DRIFT Search 会比单纯 Local 或 Global 更自然。
6 GraphRAG 的几种接入方式#
GraphRAG 不是一种固定写法。
根据图谱参与的位置不同,它可以有几种不同的接入方式,大致可以分成三类:
- 图谱作为"上下文补充器":6.1、6.2、6.3。在传统 RAG 链路里引入图谱,区别在于图谱介入的深度
- 图谱作为"全局视角的载体":6.4。通过社区摘要支持全局聚合类问题,是 Microsoft GraphRAG 的核心特性
- 图谱作为"Agent 的工具":6.5。把图谱查询和向量检索一起当作工具交给模型自主调用
实际系统里这几种方式可以组合使用,并不是互斥的选择。
6.1 图谱只补充上下文#
最轻量的方式,是先按普通 RAG 召回文本,再根据召回文本反查图谱关系。
问题 -> 向量检索 -> chunks -> 反查实体和关系 -> chunks + triples -> LLM这种方式里,图谱不参与召回排序,只负责补充结构化上下文。
它适合在已有 RAG 系统上做渐进增强,改动比较小。
6.2 图谱参与召回#
更进一步,可以让图谱直接参与召回。
问题 -> 抽实体 -> 实体链接 -> 图谱遍历 -> triples -> 反查 chunks -> LLM这里的"实体链接"是把 LLM 抽出来的实体名字对齐到图谱里真实存在的节点。
例如 LLM 抽出 GraphRAG,图谱里可能存的是 Graph RAG 或 图检索增强生成,需要做一次对齐。
常见做法是:精确匹配 -> 别名匹配 -> 向量相似度兜底。
这种方式适合实体关系比较明确的问题,例如:
GraphRAG 和 Neo4j 有什么关系?系统可以先识别出 GraphRAG 和 Neo4j,再沿着图谱查找它们之间的关系、邻居节点和证据来源。
6.3 图谱参与重排#
图谱也可以不直接进入上下文,而是参与 chunk 排序。
问题 -> 向量 / BM25 召回 chunks
chunks -> 映射实体
根据实体距离、路径关系、社区归属重新打分
重排 chunks -> LLM具体打分可以做得很简单,例如:
- chunk 中提到的实体,在图谱中距离种子实体的最短跳数越小,加分越高
- chunk 中涉及的多个实体属于同一社区,加分
- chunk 中涉及的实体之间存在直接关系,加分
这种方式的好处是对原有 RAG 链路影响较小。
图谱只负责告诉系统哪些 chunk 和核心实体更相关,最终给 LLM 的仍然主要是文本证据。
Rerank 看文本相关性,图谱重排看结构相关性。
6.4 社区摘要支持全局检索#
如果问题偏全局总结,就可以使用社区摘要。
文档 -> 抽实体关系 -> 构图 -> 社区发现 -> 社区摘要
问题 -> 社区摘要评分 -> 聚合相关社区 -> LLM这里"评分 + 聚合"的具体执行方式是典型的 Map-Reduce:
- Map:对每一个社区摘要单独调用 LLM,让它判断这份摘要和问题的相关度,并写出能贡献的部分答案
- Reduce:把高分的部分答案合并起来,再让 LLM 综合生成最终答案
这种方式适合回答:
- 这批文档的核心主题是什么
- 不同实体群体之间有哪些主要关系
- 整体上有哪些关键发现
它的重点不是查某个实体的一跳邻居,而是利用社区摘要获得全局视角。
需要注意的是,社区摘要不仅服务于 Global Search。
Local Search 也会把种子实体所属社区的摘要作为背景信息一并放进上下文,让模型在回答具体问题时仍然能看到全局结构。
6.5 Agent 调用图谱工具#
还有一种更灵活的方式,是把图谱查询、向量检索、关键词检索都作为工具交给 Agent。
问题 -> Agent 判断下一步
-> 调用向量检索
-> 调用图谱查询
-> 调用关键词检索
-> 汇总答案这种方式适合复杂分析任务,但成本和稳定性也更难控制。
LLM 自己决定何时调用、调用哪个工具、调几次,对模型的指令遵循和工具使用能力要求较高。
工程上还要在编排层加上步数上限、循环检测、错误兜底等保护,避免 Agent 卡在工具调用循环里。
7 Local Search 示例#
完整代码:Yu-Yantao/GraphRAG。
7.1 入库阶段#
Local Search 能跑起来,前提是入库时已经做好两件事:
- 把 chunk 里的实体和关系抽出来,建立图谱
- 把所有实体向量化,建立实体向量库
入库流程:
flowchart TD
Doc["Markdown 文档"]
Doc --> Split["切分 chunks"]
Split --> Chunks["chunks"]
Chunks --> ChunkEmbed["chunks 向量化"]
ChunkEmbed --> ChromaC[("Chroma
chunks 向量库")]
Chunks --> Extract["LLM 抽实体和关系"]
Extract --> Graph[("Neo4j
图谱: Entity + RELATED_TO")]
Graph --> Louvain["Louvain 社区检测"]
Louvain --> CommunitySum["LLM 生成社区摘要"]
CommunitySum --> Community[("Neo4j
Community 节点")]
Graph --> EntityEmbed["实体向量化
(name + type)"]
EntityEmbed --> ChromaE[("Chroma
实体向量库")]
第 2 步的实体向量库是查询阶段的入口。
它把所有实体的 name + type 做 embedding 存进向量库,相当于把每个实体变成一个可被相似度检索的向量。
7.2 查询阶段#
查询时的流程:
flowchart TD Q["问题"] Q --> Embed["问题向量化"] Embed --> Search["实体向量库检索
top-k 种子实体"] Search --> Seeds["种子实体"] Seeds --> Walk["图谱 N 跳遍历"] Walk --> Triples["相关三元组"] Triples --> Reverse["按 chunk_id
反查原文 chunks"] Seeds --> CommunityRead["读取所属社区报告"] Seeds --> CTX["context"] Triples --> CTX Reverse --> CTX CommunityRead --> CTX CTX --> LLM["LLM 生成答案"]
注意流程里没有"LLM 抽问题实体 + 实体链接"那两步。
入库时已经把所有实体向量化了,查询时直接用问题向量在实体库里做相似度检索,就能找到种子实体。
这等价于"LLM 抽实体 + 实体链接"两步合并,但只需要一次 embedding 调用,比 LLM 推理便宜得多,也天然处理了"陆 CTO"、“那个搞 NebulaCore 的人"这种说法模糊的问题。
例如用户问:
陆向晚是谁?问题向量化后,在实体向量库里命中:
陆向晚 (人物) ← 余弦相似度最高
林夏 (人物)
周屿 (人物)这几个就是种子实体。
后续沿着每个种子在图谱里做 N 跳遍历,得到相关三元组,再按三元组里的 chunk_id 反查回原文。
N 通常取 1 或 2。N=3 之后容易触发邻居爆炸,反而把无关信息塞进上下文。
7.3 最终上下文#
最终给 LLM 的 context 由四部分组成:
- 种子实体与邻居:种子实体及其类型、所属社区、一跳邻居
- 实体间关系:种子实体相关的三元组
- 相关社区背景:种子实体所属社区的摘要
- 原文证据:三元组涉及的原文 chunk
一个具体的上下文长这样:
【种子实体与邻居】
1. 陆向晚 (人物) [community=0]
邻居: 林夏, 周屿, 星海科技, NebulaCore, 墨弦科技
【实体间关系】
1. 陆向晚 -[co_founded]-> 星海科技
证据: 由林夏、陆向晚、周屿三人在杭州联合创办
2. 陆向晚 -[serves_as]-> CTO
3. 陆向晚 -[creates]-> NebulaCore
4. 陆向晚 -[leaves]-> 星海科技
【相关社区背景】
1. 星海核心团队 (cid=0)
摘要: 这个社区由星海科技的三位创始人和早期产品构成...
关键点:
- 林夏、陆向晚、周屿三人共同创立星海科技
- 陆向晚是 NebulaCore 的核心设计者
- 陆向晚在 2023 年离开公司创办墨弦科技
【原文证据】
chunk_3:
星海科技成立于 2018 年春天,由林夏、陆向晚、周屿三人在杭州联合创办...这种结构的好处是,LLM 不只看到原文片段,也能看到结构化关系,还能拿到社区层面的全局背景。
每条关系都能在原文里找到出处,避免变成孤立断言。
8 适用场景#
GraphRAG 并不是所有场景都比普通 RAG 更合适。
8.1 适合使用 GraphRAG 的场景#
- 文档里有大量实体和关系
- 需要跨文档分析
- 经常需要全局总结
- 问题涉及多跳关系
- 希望回答时能解释实体之间的联系
这类场景中,问题本身通常不只是“哪段文本最相关”,而是“这些信息之间如何组织”。
8.2 不太适合使用 GraphRAG 的场景#
- 简单 FAQ
- 文档规模很小
- 问题大多是局部事实查询
- 数据更新非常频繁,重建图谱成本过高
如果普通 RAG 已经能稳定召回答案,就没有必要为了引入图结构而增加额外复杂度。
