知识图谱+LLM:增强Agent的事实推理能力
知识图谱+LLM:增强Agent的事实推理能力
副标题:从理论到实践,全方位解析如何构建具备精准事实推理能力的下一代智能Agent
第一部分:引言与基础 (Introduction & Foundation)
1. 摘要/引言 (Abstract / Introduction)
1.1 问题陈述
在人工智能技术飞速发展的今天,大语言模型(LLMs)如GPT-4、Claude、Llama等无疑是最耀眼的明星。它们展现出了令人惊叹的语言理解、生成和初步推理能力,仿佛让我们看到了通用人工智能(AGI)的曙光。然而,当我们深入使用这些模型时,会发现它们存在几个致命的缺陷:
- “幻觉”(Hallucination)问题:LLMs经常会一本正经地编造事实,给出听起来合理但实际上完全错误的信息。
- 知识的“静态性”:模型的知识截止到训练数据的时间点,对于训练后发生的事件或更新的信息一无所知。
- 可解释性差:当LLMs给出一个答案时,我们很难追溯它是如何得出这个结论的,缺乏透明度。
- 复杂事实推理能力有限:在需要多步逻辑推理、精确知识检索的任务上,LLMs往往表现不佳。
与此同时,知识图谱(Knowledge Graphs, KGs)作为一种结构化的知识表示方式,虽然在处理非结构化文本方面不如LLMs灵活,但却具有高度的可靠性、可解释性和可更新性。它以“实体-关系-实体”的三元组形式存储知识,能够支持复杂的查询和推理。
那么,一个自然的想法是:能否将知识图谱的“严谨”与LLMs的“灵活”结合起来,打造一个既懂语言又懂事实的智能体? 这正是本文要探讨的核心问题。
1.2 核心方案
本文提出的核心方案是构建一个知识图谱增强的大语言模型Agent。具体来说,我们将:
- 利用知识图谱作为外部“大脑”:存储结构化的、可验证的事实知识。
- 利用LLMs作为“中央控制器”:负责理解用户意图、生成查询计划、整合检索结果并生成最终回答。
- 设计高效的交互机制:让LLMs能够“访问”和“操作”知识图谱,将图谱知识无缝融入到推理过程中。
这种结合方式不仅能够减少LLMs的幻觉,提高回答的准确性,还能增强系统的可解释性和知识的实时更新能力。
1.3 主要成果/价值
读完本文,你将能够:
- 深刻理解知识图谱和LLMs各自的优缺点以及它们的互补性。
- 掌握知识图谱增强LLM的几种主流架构模式和技术路径。
- 亲手实践一个完整的项目:从构建一个简单的知识图谱,到开发一个能利用该图谱进行事实推理的Agent。
- 了解当前该领域的最佳实践、常见挑战以及未来发展方向。
无论你是一名想提升AI应用能力的开发者,还是一名对知识表示和推理感兴趣的研究者,本文都将为你提供有价值的参考。
1.4 文章导览
本文将分为四个部分,共16个章节,循序渐进地带你探索知识图谱与LLMs的结合之道:
- 第一部分(第1-4章):奠定基础,介绍问题背景、核心概念和文章结构。
- 第二部分(第5-9章):深入核心,讲解理论基础、环境搭建,并带你一步步实现项目。
- 第三部分(第10-13章):扩展提升,展示结果、讨论优化、解答疑问并展望未来。
- 第四部分(第14-16章):总结全文,列出参考资料和附录。
现在,就让我们开始这段激动人心的技术之旅吧!
2. 目标读者与前置知识 (Target Audience & Prerequisites)
2.1 目标读者
本文主要面向以下人群:
- AI/ML应用开发者:你已经有一些使用LLMs开发应用的经验,但希望解决幻觉问题,提升应用的事实准确性。
- NLP工程师:你对自然语言处理有一定了解,想探索知识增强的方法。
- 知识图谱从业者:你熟悉知识图谱的构建和应用,想知道如何与最新的LLMs技术结合。
- 对AGI和智能体感兴趣的技术人员:你好奇下一代AI系统会是什么样子,想了解知识与推理的结合之道。
2.2 前置知识
为了更好地理解本文内容,建议你具备以下基础知识:
- Python编程:我们将使用Python进行所有代码实现,你需要熟悉Python的基本语法和常用库。
- 大语言模型基础:你应该了解LLMs的基本概念,比如什么是提示词(Prompt)、什么是上下文窗口(Context Window),并且最好有使用OpenAI API或类似服务的经验。
- 数据库基础:虽然我们会详细介绍图数据库,但了解基本的数据库概念(如表、查询、索引)会有帮助。
- 基本的图论知识(可选):了解节点、边、路径等基本图论概念将有助于理解知识图谱的原理。
如果你在某些方面有所欠缺也没关系,我们会在相关章节对关键概念进行解释,你也可以通过参考资料进行补充学习。
3. 文章目录 (Table of Contents)
- 第一部分:引言与基础
- 摘要/引言
- 目标读者与前置知识
- 文章目录
- 第二部分:核心内容
4. 问题背景与动机
5. 核心概念与理论基础
6. 环境准备
7. 分步实现:构建知识图谱
8. 分步实现:开发KG-LLM交互层
9. 分步实现:构建智能Agent
10. 关键代码解析与深度剖析 - 第三部分:验证与扩展
11. 结果展示与验证
12. 性能优化与最佳实践
13. 常见问题与解决方案
14. 未来展望与扩展方向 - 第四部分:总结与附录
15. 总结
16. 参考资料
17. 附录
第二部分:核心内容 (Core Content)
4. 问题背景与动机 (Problem Background & Motivation)
4.1 LLM的局限性:繁荣背后的隐忧
在过去的几年里,大语言模型取得了令人瞩目的成就。从GPT-3的横空出世,到ChatGPT的全民热潮,再到GPT-4、Claude 3等模型的持续迭代,LLMs似乎无所不能:写代码、作文章、解数学题、进行多轮对话……然而,当我们将这些模型应用到需要高可靠性的场景(如医疗咨询、法律问答、金融分析)时,它们的局限性就暴露无遗了。
让我们通过一个具体的例子来看看LLMs的“幻觉”问题。假设我们问GPT-4一个关于电影的问题:“电影《盗梦空间》的导演是谁?他还导演过哪些电影?”GPT-4可能会给出正确的答案:“克里斯托弗·诺兰,他还导演过《星际穿越》、《蝙蝠侠:黑暗骑士》等。”但如果我们问一个更偏门的问题,或者故意设置一些陷阱,情况可能就不一样了。
更严重的是,LLMs的知识是“静态”的。如果一部电影是在2023年10月上映的,而GPT-4的训练数据截止到2023年6月,那么它就完全不知道这部电影的存在。此外,LLMs的推理过程是“黑盒”的,我们无法确认它的答案是基于真实的知识还是随机的猜测。
这些局限性使得纯LLM在处理事实密集型任务(Fact-Intensive Tasks)时显得力不从心。那么,有什么方法可以解决这些问题呢?
4.2 知识图谱的优势:结构化知识的力量
知识图谱的概念最早由Google在2012年提出,旨在提升搜索引擎的能力。但实际上,结构化知识表示的思想可以追溯到更早的语义网(Semantic Web)时代。
知识图谱的核心思想很简单:用图的结构来表示知识。在知识图谱中,我们有:
- 实体(Entities):代表现实世界中的具体事物或抽象概念,如“克里斯托弗·诺兰”、“盗梦空间”、“电影”。
- 关系(Relations):代表实体之间的联系,如“导演”、“上映时间”、“类型”。
- 属性(Attributes):代表实体的特性,如“出生日期”、“评分”。
这种表示方式有几个显著的优势:
- 高度可靠性:知识图谱中的知识通常是经过人工或半自动验证的,信息质量高。
- 可解释性:知识图谱的推理过程是透明的,我们可以沿着图中的边来追溯答案的来源。
- 可更新性:我们可以方便地向图谱中添加新的实体、关系或修改已有的知识。
- 支持复杂查询:利用图查询语言(如Cypher、SPARQL),我们可以进行复杂的多跳推理和模式匹配。
例如,在电影知识图谱中,我们可以很容易地查询:“找出所有由克里斯托弗·诺兰导演、且评分在8.5分以上的科幻电影。”这种查询对于纯LLM来说可能很困难,但对于知识图谱来说却是小菜一碟。
4.3 为什么要结合:1+1>2的可能性
既然LLMs和知识图谱各有优缺点,那么一个自然的想法就是将它们结合起来,取长补短。让我们来看看这种结合能带来什么好处:
| 特性 | 纯LLM | 纯知识图谱 | 结合后 |
|---|---|---|---|
| 自然语言理解 | 强 | 弱 | 强 |
| 事实准确性 | 中等/弱 | 强 | 强 |
| 知识时效性 | 差 | 好 | 好 |
| 可解释性 | 差 | 好 | 好 |
| 复杂推理 | 中等 | 强 | 强 |
| 泛化能力 | 强 | 弱 | 强 |
| 处理非结构化数据 | 强 | 弱 | 强 |
正如上表所示,LLMs和知识图谱的特性具有很强的互补性。通过结合,我们可以获得一个既“聪明”又“可靠”的系统:
- 减少幻觉:LLMs可以从知识图谱中检索事实信息,作为回答的依据,而不是凭空编造。
- 实时知识更新:我们不需要重新训练LLMs,只需要更新知识图谱,系统就能获取最新的信息。
- 增强可解释性:系统在给出答案的同时,可以提供知识图谱中的证据路径,让用户知道答案是怎么来的。
- 提升复杂推理能力:结合LLMs的语义理解能力和知识图谱的结构化查询能力,可以处理更复杂的推理任务。
这种结合的潜力是巨大的。事实上,在学术界和工业界,已经有越来越多的工作在探索这一方向,这也正是我们撰写本文的动机所在。
5. 核心概念与理论基础 (Core Concepts & Theoretical Foundation)
在开始动手实践之前,我们需要先建立起扎实的理论基础。在这一章中,我们将详细介绍知识图谱、LLMs、Agent以及它们结合的核心概念和架构模式。
5.1 知识图谱(Knowledge Graph)的核心概念
5.1.1 定义与组成
虽然“知识图谱”这个术语已经被广泛使用,但在不同的语境下可能有不同的含义。在本文中,我们将知识图谱定义为:一种采用图结构来建模、存储和处理知识的数据结构,其中节点代表实体,边代表实体之间的关系。
更正式地说,一个知识图谱 G G G 可以表示为一个三元组的集合:
G = { ( h , r , t ) ∣ h , t ∈ E , r ∈ R } G = \{(h, r, t) \mid h, t \in E, r \in R\} G={(h,r,t)∣h,t∈E,r∈R}
其中:
- E E E 是实体(Entity)的集合,
- R R R 是关系(Relation)的集合,
- ( h , r , t ) (h, r, t) (h,r,t) 表示“头实体 h h h 通过关系 r r r 与尾实体 t t t 相连”。
例如,(克里斯托弗·诺兰,导演,盗梦空间)就是一个这样的三元组。
除了三元组,很多知识图谱还包含实体的属性(Attributes),我们可以将其表示为(实体,属性名,属性值)的形式,例如(盗梦空间,评分,9.3)。
5.1.2 知识图谱的架构层次
一个完整的知识图谱系统通常包含以下几个层次:
- 数据源层:包含结构化数据(如数据库表)、半结构化数据(如XML、JSON)和非结构化数据(如文本、图片)。
- 信息抽取层:负责从数据源中提取实体、关系和属性,这通常涉及命名实体识别(NER)、关系抽取(RE)、实体链接(EL)等技术。
- 知识融合层:负责将不同来源的知识整合起来,解决实体对齐、冲突消解等问题。
- 知识存储层:负责将知识图谱存储起来,通常使用图数据库(如Neo4j、JanusGraph)或RDF存储(如Apache Jena)。
- 知识应用层:提供查询、推理、可视化等功能,支持上层应用。
在本文中,我们将重点关注知识存储层和知识应用层,尤其是如何将知识图谱与LLMs结合起来。
5.1.3 图查询语言
为了从知识图谱中检索信息,我们需要使用图查询语言。目前最流行的图查询语言有两种:
- Cypher:由Neo4j开发的声明式图查询语言,语法类似于SQL,但针对图结构进行了优化。例如,查询“克里斯托弗·诺兰导演的所有电影”可以写成:
MATCH (director:Person {name: '克里斯托弗·诺兰'})-[:DIRECTED]->(movie:Movie) RETURN movie - SPARQL:W3C推荐的RDF查询语言,适用于查询RDF格式的知识图谱。
在本文的项目中,我们将使用Neo4j图数据库和Cypher查询语言。
5.2 大语言模型(LLM)的核心概念
5.2.1 基本原理
大语言模型是一种基于Transformer架构的神经网络,通过在海量文本数据上进行自监督学习(预测下一个词)来训练。训练完成后,LLMs学会了语言的统计规律和世界的一些基本常识。
LLMs的核心能力是条件文本生成:给定一个提示词(Prompt),模型会根据训练数据中学到的模式,生成一个合理的续接文本。
5.2.2 关键特性
在与知识图谱结合时,LLMs的以下几个特性尤为重要:
- 上下文学习(In-Context Learning):LLMs可以在不更新参数的情况下,仅通过提示词中的几个示例就学会执行新任务。
- 思维链(Chain-of-Thought, CoT):当被要求逐步思考时,LLMs可以进行更复杂的推理。
- 工具使用(Tool Use):LLMs可以被训练或提示来使用外部工具,如搜索引擎、计算器,当然也包括知识图谱。
5.3 智能体(Agent)的核心概念
5.3.1 定义与组成
在人工智能领域,Agent可以被定义为一个能够感知环境、做出决策并采取行动的实体。一个典型的Agent包含以下几个部分:
- 感知模块:负责获取环境信息,如用户的输入。
- 推理模块:负责处理信息、制定计划、做出决策。
- 行动模块:负责执行决策,如调用工具、生成回答。
- 记忆模块:负责存储历史信息和知识。
5.3.2 LLM作为Agent的核心
近年来,一种趋势是将LLMs作为Agent的核心推理模块。这种Agent被称为LLM-based Agent,它利用LLMs强大的语言理解和生成能力来实现感知、推理和行动的统一。
在本文中,我们将构建一个这样的Agent,但不同的是,我们将为它配备知识图谱作为外部记忆和工具。
5.4 事实推理(Factual Reasoning)的核心概念
5.4.1 定义
事实推理是指基于已知的事实,通过逻辑推理得出新的事实或结论的过程。在知识图谱与LLM结合的场景下,事实推理通常涉及以下几种类型:
- 单跳推理:直接查询一个关系,如“谁导演了《盗梦空间》?”
- 多跳推理:需要经过多个关系才能得到答案,如“《盗梦空间》的导演还导演过哪些评分在8.5分以上的电影?”
- 比较推理:比较多个实体的属性,如“《盗梦空间》和《星际穿越》哪部评分更高?”
- 聚合推理:对多个结果进行聚合,如“克里斯托弗·诺兰导演的电影平均评分是多少?”
5.4.2 挑战
事实推理面临的主要挑战包括:
- 如何将自然语言问题转换为结构化的查询?
- 如何处理推理过程中的不确定性?
- 如何处理知识图谱中缺失的信息?
- 如何在推理效率和准确性之间取得平衡?
5.5 KG与LLM结合的架构模式
将知识图谱与大语言模型结合,目前主要有三种主流的架构模式,我们可以用一个图来表示它们之间的关系:
让我们详细介绍这三种模式:
5.5.1 模式1:KG增强LLM (KG-augmented LLM)
在这种模式中,知识图谱作为一个外部信息源,为LLMs提供额外的知识。具体流程如下:
- 问题理解:LLMs理解用户的问题。
- 查询生成:LLMs根据问题生成一个或多个检索查询(可能是关键词,也可能是结构化查询)。
- 知识检索:使用生成的查询从知识图谱中检索相关的知识。
- 知识整合:将检索到的知识作为上下文,与原始问题一起输入给LLMs。
- 回答生成:LLMs根据上下文和问题生成最终的回答。
这种模式的优点是实现相对简单,能够利用LLMs强大的语言能力。缺点是检索到的知识可能不完整或不相关,且LLMs可能仍然会忽略检索到的知识而产生幻觉。
典型应用:检索增强生成(RAG)系统,其中知识图谱是检索源之一。
5.5.2 模式2:LLM增强KG (LLM-augmented KG)
在这种模式中,LLMs主要作为知识图谱的自然语言接口,帮助用户更方便地与知识图谱交互。具体流程如下:
- 自然语言转查询:LLMs将用户的自然语言问题转换为结构化的图查询(如Cypher)。
- 查询执行:在知识图谱上执行生成的查询。
- 结果转自然语言:LLMs将查询结果转换为自然语言回答。
这种模式的优点是回答高度依赖知识图谱,准确性高,可解释性强。缺点是受限于知识图谱的覆盖范围,如果知识图谱中没有相关信息,系统就无法回答。此外,将自然语言准确转换为图查询也是一个挑战。
典型应用:基于知识图谱的问答系统(KBQA)。
5.5.3 模式3:协同推理 (Synergistic Reasoning)
这种模式是前两种模式的结合,也是最复杂但最强大的一种模式。在这种模式中,LLMs作为一个中央控制器(Agent),能够根据需要自主选择使用知识图谱还是其他工具(如搜索引擎、计算器)。具体流程如下:
- 问题分析:LLMs分析用户的问题,决定需要哪些信息。
- 工具选择:LLMs选择合适的工具(可能是知识图谱,也可能是其他工具)。
- 工具使用:LLMs生成工具调用指令,执行工具调用。
- 结果整合:LLMs整合工具返回的结果。
- 迭代:如果需要,LLMs可能会多次调用工具,直到获得足够的信息。
- 回答生成:LLMs生成最终的回答。
这种模式的优点是灵活性高,能够处理复杂的任务,结合了多种工具的优势。缺点是实现复杂,需要精心设计提示词和工具接口。
典型应用:高级Agent系统,如AutoGPT、Microsoft 365 Copilot。
5.6 概念对比与联系
为了帮助大家更好地理解这些概念,我们用一个表格来对比一下三种结合模式:
| 特性 | KG增强LLM | LLM增强KG | 协同推理 |
|---|---|---|---|
| 核心思想 | KG作为LLM的外部知识源 | LLM作为KG的自然语言接口 | LLM作为控制器,协同使用KG和其他工具 |
| LLM的角色 | 回答生成者 | 翻译器(NL⇄查询) | 决策者和协调者 |
| KG的角色 | 信息提供者 | 核心知识库 | 工具之一 |
| 准确性 | 中等 | 高 | 高(取决于工具选择) |
| 灵活性 | 高 | 低(受限于KG) | 最高 |
| 可解释性 | 中等 | 高 | 中等(可通过工具调用链解释) |
| 实现难度 | 低到中等 | 中等 | 高 |
| 适用场景 | 开放域问答 | 封闭域事实查询 | 复杂任务处理 |
这些模式之间并不是完全互斥的,在实际应用中,我们可能会根据具体需求混合使用它们。在本文的项目中,我们将主要实现模式2和模式3的结合,因为它们能更好地展示知识图谱与LLMs结合的威力。
6. 环境准备 (Environment Setup)
在这一章中,我们将准备好开发环境,为后续的实践项目做好准备。我们将使用Python作为主要编程语言,Neo4j作为图数据库,LangChain作为开发框架,并使用OpenAI的GPT模型作为LLM。
6.1 所需软件与库
首先,让我们列出所需的软件和库:
- Python 3.9+:我们将使用Python的最新特性,建议使用3.9或更高版本。
- Neo4j图数据库:我们将使用Neo4j Community Edition,这是一个免费的开源版本。
- Python库:
openai:用于访问OpenAI的API。neo4j:用于连接和操作Neo4j数据库。langchain:用于构建LLM应用的框架。langchain-openai:LangChain与OpenAI的集成。python-dotenv:用于管理环境变量。
6.2 安装步骤
6.2.1 安装Python
如果你还没有安装Python,可以从Python官网下载并安装。安装完成后,你可以在终端中运行以下命令来检查版本:
python --version
确保版本号大于等于3.9。
6.2.2 安装Neo4j
我们将使用Neo4j Desktop来方便地管理数据库,你也可以直接安装Neo4j Community Edition。
使用Neo4j Desktop(推荐):
- 从Neo4j官网下载并安装Neo4j Desktop。
- 打开Neo4j Desktop,创建一个新项目。
- 在项目中添加一个新的数据库,记住你设置的用户名和密码(默认用户名是
neo4j)。 - 启动数据库。
直接安装Neo4j Community Edition:
- 从Neo4j下载中心下载适合你操作系统的版本。
- 按照官方文档进行安装和配置。
- 启动数据库。
安装完成后,你可以通过浏览器访问 http://localhost:7474 来打开Neo4j Browser,这是一个用于操作Neo4j的Web界面。
6.2.3 安装Python库
我们将使用pip来安装所需的Python库。为了避免依赖冲突,建议先创建一个虚拟环境:
# 创建虚拟环境
python -m venv kg-llm-env
# 激活虚拟环境
# Windows:
kg-llm-env\Scripts\activate
# macOS/Linux:
source kg-llm-env/bin/activate
然后,安装所需的库:
pip install openai neo4j langchain langchain-openai python-dotenv
你也可以创建一个requirements.txt文件,内容如下:
openai>=1.0.0
neo4j>=5.0.0
langchain>=0.1.0
langchain-openai>=0.0.5
python-dotenv>=1.0.0
然后运行:
pip install -r requirements.txt
6.3 配置环境变量
我们需要设置一些环境变量,包括OpenAI的API密钥和Neo4j的连接信息。创建一个名为.env的文件,内容如下:
# OpenAI配置
OPENAI_API_KEY=your_openai_api_key_here
# Neo4j配置
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_neo4j_password_here
注意:
- 请将
your_openai_api_key_here替换为你的真实OpenAI API密钥。如果你没有,可以在OpenAI官网注册并获取。 - 请将
your_neo4j_password_here替换为你设置的Neo4j密码。 - 确保
.env文件不会被提交到版本控制系统中(你可以将其添加到.gitignore文件)。
6.4 测试环境
现在,让我们编写一个简单的脚本来测试环境是否配置正确。创建一个名为test_env.py的文件:
import os
from dotenv import load_dotenv
from neo4j import GraphDatabase
from openai import OpenAI
# 加载环境变量
load_dotenv()
def test_neo4j_connection():
"""测试Neo4j连接"""
uri = os.getenv("NEO4J_URI")
user = os.getenv("NEO4J_USER")
password = os.getenv("NEO4J_PASSWORD")
try:
driver = GraphDatabase.driver(uri, auth=(user, password))
driver.verify_connectivity()
print("✅ Neo4j连接成功!")
# 执行一个简单的查询
with driver.session() as session:
result = session.run("RETURN 1 AS num")
record = result.single()
print(f"✅ 执行查询成功,结果: {record['num']}")
driver.close()
return True
except Exception as e:
print(f"❌ Neo4j连接失败: {e}")
return False
def test_openai_connection():
"""测试OpenAI连接"""
api_key = os.getenv("OPENAI_API_KEY")
try:
client = OpenAI(api_key=api_key)
# 发送一个简单的请求
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "你好,请回复'连接成功'"}],
temperature=0
)
message = response.choices[0].message.content.strip()
if message == "连接成功":
print(f"✅ OpenAI连接成功!模型回复: {message}")
return True
else:
print(f"⚠️ OpenAI连接成功,但回复不符合预期: {message}")
return True
except Exception as e:
print(f"❌ OpenAI连接失败: {e}")
return False
if __name__ == "__main__":
print("开始测试环境...")
neo4j_ok = test_neo4j_connection()
openai_ok = test_openai_connection()
if neo4j_ok and openai_ok:
print("\n🎉 所有环境测试通过!")
else:
print("\n❌ 部分环境测试失败,请检查配置。")
运行这个脚本:
python test_env.py
如果一切正常,你应该会看到所有测试都通过的消息。如果有任何错误,请根据提示检查你的配置。
7. 分步实现:构建知识图谱 (Step-by-Step Implementation: Building the Knowledge Graph)
现在,我们的环境已经准备好了,接下来我们将开始构建一个知识图谱。为了让示例既有趣又实用,我们将构建一个电影知识图谱,包含电影、演员、导演、类型等实体以及它们之间的关系。
7.1 设计图谱Schema
在构建知识图谱之前,我们首先需要设计它的Schema(模式),也就是定义我们有哪些实体类型、哪些关系类型以及哪些属性。
我们的电影知识图谱将包含以下内容:
实体类型(Labels):
Person:人物,包括演员和导演Movie:电影Genre:电影类型
关系类型(Relationship Types):
ACTED_IN:演员参演电影DIRECTED:导演执导电影IN_GENRE:电影属于某个类型
属性:
Person:name(姓名),birthYear(出生年份)Movie:title(标题),releaseYear(上映年份),rating(评分)Genre:name(类型名称)ACTED_IN:role(角色名)
我们可以用一个ER图来表示这个Schema:
7.2 准备数据
为了方便演示,我们将手动准备一些电影数据。在实际应用中,你可能需要从公开数据源(如IMDb、Wikidata)获取数据,或者使用信息抽取技术从文本中提取知识。
我们将选择几部克里斯托弗·诺兰的经典电影以及一些相关的演员和导演:
人物:
- 克里斯托弗·诺兰(Christopher Nolan),1970年出生,导演
- 莱昂纳多·迪卡普里奥(Leonardo DiCaprio),1974年出生,演员
- 约瑟夫·高登-莱维特(Joseph Gordon-Levitt),1981年出生,演员
- 艾伦·佩吉(Ellen Page),1987年出生,演员
- 马修·麦康纳(Matthew McConaughey),1969年出生,演员
- 安妮·海瑟薇(Anne Hathaway),1982年出生,演员
- 克里斯蒂安·贝尔(Christian Bale),1974年出生,演员
- 希斯·莱杰(Heath Ledger),1979年出生,演员
电影:
- 《盗梦空间》(Inception),2010年上映,评分8.8
- 《星际穿越》(Interstellar),2014年上映,评分8.6
- 《蝙蝠侠:黑暗骑士》(The Dark Knight),2008年上映,评分9.0
类型:
- 科幻(Sci-Fi)
- 动作(Action)
- 惊悚(Thriller)
- 剧情(Drama)
- 犯罪(Crime)
关系:
- 克里斯托弗·诺兰执导了这三部电影
- 莱昂纳多·迪卡普里奥在《盗梦空间》中饰演Cobb
- 约瑟夫·高登-莱维特在《盗梦空间》中饰演Arthur
- 艾伦·佩吉在《盗梦空间》中饰演Ariadne
- 马修·麦康纳在《星际穿越》中饰演Cooper
- 安妮·海瑟薇在《星际穿越》中饰演Brand
- 克里斯蒂安·贝尔在《蝙蝠侠:黑暗骑士》中饰演Bruce Wayne / Batman
- 希斯·莱杰在《蝙蝠侠:黑暗骑士》中饰演Joker
- 《盗梦空间》属于科幻、动作、惊悚类型
- 《星际穿越》属于科幻、剧情类型
- 《蝙蝠侠:黑暗骑士》属于动作、剧情、犯罪类型
7.3 创建Cypher语句导入数据
现在,我们将编写Cypher语句来创建这些实体和关系。创建一个名为import_data.cypher的文件:
// 创建人物节点
CREATE (nolan:Person {name: 'Christopher Nolan', birthYear: 1970})
CREATE (dicaprio:Person {name: 'Leonardo DiCaprio', birthYear: 1974})
CREATE (gordon_levitt:Person {name: 'Joseph Gordon-Levitt', birthYear: 1981})
CREATE (page:Person {name: 'Ellen Page', birthYear: 1987})
CREATE (mcconaughey:Person {name: 'Matthew McConaughey', birthYear: 1969})
CREATE (hathaway:Person {name: 'Anne Hathaway', birthYear: 1982})
CREATE (bale:Person {name: 'Christian Bale', birthYear: 1974})
CREATE (ledger:Person {name: 'Heath Ledger', birthYear: 1979})
// 创建电影节点
CREATE (inception:Movie {title: 'Inception', releaseYear: 2010, rating: 8.8})
CREATE (interstellar:Movie {title: 'Interstellar', releaseYear: 2014, rating: 8.6})
CREATE (dark_knight:Movie {title: 'The Dark Knight', releaseYear: 2008, rating: 9.0})
// 创建类型节点
CREATE (sci_fi:Genre {name: 'Sci-Fi'})
CREATE (action:Genre {name: 'Action'})
CREATE (thriller:Genre {name: 'Thriller'})
CREATE (drama:Genre {name: 'Drama'})
CREATE (crime:Genre {name: 'Crime'})
// 创建导演关系
CREATE (nolan)-[:DIRECTED]->(inception)
CREATE (nolan)-[:DIRECTED]->(interstellar)
CREATE (nolan)-[:DIRECTED]->(dark_knight)
// 创建演员关系
CREATE (dicaprio)-[:ACTED_IN {role: 'Cobb'}]->(inception)
CREATE (gordon_levitt)-[:ACTED_IN {role: 'Arthur'}]->(inception)
CREATE (page)-[:ACTED_IN {role: 'Ariadne'}]->(inception)
CREATE (mcconaughey)-[:ACTED_IN {role: 'Cooper'}]->(interstellar)
CREATE (hathaway)-[:ACTED_IN {role: 'Brand'}]->(interstellar)
CREATE (bale)-[:ACTED_IN {role: 'Bruce Wayne / Batman'}]->(dark_knight)
CREATE (ledger)-[:ACTED_IN {role: 'Joker'}]->(dark_knight)
// 创建类型关系
CREATE (inception)-[:IN_GENRE]->(sci_fi)
CREATE (inception)-[:IN_GENRE]->(action)
CREATE (inception)-[:IN_GENRE]->(thriller)
CREATE (interstellar)-[:IN_GENRE]->(sci_fi)
CREATE (interstellar)-[:IN_GENRE]->(drama)
CREATE (dark_knight)-[:IN_GENRE]->(action)
CREATE (dark_knight)-[:IN_GENRE]->(drama)
CREATE (dark_knight)-[:IN_GENRE]->(crime)
现在,我们可以通过Neo4j Browser来执行这些Cypher语句,或者我们也可以编写一个Python脚本来自动导入数据。让我们选择后者,这样更方便自动化。
创建一个名为build_kg.py的文件:
import os
from dotenv import load_dotenv
from neo4j import GraphDatabase
# 加载环境变量
load_dotenv()
def clear_database(session):
"""清空数据库(谨慎使用!)"""
print("正在清空数据库...")
session.run("MATCH (n) DETACH DELETE n")
print("✅ 数据库已清空")
def import_data(session):
"""导入数据"""
print("正在导入数据...")
# 读取Cypher文件
with open("import_data.cypher", "r", encoding="utf-8") as f:
cypher = f.read()
# 执行Cypher语句
session.run(cypher)
print("✅ 数据导入完成")
def verify_data(session):
"""验证数据是否导入成功"""
print("正在验证数据...")
# 统计节点数量
person_count = session.run("MATCH (p:Person) RETURN count(p) AS count").single()["count"]
movie_count = session.run("MATCH (m:Movie) RETURN count(m) AS count").single()["count"]
genre_count = session.run("MATCH (g:Genre) RETURN count(g) AS count").single()["count"]
# 统计关系数量
acted_in_count = session.run("MATCH ()-[r:ACTED_IN]->() RETURN count(r) AS count").single()["count"]
directed_count = session.run("MATCH ()-[r:DIRECTED]->() RETURN count(r) AS count").single()["count"]
in_genre_count = session.run("MATCH ()-[r:IN_GENRE]->() RETURN count(r) AS count").single()["count"]
print(f"✅ 数据统计:")
print(f" - 人物节点: {person_count}")
print(f" - 电影节点: {movie_count}")
print(f" - 类型节点: {genre_count}")
print(f" - 参演关系: {acted_in_count}")
print(f" - 导演关系: {directed_count}")
print(f" - 类型关系: {in_genre_count}")
# 验证几个具体的查询
print(f"\n✅ 执行几个验证查询:")
# 查询1: 谁导演了《盗梦空间》?
result = session.run("""
MATCH (p:Person)-[:DIRECTED]->(m:Movie {title: 'Inception'})
RETURN p.name AS director
""")
director = result.single()["director"]
print(f" - 《盗梦空间》的导演是: {director}")
# 查询2: 《盗梦空间》有哪些演员?
result = session.run("""
MATCH (p:Person)-[:ACTED_IN]->(m:Movie {title: 'Inception'})
RETURN p.name AS actor, collect(r.role) AS roles
""")
actors = [record["actor"] for record in result]
print(f" - 《盗梦空间》的演员有: {', '.join(actors)}")
# 查询3: 克里斯托弗·诺兰导演了哪些评分在8.5以上的电影?
result = session.run("""
MATCH (p:Person {name: 'Christopher Nolan'})-[:DIRECTED]->(m:Movie)
WHERE m.rating >= 8.5
RETURN m.title AS title, m.rating AS rating
ORDER BY m.rating DESC
""")
movies = [f"{record['title']} ({record['rating']})" for record in result]
print(f" - 诺兰导演的评分8.5以上的电影: {', '.join(movies)}")
def main():
# 连接数据库
uri = os.getenv("NEO4J_URI")
user = os.getenv("NEO4J_USER")
password = os.getenv("NEO4J_PASSWORD")
driver = GraphDatabase.driver(uri, auth=(user, password))
with driver.session() as session:
# 询问用户是否要清空数据库
response = input("是否要清空数据库?这将删除所有数据!(y/n): ")
if response.lower() == "y":
clear_database(session)
# 导入数据
import_data(session)
# 验证数据
verify_data(session)
driver.close()
print("\n🎉 知识图谱构建完成!")
if __name__ == "__main__":
main()
现在,让我们运行这个脚本来构建知识图谱:
python build_kg.py
当被询问是否要清空数据库时,如果你是第一次运行,可以选择n,因为数据库是空的。但如果你之前已经运行过,建议选择y来避免重复数据。
如果一切正常,你应该会看到数据导入和验证成功的消息。你也可以打开Neo4j Browser,运行以下查询来查看图谱:
MATCH (n) RETURN n
你应该能看到一个漂亮的图,展示了我们的电影、人物和类型之间的关系。
8. 分步实现:开发KG-LLM交互层 (Step-by-Step Implementation: Developing the KG-LLM Interaction Layer)
现在,我们已经有了一个知识图谱,接下来我们需要开发一个交互层,让LLMs能够与知识图谱进行交互。在这一章中,我们将实现两种关键的交互方式:
更多推荐


所有评论(0)