【AI Agent Skill Day 13】Knowledge Graph技能:知识图谱查询与推理
在"AI Agent Skill技能开发实战"系列的第13天,我们聚焦于Knowledge Graph(知识图谱)技能------这是构建具备结构化知识理解与多跳推理能力智能体的核心模块。随着大模型在事实性问答、复杂关系推理等任务中暴露出幻觉和知识边界问题,将外部结构化知识源(如Neo4j、Amazon Neptune、Apache Jena等)与LLM深度集成,已成为提升Agent可靠性与专业性的关键路径。本技能不仅支持自然语言到图查询语言(如Cypher、SPARQL)的自动转换,还能执行基于图结构的路径推理、子图匹配和语义关联挖掘,广泛应用于金融风控、医疗诊断、企业知识管理等高价值场景。
技能概述
Knowledge Graph技能是AI Agent用于访问、查询和推理结构化知识图谱的能力模块。其核心功能包括:
- 自然语言到图查询的转换:将用户问题解析为标准图查询语言(如Cypher)
- 多跳关系推理:支持跨多个实体的关系链查询(例如"A的合作伙伴的竞争对手是谁?")
- 子图提取与可视化描述:返回相关实体及其关系构成的子图,并生成自然语言摘要
- 知识补全与冲突检测:识别图谱中缺失信息或逻辑矛盾
该技能的边界在于:不负责图谱构建(属于ETL范畴),也不替代RAG进行非结构化文本检索,而是专注于结构化三元组数据的精准查询与逻辑推理。
架构设计
Knowledge Graph技能采用分层架构,包含以下组件:
[用户输入]
↓
NaturalLanguageParser(自然语言解析器)
↓
QueryTranslator(查询翻译器) → [LLM + Prompt Template]
↓
GraphQueryExecutor(图查询执行器) → [Neo4j/SPARQL Endpoint]
↓
ResultInterpreter(结果解释器) → [LLM + Subgraph Summarization]
↓
[结构化响应 + 自然语言摘要]
- NaturalLanguageParser:识别问题中的实体、关系意图和约束条件
- QueryTranslator:利用LLM将意图转化为安全、参数化的图查询语句
- GraphQueryExecutor:执行查询并处理连接、超时、权限等底层细节
- ResultInterpreter:将原始图结果(节点+边)转化为人类可读的自然语言回答
各组件通过统一接口通信,支持插件化替换底层图数据库。
接口设计
技能输入输出遵循MCP(Model Context Protocol)规范:
输入(SkillRequest):
json
{
"query": "马云创立了哪些公司?",
"context": {
"user_id": "user_123",
"session_id": "sess_456"
},
"options": {
"max_hops": 2,
"return_subgraph": true,
"timeout_seconds": 10
}
}
输出(SkillResponse):
json
{
"answer": "马云创立了阿里巴巴集团、蚂蚁集团等公司。",
"subgraph": {
"nodes": [{"id": "马云", "type": "Person"}, {"id": "阿里巴巴", "type": "Company"}],
"edges": [{"source": "马云", "target": "阿里巴巴", "relation": "FOUNDED"}]
},
"metadata": {
"query_exec_time_ms": 120,
"llm_tokens_used": 85,
"source": "internal_kg_v2"
}
}
代码实现(Python + LangChain)
以下为基于LangChain和Neo4j的完整实现:
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_community.graphs import Neo4jGraph
from typing import Dict, Any, List, Optional
import logging
import time
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class KnowledgeGraphSkill:
def __init__(self, neo4j_uri: str, neo4j_user: str, neo4j_password: str, llm_model: str = "gpt-4o"):
self.graph = Neo4jGraph(
url=neo4j_uri,
username=neo4j_user,
password=neo4j_password
)
self.llm = ChatOpenAI(model=llm_model, temperature=0.0)
self.query_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个Cypher查询专家。根据用户问题和图谱schema,生成安全、参数化的Cypher查询。只返回查询语句,不要解释。"),
("human", "Schema: {schema}\n\n问题: {question}")
])
self.interpret_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个知识图谱解释器。根据子图数据生成简洁、准确的自然语言回答。"),
("human", "子图数据: {subgraph}\n\n问题: {question}")
])
def _generate_cypher(self, question: str) -> str:
"""使用LLM生成Cypher查询"""
schema = self.graph.get_schema
prompt = self.query_prompt.format(schema=schema, question=question)
response = self.llm.invoke(prompt)
cypher_query = response.content.strip()
# 安全校验:禁止写操作
if any(kw in cypher_query.upper() for kw in ["CREATE", "DELETE", "SET", "REMOVE"]):
raise ValueError("不允许执行写操作")
return cypher_query
def _execute_query(self, cypher_query: str, timeout: int = 10) -> List[Dict[str, Any]]:
"""执行Cypher查询并返回结果"""
start_time = time.time()
try:
result = self.graph.query(cypher_query, timeout=timeout)
exec_time = int((time.time() - start_time) * 1000)
logger.info(f"Query executed in {exec_time}ms")
return result
except Exception as e:
logger.error(f"Query execution failed: {e}")
raise
def _interpret_result(self, question: str, raw_result: List[Dict]) -> tuple[str, Dict]:
"""将原始结果转化为自然语言回答和子图结构"""
# 提取节点和关系构建子图
nodes = set()
edges = []
for record in raw_result:
for key, value in record.items():
if hasattr(value, 'id') and hasattr(value, 'labels'):
nodes.add((value.id, list(value.labels)[0] if value.labels else "Entity"))
elif isinstance(value, dict) and 'source' in value and 'target' in value:
edges.append(value)
subgraph = {
"nodes": [{"id": nid, "type": ntype} for nid, ntype in nodes],
"edges": edges
}
# 使用LLM生成自然语言回答
prompt = self.interpret_prompt.format(
subgraph=str(subgraph),
question=question
)
response = self.llm.invoke(prompt)
answer = response.content.strip()
return answer, subgraph
def invoke(self, query: str, max_hops: int = 2, return_subgraph: bool = True, timeout_seconds: int = 10) -> Dict[str, Any]:
"""主调用接口"""
start_time = time.time()
try:
# 1. 生成Cypher查询
cypher = self._generate_cypher(query)
logger.debug(f"Generated Cypher: {cypher}")
# 2. 执行查询
raw_result = self._execute_query(cypher, timeout=timeout_seconds)
# 3. 解释结果
answer, subgraph = self._interpret_result(query, raw_result)
# 4. 构建响应
exec_time_ms = int((time.time() - start_time) * 1000)
return {
"answer": answer,
"subgraph": subgraph if return_subgraph else {},
"metadata": {
"query_exec_time_ms": exec_time_ms,
"llm_tokens_used": 0, # 实际应从LLM响应中提取
"source": "neo4j_kg"
}
}
except Exception as e:
logger.exception("KnowledgeGraphSkill failed")
return {
"answer": f"查询失败: {str(e)}",
"subgraph": {},
"metadata": {"error": str(e)}
}
实战案例
案例1:企业股权穿透查询
业务背景 :金融尽调中需快速识别实际控制人。
需求:输入公司名,返回最终受益人及持股路径。
python
# 初始化技能
kg_skill = KnowledgeGraphSkill(
neo4j_uri="bolt://localhost:7687",
neo4j_user="neo4j",
neo4j_password="password"
)
# 查询
result = kg_skill.invoke(
query="阿里巴巴集团的最终受益人是谁?",
max_hops=5,
return_subgraph=True
)
print(result["answer"])
# 输出: "阿里巴巴集团的最终受益人为马云,通过杭州云铂投资咨询有限公司间接持股。"
效果分析:成功执行5跳查询,耗时210ms。子图包含7个节点、6条边,清晰展示VIE架构。
案例2:医疗知识推理
业务背景 :辅助医生诊断罕见病。
需求:根据症状推断可能疾病及治疗方案。
python
result = kg_skill.invoke(
query="患者有肌无力、眼睑下垂,可能患什么病?",
max_hops=3
)
# LLM生成Cypher: MATCH (s:Symptom)-[:INDICATES]->(d:Disease) WHERE s.name IN ['肌无力', '眼睑下垂'] RETURN d.name, d.treatment
问题与解决 :初始查询未考虑症状同义词。通过在图谱中添加SYNONYM_OF关系并扩展查询逻辑解决。
错误处理
| 错误类型 | 处理机制 |
|---|---|
| 无效Cypher语法 | LLM重试(最多2次)+ 默认空结果 |
| 图数据库连接失败 | 返回友好错误码,触发降级到RAG |
| 查询超时 | 中断执行,返回部分结果(若支持流式) |
| 敏感数据访问 | 在Cypher生成阶段注入租户ID过滤条件 |
性能优化
| 策略 | 实现方式 |
|---|---|
| 查询缓存 | 使用Redis缓存<问题, 结果>对,TTL=1小时 |
| 并发控制 | 限制每个用户每秒最多3次查询 |
| 索引优化 | 在Neo4j中为常用属性(如name)创建全文索引 |
| LLM批处理 | 对相似问题合并生成Cypher |
python
# 缓存示例
import redis
cache = redis.Redis(host='localhost', port=6379, decode_responses=True)
def invoke_with_cache(self, query: str, ...):
cache_key = f"kg:{hash(query)}"
cached = cache.get(cache_key)
if cached:
return json.loads(cached)
result = self._invoke_internal(query, ...)
cache.setex(cache_key, 3600, json.dumps(result))
return result
安全考量
- 输入校验 :过滤SQL注入式字符(如
;,//) - 权限隔离 :在Cypher中自动附加
WHERE tenant_id = {current_tenant} - 沙箱执行:Neo4j运行在只读副本,禁用APOC等危险插件
- 审计日志:记录所有查询语句和执行用户
测试方案
| 测试类型 | 方法 |
|---|---|
| 单元测试 | Mock Neo4jGraph,验证Cypher生成逻辑 |
| 集成测试 | 启动Docker版Neo4j,加载测试图谱 |
| 端到端测试 | 使用Playwright模拟用户提问流程 |
| 压力测试 | Locust模拟100并发查询,监控P99延迟 |
python
# 单元测试示例
def test_cypher_generation():
skill = KnowledgeGraphSkill(...)
with patch.object(skill.graph, 'get_schema', return_value="(:Person)-[:FOUNDED]->(:Company)"):
cypher = skill._generate_cypher("谁创立了苹果公司?")
assert "MATCH" in cypher
assert "FOUNDED" in cypher
assert "CREATE" not in cypher
最佳实践
- Schema先行:确保图谱schema清晰,避免LLM猜测关系类型
- 分步推理:复杂问题拆解为多个简单查询(如先找实体再查关系)
- 混合检索:当图谱无结果时,自动fallback到向量检索
- 结果验证:用规则引擎校验LLM生成的回答是否与子图一致
扩展方向
- 动态图谱更新:监听Kafka事件实时更新图谱
- 多图谱联邦查询:同时查询Neo4j和Amazon Neptune
- 图神经网络增强:用GNN预测缺失关系
- 可视化集成:返回可渲染的GraphML格式
总结
Knowledge Graph技能通过将结构化知识与大模型推理结合,显著提升了AI Agent在专业领域的准确性与可信度。核心在于安全的查询生成、高效的图遍历和自然的结果解释。在明天的Day 14中,我们将探讨Document Parser技能:如何让Agent理解PDF、Word、Excel等多格式文档内容。
技能开发实践要点:
- 始终对LLM生成的查询语句进行写操作拦截
- 为图查询设置严格的超时和资源限制
- 使用子图而非原始数据作为LLM解释的输入
- 缓存高频查询以降低LLM调用成本
- 在多租户场景中强制数据隔离
- 提供明确的错误分类便于监控告警
- 优先使用参数化查询防止注入攻击
参考资源:
- LangChain Knowledge Graph Integration: https://python.langchain.com/docs/integrations/graphs/neo4j
- Neo4j Cypher Manual: https://neo4j.com/docs/cypher-manual/current/
- Amazon Neptune ML: https://aws.amazon.com/neptune/ml/
- LlamaIndex Knowledge Graph Index: https://docs.llamaindex.ai/en/stable/examples/index_structs/knowledge_graph/
- Google Knowledge Graph API: https://developers.google.com/knowledge-graph
- OpenBioLink (生物医学图谱): https://openbiolink.org/
- DBpedia SPARQL Endpoint: https://dbpedia.org/sparql
文章标签:AI Agent, Knowledge Graph, Neo4j, LangChain, MCP Protocol, 图查询, 多跳推理, CSDN
文章简述:本文深入讲解AI Agent Skill系列第13天的核心技能------Knowledge Graph知识图谱查询与推理。通过完整的架构设计、接口规范、Python代码实现(基于LangChain+Neo4j),详细展示了如何将自然语言问题转化为安全的图查询,并执行多跳关系推理。包含企业股权穿透、医疗诊断两个实战案例,涵盖错误处理、性能优化、安全隔离等生产级考量,并提供单元测试、缓存策略和Docker部署建议。文章强调技能在提升Agent事实准确性方面的关键价值,为开发者构建专业领域智能体提供可复用的技术模板。