首页 > 应用开发 > IT综合 > GraphRAG进阶实践:构建私有知识图谱问答系统
# GraphRAG进阶实践:构建私有知识图谱问答系统
传统RAG系统在复杂推理和深层关系挖掘方面存在局限,GraphRAG通过知识图谱技术为问答系统提供结构化的语义理解。本文将介绍基于GraphRAG的工业级问答系统实现方案。
## 系统架构设计
```python
from typing import List, Dict, Any, Optional
from dataclasses import dataclass
import networkx as nx
from langchain.schema import Document
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
import torch
@dataclass
class KnowledgeGraph:
"""知识图谱数据结构"""
nodes: Dict[str, Dict] # 节点ID到节点属性的映射
edges: List[Dict] # 边列表
embeddings: Dict[str, torch.Tensor] # 节点嵌入表示
class GraphRAGSystem:
"""GraphRAG核心系统"""
def __init__(self,
embedding_model: str = "text-embedding-ada-002",
llm_model: str = "gpt-4"):
self.embedding_model = OpenAIEmbeddings(
model=embedding_model
)
self.llm_model = llm_model
self.knowledge_graph = KnowledgeGraph({}, [], {})
self.vector_store = None
self.graph_index = None
def initialize_system(self, private_data_path: str):
"""初始化系统"""
# 1. 加载私有数据
documents = self._load_private_data(private_data_path)
# 2. 构建知识图谱
self.knowledge_graph = self._build_knowledge_graph(documents)
# 3. 创建向量索引
self.vector_store = self._create_vector_store(documents)
# 4. 构建图索引
self.graph_index = self._build_graph_index()
return self
```
## 私有数据处理与知识抽取
```python
class PrivateDataProcessor:
"""私有数据处理器"""
def __init__(self):
self.entity_types = [
"人物", "组织", "产品", "技术", "概念",
"事件", "地点", "时间", "数值"
]
def process_documents(self, documents: List[Document]) -> List[Dict]:
"""处理文档并提取结构化信息"""
processed_docs = []
for doc in documents:
# 实体识别
entities = self._extract_entities(doc.page_content)
# 关系抽取
relations = self._extract_relations(doc.page_content, entities)
# 事件抽取
events = self._extract_events(doc.page_content)
processed_docs.append({
"id": doc.metadata.get("id", f"doc_{len(processed_docs)}"),
"content": doc.page_content,
"metadata": doc.metadata,
"entities": entities,
"relations": relations,
"events": events,
"embedding": self._generate_document_embedding(doc.page_content)
})
return processed_docs
def _extract_entities(self, text: str) -> List[Dict]:
"""使用NER模型抽取实体"""
prompt = f"""
从以下文本中提取实体:
文本:{text[:1000]}
实体类型包括:{', '.join(self.entity_types)}
返回JSON格式:
{{
"entities": [
{{
"text": "实体文本",
"type": "实体类型",
"start_pos": 起始位置,
"end_pos": 结束位置
}}
]
}}
"""
# 调用LLM进行实体识别
response = self._call_llm(prompt)
return response.get("entities", [])
def _extract_relations(self, text: str, entities: List[Dict]) -> List[Dict]:
"""抽取实体间关系"""
if len(entities) < 2:
return []
prompt = f"""
分析以下文本中实体之间的关系:
文本:{text[:800]}
实体列表:
{json.dumps(entities[:10], ensure_ascii=False, indent=2)}
关系类型包括:属于、参与、导致、包含、相似、对比
返回JSON格式:
{{
"relations": [
{{
"subject": "主体实体",
"predicate": "关系谓词",
"object": "客体实体",
"confidence": 置信度
}}
]
}}
"""
response = self._call_llm(prompt)
return response.get("relations", [])
def _extract_events(self, text: str) -> List[Dict]:
"""抽取事件信息"""
prompt = f"""
从文本中提取事件信息:
文本:{text[:1200]}
返回JSON格式:
{{
"events": [
{{
"description": "事件描述",
"participants": ["参与者1", "参与者2"],
"time": "时间信息",
"location": "地点信息",
"outcome": "结果影响"
}}
]
}}
"""
response = self._call_llm(prompt)
return response.get("events", [])
```
## 知识图谱构建与优化
```python
class KnowledgeGraphBuilder:
"""知识图谱构建器"""
def __init__(self, embedding_model):
self.embedding_model = embedding_model
self.graph = nx.MultiDiGraph()
def build_from_documents(self, processed_docs: List[Dict]) -> KnowledgeGraph:
"""从处理后的文档构建知识图谱"""
# 第一步:创建节点
node_id_map = {} # 实体文本到节点ID的映射
for doc in processed_docs:
# 添加文档节点
doc_node_id = f"doc_{doc['id']}"
self.graph.add_node(doc_node_id,
type="document",
content=doc["content"],
embedding=doc["embedding"])
# 添加实体节点并建立链接
for entity in doc["entities"]:
entity_text = entity["text"]
if entity_text not in node_id_map:
# 创建新实体节点
entity_node_id = f"entity_{len(node_id_map)}"
node_id_map[entity_text] = entity_node_id
self.graph.add_node(entity_node_id,
type="entity",
text=entity_text,
entity_type=entity["type"],
embedding=self._embed_entity(entity_text))
# 建立文档-实体关系
self.graph.add_edge(doc_node_id, node_id_map[entity_text],
relation="mentions")
self.graph.add_edge(node_id_map[entity_text], doc_node_id,
relation="mentioned_in")
# 第二步:添加关系边
for doc in processed_docs:
doc_node_id = f"doc_{doc['id']}"
for relation in doc["relations"]:
subject = relation["subject"]
object_ = relation["object"]
if subject in node_id_map and object_ in node_id_map:
self.graph.add_edge(node_id_map[subject],
node_id_map[object_],
relation=relation["predicate"],
confidence=relation["confidence"])
# 第三步:图谱优化和增强
self._enrich_graph()
# 转换为系统需要的格式
return self._convert_to_knowledge_graph()
def _embed_entity(self, entity_text: str) -> torch.Tensor:
"""生成实体嵌入向量"""
embedding = self.embedding_model.embed_query(entity_text)
return torch.tensor(embedding)
def _enrich_graph(self):
"""图谱增强:添加隐含关系和计算中心性"""
# 1. 计算节点中心性
degree_centrality = nx.degree_centrality(self.graph)
betweenness_centrality = nx.betweenness_centrality(self.graph)
for node in self.graph.nodes():
self.graph.nodes[node]["degree_centrality"] = degree_centrality.get(node, 0)
self.graph.nodes[node]["betweenness_centrality"] = betweenness_centrality.get(node, 0)
# 2. 发现隐含关系
self._discover_implicit_relations()
# 3. 社区检测
communities = self._detect_communities()
for node, community_id in communities.items():
self.graph.nodes[node]["community"] = community_id
def _discover_implicit_relations(self):
"""发现隐含关系(例如:基于嵌入相似性)"""
entity_nodes = [n for n, attr in self.graph.nodes(data=True)
if attr.get("type") == "entity"]
# 计算实体相似性
for i, node1 in enumerate(entity_nodes):
for node2 in entity_nodes[i+1:]:
emb1 = self.graph.nodes[node1]["embedding"]
emb2 = self.graph.nodes[node2]["embedding"]
similarity = torch.cosine_similarity(emb1, emb2, dim=0).item()
# 如果相似度高且没有现有关系,添加相似关系
if similarity > 0.8 and not self.graph.has_edge(node1, node2):
self.graph.add_edge(node1, node2,
relation="similar_to",
similarity=similarity,
inferred=True)
def _convert_to_knowledge_graph(self) -> KnowledgeGraph:
"""将NetworkX图转换为KnowledgeGraph格式"""
nodes = {}
edges = []
embeddings = {}
for node, attr in self.graph.nodes(data=True):
nodes[node] = attr
if "embedding" in attr:
embeddings[node] = attr["embedding"]
for u, v, key, attr in self.graph.edges(data=True, keys=True):
edges.append({
"source": u,
"target": v,
"relation": attr.get("relation", "unknown"),
"properties": {k: v for k, v in attr.items() if k != "relation"}
})
<"t9.j9k5.org.cn"><"i2.j9k5.org.cn"><"o5.j9k5.org.cn">
return KnowledgeGraph(nodes, edges, embeddings)
```
## 图检索与增强生成
```python
class GraphRetriever:
"""图检索器"""
def __init__(self, knowledge_graph: KnowledgeGraph, vector_store):
self.knowledge_graph = knowledge_graph
self.vector_store = vector_store
self.graph = self._convert_to_networkx(knowledge_graph)
def retrieve(self, query: str, top_k: int = 5) -> Dict:
"""检索与查询相关的图谱信息"""
# 1. 向量检索(传统RAG)
vector_results = self.vector_store.similarity_search(query, k=top_k)
# 2. 图谱检索
graph_results = self._graph_based_retrieval(query)
# 3. 融合检索结果
fused_results = self._fuse_retrieval_results(
vector_results, graph_results
)
# 4. 提取相关子图
relevant_subgraph = self._extract_relevant_subgraph(
fused_results["entity_nodes"]
)
return {
"vector_results": vector_results,
"graph_results": graph_results,
"fused_results": fused_results,
"relevant_subgraph": relevant_subgraph
}
def _graph_based_retrieval(self, query: str) -> Dict:
"""基于图谱的检索"""
# 实体链接
query_entities = self._extract_query_entities(query)
# 找到相关实体节点
entity_nodes = []
for entity in query_entities:
# 在知识图谱中查找相似实体
similar_nodes = self._find_similar_entities(entity)
entity_nodes.extend(similar_nodes)
# 扩展检索:获取邻居节点和路径
expanded_nodes = self._expand_around_entities(entity_nodes)
# 路径发现:找到实体间的联系路径
connection_paths = self._find_connection_paths(entity_nodes)
return {
"query_entities": query_entities,
"entity_nodes": entity_nodes,
"expanded_nodes": expanded_nodes,
"connection_paths": connection_paths
}
def _extract_relevant_subgraph(self, entity_nodes: List[str]) -> Dict:
"""提取相关子图"""
# 提取以实体节点为中心的k-hop子图
subgraph_nodes = set(entity_nodes)
for node in entity_nodes:
# 获取2-hop邻居
neighbors = nx.single_source_shortest_path_length(
self.graph, node, cutoff=2
)
subgraph_nodes.update(neighbors.keys())
# 创建子图
subgraph = self.graph.subgraph(subgraph_nodes)
return {
"nodes": list(subgraph.nodes(data=True)),
"edges": list(subgraph.edges(data=True)),
"summary": self._summarize_subgraph(subgraph)
}
def _summarize_subgraph(self, subgraph) -> str:
"""生成子图摘要"""
entities = [n for n, attr in subgraph.nodes(data=True)
if attr.get("type") == "entity"]
relations = []
for u, v, attr in subgraph.edges(data=True):
if "relation" in attr:
u_text = subgraph.nodes[u].get("text", u)
v_text = subgraph.nodes[v].get("text", v)
relations.append(f"{u_text} - {attr['relation']} -> {v_text}")
summary = f"""
相关子图包含 {len(entities)} 个实体和 {len(relations)} 种关系。
主要实体:
{', '.join([subgraph.nodes[e].get('text', e) for e in entities[:10]])}
关键关系:
{chr(10).join(relations[:10])}
"""
return summary
```
## 图增强生成模块
```python
class GraphEnhancedGenerator:
"""图增强生成器"""
def __init__(self, llm_model: str = "gpt-4"):
self.llm_model = llm_model
def generate_answer(self, query: str, retrieval_results: Dict) -> Dict:
"""基于检索结果生成答案"""
# 准备上下文
context = self._prepare_context(retrieval_results)
# 生成基础答案
base_answer = self._generate_base_answer(query, context)
# 图验证和增强
enhanced_answer = self._enhance_with_graph(
query, base_answer, retrieval_results
)
# 生成解释和来源
explanation = self._generate_explanation(
query, enhanced_answer, retrieval_results
)
return {
"answer": enhanced_answer,
"explanation": explanation,
"confidence": self._calculate_confidence(
enhanced_answer, retrieval_results
),
"sources": self._extract_sources(retrieval_results)
}
def _prepare_context(self, retrieval_results: Dict) -> str:
"""准备生成上下文"""
context_parts = []
# 1. 向量检索结果
vector_context = "文档信息:\n"
for i, doc in enumerate(retrieval_results["vector_results"][:3]):
vector_context += f"{i+1}. {doc.page_content[:500]}...\n\n"
# 2. 图谱信息
graph_context = "知识图谱信息:\n"
subgraph_summary = retrieval_results["relevant_subgraph"]["summary"]
graph_context += subgraph_summary
# 3. 路径信息
if retrieval_results["graph_results"]["connection_paths"]:
paths_context = "\n实体关联路径:\n"
for path in retrieval_results["graph_results"]["connection_paths"][:3]:
paths_context += f"- {self._format_path(path)}\n"
graph_context += paths_context
return f"{vector_context}\n{graph_context}"
def _enhance_with_graph(self, query: str, base_answer: str,
retrieval_results: Dict) -> str:
"""使用图谱信息增强答案"""
prompt = f"""
基于以下查询、基础答案和图谱信息,生成增强版答案:
查询:{query}
基础答案:{base_answer}
知识图谱摘要:
{retrieval_results['relevant_subgraph']['summary']}
任务要求:
1. 确保答案准确反映图谱中的关系
2. 如果图谱信息与基础答案矛盾,以图谱为准
3. 补充图谱中独有的深度信息
4. 保持答案的连贯性和完整性
返回增强后的答案。
"""
enhanced_answer = self._call_llm(prompt)
return enhanced_answer
def _generate_explanation(self, query: str, answer: str,
retrieval_results: Dict) -> str:
"""生成推理过程解释"""
# 提取关键证据节点
evidence_nodes = self._extract_evidence_nodes(
answer, retrieval_results
)
prompt = f"""
为以下问答生成推理过程解释:
问题:{query}
答案:{answer}
关键证据节点:
{json.dumps(evidence_nodes, ensure_ascii=False, indent=2)}
解释要求:
1. 说明使用了哪些信息来源
2. 描述推理过程中的关键步骤
3. 解释如何从证据推导出结论
4. 提及不确定性和假设
返回详细的解释文本。
"""
return self._call_llm(prompt)
```
## 工业级部署与优化
```python
class IndustrialGraphRAG:
"""工业级GraphRAG系统"""
def __init__(self, config: Dict):
self.config = config
self.system = GraphRAGSystem(
embedding_model=config.get("embedding_model"),
llm_model=config.get("llm_model")
)
# 初始化组件
self.processor = PrivateDataProcessor()
self.graph_builder = KnowledgeGraphBuilder(
self.system.embedding_model
)
self.retriever = None
self.generator = GraphEnhancedGenerator(
llm_model=config.get("llm_model")
)
# 性能监控
self.monitor = PerformanceMonitor()
def initialize_with_data(self, data_source: str):
"""使用数据源初始化系统"""
print("步骤1: 加载和处理私有数据...")
raw_documents = self._load_documents(data_source)
processed_docs = self.processor.process_documents(raw_documents)
print("步骤2: 构建知识图谱...")
self.system.knowledge_graph = self.graph_builder.build_from_documents(
processed_docs
)
print("步骤3: 创建向量存储...")
self.system.vector_store = self._create_vector_store(raw_documents)
print("步骤4: 初始化检索器...")
self.retriever = GraphRetriever(
self.system.knowledge_graph,
self.system.vector_store
)
print("系统初始化完成!")
return self
def query(self, question: str) -> Dict:
"""处理用户查询"""
# 监控开始
self.monitor.start_query(question)
<"l1.j9k5.org.cn"><"c8.j9k5.org.cn"><"y0.j9k5.org.cn">
try:
# 1. 检索相关上下文
retrieval_start = time.time()
retrieval_results = self.retriever.retrieve(question)
retrieval_time = time.time() - retrieval_start
# 2. 生成增强答案
generation_start = time.time()
answer_result = self.generator.generate_answer(
question, retrieval_results
)
generation_time = time.time() - generation_start
# 3. 记录性能指标
self.monitor.record_performance({
"retrieval_time": retrieval_time,
"generation_time": generation_time,
"answer_quality": self._evaluate_answer_quality(
question, answer_result["answer"]
)
})
# 4. 返回完整结果
return {
"question": question,
"answer": answer_result["answer"],
"explanation": answer_result.get("explanation"),
"confidence": answer_result.get("confidence", 0.0),
"sources": answer_result.get("sources", []),
"subgraph": retrieval_results.get("relevant_subgraph"),
"performance": {
"retrieval_time": retrieval_time,
"generation_time": generation_time,
"total_time": retrieval_time + generation_time
}
}
except Exception as e:
self.monitor.record_error(e)
raise
def incremental_update(self, new_documents: List[Document]):
"""增量更新知识图谱"""
print("执行增量更新...")
# 1. 处理新文档
processed_new_docs = self.processor.process_documents(new_documents)
# 2. 更新知识图谱
new_kg = self.graph_builder.build_from_documents(processed_new_docs)
# 3. 合并到现有图谱
self._merge_knowledge_graphs(new_kg)
# 4. 更新向量存储
self._update_vector_store(new_documents)
print(f"增量更新完成,添加了 {len(new_documents)} 个文档")
def _merge_knowledge_graphs(self, new_kg: KnowledgeGraph):
"""合并知识图谱"""
# 合并节点
for node_id, attributes in new_kg.nodes.items():
if node_id not in self.system.knowledge_graph.nodes:
self.system.knowledge_graph.nodes[node_id] = attributes
else:
# 合并属性
existing_attrs = self.system.knowledge_graph.nodes[node_id]
existing_attrs.update(attributes)
# 合并边
self.system.knowledge_graph.edges.extend(new_kg.edges)
# 合并嵌入
self.system.knowledge_graph.embeddings.update(new_kg.embeddings)
```
## 性能监控与优化
```python
class PerformanceMonitor:
"""性能监控器"""
def __init__(self):
self.metrics = {
"queries_processed": 0,
"avg_response_time": 0,
"accuracy_scores": [],
"error_rate": 0
}
self.query_log = []
def start_query(self, question: str):
"""开始记录查询"""
self.query_log.append({
"question": question,
"start_time": time.time(),
"status": "processing"
})
def record_performance(self, performance_metrics: Dict):
"""记录性能指标"""
current_query = self.query_log[-1] if self.query_log else {}
current_query.update({
"end_time": time.time(),
"status": "completed",
"performance": performance_metrics
})
# 更新统计指标
self.metrics["queries_processed"] += 1
response_time = performance_metrics.get("total_time", 0)
total_queries = self.metrics["queries_processed"]
current_avg = self.metrics["avg_response_time"]
# 计算移动平均
self.metrics["avg_response_time"] = (
current_avg * (total_queries - 1) + response_time
) / total_queries
def generate_report(self) -> Dict:
"""生成性能报告"""
return {
"summary": {
"total_queries": self.metrics["queries_processed"],
"average_response_time": self.metrics["avg_response_time"],
"estimated_accuracy": np.mean(self.metrics["accuracy_scores"])
if self.metrics["accuracy_scores"] else 0
},
"recent_queries": self.query_log[-10:],
"recommendations": self._generate_recommendations()
}
```
## 实施建议与总结
GraphRAG系统实施的关键要点:
1. **数据准备阶段**
- 确保私有数据的质量和完整性
- 设计适合领域的实体和关系类型
- 建立持续的数据更新机制
2. **图谱构建优化**
- 平衡图谱的规模和查询效率
- 实现增量更新能力
- 建立质量评估标准
3. **部署运维考虑**
- 设计水平扩展架构
- 实现全面的监控和告警
- 建立A/B测试框架
通过GraphRAG技术,问答系统能够突破传统RAG的语义理解局限,提供更深层次的推理能力和更准确的答案。系统在实际部署中应持续优化知识图谱质量,并建立有效的反馈循环机制。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3110304/ ,如需转载,请注明出处,否则将追究法律责任。