这两年大家在群里聊大模型应用,最常被提起的检索方案已经从“先分块再向量化”变成“要不要上GraphRAG”。我身边不少程序员朋友,传统RAG已经玩得很熟了,文档加载、切块、embedding、向量检索、拼提示词这一套流程闭着眼都能搭出来,可一碰到GraphRAG就有点发怵。问下来无非是几个原因:看不懂知识图谱那套术语,觉得实体抽取和社区检测太玄,再加上网上教程动不动就甩一大段配置文件,看着像天书。
其实GraphRAG并没有想象中那么高不可攀,它解决的是普通RAG一个非常具体的短板—— 回答不了需要跨文档、跨段落进行多跳推理的问题 。这篇文章就从“普通RAG到底哪里不够用”讲起,先把原理拆明白,再给出一套可以照着抄的最小可跑配置,最后把我实际跑索引、调查询时踩过的坑一并列出来。适合有一定RAG基础、想搞清楚GraphRAG到底怎么落地的人,哪怕你之前完全没碰过知识图谱,只要跟着走一遍,也能知道自己在做什么、为什么这么做。
1. 先别急着敲代码:普通RAG到底卡在哪
1.1 向量召回的本质是“找相似”,不是“找关系”
很多人以为RAG效果不好是embedding模型不行,换更大的向量模型就能解决。这个想法对了一小半,但没说到根子上。传统RAG的链路是:把文档切成若干文本块,每块让embedding模型转成一串向量,查询时把用户的问句也转成向量,然后在库里找余弦距离最近的Top-K块,最后把这些块塞进大模型生成答案。
问题就出在这个“最近”上。向量相似度衡量的是语义上的近似,它擅长的是“我给你的问题,答案就藏在某一块文本里”。但真实业务里大量问题不是这种单一命中的,比如:
- “过去半年哪个故障原因累计导致的停机时间最长?”
- “A模块的异常会不会连带影响B模块的稳定性?”
- “这份合同里的违约责任和另一份合同的补充条款有没有冲突?”
这类问题有一个共同特点: 答案分散在多段文本里,需要先建立实体之间的关联,再沿着关联做推理 。普通RAG把文档切成块之后,块与块之间的上下文就断了。给模型喂十个块,它只能看到这十个块内部的文字,块之间的因果关系、上下游依赖、时间先后顺序全丢了。向量相似度再高,也只是把“长得像”的片段捞出来,没法把“逻辑上有关联”的片段拼起来。
我做过一个小实验,拿一份模拟的设备维护手册,里面有几十条故障记录,每条记录分散在不同的章节。问“哪种故障类型引发的平均修复时间最久”,传统RAG的答案是“请提供具体故障类型”,因为没有任何一个块单独包含完整的汇总信息。这不是模型不行,是召回阶段就没有跨越文本块做聚合的能力。
1.2 多跳问题才是普通RAG的分水岭
有人会说,那我加大Top-K不就行了?把20个块全塞进去,总能找到相关信息吧?这里有两个问题。
第一,上下文窗口有限。Top-K从5加到20,检索到的噪声也成倍增加。大模型面对一堆碎片化信息时,很容易被无关内容带偏,反而降低了准确率。第二,即便所有相关片段都塞进去了,模型仍然不知道它们之间是什么关系。它只是在做“把片段拼在一起再总结”,并没有真正理解“这就是一条完整证据链”。
这种需要跨越多个信息源、建立关联、再推理得出结论的问题,业界管它叫 多跳问题 。GraphRAG之所以能解决这类问题,核心在于它在检索之前额外做了一件普通RAG不做的事:把文档里的实体、关系抽取出来,构建成一张知识图谱。图谱天然保存了“谁和谁有关联、是什么关联”的信息,查询的时候可以沿着实体关系走,而不是仅仅靠向量距离找相似。
一句话总结:普通RAG的检索是横向扫描,GraphRAG的检索是沿着关系网的纵向穿越。理解了这一点,后面所有看不太懂的模块就都有了落脚点。
2. 读懂GraphRAG的骨架:索引与查询的分工
2.1 一个容易被忽略的事实:GraphRAG不是一种模型
不少人第一次听说GraphRAG,以为它是某个新的大模型,或者是一套端到端的推理框架。实际上它是一种 检索增强方案 ,需要你自备大模型接口、embedding接口,大模型负责抽取和生成,向量库负责相似度召回,图数据结构负责保存实体关系,GraphRAG负责把这几样东西串起来。
它的整体流程可以粗暴地分成两个大阶段: 索引阶段 和 查询阶段 。
索引阶段做的是“离线加工”:把原始文档拆成文本单元,用大模型从中抽取实体和关系,构建知识图谱,然后把图谱划分成若干社区,再让大模型为每个社区生成摘要。这些产物全部落库,等在查询阶段被调用。
查询阶段做的是“在线问答”:拿到用户问题后,决定走局部搜索还是全局搜索。局部搜索是从问题里识别出的实体出发,在图谱上检索与之相关的实体、关系、文本单元;全局搜索则是把所有社区摘要拿来做一轮“地图归约”,从全局视角提炼答案。
这个分工很像盖房子:索引阶段是把材料做成预制板,查询阶段是根据户型图把预制板拼起来。很多教程一上来就让你跑
graphrag index
,跑完之后还对着输出文件发懵,就是没搞明白这两个阶段各自生产了什么、消费什么。
2.2 为什么图谱能补上向量检索的短板
知识图谱的本质是三元组结构: 头实体—关系—尾实体 。比如“故障A—导致—停机”、“模块B—依赖—模块C”、“张三—负责—项目X”。这些三元组天然把碎片化文本里的关键对象和对象间的逻辑联系显式地存了下来。
向量检索的短板在于它只回答“哪些文本与问题语义相近”,而图谱回答的是“问题涉及的实体,和哪些其他实体存在关系,关系链有多长”。前者像照片集,每一张照片独立呈现一个场景;后者像地图,路和路的连接关系清清楚楚。地图在回答“从A到B怎么走”这类问题时,优势是碾压级的,多跳推理本质上就是在地图上寻路。
当然,图谱也不是万能的。实体抽取会漏、关系判断会错、社区划分不一定合理,这些误差都会影响最终答案。但即便存在误差,图谱结构本身就提供了普通RAG不具备的“关联上下文”,这一点在真实任务里收益非常明显。
3. 清单式搭建:最少依赖与最小可跑的配置
3.1 依赖安装与版本选择
给你一套我清理过的跑通版本,避免踩版本兼容的雷。先建立一个干净的虚拟环境,装GraphRAG主程序。如果你是Python 3.10以上的环境,直接执行:
python -m venv graphrag-demo
source graphrag-demo/bin/activate
pip install graphrag
这里提醒一句,GraphRAG对Python版本比较挑,3.9到3.11最稳,3.12在某些系统上可能出现依赖编译报错。如果非要上3.12,建议提前确认相关底层依赖库有没有对应版本。
初始化目录结构也别乱来:
graphrag init --root ./demo
执行完后,会自动生成类似这样的目录:
demo/
├── input/ # 放原始文档
├── output/ # 索引结果输出
├── prompts/ # 抽取和摘要的提示词模板
└── settings.yaml # 核心配置文件
很多教程会让你改一堆文件,其实真要跑起来,核心就一个
settings.yaml
。理解它比背命令重要得多。
3.2 settings.yaml里真正需要关心的配置项
我见过不少人栽在配置文件上,倒不是官方文档写得复杂,而是字段太多不知道该改哪里。打开
settings.yaml
,先找这几个区域:
llm:
model: 你选用的对话模型
api_key: 你的接口密钥
api_base: 接口服务地址
max_tokens: 4000
embeddings:
llm:
model: 你选用的向量模型
api_key: 你的接口密钥
api_base: 接口服务地址
chunks:
size: 1200
overlap: 200
简单说明一下这几个参数的用途。
-
llm.model是大模型主模型,负责实体抽取、社区摘要、最终答案生成,建议选指令跟随能力强的对话模型,参数规模不用一味追求最大。 -
embeddings.llm.model是向量模型,负责把文本单元和社区摘要转成向量,它是异步向量化的“经典款”。 -
chunks.size是切块大小。GraphRAG不是不切块,而是切块之后还要做实体抽取。块太大,小粒度实体容易被淹没;块太小,关系抽取缺少上下文。我用下来1200左右相对均衡,如果你文档句子很短,可以适当降到800。
配置完成后,找一个规模很小的测试语料先跑一遍索引,不要一上来就灌几十篇大文档。我第一次实践时直接塞了整本手册,索引跑了一个多小时,报错都不知道从哪里查起。后来老老实实放了两三篇样本文档,十几分钟跑完,再逐步加量,才把流程理顺。
3.3 冒烟测试:跑通第一次索引
在
input
目录放入几份内容交叉关联的文档,模拟一段内部知识库场景。比如放一份人员名单、一份项目说明、一份故障报告,这三份文档里出现重复的实体人名、项目代号、设备名称,这样后续才能看出图谱是不是真的关联上了。
然后执行:
graphrag index --root ./demo
第一次跑会看到它在逐个加载文档、切分文本单元、批量调用大模型抽取实体关系,这个过程比普通RAG的embedding慢得多,属于正常现象。看到
All workflows completed successfully
就说明索引阶段跑通了。
此时去
output
目录看一眼产物,重点看带
entities
和
relationships
字样的文件。打开后你会发现,刚才那几份文档里的人名、项目名、设备名已经被抽取成了结构化的实体列表和关系列表。到这里,索引阶段最核心的东西就已经生产出来了。
4. 索引阶段的完整逻辑:文本如何变成社区摘要
4.1 实体与关系抽取:整个流程的地基
索引阶段的第一步是抽取实体和关系。GraphRAG会先把文档切成文本单元,然后对每个文本单元调用大模型,让它找出里面的人名、地名、组织、系统、项目、指标等等实体,同时抽取实体之间的语义关系,输出成结构化的三元组。
这个环节看着简单,实际影响非常大。关系抽取质量直接决定了后续图谱的质量,而图谱质量又决定了查询阶段能找到什么。我常用的一个调试方法是打开
prompts
目录下的实体抽取提示词,自己读一遍,看看它要求大模型输出的JSON结构是什么样子。很多问题都出在提示词与真实数据的错位上,比如你的文档里全是技术术语,默认提示词却偏向人名和事件抽取,那抽出来的关系自然不准。
实际运行中,大模型抽取通常是以文本单元为粒度并行进行的。每一个文本单元都独立抽一次,之后再做融合。同一实体在不同文本单元里的叫法可能不一样,比如“维修单编号FT-2023-011”和“工单011”,需要被合并成同一个实体。GraphRAG内部会做实体对齐,但不可能100%完美。
4.2 社区检测与层级摘要:把大片图谱切成几盘菜
实体和关系都进图之后,图谱往往是乱的。几十个实体几百条关系摊在一起,直接拿去回答用户问题,大模型根本看不完。GraphRAG的处理思路是引入 社区检测 算法。
社区检测的目标是把图谱划分成若干子图,每一个子图内部的联系尽量紧密,子图之间的联系尽量稀少。你可以把它理解成按主题把地图切成几块区域,每块区域里的人相互认识的概率更高。
划分完社区之后,GraphRAG会再调用大模型,为每个社区生成一份摘要。摘要的逻辑是“先局部再全局”:先总结每个社区内部的关键实体和关系,然后把相邻社区再合并成更高层级的社区,生成更高层级的摘要。这一步产生的就是整个索引阶段最重要的资产之一—— 社区摘要 。
社区摘要解决了一个非常实际的问题:当你问一个全局性问题时,不需要把整个图谱几千条关系都塞给大模型,而是先把几十份社区摘要塞进去,让模型从这些浓缩后的信息里找答案。这就像你要了解一所学校的整体情况,不用翻每个学生的档案,先看各年级教研组的年度总结就够了。
4.3 图和向量为什么要同时存在
看到这里你可能会问:既然有了图谱和社区摘要,为什么还会看到向量文件?查询局部问题时,不也是要先去向量库找相似文本吗?
原因很简单:实体和关系是结构化的抽象信息,但答案最终要落实到原文。用户问“停机了该怎么办”,图谱可能告诉你“停机—关联—故障类型A”,但故障处理步骤的具体措辞、注意事项、联系电话还是要回到原始文本单元里去读。向量索引保存的是这些原始文本的语义表示,充当的是“回到原文的桥梁”。
所以GraphRAG从来不是用图谱替代向量库,而是用图谱提供关系上下文,用向量库定位原始文本,两者配合才能生成有依据的回答。这个设计是我认为GraphRAG做得最聪明的地方,它没有否定RAG的原有路径,而是在上面增加了一层信息组织方式。
5. 查询阶段的完整逻辑:局部搜索与全局搜索的实际分工
5.1 局部搜索:从实体出发,沿关系广度遍历
查询阶段最常见的模式是局部搜索。用户提问后,系统先在图库里找到与问题最相关的实体作为起点,然后沿着这个实体的关系边向外扩展,把相邻的实体、它们之间的具体关系描述、以及这些实体对应的文本单元全部搜集出来,统一交给大模型生成答案。
举个例子,你问“B模块最近一次升级后,和它存在依赖关系的服务有哪些”,局部搜索会先定位到“B模块”这个实体,然后找出它所有“依赖”“被依赖”的关系边,顺着边找到涉事的其他实体和原始文本片段,把这些材料组装成上下文,让大模型回答。这个过程本质上是在知识图谱上做广度优先遍历,距离起点两跳、三跳内的相关信息都会被拉进来。
局部搜索的优点是对答案的聚焦度很高,如果问题本身涉及实体明确,它比普通RAG那种大海捞针式检索精准得多。缺点也明显:如果起点实体识别错了,或者图里根本没这个实体,整条检索链路就断了。所以使用局部搜索时,我建议先把问题拆解一遍,确认核心实体是否存在于实体列表中,再去查询。
5.2 全局搜索:社区摘要的“先浓缩再提问”
当你面对的是宏观问题,比如“整个知识库里涉及哪些风险点”“哪类问题的频率最高”,局部搜索就不灵了,因为答案散布在全图,没有一个明确的实体起点。这种情况下走全局搜索。
全局搜索的逻辑是“地图归约”:把所有社区摘要收集起来,先让大模型分批提炼出候选答案,再把候选答案合并成最终答案。这个过程有点像我面试时让多组评委分别评分,最后把各组评分汇总对比,得出综合结论。它牺牲了精确的定位能力,换来了对全局信息的覆盖能力。
社区摘要的层级化在这里派上了用场:底层社区摘要太多,就先用高层摘要做初步筛选,再针对性下沉到相关子社区。全局搜索不会把几千条原始关系一股脑塞给模型,而是从几十份浓缩摘要里找线索,这大大降低了提示词超长的风险。
5.3 不同问题形态下的选择策略
我不止一次被问到“局部搜索和全局搜索哪个更强”,答案是看问题类型。做项目时我给自己定了一套判断标准:
| 问题特征 | 推荐搜索方式 | 原因 |
|---|---|---|
| 问题中出现明确人名、项目名、设备名 | 局部搜索 | 能精准定位实体,沿关系扩展效率最高 |
| 需要跨文档汇总统计趋势 | 全局搜索 | 答案不依赖单一实体,需要全局视角 |
| 问句中包含因果链条 | 局部搜索 | 多跳关系顺图谱更容易还原 |
| 开放性探讨,没有明确实体锚点 | 全局搜索 | 社区摘要能提供完整背景信息 |
| 对单点事实细节查证 | 局部搜索 | 响应更快,上下文更聚焦 |
实际项目里,我会在系统里同时暴露两种查询入口,让用户按问题类型自行选择,而不是固化成一个模式。等积累了一定查询日志后,再根据使用频率决定要不要加一层意图分类模块来自动路由。
6. 真实使用中的成本账、参数与教训清单
6.1 三个最容易忽视的坑
第一个坑是索引阶段的成本。实体抽取要反复调用大模型,社区摘要又是一轮大模型调用,而且整个过程是离线的,整体消耗通常比在线问答高一个数量级。我实际跑过一份约300页的文档集,单纯索引阶段的token消耗大约是单次问答的几十倍,耗时接近一小时。但这是 一次性投入 ,只要文档不频繁更新,摊到长期使用成本完全可接受。
第二个坑是文档更新。GraphRAG不是增量式自动更新的,你往
input
里新增了一份文档,必须重新跑索引才能让新内容进入图谱。如果你的业务是知识库日更,每次全量重跑会很痛苦。我目前的折中方案是每天凌晨定时全量重建一次,同时把当天热查询涉及的文档单独做一份小索引做实时补充。
第三个坑是提示词超长。社区摘要叠加原始文本之后,上下文依然会变得很大。特别是全局搜索时,如果社区划分过细,摘要数量会膨胀。这时候要回头调社区检测参数,把社区粒度调大一点,减少摘要数量。不要盲目加
max_tokens
,上下文越长,模型越容易在长文本里丢失早期信息。
6.2 什么情况下其实不需要GraphRAG
GraphRAG不是银弹。如果你的业务里绝大多数问题是“某文档某条款是什么”,单个文本块就能覆盖,那普通RAG完全够用,而且速度更快、部署更简单、成本更低。我见过一些项目,文档之间几乎没有交叉引用,强行上GraphRAG,索引阶段消耗了大量算力,线上效果却没有明显提升。
判断是否需要GraphRAG,我建议先问自己三个问题:文档之间是否存在大量实体交叉引用?用户问题里是否频繁出现跨文档的因果、对比、聚合?现有RAG是否因为缺乏关联信息而频频答错?如果三个答案都是否,那你的核心矛盾不在这。
6.3 调参与落地建议
参数调优方面,我给出几个经验值供参考,不是金科玉律但胜在稳:
- 文本单元大小保持在800到1200之间,太短抽取关系不完整,太长小实体被淹没。
- 社区检测的粒度先按默认值跑,观察摘要数量。摘要超过一百份就调大粒度,少于二十份可以调小。
- 抽取提示词里尽量加入领域术语表。比如你的文档全是电力设备,就在提示词里明确告诉模型需要关注“设备型号、告警代码、维修动作”,效果提升比换模型更显著。
- 索引阶段卡顿先看API调用频率限制,再考虑切块大小,不要一上来就怀疑配置。
在真正压到生产环境之前,我强烈建议手工抽查一批实体抽取结果。打开实体文件,随机找二十个实体,看有没有出现大量张冠李戴、实体合并错误、关系方向颠倒的情况。这些错误在本地小样本上可能看不出来,但语料一多就会被放大,最终影响答案可靠性。
最后分享一点我个人实践中的体会:GraphRAG带来的提升不是“答案从错的变成对的”那么戏剧化,更多是“答案从拼凑感变成有依据感”。它让模型在回答时能意识到资料之间的关联,而不是像普通RAG那样对着几个孤立的片段自由发挥。建议想尝试的朋友,不要一上来就追求大而全的部署,先拿一份自己最熟悉的领域文档,把索引产物打开翻一翻,看实体、看关系、看社区摘要,等你亲手摸过这些中间产物之后,再来谈参数调优也不会迟。从观察图谱到理解查询路径,整个流程你会比看任何教程都更有底。
1万+




被折叠的 条评论
为什么被折叠?



