朴素 RAG(Retrieval-Augmented Generation)的做法很简单:把语料切成块、每块过 embedding 模型、建 ANN 索引,查询时按向量相似度找 Top-k、拼进 prompt 交给 LLM。这套管线在”事实在单块文档内、问题在语义上和答案直接相近”的场景里表现不错。但只要问题涉及多跳推理、跨文档关联、或者需要基于全局语料结构回答(“这份材料里有几条关于 X 的主要观点”),向量 RAG 就会明显掉队。
Microsoft Research 2024 年公开的 GraphRAG(Edge et al., arXiv:2404.16130)正面回应这个问题。它在原有 RAG 管线之外额外构建了一张知识图(Knowledge Graph),并用社区检测(Community Detection)把图切成层级化的社区、为每个社区预生成摘要报告。查询时不再只是拿相似块,而是结合图的拓扑结构做全局问答。
本文上半部分讲清楚:为什么单靠向量检索在多跳和全局问题上失败;图结构作为 evidence path 为什么更合适;GraphRAG 的抽取、索引、查询三段式管线;社区检测与 community report 生成的关键设计点。下半部分给出 Neo4j、NebulaGraph、KuzuDB 三类图存储的工程差异,以及一个基于 NetworkX 的 50 行最小 GraphRAG 原型(从 markdown 抽 triple → 建图 → 查询)。
系列上一篇 向量与标量的混合过滤检索 处理的是”向量 + 结构化过滤”;本文处理”向量 + 图结构”,两者在工程上正逐渐融合进同一个”多模态数据库”话语下,见 多模态数据库 。
一、为什么 RAG 需要图
回顾:RAG
的工程前提。传统检索增强生成(Retrieval-Augmented
Generation,
RAG)有一个朴素前提:把文档切块(chunking),每块算
embedding 存向量库,用户问题也算 embedding,取 top-k 块塞进
prompt 让 LLM
回答。这个流水线在单一文档的单一事实查询下很有效(“Python 里
dict.get
的默认值是什么?”),但在多跳问答和需要全局综合的问题上经常失败,这正是
GraphRAG 提出的背景。GraphRAG 并不是要替代向量
RAG,而是在向量之上引入结构化的证据路径,让 LLM
拿到的上下文不再是”k 个孤立的块”而是”一张有连接的小图”。
1.1 向量 RAG 的三类典型失效
记检索单元为 chunk,查询为 \(q\),LLM 回答函数为 \(g(\text{prompt})\)。向量 RAG 的响应是 \(g(q \oplus \text{top-k chunks by cosine}(q, c))\)。这个范式在下面三类问题上会退化:
A. 多跳推理(multi-hop QA)。问”X 的博士导师的合作者里谁拿过图灵奖?“,答案的支持证据可能分散在三篇不相关的文档里。向量检索返回的 Top-k 基本只围绕 X 本人,中间环节的文档根本没机会被召回。
B. 全局问答(global QA)。问”这份 500 页报告的主要主题有哪些?“,答案需要对全语料的结构有概览,不是任何一个 chunk 能直接回答的。这种”summarization-style”的问题,向量 RAG 连合适的 chunk 都找不出来。
C. 关系敏感查询。问”谁在 2023 年从 A 公司跳槽到 B 公司?“,这是一个关系谓词,语义上和”跳槽”词面相关的 chunk 未必包含 A 和 B 的实际关系。
根源在于:向量相似度是”语义邻近”,但回答多跳问题需要的是”结构可达”。这两者在嵌入空间里没有稳定的映射关系。
1.2 图作为 evidence path
把实体(Entity)作为节点、关系(Relation)作为边,文本语料就被投影成一张属性图。多跳查询在图上是一个 \(k\)-hop 路径搜索,全局查询是一个社区划分或中心性分析,关系查询是一次边的模式匹配——这些在图上都是被充分研究过的操作。
“evidence path”(证据路径)的概念意味着:回答不再只是把相似 chunk 扔给 LLM,而是先在图上找到一条或多条连接查询中涉及实体的路径,再把路径上的节点、边、源文档一起拼进 prompt。LLM 不仅拿到了相关文本,还拿到了文本之间的结构关系。这是 GraphRAG 相对向量 RAG 的核心价值来源。
1.3 与 Knowledge Graph 问答的区别
GraphRAG 并不是传统 KBQA(Knowledge Base Question Answering)的简单复活。KBQA 通常面向人工构建的高精度知识库(Freebase、DBpedia),而 GraphRAG 的图是从语料里自动抽取出来的——质量参差、实体歧义、关系稀疏。它的实用哲学是:“LLM 既是图的构造者,又是图的消费者”:抽取 triple 用 LLM,生成社区报告用 LLM,最终回答也用 LLM。图只是结构支撑,不追求 Schema 级别的严谨。
二、Microsoft GraphRAG 的三段式管线
2.1 阶段一:索引构建(Indexing)
从原始语料到图 + 报告的离线过程:
Docs → Chunks → (LLM) Entity/Relation Extraction
↓
Entity merge & canonicalization
↓
Knowledge Graph G
↓
Community Detection (Leiden)
↓
Hierarchical Communities C₀ ⊂ C₁ ⊂ C₂
↓
(LLM) Community Report Generation
↓
Final Index: G + Reports + Chunks
Entity/Relation Extraction。每个 chunk
过一轮 LLM,用提示词(prompt)抽出
(subject, relation, object, description)
四元组。关键细节:
- 提示词里显式指定抽取的实体类型列表(person、organization、location、…)。开放抽取的召回高但噪音也高。
- 同一 chunk 允许抽多个 triple,关系文本保留为自然语言而不是硬编码标签——这让后续可读性更好,代价是同义关系不能直接等同。
- 抽取时顺带生成每个实体和关系的自然语言描述(description),为后续 community report 提供素材。
Entity merge / canonicalization。同一实体在不同 chunk 里可能被写成不同字符串(“OpenAI” / “Open AI Inc.” / “该公司”)。GraphRAG 使用 embedding + 字符串相似度做粗合并,再用 LLM 做最终裁决。这一步是 recall 与 precision 的平衡点:合并过多会把不同实体混成一个,合并过少图会被同义节点稀释。
2.2 阶段二:社区检测与层级摘要
图构造好后,用 Leiden 算法(Traag et al., 2019)做社区检测。Leiden 是 Louvain 算法的改进版本,优化目标相同(最大化模块度 modularity \(Q\)),但 Leiden 保证了每次迭代产生”良好连通”的社区(每个社区的子图自身也必须连通),收敛更稳定。
模块度的定义:
\[Q = \frac{1}{2m} \sum_{ij} \left[ A_{ij} - \frac{k_i k_j}{2m} \right] \delta(c_i, c_j)\]
\(A\) 是邻接矩阵,\(m\) 是边数,\(k_i\) 是节点度数,\(c_i\) 是节点所属社区。\(Q > 0\) 意味着社区内部的连接比随机图期望的更多。
GraphRAG 运行 Leiden 产生层级化社区:
Level 0: 最细粒度社区 (~数十节点 / 社区)
Level 1: 合并后的中粒度
Level 2: 粗粒度(可能只有少数几个大社区)
为每个社区,对其内部节点 + 边 + 原文描述做 LLM 摘要,生成 community report(结构化 JSON:社区主题、关键实体、关键关系、关键发现、重要性评分)。层级越高的 report 覆盖更广,层级越低越细。
2.3 阶段三:查询(Local vs Global)
GraphRAG 把查询分为两类:
Local Search。当问题围绕少数实体时,先用 embedding 找到查询中涉及的实体节点,在图上做 \(k\)-hop 扩展,收集邻居、邻居的 report 和相关 chunk 文本,组装成 context 给 LLM。
q → entity match → expand neighbors → gather chunks/reports → LLM
这是 multi-hop QA 的主场景。
Global Search。面对”这份资料主要讲什么”这类问题,枚举相关层级的所有 community reports(或按重要性挑选 Top-N),每个 report 产生一个局部答案,最后做 reduce 合成全局答案(Map-Reduce 风格)。
q → pick community level → for each report: LLM → partial answer
↓
merge → final
Global Search 的 LLM 调用次数和社区数成正比,延迟和成本显著高于 Local。工程上一般只对明确的全局类问题开启。
2.4 论文报告的效果
论文在 Podcast Transcripts、News Articles 两个数据集上做了评估,用 LLM-as-Judge 在 comprehensiveness(全面性)、diversity(多样性)、empowerment(赋能)三个维度上让评委比较 GraphRAG 与纯向量 RAG。GraphRAG 在 global 类查询上全面占优,在 local 类查询上也有不小提升。具体分数依赖 LLM 评委本身,作为”相对比较”参考而非绝对数字。
三、GraphRAG 的代价与开放问题
3.1 成本结构
GraphRAG 不是免费的。抽 triple 和生成 report 都要调 LLM,成本可观:
- 1 GB 语料 ≈ 10–20 M tokens;
- 每个 chunk 的 triple 抽取 prompt 按输入 1–2k、输出 500 tokens 估计;
- 每个社区的 report 按输入 5–10k、输出 1–2k 估计;
- 整体索引成本 \(\sim 5\times\)–\(20\times\) 朴素 RAG 的 embedding 成本。
这也决定了 GraphRAG 目前适合”语料相对静态、查询场景多样”的应用:研究报告问答、企业内部知识管理、法律/医学资料检索。对”每天万亿 tokens 流入”的互联网级场景,全量 GraphRAG 不现实;需要增量抽取和选择性重建。
3.2 抽取质量的传导
图的质量几乎决定了上限。实体合并过激会丢信息,合并不足会稀释图;关系抽取漏掉中间跳会让多跳失败。目前业界共识是:
- 提示词要针对领域定制;
- 抽取结果必须有人工采样核验;
- 对高价值实体维护 alias 表、人工矫正 canonicalization;
- 社区粒度与 LLM 上下文窗口强相关,新一代长上下文模型让 Level 提升成为可能。
3.3 开放问题
- 增量更新:新文档进来,是否必须重跑 Leiden?目前还没有成熟的增量社区检测算法能同时保证层级一致性。
- 图 + 向量的统一存储:是否把两者放进同一个后端?见第四节。
- Schema 漂移:抽取关系文本随模型版本变化,历史图与新图之间的关系语义未必可比。
- 评估:LLM-as-Judge 的可靠性本身存在争议,end-to-end 评估的基准仍不完善。
四、抽取提示词工程与 triple 质量
GraphRAG 的图构造高度依赖 LLM 抽取质量,这里的工程细节多到足以单独成文。几个关键实践。
4.1 提示词结构
Microsoft 官方实现的抽取 prompt 由几部分组成:
目标描述:明确告诉模型”从文本中抽取实体与关系”。
实体类型列表:如
[organization, person, geo, event]。限定类型能显著提升 precision,代价是固定了本体。抽取格式:用分隔符(常见是
<|>或 tuple_delimiter)分隔字段,避免 JSON 解析脆弱。格式例:("entity"<|>Alice<|>person<|>一位工程师) ("entity"<|>OpenAI<|>organization<|>一家 AI 公司) ("relationship"<|>Alice<|>OpenAI<|>Alice 在 OpenAI 工作<|>0.9)Few-shot 示例:2–3 条示例,和目标领域风格一致。
Gleaning(补抽):同一段文本问一次”是否还有遗漏的实体?“,循环 1–2 次,recall 显著提升。
4.2 实体合并(canonicalization)的三种做法
- 字符串规则:大小写、空格、词干化处理,适合领域词汇统一的场景。
- Embedding 聚类:对每个实体描述过 embedding,聚类后合并阈值以内的。需要调阈值,过高漏合并、过低误合并。
- LLM 裁决:对每对候选问 LLM “是否同一实体”。准确但 token 消耗大,一般只在高置信候选对上用。
实际系统往往三者叠加:先规则 + embedding 粗合并,再对”仍不确定”的少数对用 LLM 裁决。
4.3 关系合并
关系文本的同义比实体更难。“工作于”、“任职于”、“在…担任”可能指同一关系,但若完全统一为一个标签会丢信息。实践做法:不强行合并关系,保留原始文本;在查询阶段用 embedding 匹配相关关系文本。GraphRAG 官方实现就是这条路线。
4.4 抽取质量如何评估
没有 ground truth 的时候,常用代理指标:
- 实体密度:每 1000 tokens 抽出的实体数量。过低说明 prompt 太保守,过高(>20)多半是噪声。
- 重复率:同一实体在不同 chunk 被抽到的次数,反映 entity matching 机制是否生效。
- 图连通度:最大连通分量占比。若只有 20%,大多数实体是孤立的,说明关系抽取太弱。
人工采样 50–100 条 triple 做 precision 估计是基本功。工业级 GraphRAG 团队通常维护一个”标注金标”集合,用于回归评估提示词和模型变化。
五、社区检测与层级报告的工程细节
5.1 Leiden vs Louvain
Leiden 比 Louvain 主要的改进:
- 保证每次迭代后社区是”良好连通”(well-connected)——社区子图本身连通。Louvain 可能产生非连通社区(奇怪的孤立小簇)。
- 收敛更快、结果更稳定(对节点顺序不敏感)。
GraphRAG 官方实现用 Python 的
graspologic.partition.hierarchical_leiden。NetworkX
目前只有 Louvain,实验级场景足够。Leiden
的分辨率参数(resolution \(\gamma\))控制社区粒度:\(\gamma\) 小 → 社区大、少;\(\gamma\) 大 →
社区小、多。GraphRAG 通过多次运行不同 \(\gamma\) 得到层级结构。
5.2 Community Report 生成
每个社区的 prompt 输入大致是:
- 社区包含的实体及其描述;
- 社区内部的所有关系;
- 每个关系对应的原文片段(用于提供上下文)。
LLM 输出结构化 JSON:
{
"title": "社区主题",
"summary": "一段概括",
"rating": 8.5,
"rating_explanation": "...",
"findings": [
{"summary": "关键发现 1 的标题", "explanation": "详细说明"}
]
}findings
是一个重要的设计:它让每个社区可以有多个可独立引用的子结论,查询时
LLM 可以按需引用。这比单一长摘要更利于组合检索。
5.3 报告层级与 Drill-down
GraphRAG 的层级报告允许”先看高层摘要、需要细节时下钻”:
- Level 2 报告(最粗):整个语料的主要主题;
- Level 1 报告:每个主题内部的子话题;
- Level 0 报告:最细粒度的实体群。
Global Search 通常从 Level 2 开始;Local Search 根据实体定位到 Level 0。这种层级检索结构对人类阅读也友好——它把”语料结构”显式地表达出来了。
六、图存储的工程选型
6.1 三类主流图数据库
| 系统 | 存储模型 | 查询语言 | 部署形态 | 适合场景 |
|---|---|---|---|---|
| Neo4j | Property graph(磁盘 + 缓存) | Cypher | 单机 / 集群(Enterprise) | 通用、生态最成熟 |
| NebulaGraph | 分布式属性图(RocksDB) | nGQL / openCypher | 分布式 | 十亿节点、大规模生产 |
| KuzuDB | 列存属性图(嵌入式) | Cypher | 嵌入式(单进程) | 分析型、OLAP 场景 |
| TigerGraph | 属性图(自研) | GSQL | 分布式 | 企业级、复杂 OLAP |
| JanusGraph | 属性图(后端插件) | Gremlin | 分布式 | 基于 HBase / Cassandra 的老牌方案 |
几个非直觉的选型点:
- KuzuDB(CIDR 2023)是一个有意思的新秀:嵌入式 + 列存,适合像 GraphRAG 这样”一次性建图 + 多次 OLAP 式查询”的场景。它的多路径 JOIN 执行比 Neo4j 在某些基准上快一到两个数量级。但它不是 OLTP 图数据库——不支持高并发写入。
- NebulaGraph 面向”真生产大规模”场景,十亿级节点上可以水平扩容。代价是运维复杂度高,需要 Meta / Storage / Graph 三种节点协同。
- Neo4j 依然是”生态最好的选项”:Cypher 语法被广泛学习、APOC / GDS 图算法库成熟、可视化 Bloom 用户友好。在数据规模不超过单机能力(通常节点数 \(<10^9\))的场景下是默认选项。
- SurrealDB / ArangoDB 等多模数据库也提供图能力,但在复杂图遍历性能上通常不如专用图库。
6.2 GraphRAG 选型建议
- 快速原型 / < 百万节点:NetworkX(纯 Python,零依赖)或 KuzuDB(嵌入式、Cypher)。
- 企业内部生产 / 百万 ~ 千万节点:Neo4j Community / Enterprise。
- 多租户 / 十亿节点:NebulaGraph 或 TigerGraph。
- 图 + 向量同库:Neo4j 5.11+ 支持向量索引;KuzuDB 2024 年起原生支持 vector;NebulaGraph 通过 ext 支持。是否用同库取决于对事务一致性的要求——多数 GraphRAG 场景”图和向量分库 + 应用层 join”已够用。
6.3 官方 GraphRAG 实现
Microsoft 的开源实现(github.com/microsoft/graphrag)用 Parquet 文件直接落地(实体表、关系表、社区表、报告表),查询时按需加载到 NetworkX / igraph,不绑定特定图数据库。这种”文件格式优先”的设计降低了部署门槛,但也意味着对超大规模场景需要用户自己接专业图库。
另一个值得关注的实现是 LightRAG(HKU, 2024),精简了社区检测步骤,用双向实体-文档映射代替,成本更低。适合对成本敏感的场景。
七、图与向量的联合存储
GraphRAG 的实际查询既要图结构(邻居、路径、社区)又要向量(实体匹配、相似报告召回)。两者能否放进同一个后端,是工程上经常被问到的问题。
7.1 两种部署形态
- 双库:图库(Neo4j)+ 向量库(Milvus / pgvector),应用层用实体 ID 做 join。优势是每种模态都用”业界最强”的专用系统;代价是跨库事务和运维复杂度。
- 单库:Neo4j 5.11+ / KuzuDB / SurrealDB / ArangoDB 等支持同库既有图又有向量。优势是一致性和简化部署;代价是单一系统在两种模态上都不是顶尖。
对多数 GraphRAG 应用(<= 千万节点),单库方案已经足够。超过这个量级的系统通常走双库。
7.2 官方 GraphRAG 的存储选择
Microsoft 官方实现有意不绑定任何图数据库,而是把结果落地成 Parquet:
entities.parquet:实体表(id, name, description, type, embedding)。relationships.parquet:关系表(source, target, description, weight)。communities.parquet/community_reports.parquet:社区与报告。text_units.parquet:原始 chunk。
查询时按需加载到内存(NetworkX / igraph)。这套设计让 GraphRAG 成为一个”数据集格式”而不是数据库,可以直接放进 Data Lakehouse(见 数据湖表格式 )。代价是每次查询都要加载图——规模大时要自己做缓存或改走数据库。
7.3 GraphRAG 变体:LightRAG、HybridRAG、MedGraphRAG
GraphRAG 发布后几个月内就涌现了大量变体:
- LightRAG(HKU, 2024):省略社区检测与层级报告生成,只做”实体-文档双向映射 + 向量检索”。成本减半,但 global search 能力弱于原版。
- HybridRAG(arXiv 2024):把向量 RAG 与 GraphRAG 并行运行,用 rerank 合并结果。在金融文档 QA 上报告有 10%+ 的准确率提升。
- MedGraphRAG(arXiv 2024):针对医学文献做领域定制,加入本体匹配(UMLS),对实体抽取做强约束。
这些变体反映了一个共识:GraphRAG 是一套框架而不是固定方案,具体配置应根据数据与查询特征定制。
八、最小 GraphRAG:NetworkX 版本
下面给一个约 150 行的 Python 原型,放在 demo/graphrag_mini.py
。流程:
- 读入几篇 markdown 文档;
- 离线 LLM 被替换为规则抽取(关键字 + 简单句式)——保证离线可跑,不依赖 API;
- 构建 NetworkX 图;
- 用 Louvain(NetworkX 内置的近似 Leiden)做社区检测;
- 为每个社区生成一个规则驱动的”报告”;
- 接受查询,找到涉及实体,做 2-hop 扩展,返回结构化证据。
5.1 依赖与运行
cd post/db-frontier/10-graphrag/demo
python -m venv .venv && source .venv/bin/activate
pip install networkx
python graphrag_mini.py示例输出:
== Knowledge Graph ==
Nodes: 12
Edges: 14
== Communities ==
C0: {'Alice', 'Bob', 'OpenAI'}
C1: {'PostgreSQL', 'pgvector', 'Bruce'}
== Query: Who works with Bob? ==
Entity matches: ['Bob']
2-hop evidence:
Bob -[works_at]-> OpenAI
Alice -[collaborates_with]-> Bob
Answer (mock): 与 Bob 有直接关系的人/机构:OpenAI, Alice
5.2 核心代码
# demo/graphrag_mini.py (节选)
import re
from collections import defaultdict
import networkx as nx
from networkx.algorithms.community import louvain_communities
TRIPLE_PATTERNS = [
# (subj, rel, obj) - 极简规则:X works at Y / X collaborates with Y / X uses Y
(r"([A-Z][a-zA-Z]+) works at ([A-Z][a-zA-Z]+)", "works_at"),
(r"([A-Z][a-zA-Z]+) collaborates with ([A-Z][a-zA-Z]+)", "collaborates_with"),
(r"([A-Z][a-zA-Z]+) uses ([A-Za-z]+)", "uses"),
]
def extract_triples(text):
triples = []
for pat, rel in TRIPLE_PATTERNS:
for m in re.finditer(pat, text):
triples.append((m.group(1), rel, m.group(2)))
return triples
def build_graph(docs):
g = nx.MultiDiGraph()
for doc_id, text in docs.items():
for s, r, o in extract_triples(text):
g.add_node(s); g.add_node(o)
g.add_edge(s, o, rel=r, doc=doc_id)
return g
def detect_communities(g):
# Louvain 运行在无向简单图上
ug = nx.Graph(g)
return louvain_communities(ug, seed=0)
def community_reports(g, communities):
reports = []
for i, c in enumerate(communities):
ents = sorted(c)
edges = [(u, d["rel"], v) for u, v, d in g.edges(data=True)
if u in c and v in c]
reports.append({"id": f"C{i}", "entities": ents, "edges": edges})
return reports
def local_search(g, query, hops=2):
tokens = re.findall(r"[A-Z][a-zA-Z]+", query)
hits = [n for n in g.nodes if n in tokens]
evidence = []
for ent in hits:
for u, v, d in g.edges(ent, data=True):
evidence.append(f"{u} -[{d['rel']}]-> {v}")
# 反向边
for u, v, d in g.in_edges(ent, data=True):
evidence.append(f"{u} -[{d['rel']}]-> {v}")
return hits, evidence
def mock_llm_answer(query, evidence):
ents = set()
for line in evidence:
for part in line.split():
if part[:1].isupper():
ents.add(part)
return "与查询相关的实体(demo mock):" + ", ".join(sorted(ents))
if __name__ == "__main__":
docs = {
"d1": "Alice works at OpenAI. Alice collaborates with Bob.",
"d2": "Bob works at OpenAI. Bob uses PostgreSQL and pgvector.",
"d3": "Bruce works at Stripe. Bruce uses pgvector for search.",
}
g = build_graph(docs)
coms = detect_communities(g)
reps = community_reports(g, coms)
print("== Knowledge Graph ==")
print("Nodes:", g.number_of_nodes(), "Edges:", g.number_of_edges())
print("== Communities ==")
for r in reps:
print(r["id"], r["entities"])
q = "Who works with Bob?"
print(f"== Query: {q} ==")
hits, ev = local_search(g, q)
print("Entity matches:", hits)
print("Evidence:")
for e in ev: print(" ", e)
print("Answer:", mock_llm_answer(q, ev))5.3 从 demo 到生产的差距
这个 demo 有意省掉了几个生产关键点:
- LLM 抽取:真实场景用 GPT-4o / Claude / Qwen 抽 triple,需要提示词工程 + 成本控制。
- 实体合并:demo 按字符串精确匹配;真实场景要做 embedding + 别名表。
- 向量侧:demo 没有向量索引;真实 GraphRAG 会为每个实体、每个 chunk、每份 report 分别建 embedding。
- 层级社区:demo 只做一层 Louvain;真实 GraphRAG 会做多层并生成层级报告。
- 持久化:demo 每次重跑;真实系统写 Parquet / 图数据库。
但它展示了核心思想:图结构 + 社区 +
局部证据检索。想进一步扩展,官方实现
microsoft/graphrag 是值得参考的模板。
九、落地建议
如果你正准备把 GraphRAG 引入生产系统,几个实用判断:
9.0 先决条件检查清单
在真正投入 GraphRAG 的索引管线之前,先问自己以下几个问题,任何一个回答”否”都意味着 GraphRAG 投入产出比存疑:
- 业务中 20% 以上的问题需要跨多个文档 / 段落综合(多跳或全局)吗?
- 现有 RAG 的 bad case 集中在”文档间关系未连接”而不是”chunking 不好”吗?
- 愿意在索引阶段承担 LLM 抽取的成本(通常比纯 embedding 贵 10–50×)吗?
- 业务对回答的 evidence 可追溯性有要求吗?
如果四条里只命中一两条,纯向量 RAG + 更好的 chunking + rerank 多半就够。GraphRAG 不是”更先进的 RAG”,而是”更重的 RAG”。
- 先量化瓶颈:把当前向量 RAG 的 bad case 收集 100 条,分类看多少是多跳、多少是全局、多少是关系敏感、多少是 chunking 不好。如果多跳 + 全局占比低于 30%,可能加 rerank、更好的 chunking、HyDE(Hypothetical Document Embeddings)就够了,GraphRAG 的投入不值得。
- 从 Local Search 开始:Global Search 成本高、质量受社区检测影响大。Local Search 对 multi-hop 已经有效,可以先上 Local 一档。
- 控制抽取成本:限定实体类型、设置 chunk 大小(通常 600–1200 tokens)、限制每块的 triple 上限。
- 保留可解释性:GraphRAG 的一个工程优势是答案可以附带 evidence path(“根据 Alice-works_at-OpenAI 和 Bob-works_at-OpenAI”)。把这条链路露给用户,比纯 RAG 的”来自文档 X”更具说服力。
- 不要盲目追新:到 2024 年底,GraphRAG 及其变体(LightRAG、MedGraphRAG、HybridRAG 等)还在快速演进,选型应基于自己的数据而非 benchmark 数字。
9.1 常见失败模式
- 实体过度泛化:LLM 把 “the company” 也抽成实体,导致图里充斥无意义节点。解决:提示词显式禁止抽代词/泛指。
- 关系重复爆炸:同一对实体被反复抽出多种表述(works at / is employed by / is part of),图上变成多重边。解决:合并阶段用 embedding 聚类关系文本,或用图加权。
- 社区粒度失衡:分辨率参数不合适导致一个巨型社区 + 很多小社区。解决:多运行几个 \(\gamma\),选择社区大小分布较均匀的一档。
- 查询不激活社区报告:Local Search 默认只取邻居不看社区报告。如果业务问题经常需要概览能力,要显式混入相关社区的报告文本。
9.2 与现有 RAG 系统的渐进集成
不需要一上来就替换整套 RAG。典型渐进路径:
阶段 1: 纯向量 RAG,保持在线
阶段 2: 离线跑 GraphRAG 索引管线,生成图与报告,存为 Parquet 旁路
阶段 3: 在线查询路径上增加"entity match → 若命中则取 2-hop 证据拼进 prompt"
阶段 4: 对 global 类问题引入 Global Search 分支
阶段 5: 逐步淘汰纯向量 fallback 或保持双栈
整个过程可以覆盖 3–6 个月,每一步都能独立上线与回退。
十、评估方法论:如何判断 GraphRAG 真的比向量 RAG 好
GraphRAG 的评估是这类系统里最难做的部分。原因有三:
- 没有公认 benchmark。现有 RAG benchmark(HotpotQA、TriviaQA、MuSiQue)侧重多跳问答但不是 GraphRAG 专门设计的;GraphRAG 的 global search 能力没有对应的 benchmark 能测。
- 依赖 LLM 裁判。大多数论文用 LLM-as-Judge 比较两个系统的回答,但裁判 LLM 本身的偏好(长答案更好、格式化更好)会影响结果。
- 成本差异大。GraphRAG 的索引和查询成本可能是向量 RAG 的几倍到几十倍,“质量提升 + 成本增加” 的权衡因业务而异。
实际工程中可以参考的方法:
- 分问题类别做评估:把测试集按多跳、全局、单跳事实、关系敏感等类别分组,对每类分别评估。避免汇总分数掩盖真相。
- Blind pairwise comparison:人工对照标注,不给标注员看哪个是 GraphRAG,避免先入为主。
- End-to-end 指标:不是只看回答正确率,还看引用正确率(citation accuracy)、延迟、用户满意度。
- A/B 线上测试:小流量对照,观察业务指标(回答被采纳率、点踩率)。
没有银弹。“GraphRAG 比 RAG 好”在今天还是一个需要上下文限定的判断。
十一、GraphRAG 与 SQL 仓库的融合
虽然 GraphRAG 常被当作”RAG 的一种实现”讨论,另一条值得关注的线是它与数据仓库 / Lakehouse 的融合。企业场景里,知识图谱往往已经以星形模型或宽表的形式存在于数仓里(例如员工-部门-项目表),GraphRAG 的管线可以直接读这些表建图而不必重新从文本抽取。
这种”结构化优先”的 GraphRAG 有几个优势:
- 抽取成本近零:不依赖 LLM 抽三元组。
- 事实一致性强:源数据经过数仓 ETL 校验。
- 增量成本低:数仓的 CDC 可以直接驱动图增量。
代价是社区检测与报告仍需要 LLM 参与,否则查询侧只能走 Local Search。对这类场景,GraphRAG 更准确的定位是”把数仓的结构化知识转成 LLM 可组合的 evidence”,而不是”从非结构化文本里建图”。
另一个正在兴起的方向是把 GraphRAG 的图查询当作 SQL 的语义增强层:用户自然语言问题先映射到”图节点/路径”,再翻译为 SQL + 图遍历组合查询。KuzuDB、ArangoDB 等支持原生 Cypher 的 OLAP 图库在这类场景下具有独特优势。
十二、开放问题与近期研究方向
几个到 2024 年底仍未解决的问题:
- 增量社区检测:新文档进来后如何避免重跑整个 Leiden?学术上有 streaming community detection 研究但工程化程度低。
- 跨语言 / 多语言 GraphRAG:同一个实体在中英文抽取结果可能不同,合并策略还没有好的开源实现。
- 事实性约束:LLM 抽取的关系可能和源文档不一致(尤其是 “summarize” 类 prompt 偏软的情况下)。如何让图严格基于证据仍是开放问题。
- 成本-质量 Pareto:LightRAG 砍掉社区、HybridRAG 并行两路,这条”精简 GraphRAG”路线是否能保持多跳 / 全局能力的大部分,研究很多但共识少。
- 与代理(Agent)系统结合:GraphRAG 的 evidence path 很适合作为 Agent 的推理输入,但目前二者集成的最佳实践仍在摸索中。
对这个方向感兴趣的读者可以关注:微软 GraphRAG repo 的 issues 与 PR、HKU 的 LightRAG 系列、arXiv 上 “graph-based retrieval augmented generation” 每月的更新。
参考文献
- Edge, D., Trinh, H., Cheng, N., et al. “From Local to Global: A Graph RAG Approach to Query-Focused Summarization.” arXiv:2404.16130, 2024. https://arxiv.org/abs/2404.16130
- Guo, Z., Xia, L., Yu, Y., et al. “LightRAG: Simple and Fast Retrieval-Augmented Generation.” arXiv:2410.05779, 2024. https://arxiv.org/abs/2410.05779
- Traag, V. A., Waltman, L., van Eck, N. J. “From Louvain to Leiden: Guaranteeing Well-Connected Communities.” Scientific Reports, 9:5233, 2019. https://www.nature.com/articles/s41598-019-41695-z
- Blondel, V. D., Guillaume, J.-L., Lambiotte, R., Lefebvre, E. “Fast Unfolding of Communities in Large Networks.” Journal of Statistical Mechanics, 2008.
- Lewis, P., Perez, E., Piktus, A., et al. “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks.” NeurIPS, 2020.
- Feng, X., Yan, A., Chen, X., et al. “KuzuDB: An Embeddable Graph Database Management System for Query Composability.” CIDR, 2023. https://www.cidrdb.org/cidr2023/papers/p48-jin.pdf
- Microsoft GraphRAG, https://github.com/microsoft/graphrag
- Neo4j Graph Data Science Library, https://neo4j.com/docs/graph-data-science/current/
- NebulaGraph, https://docs.nebula-graph.io/
- NetworkX, https://networkx.org/
上一篇:向量与标量的混合过滤检索:ACORN、Milvus、pgvector 的算法权衡 下一篇:多模态数据库:文本、向量、图、张量的统一存储
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【数据库研究前沿】数据库作为 LLM 记忆体:语义缓存、RAG 与一致性
把数据库当 LLM 长期记忆的系统视角:GPTCache、MemGPT、向量 vs 事实记忆;用 pgvector + 触发器实现会话级一致性语义缓存
【数据库研究前沿】系列导论:从 System R 到 AI-Native 的 2026 研究地图
以 System R、Postgres、Bigtable、Spanner、Snowflake 等关键节点串起 50 年数据库史,勾勒 2026 年 AI-Native、向量检索、HTAP 云原生、新硬件、隐私计算、新范式、方法论七条主线,并给出 25 篇系列文章的完整阅读地图。
【数据库研究前沿】如何读数据库顶会论文:SIGMOD/VLDB/CIDR 阅读路线
从顶会定位、检索渠道、三遍读法到工业与学术论文的辨别方法,给出 2023–2025 年数据库领域可信必读二十篇,并配套 CMU 15-721、Stanford CS 245 等公开课清单。
【数据库研究前沿】学习型查询优化器:Neo、Bao、Balsa 到 LLM-CBO
系统梳理 Neo、Bao、Balsa 以及新兴 LLM-assisted 查询优化的核心思想,结合 PostgreSQL pg_hint_plan 给出一条可落地的 learned QO 工程路径