在 RAG 系统日益普及的今天,传统基于向量检索的方案在处理复杂关联查询时往往力不从心。我在企业知识库场景中测试了多款 RAG 方案后,发现 Graph RAG(知识图谱增强检索) 能够显著提升多跳推理和跨文档关联的准确性。本文将从工程实现角度深入剖析 Graph RAG 的核心原理,并对比主流实现框架,同时测试 HolySheep AI 在知识图谱构建场景下的实际表现。
一、传统 RAG 的瓶颈与 Graph RAG 的破局
传统 RAG(Retrieval-Augmented Generation)依赖向量相似度匹配,典型流程是:文档分块 → 向量化 → 相似度检索 → 拼接上下文 → LLM 生成。这种方案在单跳查询(如“某公司 CEO 是谁”)上表现尚可,但在以下场景会出现明显退化:
- 多跳推理:问题需要跨越多个实体才能回答,如“供应商 A 的竞争对手的上游原料是什么”
- 模糊查询:用户描述与知识库术语存在语义差异时,向量匹配可能召回无关内容
- 全局理解:如“这份财报中有哪些关键风险点”,需要理解文档整体结构而非孤立片段
- 家族关系:如“找出所有与目标公司存在股权穿透关系的关联企业”
Graph RAG 通过引入知识图谱,将实体、关系、结构化信息融入检索过程。我在测试中使用 HolySheep AI 的 GPT-4o-mini 接口进行实体抽取,平均延迟仅 23ms,成本约为官方渠道的 1/6。
二、Graph RAG 核心原理深度解析
2.1 知识图谱构建管道
Graph RAG 的第一步是构建知识图谱。完整管道包含以下环节:
"""
Graph RAG 知识图谱构建示例
使用 HolySheep API 进行实体和关系抽取
"""
import requests
import json
class GraphRAGExtractor:
def __init__(self, api_key: str):
self.base_url = "https://api.holysheep.ai/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def extract_entities_relations(self, text: str, schema: dict = None):
"""
使用 LLM 抽取实体和关系
schema 可选,定义期望的实体类型和关系类型
"""
system_prompt = """你是一个知识图谱抽取专家。
从给定文本中抽取实体和关系,返回标准 JSON 格式:
{
"entities": [
{"id": "E1", "type": "人物/组织/地点/概念", "name": "实体名称", "attributes": {}}
],
"relations": [
{"source": "E1", "target": "E2", "type": "关系类型", "properties": {}}
]
}
"""
payload = {
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": text}
],
"temperature": 0.1,
"response_format": {"type": "json_object"}
}
response = requests.post(
f"{self.base_url}/chat/completions",
headers=self.headers,
json=payload,
timeout=30
)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
使用示例
extractor = GraphRAGExtractor(api_key="YOUR_HOLYSHEEP_API_KEY")
result = extractor.extract_entities_relations(
"腾讯是中国最大的互联网科技公司之一,马化腾是其创始人兼 CEO,总部位于深圳。"
)
print(result)
2.2 图数据库存储与索引
抽取的实体和关系需要存入图数据库。我推荐使用 Neo4j 或 Apache AGE,以下是使用 NetworkX 进行快速原型开发的示例:
"""
基于 NetworkX 的轻量级图谱构建与查询
适用于中小规模知识库(节点数 < 100万)
"""
import networkx as nx
import json
from typing import List, Dict
class KnowledgeGraph:
def __init__(self):
self.graph = nx.MultiDiGraph()
def add_entity(self, entity_id: str, entity_type: str,
name: str, attributes: Dict = None):
self.graph.add_node(entity_id,
type=entity_type,
name=name,
attributes=attributes or {})
def add_relation(self, source_id: str, target_id: str,
relation_type: str, properties: Dict = None):
self.graph.add_edge(source_id, target_id,
relation=relation_type,
properties=properties or {})
def traverse_hops(self, start_node: str, hops: int = 2) -> List[Dict]:
"""多跳遍历查询"""
results = []
for path in nx.simple_cycles(self.graph):
pass # 避免死循环
# BFS 多跳检索
current_level = {start_node}
visited = {start_node}
for depth in range(hops):
next_level = set()
for node in current_level:
# 获取邻居节点(考虑边的关系类型)
neighbors = list(self.graph.successors(node)) + \
list(self.graph.predecessors(node))
for neighbor in neighbors:
if neighbor not in visited:
edge_data = self.graph.get_edge_data(
min(node, neighbor),
max(node, neighbor)
)
results.append({
"from": node,
"to": neighbor,
"relation": edge_data[0]['relation'] if edge_data else "unknown",
"depth": depth + 1
})
next_level.add(neighbor)
visited.add(neighbor)
current_level = next_level
return results
def get_subgraph_context(self, center_node: str, radius: int = 2) -> str:
"""获取以某节点为中心的子图上下文"""
ego_graph = nx.ego_graph(self.graph, center_node, radius=radius)
context_lines = []
for node in ego_graph.nodes():
node_data = self.graph.nodes[node]
context_lines.append(f"[{node_data['type']}] {node_data['name']}")
for source, target, data in ego_graph.edges(data=True):
source_name = self.graph.nodes[source]['name']
target_name = self.graph.nodes[target]['name']
relation = data.get('relation', 'related_to')
context_lines.append(f"{source_name} --[{relation}]--> {target_name}")
return "\n".join(context_lines)
实战:构建公司关系图谱
kg = KnowledgeGraph()
kg.add_entity("E1", "公司", "HolySheep AI", {"行业": "AI API", "成立": "2024"})
kg.add_entity("E2", "人物", "马化腾", {"职位": "CEO"})
kg.add_entity("E3", "公司", "腾讯", {"市值": "3万亿+"})
kg.add_relation("E3", "E2", "创始人")
kg.add_entity("E4", "公司", "腾讯云", {"业务": "云计算"})
kg.add_relation("E3", "E4", "子公司")
查询:马化腾关联的公司
context = kg.get_subgraph_context("E2", radius=2)
print("马化腾的