这篇的任务
前两篇建好了测试集,并测完了经典向量 RAG(QAnything vs LightRAG)。
这篇测"图增强 RAG"------理论上,知识图谱应该能帮助多跳推理:A 指向 B,B 指向 C,传统向量检索往往只能找到 B,而图结构能顺着边找到 C。
我选了两个代表框架:
- GraphRAG 3.1.1(微软,2024 年把"图谱 RAG"这个词打出圈的那个)
- HippoRAG 2.0(2025 年的学术框架,用海马体记忆模型类比图检索)
两个框架,同一套 89 道题(50 单跳 / 20 多跳 / 19 边界),同一个 LLM(GLM-4-flash),数字说话。
两个框架是什么东西
GraphRAG:LLM 驱动的知识图谱提取
GraphRAG 的流程比较重:先用 LLM 从文档里抽取实体和关系,构建一个显式的知识图谱;然后把图谱里的节点按社区(Louvain 算法)分组,每个社区用 LLM 生成摘要报告;查询时,local search 在图谱里做近邻检索,global search 则聚合全局社区报告。
sql
文档 → LLM 抽实体/关系 → 知识图谱 → 社区划分 → 社区摘要报告
↓
查询 ─── local search: 图谱近邻 + 向量检索 ──────────→ LLM 生成答案
└── global search: 聚合社区报告 ─────────────→ LLM 生成答案
核心特点:建库成本极高(要对每个文本块调 LLM 抽关系),但建好后支持结构化图谱查询。
HippoRAG:海马体启发的图检索
HippoRAG 把检索过程类比成人类记忆的 PPR(Personalized PageRank)机制:用 LLM 从文档里提取三元组(实体、关系、实体),用大维度 embedding(NV-Embed-v2,1024 维)把所有实体存入向量索引,查询时先做向量召回找到种子节点,再沿图谱边做 PPR 扩散找到关联节点。
bash
文档 → LLM 提取三元组 (head, rel, tail) → 知识图谱
→ NV-Embed-v2 把实体向量化 → 向量索引
↓
查询 → 向量召回种子实体 → PPR 图谱扩散 → 召回相关段落 → LLM 生成答案
核心特点:依赖本地大模型 NV-Embed-v2(7B 参数,~14 GB),不依赖 LLM 做 embedding,理论上 embedding 质量更高。
部署过程与踩坑
GraphRAG:pipeline 比想象的脆
GraphRAG 用 YAML 配置文件驱动整个 pipeline,graphrag index 命令会按顺序执行一系列 workflow。文档挺齐,配置也不复杂,但有几个坑。
坑 1:LLM 不支持结构化输出导致 pipeline 崩溃
GraphRAG 的社区报告生成(create_community_reports)期望 LLM 返回 JSON,但 GLM-4-flash 的 structured output 实现不稳定,大量 prompt 会返回空 JSON,导致 DataFrame 里没有 "community" 列,merge 报 KeyError 直接崩溃。
解决方案是在 settings.yaml 的 workflows: 列表里跳过这个步骤,同时手动创建一个符合 schema 的空 community_reports.parquet------local search 会读这个文件,但允许它是空的。
坑 2:向量维度不匹配
GraphRAG 默认 vector_size: 3072(对应 OpenAI text-embedding-3-large),但我用的 BGE-large-en-v1.5 输出 1024 维。直接跑会报 Vector has dimension 1024, but index configured with 3072,需要在 settings.yaml 里手动加 vector_size: 1024。
坑 3:全流程重跑会重新消耗 LLM 配额
第一次跑崩后,再次执行 graphrag index 会从头重跑所有步骤,包括已经完成的 extract_graph(对 4000+ 文本块调 LLM 提取实体关系,费时费钱)。需要单独写一个脚本只跑 generate_text_embeddings 步骤,利用已有的中间产物。
坑 4:SiliconFlow API 对特定内容拒绝
测试文档里包含 .env 配置文件的内容,里面有类 API key 格式的字符串。SiliconFlow 的内容过滤会对这类输入返回 400 错误(code 20015),导致 embedding 步骤批量失败。把 embed_text.names 限定为只嵌入 entity_description(而不是整个 text_unit),可以绕过这个问题,同时 local search 也不需要 text_unit 的 embedding。
HippoRAG:本地大模型的环境依赖地狱
HippoRAG 最大的依赖是 NV-Embed-v2,一个基于 Mistral-7B 的 7B embedding 模型。
坑 1:离线加载失败
NV-Embed-v2 的 modeling_nvembed.py 在 __init__ 里调用 AutoTokenizer.from_pretrained("nvidia/NV-Embed-v2")(字符串 ID,非本地路径),导致 transformers 每次都去 HuggingFace hub 下载,断网环境直接报错。
解决方案是在脚本最顶部 monkey-patch AutoTokenizer.from_pretrained,把 "nvidia/NV-Embed-v2" 这个字符串重定向到本地模型路径。
坑 2:显存不足
RTX 3060(12 GB)在跑 NV-Embed-v2(Mistral-7B bf16,~14 GB 权重)时,device_map="auto" 会把部分层卸载到 CPU,但前向推理的激活值仍需要 GPU 临时空间。默认的 batch_size=16 加上 max_seq_len=2048 会导致 OOM。
调小参数即可:embedding_max_seq_len=512,embedding_batch_size=1,同时显式指定 embedding_model_dtype="bfloat16" 防止 auto 选到 fp32。
评测数据
数值汇总
| 指标 | GraphRAG 3.1.1 | HippoRAG 2.0 |
|---|---|---|
| 建库时间 | 31.1 min | 36.5 min |
| 边界拒答率 | 15.8% | 5.3% |
| P90 延迟 | 32.4 s | 84.0 s |
| 平均延迟 | 26.6 s | 30.1 s |
| 单跳匹配率 | 0.107 | 0.122 |
| 多跳匹配率 | 0.211 | 0.163 |
| 边界题匹配率 | 0.030 | 0.021 |
答案匹配用 Jaccard 关键词重叠,非 LLM judge;LLM 均为 GLM-4-flash
多跳推理:GraphRAG 赢了,但没赢太多
GraphRAG 的 multi_hop 匹配率 0.211,高于 HippoRAG 的 0.163。这符合预期------微软的论文里也是拿多跳推理作为卖点。
但差距没有大到"质变"的程度:0.211 vs 0.163,只高了约 30%。考虑到 GraphRAG 的建库成本(31 分钟,期间调用 LLM 提取了数千次实体关系),这个收益并不那么令人振奋。
和上一篇的向量 RAG 对比一下:LightRAG 的 multi_hop 匹配率是 0.152,QAnything 是 0.125。GraphRAG 的 0.211 确实比向量 RAG 高出不少,但 HippoRAG 的 0.163 仅比 LightRAG 高了一点点。
单跳检索:图增强没有优势
单跳事实查询("X 的默认值是什么")上,HippoRAG(0.122)比 GraphRAG(0.107)还略高,两者都不如上一篇的 LightRAG(0.156)。
这说明:知识图谱结构对直接的事实查询没有帮助,甚至有干扰。图谱检索路径更长,引入了更多的"图谱噪声"(社区摘要、关系路径),反而稀释了直接的答案。
边界拒答:GraphRAG 意外有优势
GraphRAG 的边界拒答率 15.8%,HippoRAG 只有 5.3%。这个差异出乎意料。
GraphRAG 的 local search 会说"根据知识库内容,我无法回答......",而 HippoRAG 因为 PPR 扩散几乎总能找到"相关"节点,LLM 便倾向于硬答。
不过,15.8% 对比上一篇 QAnything 的 52.6% 仍差距悬殊。图增强 RAG 在拒答上的表现整体不如有明确 confidence threshold 的向量 RAG 系统。
延迟:HippoRAG 慢得超出预期
HippoRAG 的 P90 延迟高达 84 秒,平均 30 秒。这和我最初的预期相反------本地模型推理应该更快才对。
原因是双重的:
embedding_batch_size=1降低了显存压力,但批量推理效率也大幅下降。在正常显存配置(A100 或 3090 Ti)下,batch_size 调回 16,嵌入速度会快 10-20 倍。- HippoRAG 的查询路径比较长:向量召回 → PPR 扩散 → 段落组装 → LLM 生成,每步都有开销。
GraphRAG 的平均 26.6 秒也不快,主要是 GLM-4-flash 的 rate limit 压制了并发(concurrent_requests: 1)。
横向对比:四个框架的完整数据
把这两篇的数字放一起:
| 框架 | 类型 | 建库时间 | 拒答率 | P90 延迟 | 单跳 | 多跳 |
|---|---|---|---|---|---|---|
| QAnything v2 | 向量 RAG | ~5 min | 52.6% | 49.2 s | 0.132 | 0.125 |
| LightRAG 1.5.6 | 图+向量 | ~8 min | 21.1% | 17.9 s | 0.156 | 0.152 |
| GraphRAG 3.1.1 | 图 RAG | 31.1 min | 15.8% | 32.4 s | 0.107 | 0.211 |
| HippoRAG 2.0 | 图 RAG | 36.5 min | 5.3% | 84.0 s | 0.122 | 0.163 |
几个明显的规律:
- 建库时间跟"图谱有多重"正相关:LightRAG 靠 LLM 异步抽图,8 分钟;GraphRAG 和 HippoRAG 要对每个块调 LLM 提取结构化三元组,30 分钟级别。
- 多跳推理图 RAG 确实比向量 RAG 强:GraphRAG 0.211 vs LightRAG 0.152,图结构对多跳推理有统计上可见的优势。
- 单跳检索向量 RAG 更胜任:LightRAG 的 0.156 优于所有图 RAG 方案。
- 拒答能力与检索机制无关,与系统设计有关:QAnything 有置信度过滤,所以拒答率高;图 RAG 框架没做这层,几乎不拒答。
选哪个?
基于这次评测:
优先选 GraphRAG,如果:
- 核心场景是复杂多跳推理(政策关联、因果链分析)
- 有足够的 LLM 配额承担建库成本
- 使用支持结构化输出的 LLM(GPT-4o、Claude 等),可以启用社区报告
- 不在乎建库时间(30 分钟级别)
优先选 HippoRAG,如果:
- 有本地 GPU(>12 GB,最好 24 GB),不想依赖外部 embedding API
- 知识库需要频繁更新(HippoRAG 的增量更新比 GraphRAG 快)
- 愿意接受更高延迟换取更强的本地私有化部署
这两个框架都不适合,如果:
- 主要场景是快速事实查询(选 LightRAG)
- 需要强拒答能力(选 QAnything,或在图 RAG 上加置信度后处理)
- 对部署成本敏感(图 RAG 的建库 LLM 开销是向量 RAG 的 5-10 倍)
本次评测的限制:
- LLM 使用 GLM-4-flash(免费额度),对结构化输出支持有限,GraphRAG 无法启用社区报告------社区报告是 global search 的核心,本次只测了 local search
- HippoRAG 受显存限制强制降低了 batch_size 和 max_seq_len,延迟数据有失真,在正常硬件上会好很多
- 答案匹配用 Jaccard 关键词重叠,不是 LLM judge,偏保守
评测代码
完整代码在 llm-in-action/kb-03-graphrag-eval/ 和 llm-in-action/kb-03-hipporag-eval/。
GraphRAG 评测关键配置:
yaml
# settings.yaml 关键调整
workflows: # 跳过社区报告生成(LLM 结构化输出不稳定时)
- create_base_text_units
- create_final_documents
- extract_graph
- finalize_graph
- extract_covariates
- create_communities
- create_final_text_units
- generate_text_embeddings
vector_store:
type: lancedb
vector_size: 1024 # 必须与 embedding 维度一致
embed_text:
names:
- entity_description # 只嵌入实体描述,跳过 text_unit
batch_max_tokens: 300
batch_size: 4
concurrent_requests: 1 # GLM-4-flash rate limit 限制
HippoRAG 评测关键初始化:
python
from hipporag.utils.config_utils import BaseConfig
global_config = BaseConfig(
embedding_max_seq_len=512, # 降低显存需求
embedding_batch_size=1,
embedding_model_dtype="bfloat16",
)
hipporag = HippoRAG(
global_config=global_config,
save_dir=SAVE_DIR,
llm_model_name=LLM_MODEL,
llm_base_url=LLM_BASE_URL,
embedding_model_name=EMBEDDING_MODEL_PATH, # 本地路径
)
下一篇:HyperGraphRAG 实测------超图结构的多跳推理。同样 89 道题,看看把二元关系升级为超图之后,多跳推理能提升多少。
欢迎访问 PrimeSkills ------ 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。
更多实用知识和有趣产品,欢迎访问我的个人主页