高级 📋 8 个步骤 第 452 / 455 篇

GraphRAG 知识图谱检索实战:用 LlamaIndex PropertyGraphIndex 让 Agent 会「推理关系」

普通向量 RAG 只能找到「相似的句子」,回答不了「谁和谁什么关系」。本文用 LlamaIndex PropertyGraphIndex 从文档抽取实体与关系,构建本地知识图谱,再让 Agent 在图谱上做多跳推理,完整跑通从文档到可追问的关系检索。

2026.09.19· 26 分钟阅读· 约 1375 字· 🕸️ GraphRAG / 🦙 LlamaIndex

你问向量 RAG「小明和小红是什么关系?」,它往往答不上来——因为它只会把问题 embedding 后找字面最像的句子,而「关系」往往藏在多段文字的连接里。GraphRAG 的思路是:先把文档里的实体(人/公司/概念)和它们之间的关系抽出来,建成一张知识图谱,再让检索在「图」上做多跳推理。本文用 LlamaIndex 的 PropertyGraphIndex 跑通一条本地、无需 Neo4j、可复现的最小链路。

🕸️ 学完你能做到:① 把若干文档变成一张本地知识图谱;② 直接问「A 和 B 什么关系」并得到基于图谱的回答;③ 知道什么时候该上 Neo4j、怎么和 Agent 结合。有 LLM Key 即可(推荐 gpt-4o-mini 级别,关系抽取对模型有一定要求)。

先搞懂:向量 RAG 和图 RAG 差在哪?

维度向量 RAGGraphRAG(本文)
检索单位chunk(文本块)实体 + 关系(节点 + 边)
擅长「某段话讲了什么」「谁和谁什么关系、怎么连起来」
多跳推理弱(靠 chunk 重叠碰运气)强(沿边遍历)
代价抽取成本高、需更强模型

别盲目上 GraphRAG。如果你的问答只是「某份文档里某段原话」,向量 RAG 又快又便宜;只有碰到「关系 / 多跳 / 全局总结」类问题,图检索才明显占优。本文聚焦后者。

Step 1:准备环境与数据

1 装依赖 + 放几段文本
pip install "llama-index>=0.11" "llama-index-llms-openai"

mkdir data && cd data
# 放几段 txt/md,内容最好是「人物/公司/概念 + 它们之间关系」的叙事
# 例:小明创办了 X 公司;X 公司投资了 Y 项目;小红是 Y 的项目负责人……
💡 关系抽取的质量高度依赖 LLM。用 gpt-4o-mini 或更强的模型;太小的本地模型抽关系会大量失真,反而得到一张「假图谱」。

Step 2:用 PropertyGraphIndex 建本地图谱

2 一条 from_documents 搞定抽取 + 建图
from llama_index.core import PropertyGraphIndex, SimpleDirectoryReader
from llama_index.core.graph_stores import SimplePropertyGraphStore
from llama_index.llms.openai import OpenAI

llm = OpenAI(model="gpt-4o-mini")   # 需 OPENAI_API_KEY

docs = SimpleDirectoryReader("./data").load_data()

index = PropertyGraphIndex.from_documents(
    docs,
    llm=llm,
    graph_store=SimplePropertyGraphStore(),   # 本地内存图,无需 Neo4j
    show_progress=True,
)

版本敏感点。PropertyGraphIndexSimplePropertyGraphStore 的 import 路径、参数在不同 llama-index 版本有变动。跑前先 pip show llama-index-core 看版本,若 import 报错,按官方对应版本文档微调(常见是 llama_index.core.graph_stores 路径调整)。

Step 3:看看图谱到底抽出了什么

3 把节点和关系打印出来

建完别急着查,先确认抽取质量——这是 GraphRAG 最容易翻车的地方:

rel_map = index.property_graph_store.get_rel_map()
for k, v in list(rel_map.items())[:10]:
    print(k, "->", v)

理想输出类似:小明 --创办--> X公司X公司 --投资--> Y项目。如果关系稀稀拉拉或全是噪声,说明文档太短 / 模型太弱 / prompt 没讲清要抽什么。

🔍 这一步是「体检」。关系抽得对,后面检索才靠谱;抽得乱,后面再花哨也是 garbage in garbage out。

Step 4:关系检索查询(对比向量 RAG 答不上来的问题)

4 直接问「关系」,看图谱怎么答
query_engine = index.as_query_engine()
print(query_engine.query("小明和 Y 项目之间有什么关系?"))

模型会沿「小明→创办→X公司→投资→Y项目」这条边做多跳,给出「小明通过创办的 X 公司投资了 Y 项目」这类回答。换成纯向量 RAG,这种跨越 3 段文本的关系往往拼不出来。

Step 5:让检索在图谱上做多跳推理

5 调检索器,控制跳数与召回

想更可控,可以单独用 retriever 看它从图里取回了哪些子图,再喂给模型:

retriever = index.as_retriever(include_text=False)
nodes = retriever.retrieve("小红负责什么?")
for n in nodes:
    print(n.get_content())
🧩 include_text=False 让它只回图谱里的「实体-关系」片段,更聚焦关系本身;需要原文佐证时再开 True

Step 6:进阶——换 Neo4j 图库(生产级、可 Cypher)

6 从内存图平滑迁移到 Neo4j

本地 SimplePropertyGraphStore 重启即丢、不能多人并发。生产环境把图存进 Neo4j:

from llama_index.graph_stores.neo4j import Neo4jPropertyGraphStore

graph_store = Neo4jPropertyGraphStore(
    username="neo4j", password="你的密码",
    url="bolt://localhost:7687", refresh_schema=False)

index = PropertyGraphIndex.from_documents(
    docs, llm=llm, graph_store=graph_store, show_progress=True)
# 之后可用 Cypher 直接查图,也支持更复杂的图算法

Neo4j 需要单独起服务(Docker 一条命令即可),并暴露 7687/7474 端口。本地演示阶段完全不必上它,等图谱要持久化、要 Cypher 查询、要并发访问时再迁。

Step 7:与 Agent 结合——把图谱当成一个工具

7 让 Agent 主动在图谱上查关系

把上面的 query engine 包成一个工具,Agent 就能「想查关系时查关系、想读原文时读原文」:

from llama_index.core.tools import QueryEngineTool

graph_tool = QueryEngineTool.from_defaults(
    query_engine=index.as_query_engine(),
    name="knowledge_graph",
    description="当用户问实体之间的关系、谁和谁有什么关联时使用",
)
# 把 graph_tool 交给你的 Agent(如 LlamaIndex Agent / LangChain)即可

常见问题与避坑

现象原因 & 解决
关系抽得很少 / 很乱文档太短或模型太弱;换更强模型、加长文档、明确抽取目标
import PropertyGraphIndex 报错版本不对应;按当时 llama-index 文档调整路径与参数
回答还是像向量检索问题本就是「原文复述」类,GraphRAG 优势不在;混用向量+图双路检索
成本飙升抽取每个 chunk 都过 LLM;控制文档量、用便宜模型做初抽、强模型做精修
← 返回教程中心