大家好!
在这个全民 RAG 的时代,人们似乎找到了一条蹭 AI 的捷径。大模型加上领域知识分分钟包装成知识库,智能体,垂直大模型?但在实际应用中,传统 RAG 并不能解决所有问题,尤其是需要复杂推理和关系分析的场景。知识图谱(Knowledge Graph)作为结构化语义网络,能更好地表达实体及其关系,补足 RAG 的不足。
本文将结合 Neo4j 图数据库和大语言模型(LLM),介绍如何实现一个简单的问答系统。当然我也还在学习跟尝试当中,如有不当的地方请友好探讨。
什么是 Knowledge Graph
知识图谱(Knowledge Graph)是一种通过节点和关系来表达知识的结构化方式。
节点(Node):节点代表知识图谱中的实体,可以是人、地点、事物、事件等。例如,“张三”、“北京”、“苹果公司”都可以作为节点。
边(Edge):边用于连接两个节点,表示它们之间存在某种关系。每条边都有方向和类型。例如,“张三”——[居住于]——>“北京”,“苹果公司”——[创始人]——>“乔布斯”。
关系(Relationship):关系是边的具体类型,描述节点之间的语义联系。关系可以是“属于”、“包含”、“朋友”、“创始人”等。关系通常带有属性,比如时间、权重等。
通过节点和边的组合,知识图谱能够以图结构的方式表达复杂的现实世界知识,实现语义理解和推理。
知识图谱与RAG的对比
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合检索与生成的AI问答技术。它通常通过向量数据库检索相关文档片段,然后用大模型进行生成式回答。
对比点:
- 结构化 vs 非结构化:知识图谱以结构化的图数据存储知识,节点和关系清晰;RAG主要处理非结构化文本,通过语义检索相关内容。
- 推理能力:知识图谱支持复杂的语义推理和关系查询,适合多跳问答和实体关系分析;RAG更依赖检索结果和大模型的生成能力,推理能力受限于检索和模型本身。
- 更新与扩展:知识图谱需要人工或自动化方式维护结构和关系,扩展时需保证一致性;RAG可以直接添加新文档,扩展更灵活。
- 应用场景:知识图谱适合企业知识管理、推荐、风控等场景;RAG适合快速搭建问答系统、文档检索、智能客服等。
实际应用中,知识图谱和RAG可以结合使用,既利用结构化知识进行推理,又用检索增强生成提升问答的广度和灵活性。
Neo4j
本次试验我们使用 Neo4j 作为图数据库。
Neo4j 是一个高性能的开源图数据库,专门用于存储和管理图结构数据。它以节点、关系和属性为核心,能够高效地处理复杂的连接和关系查询。
Neo4j 的主要特点:
- 原生图存储:Neo4j 采用原生图结构进行存储和处理,节点和关系都是一等公民,查询效率高。
- 强大的查询语言 Cypher:Cypher 是 Neo4j 的声明式图查询语言,语法简洁,易于表达复杂的图查询。
- 高性能关系查询:相比传统关系型数据库,Neo4j 在多跳关系、路径查找等场景下有显著性能优势。
- 灵活的数据模型:支持动态添加节点、关系和属性,适合不断变化的业务需求。
- 可扩展性和高可用性:支持集群部署,适合大规模数据和高并发访问。
Neo4j 广泛应用于社交网络、推荐系统、知识图谱、风控反欺诈等领域,能够帮助企业高效地挖掘和分析数据中的关联关系。
初始化数据
安装 Neo4j
安装的话使用 docker 非常的方便,不多说。
docker run \
--restart always \
--publish=7474:7474 --publish=7687:7687 \
neo4j:2025.06.2
在我们进行试验前,需要先准备一些数据到 neo4j 的数据库里。这里采用 Neo4j 安装向导自带的一个关于演员与电影之间的知识库。包含 38 部电影与 133 个演员的信息。
CREATE CONSTRAINT movie_title IF NOT EXISTS FOR (m:Movie) REQUIRE m.title IS UNIQUE;
CREATE CONSTRAINT person_name IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE;
MERGE (TheMatrix:Movie {title:'The Matrix'}) ON CREATE SET TheMatrix.released=1999, TheMatrix.tagline='Welcome to the Real World'
MERGE (Keanu:Person {name:'Keanu Reeves'}) ON CREATE SET Keanu.born=1964
MERGE (Carrie:Person {name:'Carrie-Anne Moss'}) ON CREATE SET Carrie.born=1967
MERGE (Laurence:Person {name:'Laurence Fishburne'}) ON CREATE SET Laurence.born=1961
MERGE (Hugo:Person {name:'Hugo Weaving'}) ON CREATE SET Hugo.born=1960
MERGE (LillyW:Person {name:'Lilly Wachowski'}) ON CREATE SET LillyW.born=1967
MERGE (LanaW:Person {name:'Lana Wachowski'}) ON CREATE SET LanaW.born=1965
MERGE (JoelS:Person {name:'Joel Silver'}) ON CREATE SET JoelS.born=1952
...
访问数据库
使用 C# 去访问 Neo4j 呢也相当简单。安装相关的驱动把 cypher 发过去就行了。
<ItemGroup>
<PackageReference Include="Neo4j.Driver" Version="5.28.2" />
</ItemGroup>
代码:
const string dbUri = "neo4j://125.gen8.com:7687";
const string dbUser = "neo4j";
const string dbPassword = "neo4j@123";
await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Basic(dbUser, dbPassword));
await driver.VerifyConnectivityAsync();
Console.WriteLine("Connection established.");
var query = "MATCH (n)-[r]-(m) RETURN *";
var result = await driver.ExecutableQuery(query)
.WithConfig(new QueryConfig(database: "neo4j"))
.ExecuteAsync();
实现 chatbot
要实现这个 chatbot 呢,首先让我们来理一下整个流程:
graph TD
A[用户输入问题] --> B[LLM 生成 Cypher 查询语句]
B --> C[C# 代码访问 Neo4j 数据库]
C --> D[Neo4j 返回查询结果]
D --> E[LLM 总结并生成回答]
E --> F[返回给用户]
流程说明:
- 用户输入自然语言问题。
- LLM(大语言模型)将问题转化为 Cypher 查询语句。
- C# 程序将 Cypher 语句发送到 Neo4j 数据库。
- Neo4j 执行查询并返回结果。
- LLM 根据查询结果生成最终回答。
- 答案返回给用户。
直接看完整代码吧,测试模型试验 gpt-4.1,SK 什么的背景知识就不解释了,可以翻以前的文章。
// Populate values from your OpenAI deployment
var modelId = "gpt-4.1";
var endpoint = "https://kklldog-openai.openai.azure.com/";
var apiKey = "";
// Create a kernel with Azure OpenAI chat completion
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(modelId, endpoint, apiKey);
var sk = builder.Build();
var chatCompletionService = sk.GetRequiredService<IChatCompletionService>();
//var q = "Who is Tom Cruise ?";
var q = Console.ReadLine();
// round1 => get cypher query
ChatHistory chatHistory = [
new() {
Role = AuthorRole.System,
Content = "你是一个neo4j的专家,当收到问题后,请尝试给出可以帮助回答问题的 cypher 查询语句。" +
"你可以使用以下标签:" +
"Movie,Person " +
"你可以使用以下关系:" +
"ACTED_IN,DIRECTED,FOLLOWS,PRODUCED,REVIEWED,WROTE " +
"请直接返回cypher语句,不需要多余的内容"
},
new() {
Role = AuthorRole.User,
Content = q
}
];
var chatResponse = await chatCompletionService.GetChatMessageContentAsync(
chatHistory
);
string query = chatResponse.ToString();
Console.WriteLine(query);
const string dbUri = "neo4j://125.gen8.com:7687";
const string dbUser = "neo4j";
const string dbPassword = "neo4j@123";
await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Basic(dbUser, dbPassword));
await driver.VerifyConnectivityAsync();
Console.WriteLine("Connection established.");
var result = await driver.ExecutableQuery(query)
.WithConfig(new QueryConfig(database: "neo4j"))
.ExecuteAsync();
var answerTxt = JsonConvert.SerializeObject(result.Result);
Console.WriteLine(answerTxt);
// round2 => get answer
ChatHistory chatHistory_1 = [
new() {
Role = AuthorRole.System,
Content = "我会给你一段 cypher 语句,以及它的查询结果。请根据这些内容对问题进行回答,如果无法回答就说不知道。" +
"query:" + query +
"answer:" + answerTxt
},
new() {
Role = AuthorRole.User,
Content = q
}
];
var chatResponse_1 = await chatCompletionService.GetChatMessageContentAsync(
chatHistory_1
);
Console.WriteLine(chatResponse_1);
运行程序
让我们试跑一下,输入问题:How many movies does tom cruise acted in?
Hello, World!
How many movies does tom cruise acted in?
MATCH (p:Person {name: "Tom Cruise"})-[:ACTED_IN]->(m:Movie)
RETURN count(m) AS num_movies
Connection established.
[{"num_movies":3}]
Tom Cruise has acted in 3 movies.
总结
本文介绍了如何结合 Neo4j 图数据库与大语言模型(LLM)实现一个简单的问答系统。通过知识图谱结构化存储信息,利用 LLM 自动生成 Cypher 查询语句,并用 C# 代码访问 Neo4j 获取结果,最后由 LLM 进行答案总结,实现了从自然语言到结构化知识的闭环。
这种方案的优势在于:
- 能够充分发挥知识图谱的语义推理和关系查询能力;
- LLM 自动生成查询语句,降低了用户的技术门槛;
- 查询结果可直接用于生成自然语言答案,提升问答系统的智能化水平。
未来可以进一步扩展:
- 丰富知识图谱的数据和关系类型;
- 优化 LLM 的提示词和上下文设计,提高查询准确率;
- 支持更复杂的问题和多轮对话。
总之,Neo4j + LLM 的结合为智能问答和知识管理提供了强大的技术基础,值得在更多场景中探索和应用。