如何用Neo4j构建问答系统?

摘要:大家好! 在这个全民 RAG 的时代,人们似乎找到了一条蹭 AI 的捷径。大模型加上领域知识分分钟包装成知识库,智能体,垂直大模型?但在实际应用中,传统 RAG 并不能解决所有问题,尤其是需要复杂推理和关系分析的场景。知识图谱(Knowle
大家好! 在这个全民 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 的结合为智能问答和知识管理提供了强大的技术基础,值得在更多场景中探索和应用。