Graph RAG
Graph RAG 用实体与关系图补充文本检索,适合需要跨文档关联和多跳关系的问题。纯文本检索擅长「找相似段落」,但不擅长「A 与 B 通过什么关系相连」这类跨文档问题,图结构正是用来表达这种关联的。它的由来,是向量检索在「需要把散落多处的实体串成一条推理链」的全局性问题上的不足,Microsoft 的 GraphRAG 论文 提出用社区摘要来回答这类问题,成为这一方向最有代表性的工作。
快速开始¶
先定义 schema:哪些是实体(产品、条款、地区等)、哪些是关系(适用于、引用、禁止等)、每条边携带哪些属性,以及如何从原文抽取这些信息。抽取可以靠规则或模型,但抽取结果必须可回放、可校验。
以 GraphRAG 论文 与 microsoft/graphrag 的实现为参照,索引阶段由三部分构成:先用 LLM 从每个文本片段抽取「实体-关系-实体」三元组并记录来源,再把同一实体合并去重成图节点,最后对图做社区检测(常用 Leiden 算法)并为每个社区生成摘要。查询阶段分两种:本地检索(local search)从某个实体出发沿邻居展开,适合实体明确的局部问题;全局检索(global search)聚合相关社区摘要回答跨文档的整体性问题。社区摘要这一步是 GraphRAG 相对普通知识图谱检索的关键增量——它把「图的局部结构」压成「高层语义」,让模型能在有限上下文里理解全局。
给每条边记录来源:它出自哪篇文档、哪个片段。这样图里的任意路径都能回溯到证据文本,回答时可以附上原文,而不是凭空断言。缺少来源的边应被丢弃或标记为低置信。
一个最小的实体关系抽取调用如下,返回结果必须带 source 字段才能溯源:
def extract_triples(chunk, source):
prompt = f"从以下文本抽取 (实体, 关系, 实体) 三元组,并标注来源:\n{chunk}"
# 实际调用 LLM,此处省略;返回结构化三元组列表
return [
{"head": "产品 A", "relation": "适用于", "tail": "地区 B", "source": source},
]
明确图的更新策略:文档变更后,新增、修改还是删除哪些实体与边,何时重跑抽取、是否增量更新。图一旦与原文不同步,就会给出过时结论,因此更新策略比「建图」本身更重要——这正是图与向量索引的共性:两者都只是原文的派生索引,过期风险必须显式管理。
案例¶
一个合规助手需要回答「某产品在某地区是否允许销售」。用「产品 -> 地区 -> 条款」图检索:从产品节点出发,沿关系找到适用地区,再关联到具体条款节点,得到相关路径,然后把这些路径对应的原文片段一并交给模型回答。这类多跳问题正是向量检索的短板:产品、地区、条款可能分处三篇文档,单靠相似度很难把三者同时召回。
当条款被修订、图尚未更新时,图中旧关系会给出过期结论。此时应降级到纯文本检索,或对图结果标注「可能过期」并强制附上最新原文,让模型基于原文而非过期边作答——这体现了「图是索引、原文是真相」的原则。
该案例说明 Graph RAG 的价值在于跨文档关联与多跳,但前提是图与证据同步、每条边可溯源。评估时要看「路径召回是否覆盖标准答案所需的关系链」,而不是只看文本检索的 Recall@k——图检索的关键指标是「关系链是否被正确命中并串起来」,这与「片段是否被召回」是两回事。