记忆点:相似内容用向量,关系推理看图谱;GraphRAG 并非总是更优。
💡 答案要点
GraphRAG = 知识图谱 + RAG,用实体关系图做检索而非纯向量相似度
核心区别
| 维度 | 向量RAG | GraphRAG |
|---|---|---|
| 数据组织 | 文本切块→向量 | 实体+关系→图节点/边 |
| 检索方式 | 语义相似度(近似邻居) | 图遍历/Cypher查询 |
| 多跳推理 | ❌ 难以关联多个文档 | ✅ 沿关系路径自然推理 |
| 可解释性 | 低(黑盒相似度) | 高(关系路径可追踪) |
| 构建成本 | 低 | 高(需要NER+关系抽取) |
| 适用场景 | 语义搜索、文档问答 | 复杂关系推理、知识密集 |
GraphRAG实现流程
Step 1:知识图谱构建
展开 Python 代码示例(60 行)
python
from neo4j import GraphDatabase
import spacy
class KnowledgeGraphBuilder:
def __init__(self, neo4j_uri, user, password):
self.driver = GraphDatabase.driver(neo4j_uri, auth=(user, password))
self.nlp = spacy.load("zh_core_web_sm")
def extract_entities_relations(self, text: str):
"""用LLM抽取实体和关系"""
prompt = f"""
从以下文本中提取实体和关系,以JSON格式输出:
文本:{text}
输出格式:
{{
"entities": [
{{"name": "实体名", "type": "Person/Organization/Product/Location"}}
],
"relations": [
{{"source": "实体A", "relation": "关系类型", "target": "实体B"}}
]
}}
"""
result = llm.generate(prompt, temperature=0)
return json.loads(result)
def build_graph(self, documents: list):
"""将文档转化为知识图谱"""
with self.driver.session() as session:
for doc in documents:
data = self.extract_entities_relations(doc)
# 创建实体节点
for entity in data["entities"]:
session.run(
"MERGE (e:Entity {name: $name}) SET e.type = $type",
name=entity["name"], type=entity["type"]
)
# 创建关系边
for rel in data["relations"]:
session.run("""
MATCH (a:Entity {name: $source})
MATCH (b:Entity {name: $target})
MERGE (a)-[r:RELATION {type: $rel_type}]->(b)
""", source=rel["source"],
target=rel["target"],
rel_type=rel["relation"])
# 示例:构建公司知识图谱
builder = KnowledgeGraphBuilder("bolt://localhost:7687", "neo4j", "password")
docs = [
"张三是阿里巴巴的CTO,负责技术战略",
"阿里巴巴旗下有淘宝、天猫、支付宝等产品",
"支付宝由彭蕾创立,现由韩歆毅担任CEO",
]
builder.build_graph(docs)Step 2:图检索查询
展开 Python 代码示例(56 行)
python
class GraphRAGRetriever:
def __init__(self, driver, llm):
self.driver = driver
self.llm = llm
def query_to_cypher(self, user_query: str) -> str:
"""将自然语言查询转为Cypher图查询"""
prompt = f"""
将以下问题转为Neo4j Cypher查询语句:
问题:{user_query}
图结构:节点(Entity)有name和type属性,关系(RELATION)有type属性
只输出Cypher语句,不加解释:
"""
return self.llm.generate(prompt, temperature=0).strip()
def retrieve(self, user_query: str) -> list:
"""图检索 + 向量检索混合"""
results = []
# 1. 图检索:精确关系查询
try:
cypher = self.query_to_cypher(user_query)
with self.driver.session() as session:
graph_results = session.run(cypher).data()
results.extend(graph_results)
except Exception as e:
print(f"图查询失败,降级到向量检索:{e}")
# 2. 向量检索:语义相似度补充
vector_results = vectordb.search(user_query, k=3)
results.extend(vector_results)
return results
def multi_hop_reasoning(self, query: str, max_hops=3) -> str:
"""多跳推理:沿图关系路径推理"""
# 提取问题中的实体
entities = self.extract_entities(query)
reasoning_chain = []
for entity in entities:
# 从实体出发,遍历K跳邻居
cypher = f"""
MATCH path = (start:Entity {{name: '{entity}'}})-[*1..{max_hops}]-(end:Entity)
RETURN path, length(path) as hops
ORDER BY hops
LIMIT 20
"""
with self.driver.session() as session:
paths = session.run(cypher).data()
reasoning_chain.extend(paths)
return reasoning_chainStep 3:结合LLM生成
python
def graphrag_answer(user_query: str):
retriever = GraphRAGRetriever(driver, llm)
# 1. 多跳图检索
graph_context = retriever.multi_hop_reasoning(user_query, max_hops=2)
# 2. 格式化图上下文
graph_text = format_graph_paths(graph_context)
# 3. LLM生成
prompt = f"""
基于以下知识图谱信息回答问题:
图谱信息(实体关系路径):
{graph_text}
问题:{user_query}
请基于上述关系链条进行推理并回答:
"""
return llm.generate(prompt)
# 示例
answer = graphrag_answer("支付宝的创始人和阿里巴巴CTO是什么关系?")
# 推理路径:彭蕾 → 创立 → 支付宝 → 归属 → 阿里巴巴 ← 任职 → 张三(CTO)
# 回答:"彭蕾创立了支付宝,支付宝隶属于阿里巴巴,张三是阿里巴巴的CTO,所以彭蕾和张三都服务于阿里巴巴体系..."选型建议
问自己3个问题:
1. 问题需要多跳推理吗?
例:"A的老板的老板是谁?" → 需要 → 选GraphRAG
2. 实体间关系是核心信息吗?
例:医药、法律、供应链 → 是 → 选GraphRAG
3. 数据是自由文本为主吗?
例:文章、客服记录 → 是 → 选向量RAG
推荐:生产环境用混合方案(向量召回 + 图精排)面试话术:
"GraphRAG用知识图谱替代纯向量存储,核心优势是多跳推理和可解释性。实现分3步:LLM抽取实体关系建图、自然语言转Cypher图查询、沿关系路径推理生成答案。我用过混合方案:向量检索做宽召回,图遍历做精确关系推理,在医疗知识图谱项目中,多跳问题准确率从向量RAG的45%提升到GraphRAG的82%。代价是构建成本高,需要NER+关系抽取流程。"
