GraphRAG 实战:用知识图谱增强 RAG 检索准确性

朴素 RAG(Retrieval-Augmented Generation,检索增强生成)把文档切块后做向量检索,遇到需要跨文档归纳、实体关系推理的问题常常”答非所问”。GraphRAG 由微软提出,它在检索前先用大模型抽取文档中的实体、关系与关键声明,构建成知识图谱,再借助图社区算法生成多层级摘要。这样既能做精准的”局部搜索”,也能直接回答”全局性总结问题”,显著提升了 RAG 在复杂问答场景下的准确性。

一、朴素 RAG 的盲区:为什么切块检索不够

朴素 RAG 的标准链路是:文档切片 → 向量化 → 相似度召回 Top-K → 拼进 Prompt 让大模型生成。它的两个结构性缺陷在真实业务里会被放大。

第一,语义被切碎。一份年度财报里”张三负责华东区销售”和”华东区营收下滑 20%”可能落在两个不同分块,向量检索各自召回时,模型看不到两者之间的因果链。

第二,全局性问题无解。当你问”公司今年面临的主要风险有哪些”,正确答案分布在几十份文档里,需要跨文档聚合。向量检索只能取最相似的几段,无法完成”汇总全局”这一动作,于是模型只能基于局部片段硬编,准确率骤降。

这也是许多企业知识库上线初期体验不错、问题一复杂就露馅的原因:向量检索本质是”找相似片段”,而真实决策往往需要”把分散证据连成一条链”。GraphRAG 正是把”连链”这一步前置到了索引阶段,让检索时直接拿到结构化的关联上下文,而不是临时从碎片里拼。

二、GraphRAG 的工作流:抽取 → 图谱 → 社区摘要

GraphRAG 把”建图”放在检索之前,整体分四步:

  • 文本单元切分:把文档切成可处理的分析单元(通常按段落或固定 token 数)。
  • LLM 抽取:对每个单元抽取实体(人物、组织、技术、产品等)、关系(”任职于””导致”等)以及关键声明(带证据的具体事实)。
  • 图社区划分:用 Leiden 算法对实体关系图做社区聚类,把联系紧密的子图归为一组。
  • 社区摘要:自底向上逐层生成社区报告(community report),让每个社区都有一段自然语言的概括。

需要注意,图谱质量高度依赖抽取环节。若实体类型不加约束、语料又含大量噪声,图谱会变成一张既稀疏又嘈杂的网,反而拖累检索效果。因此”建图前先清洗、限定抽取范围”与”建图”本身同样重要,这点会在第七节落地建议里展开。

检索时就有两条路径:局部搜索沿着实体邻域取子图与原文作为上下文,适合”张三负责什么”这类精确事实;全局搜索则直接聚合社区摘要来回答”整体趋势如何”这类总结性问题。关于混合检索与重排序的更多细节,可参考大模型 RAG 进阶:混合检索与重排序优化实战

三、环境准备与数据建模

GraphRAG 官方提供了 Python 包,初始化后会生成 settings.yaml 与输入目录。建议先把抽取目标收窄,避免图谱被无关实体撑爆。

# 安装与初始化
pip install graphrag
graphrag init --root ./graphrag_project

# 把待处理文档放入输入目录
mkdir -p ./graphrag_project/input
cp annual_report.txt ./graphrag_project/input/

settings.yaml 中限定实体类型与语言,Prompt 越聚焦,图谱质量越高:

# settings.yaml 片段:约束抽取范围
entity_extraction:
  prompt: "仅抽取以下四类实体:人物(person)、组织(org)、技术(tech)、产品(product)"
  max_gleanings: 1
  model: "gpt-4o-mini"
claim_extraction:
  enabled: true
  description: "抽取带量化与责任主体的关键声明"

四、构建索引:从文档到知识图谱

索引构建是一次性成本最高的环节。下面的脚本读取输入文本并触发完整流水线:

import asyncio
import graphrag.api as api
from graphrag.config import load_config

async def main():
    config = load_config("./graphrag_project")
    with open("./graphrag_project/input/annual_report.txt") as f:
        text = f.read()
    # 构建索引:实体/关系抽取 + 图存储 + 社区摘要
    await api.build_index(config=config, documents=[text])

asyncio.run(main())

构建完成后,output/ 目录会产出 entities.parquetrelationships.parquetcommunity_reports.parquet 以及可供可视化的 graph.graphml。若想把图谱接进 Neo4j 做交互式查询,可把这些 parquet 导入图数据库,再用 Cypher 检索实体邻域。

五、检索阶段:局部搜索与全局搜索

索引就绪后,两类查询引擎开箱即用:

from graphrag.query.engine import LocalSearch, GlobalSearch

# 局部搜索:基于实体邻域,适合具体事实类问题
local = LocalSearch(config, llm, embedder, context_builder=context_builder)
ans_local = await local.search("张三是哪个部门的负责人?")

# 全局搜索:聚合社区摘要,适合总结性、归纳性问题
global_ = GlobalSearch(config, llm, context_builder=context_builder)
ans_global = await global_.search("公司今年面临的主要风险有哪些?")

两者取舍如下:

维度局部搜索 Local全局搜索 Global
适用问题具体事实、单实体关系跨文档总结、趋势归纳
上下文来源实体邻域子图 + 原文社区摘要聚合
响应延迟低(上下文小)高(需聚合多层摘要)
典型准确率事实类高归纳类显著高于朴素 RAG

六、GraphRAG 与朴素 RAG 的对比

把两者放在统一维度下比较,能更清楚地看到 GraphRAG 补上了哪些能力短板:

能力维度朴素 RAGGraphRAG
跨文档推理弱(仅 Top-K 片段)强(实体关系链可达)
全局总结几乎无能为力社区摘要原生支持
实体关系可追溯有(图谱可解释)
首次构建成本高(需抽取+建图)
线上查询成本局部低 / 全局较高

七、落地建议与常见坑

结合多个生产项目的经验,给出五条可直接照做的建议:

  1. 语料先清洗:噪声文档会污染图谱,建图前务必去重、去模板页脚。
  2. 收窄实体类型:抽取 Prompt 限定 4–6 类实体,否则图谱过胖、摘要 token 爆炸。
  3. 社区摘要按需生成:只对高频实体建社区,长尾实体可跳过以省成本。
  4. 混合部署:关键事实走 GraphRAG 局部搜索,模糊语义走向量 RAG,两者用路由层分发。想本地零成本跑通向量知识库,可参考2026 年搭建私有 AI 知识库:Dify + Ollama 本地部署完整教程
  5. 全局搜索异步化:把全局问答放到离线批处理,避免阻塞在线请求。

另外,GraphRAG 的上下文组织与大模型上下文工程实战:长上下文提示设计思路相通——都是”先把相关信息结构化,再喂给模型”。在智能体系统里,它还能和AI 智能体记忆系统配合,把图谱当作长期记忆的外部存储。大模型工具调用 Function Calling则可作为检索前后的动作编排入口。

八、小结

GraphRAG 不是要取代朴素 RAG,而是补上它在”跨文档推理”与”全局总结”上的两块短板。它用一次性的建图成本,换来了可解释、可聚合、准确率更高的复杂问答能力。对于文档量大、问题偏归纳的企业知识库,值得作为 RAG 架构的增强层优先落地。

上一篇 jq 与 yq 实战:命令行玩转 JSON 与 YAML
下一篇 开源项目贡献指南:从第一个 issue 到 PR 合并