引言
随着大语言模型(LLM)技术的飞速发展,结合结构化知识库构建智能问答系统成为当前 AI 应用的重要方向。本文将介绍如何利用 Microsoft Semantic Kernel(SK) 与 Neo4j 图数据库 快速搭建一个轻量级、可解释、且具备上下文感知能力的问答系统。
该方案的优势在于:
- 利用 SK 简化 LLM 调用与插件集成;
- 借助 Neo4j 高效存储和查询实体关系;
- 实现"先查知识库,再生成答案"的可控推理流程。
技术栈简介
1. Semantic Kernel(SK)
Semantic Kernel 是微软推出的轻量级 SDK,支持将自然语言函数(prompt functions)、传统代码函数(native functions)以及向量记忆(memory)统一编排,便于构建 LLM 应用。它支持 Python 和 C#,本文以 Python 为例。
2. Neo4j
Neo4j 是领先的原生图数据库,擅长处理高度关联的数据。在知识图谱场景中,节点表示实体(如人物、地点),边表示关系(如"出生于"、"就职于"),非常适合用于事实型问答。
系统架构概览
用户提问
↓
[语义解析] → 提取关键实体/意图(可选)
↓
[Neo4j 查询] → 根据实体检索相关子图
↓
[结果拼接] → 将结构化数据转为自然语言上下文
↓
[SK + LLM] → 结合上下文生成最终回答
实现步骤
步骤一:准备 Neo4j 知识图谱
假设我们构建一个简单的公司员工知识图谱:
CREATE (a:Person {name: "张三", role: "工程师"})
CREATE (b:Person {name: "李四", role: "产品经理"})
CREATE (c:Company {name: "星辰科技"})
CREATE (a)-[:WORKS_AT]->(c)
CREATE (b)-[:WORKS_AT]->(c)
CREATE (a)-[:REPORTS_TO]->(b)
步骤二:编写 Neo4j 查询插件(Native Function)
在 SK 中注册一个本地函数,用于根据问题中的关键词查询 Neo4j:
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from neo4j import GraphDatabase
class Neo4jPlugin:
def __init__(self, uri, user, password):
self.driver = GraphDatabase.driver(uri, auth=(user, password))
@kernel_function(
description="根据人名查询其工作信息和汇报关系",
name="query_employee_info"
)
def query_employee_info(self, name: str) -> str:
with self.driver.session() as session:
result = session.run("""
MATCH (p:Person {name: $name})-[r]->(target)
RETURN type(r) AS rel, target.name AS target_name, target.role AS target_role
UNION
MATCH (p:Person {name: $name})<-[:WORKS_AT]-(comp:Company)
RETURN 'WORKS_AT' AS rel, comp.name AS target_name, null AS target_role
""", name=name)
facts = []
for record in result:
if record["rel"] == "REPORTS_TO":
facts.append(f"{name} 汇报给 {record['target_name']}({record['target_role']})")
elif record["rel"] == "WORKS_AT":
facts.append(f"{name} 在 {record['target_name']} 工作")
return "; ".join(facts) if facts else "未找到相关信息"
步骤三:配置 Semantic Kernel 并集成插件
import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
kernel = sk.Kernel()
kernel.add_service(OpenAIChatCompletion(
service_id="openai",
ai_model_id="gpt-3.5-turbo",
api_key="YOUR_API_KEY"
))
# 注册插件
neo4j_plugin = Neo4jPlugin("bolt://localhost:7687", "neo4j", "password")
kernel.import_plugin_from_object(neo4j_plugin, "Neo4jPlugin")
步骤四:定义语义函数(Prompt Template)
创建一个 SK 语义函数,引导 LLM 利用插件返回的信息作答:
# ask_about_employee.skprompt.txt
你是一个公司内部助手。请根据以下事实回答问题:
{{Neo4jPlugin.query_employee_info $input}}
问题:{{$input}}
回答应简洁、准确,仅基于上述事实。
加载并调用:
prompt_template = """
你是一个公司内部助手。请根据以下事实回答问题:
{{Neo4jPlugin.query_employee_info $input}}
问题:{{$input}}
回答应简洁、准确,仅基于上述事实。
"""
ask_function = kernel.create_function_from_prompt(
prompt_template,
function_name="ask_about_employee",
plugin_name="CompanyQA"
)
# 用户提问
question = "张三的上级是谁?"
answer = await kernel.invoke(ask_function, input=question)
print(answer)
效果示例
输入:
"张三在哪家公司工作?"
Neo4j 返回:
"张三 在 星辰科技 工作"
LLM 输出:
张三在星辰科技工作。
输入:
"李四负责什么?"
Neo4j 返回:
"李四 在 星辰科技 工作;张三 汇报给 李四(产品经理)"
LLM 输出:
李四是产品经理,负责管理工程师张三,任职于星辰科技。
优势与扩展方向
✅ 可控性强 :答案基于真实图谱数据,避免幻觉。
✅ 可解释性好 :每一步查询可追溯。
✅ 易于扩展:可加入向量搜索(SK Memory)处理模糊查询,或接入更多数据源。
未来优化:
- 使用 NER 模型自动提取问题中的实体;
- 支持多跳关系查询(如"张三上级的公司");
- 结合 RAG 架构融合非结构化文档。
结语
通过 Semantic Kernel 与 Neo4j 的结合,我们能够快速构建一个兼具灵活性与可靠性的问答系统。这种"结构化知识 + 语言模型"的混合架构,是迈向企业级可信 AI 应用的重要一步。