您是否想过,为什么像 Alexa 或 Google Assistant 这样的数字助理能如此准确地回答您的问题?
其背后的魔法叫作检索增强生成(RAG),它将信息检索与语言生成技术结合起来。这个过程中一个关键角色是知识图谱 ,它帮助这些助理访问庞大的结构化信息池,从而提升回答质量。
在本教程中,我们将探索知识图谱,以及如何用它来构建 RAG 应用,以获得更准确、更相关的回答。
我们将先拆解知识图谱的基础知识及其在 RAG 中的作用。接着与向量数据库进行对比,并了解在什么情况下优先使用哪一种。然后我们将动手从文本数据创建一个知识图谱,将其存入数据库,并用它来为用户查询找到相关信息。我们还会讨论如何将这种方法扩展到处理不同类型的数据和除纯文本外的多种文件格式。
如果您想进一步了解 RAG,请查看这篇关于检索增强生成 的文章。
什么是知识图谱?
知识图谱以结构化、互联的形式表示信息。它由实体(节点)以及实体之间的关系(边)组成。实体可以代表现实世界中的对象、概念或想法,而关系描述这些实体是如何相互连接的。
知识图谱背后的直觉是模仿人类理解与推理世界的方式。我们不会将信息存放在孤立的“仓”里,而是会在不同信息之间建立联系,形成丰富而互联的知识网络。
知识图谱通过清晰展示不同实体之间的关系,帮助我们看清实体是如何关联的。探索这些连接可以帮助我们发现新信息,并得出从零散信息中难以推演的结论。
我们来看一个例子。
图 1:在这个可视化表示中,节点以圆形显示,节点间的关系以带标签的箭头连接加以表示。
这个知识图谱有效地刻画了个人 Sarah 和 Michael 与公司 prismaticAI 之间的雇佣关系。在我们的示例中,有三个节点:
节点 1
节点 2
节点 3
类型:Company(公司)
名称:prismaticAI
总而言之,我们有两个人物节点(Sarah 和 Michael)以及一个公司节点(prismaticAI)。现在,我们来看看这些节点之间的关系(边):
关系 1 :Sarah --[works for]--> prismaticAI
该关系表明,由节点 1 表示的 Sarah 与由节点 3 表示的 prismaticAI 存在“works for(就职于)”关系。换句话说,Sarah 是 prismaticAI 的员工。
关系 2 :Michael --[works for]--> prismaticAI
与第一个关系类似,这里显示由节点 2 表示的 Michael 同样与 prismaticAI(节点 3)存在“works for(就职于)”关系。Michael 也是 prismaticAI 的员工。
查询与遍历知识图谱
知识图谱的一个强大之处在于,能够查询并遍历实体之间的关系,以提取相关信息或推断新知识。我们用示例知识图谱来演示如何实现这一点。
首先,需要确定我们希望从知识图谱中检索什么信息。例如:
查询 1 :Sarah 在哪里工作?
要回答这个查询,我们需要在知识图谱中找到合适的起点。在本例中,我们要从表示 Sarah 的节点开始。
从起点(Sarah 的节点)出发,沿着指向外部的“works for(就职于)”关系边前进。该边将 Sarah 的节点连接到表示 prismaticAI 的节点。通过遍历“works for”关系,我们可以得出结论:Sarah 就职于 prismaticAI。
回答 1: Sarah 就职于 prismaticAI。
再来一个查询:
查询 2 :谁在 prismaticAI 工作?
这一次,我们从表示 prismaticAI 的节点开始。
从 prismaticAI 节点出发,沿着“works for(就职于)”关系边反向回溯。这会引导我们找到那些在 prismaticAI 工作的人员节点。通过反向遍历“works for”关系,我们可以识别出 Sarah 和 Michael 都在 prismaticAI 工作。
回答 2 :Sarah 和 Michael 在 prismaticAI 工作。
再举一个例子!
查询 3 :Michael 是否与 Sarah 在同一家公司工作?
我们可以从 Sarah 的节点或 Michael 的节点任一处开始。这里从 Sarah 的节点开始。
沿着“works for(就职于)”关系到达 prismaticAI 节点。
然后,检查 Michael 是否也有一条通向同一 prismaticAI 节点的“works for”关系。由于 Sarah 和 Michael 都与该 prismaticAI 节点存在“works for”关系,我们可以得出他们在同一家公司工作的结论。
回答 3 :是的,Michael 与 Sarah 在同一家公司(prismaticAI)工作。
通过遍历知识图谱中的关系,我们能够提取特定信息,理解实体之间的连接。知识图谱可以变得更为复杂,包含众多节点与关系,从而以结构化、互联的方式表示复杂的现实世界知识。
知识图谱在 RAG 应用中的优势
RAG 应用将信息检索与自然语言生成结合起来,为用户查询或提示提供相关且连贯的回答。知识图谱具备多项优势,使其特别适合于这类应用。下面我们来看看关键收益:
结构化知识表示
正如上一节所述,知识图谱以实体(节点)及其关系(边)的方式来结构化地表示信息。相比非结构化文本数据,这种结构化表示更便于针对特定查询或任务检索相关信息。
在我们的示例知识图谱中,我们可以通过沿着“works for(就职于)”关系,轻松检索出谁在 prismaticAI 工作。
上下文理解
知识图谱捕捉实体之间的关系,从而实现对信息所处语境的更深层理解。对于在 RAG 应用中生成连贯、相关的回答而言,这种上下文理解至关重要。
回到我们的例子,理解 Sarah、Michael 与 prismaticAI 之间的“works for(就职于)”关系,可以让 RAG 应用就他们的雇佣信息给出更契合语境的回答。
推理能力
沿着知识图谱中的关系进行遍历,使 RAG 应用能够进行推断并得出可能未被明示的新知识。这种推理能力提升了生成回答的质量与完整性。
通过遍历关系,RAG 应用可以推断出 Sarah 和 Michael 在同一家公司工作,即使这条信息并未被直接陈述。
知识整合
知识图谱可以整合来自多个来源的信息,使 RAG 应用能够利用多样且互补的知识库。这种整合有助于生成更全面、更周全的回答。
我们可以将不同来源中关于公司、员工及其角色的信息加入示例知识图谱,从而为回答生成提供更完整的图景。
可解释性与透明性
知识图谱以透明的方式呈现用于生成回答的知识。这种透明性是解释生成结果背后推理过程的关键,在许多应用(如问答系统)中尤为重要。
以示例中的回答 3 为例,其解释可以是:是的,Michael 与 Sarah 在同一家公司工作。我先识别到 Sarah 就职于 prismaticAI,然后再验证 Michael 也与 prismaticAI 存在“works for(就职于)”关系。由于他们都与同一公司实体存在该关系,我可以推断他们在同一家公司工作。
这种推理过程的透明性,使用户和开发者能够理解 RAG 应用如何得到其回答,而非将其视作黑箱。同时,这也提升了对系统的信任,因为决策过程清晰可查,并可与知识图谱进行核验。
此外,如果知识图谱中存在任何不一致或缺失信息,解释过程也有助于识别并解决这些问题,从而提升回答的准确性与完整性。
借助知识图谱,RAG 应用能够生成更准确、清晰、易于理解的回答,使其适用于各类自然语言处理任务。
知识图谱 vs. 向量数据库
在构建 RAG 应用时,您可能会遇到两种不同的方法:知识图谱与向量数据库。两者都用于表示和检索信息,但它们在底层数据结构以及处理信息的方式上有所不同。
让我们来看看这两种方法的关键差异:
特性
知识图谱
向量数据库
数据表示
以实体(节点)及实体间的关系(边)组成图结构。
高维向量,每个向量代表一条信息(如文档、句子)。
检索机制
遍历图结构并沿着实体间的关系前进。支持推理与新知识的导出。
基于相似度度量(如余弦相似度)的向量相似性。返回最相似的向量及其关联信息。
可解释性
对人类更可解释的知识表示。图结构与带标签的关系能清晰说明实体连接方式。
由于高维数值表示,对人类不易解释。直接理解检索信息之间的关系或背后推理较具挑战。
知识整合
通过在统一图结构中表示实体与关系来促进整合。若实体与关系映射得当,可实现无缝整合。
更具挑战。需要向量空间对齐或集成方法来合并信息。确保向量兼容性并非易事。
推理能力
通过遍历图结构并利用实体间关系实现推理。可发现隐含连接并导出新洞见。
更受限。依赖向量相似度,可能错过隐式关系或推断。可识别相似信息,但难以像知识图谱那样捕捉复杂关系。
知识图谱与向量数据库各有优势与适用场景,如何选择取决于您的具体应用需求。知识图谱擅长表示与推理结构化知识,而向量数据库更适合高度依赖语义相似性与基于向量表示的信息检索的任务。
您可以在这篇机器学习向量数据库入门 中进一步了解向量数据库。此外,亦可查看最受欢迎的五大向量数据库 。
如何为 RAG 应用实现知识图谱
本节将介绍如何实现一个知识图谱,以增强 RAG 应用的语言生成过程。
我们将涵盖以下关键步骤:
加载并预处理文本数据。
初始化语言模型并抽取知识图谱。
将知识图谱存入数据库以便持久化与查询。
基于用户查询从图中检索相关知识。
将检索到的知识与语言模型结合,生成回答。
完成本节后,您将对在 RAG 应用中实现知识图谱有扎实的理解,从而构建更智能、更具上下文感知的语言生成系统。
先决条件
在开始之前,请确保您已安装以下内容:
Python 3.7 或更高版本
LangChain 库(pip install langchain)
LlamaIndex 库(pip install llama-index)
Neo4j 数据库(或任何其他兼容的图数据库)
步骤 1:加载并预处理文本数据
第一步是加载并预处理我们将用于抽取知识图谱的文本数据。在此示例中,我们将使用一段文本,描述一家名为 prismaticAI 的科技公司、其员工及其角色。
from langchain. document_loaders import TextLoader
from langchain. text_splitter import CharacterTextSplitter
text = """Sarah is an employee at prismaticAI, a leading technology company based in Westside Valley. She has been working there for the past three years as a software engineer.
Michael is also an employee at prismaticAI, where he works as a data scientist. He joined the company two years ago after completing his graduate studies.
prismaticAI is a well-known technology company that specializes in developing cutting-edge software solutions and artificial intelligence applications. The company has a diverse workforce of talented individuals from various backgrounds.
Both Sarah and Michael are highly skilled professionals who contribute significantly to prismaticAI's success. They work closely with their respective teams to develop innovative products and services that meet the evolving needs of the company's clients."""
loader = TextLoader( text)
documents = loader. load( )
text_splitter = CharacterTextSplitter( chunk_size= 200 , chunk_overlap= 20 )
texts = text_splitter. split_documents( documents) 技术支持
我们首先从 LangChain 引入所需的类:TextLoader 与 CharacterTextSplitter。TextLoader 用于加载文本数据,而 CharacterTextSplitter 将文本切分为更小的片段,以提升处理效率。
接下来,将文本数据定义为多行字符串变量 text。
然后使用 TextLoader 直接从该变量中加载文本数据。loader.load() 方法会返回一个 Document 对象列表,每个对象包含一段文本片段。
为了将文本切分为更小、更易管理的片段,我们创建一个 CharacterTextSplitter 实例,设置 chunk_size 为 200 个字符、chunk_overlap 为 20 个字符。chunk_overlap 参数确保相邻片段之间存在一定重叠,有助于在知识抽取过程中保持上下文。
最后,调用 CharacterTextSplitter 的 split_documents 方法对 Document 对象进行拆分,得到的更小片段以 Document 对象列表的形式存储在 texts 变量中。
通过这样的预处理,我们就为下一步做好了准备:初始化语言模型,并用它从文本片段中抽取知识图谱。
步骤 2:初始化语言模型并抽取知识图谱
在加载与预处理文本数据之后,下一步是初始化语言模型,并用它从文本片段中抽取知识图谱。在本示例中,我们将使用 LangChain 提供的 OpenAI 语言模型。
from langchain. llms import OpenAI
from langchain. transformers import LLMGraphTransformer
import getpass
import os
os. environ[ "OPENAI_API_KEY" ] = getpass. getpass( )
llm = OpenAI( temperature= 0 )
llm_transformer = LLMGraphTransformer( llm= llm)
graph_documents = llm_transformer. convert_to_graph_documents( texts) 技术支持
首先,从 LangChain 引入所需的类:OpenAI 与 LLMGraphTransformer。OpenAI 是 OpenAI 语言模型的封装,我们将用它来抽取知识图谱。LLMGraphTransformer 是一个将文本数据转换为知识图谱表示的实用类。
接着,从环境变量中加载 OpenAI API 密钥。这是避免在代码中硬编码敏感凭据的安全最佳实践。
然后以 temperature 为 0 初始化一个 OpenAI 语言模型实例。温度参数控制模型输出的随机性,较低的数值会产生更具确定性的结果。
初始化语言模型后,创建 LLMGraphTransformer 实例,并传入已初始化的 llm 对象。LLMGraphTransformer 会将文本片段(texts)转换为知识图谱表示。
最后,调用 LLMGraphTransformer 的 convert_to_graph_documents 方法,并传入 texts 列表。该方法利用语言模型分析文本片段并抽取相关实体、关系以及其他结构化信息,然后以知识图谱的形式表示。结果知识图谱存储在 graph_documents 变量中。
至此,我们已成功初始化语言模型并用它从文本数据中抽取出知识图谱。下一步,我们将把知识图谱存入数据库以便持久化与查询。
步骤 3:将知识图谱存入数据库
从文本数据中抽取出知识图谱后,将其以可持久化、可查询的格式进行存储非常重要。在本教程中,我们将使用 Neo4j 来存储知识图谱。
from langchain. graph_stores import Neo4jGraphStore
graph_store = Neo4jGraphStore( url= "neo4j://your_neo4j_url" , username= "your_username" , password= "your_password" )
graph_store. write_graph( graph_documents) 技术支持
首先,从 LangChain 引入 Neo4jGraphStore 类。该类为与 Neo4j 数据库交互并存储知识图谱提供了便捷接口。
接着,通过提供必要的连接信息(Neo4j 数据库 URL、用户名和密码)来创建 Neo4jGraphStore 实例。请将 "your_neo4j_url"、"your_username" 和 "your_password" 替换为您的 Neo4j 实例的实际值。
最后,调用 graph_store 实例的 write_graph 方法,并传入上一步得到的 graph_documents 列表。该方法会将知识图谱序列化并写入 Neo4j 数据库。
将知识图谱存入 Neo4j 数据库,确保其可持久保存,并在需要时便于查询与检索。Neo4j 的图结构非常适合高效表示与遍历知识图谱中复杂的关系与实体。
下一步,我们将设置基于该图检索知识与利用检索上下文生成回答的组件。
需要注意的是,虽然本教程使用 Neo4j 作为图数据库,LangChain 也支持其他图数据库,例如 Amazon Neptune,以及与 TinkerPop 兼容的数据库(如 Gremlin Server)。您可以将 Neo4jGraphStore 替换为与所选数据库相对应的图存储实现。
步骤 4:为 RAG 检索知识
现在我们已将知识图谱存入数据库,可以设置相关组件,基于用户查询从图中检索相关知识,并利用检索到的上下文生成回答。这是 RAG 应用的核心功能。
from llama_index. core. query_engine import RetrieverQueryEngine
from llama_index. core. retrievers import KnowledgeGraphRAGRetriever
from llama_index. core. response_synthesis import ResponseSynthesizer
graph_rag_retriever = KnowledgeGraphRAGRetriever( storage_context= graph_store. storage_context, verbose= True )
query_engine = RetrieverQueryEngine. from_args( graph_rag_retriever) 技术支持
首先,从 LlamaIndex 引入所需的类:RetrieverQueryEngine、KnowledgeGraphRAGRetriever 和 ResponseSynthesizer。
RetrieverQueryEngine 是一种查询引擎,它使用检索器从数据源(在此为知识图谱)获取相关上下文,然后基于该上下文综合生成回答。
KnowledgeGraphRAGRetriever 是专门用于从存储于数据库的知识图谱中检索相关信息的检索器。
ResponseSynthesizer 负责将检索到的上下文与语言模型结合,生成最终回答。
接着,通过传入 graph_store 实例的 storage_context 来创建 KnowledgeGraphRAGRetriever 实例。该 storage_context 包含连接与查询我们存储知识图谱的 Neo4j 数据库所需的信息。同时将 verbose=True 以启用检索过程的详细日志。
然后,使用 from_args 方法并传入我们的 graph_rag_retriever 实例来初始化 RetrieverQueryEngine。该查询引擎将负责从知识图谱中检索相关上下文并据此生成回答的完整流程。
完成这些组件的设置后,我们已准备好查询知识图谱,并利用检索到的上下文生成回答。下一步,我们将看看如何在实践中完成这一过程。
步骤 5:查询知识图谱并生成回答
最后,我们可以查询知识图谱,并利用检索到的上下文生成回答。
def query_and_synthesize ( query) :
retrieved_context = query_engine. query( query)
response = response_synthesizer. synthesize( query, retrieved_context)
print ( f"Query: { query} " )
print ( f"Answer: { response} \n" )
response_synthesizer = ResponseSynthesizer( llm)
query_and_synthesize( "Where does Sarah work?" )
query_and_synthesize( "Who works for prismaticAI?" )
query_and_synthesize( "Does Michael work for the same company as Sarah?" ) 技术支持
在这个示例中,我们定义了三个与文本数据中员工和公司相关的不同查询。对于每个查询,我们使用 query_engine 从知识图谱中检索相关上下文,创建一个 ResponseSynthesizer 实例,并调用其 synthesize 方法,传入查询与检索到的上下文。
ResponseSynthesizer 会结合语言模型与检索到的上下文,生成该查询的最终回答,并打印到控制台,结果与本文第一部分中的答案相吻合。
现实场景中的知识图谱
尽管本教程用相对简单的文本演示了在 RAG 应用中使用知识图谱,现实世界的场景往往涉及更复杂、多样的数据集。此外,输入数据也可能采用纯文本之外的多种文件格式。本节将探讨如何扩展基于知识图谱的 RAG 应用以处理这类情形。
处理大型与多样化数据集
随着输入数据规模和复杂度的提升,知识图谱抽取过程可能变得更具挑战。以下是一些应对大型与多样化数据集的策略:
分布式知识图谱构建 :对于超大数据集,可将知识图谱构建过程并行化并分布到多台机器或集群。通过对数据集进行分片并并行抽取知识图谱,随后再合并为一个统一的知识图谱。
增量式知识图谱更新 :与其在有新数据时每次都从头构建整个知识图谱,不如采用增量方式。在保留现有知识与关系的同时,将新信息更新到当前图谱中。
面向领域的知识图谱抽取 :对于跨越多个领域或主题的数据集,可构建面向具体领域的知识图谱抽取流水线。针对各领域的术语、实体与关系进行定制,有助于提升抽取图谱的准确性与完整性。
知识图谱融合与整合 :当处理来自多个来源的数据时,抽取出的知识图谱可能需要融合或整合为一个统一表示。这可能涉及实体消歧、关系对齐与冲突解决等技术,以确保一致性并避免冗余。
处理不同文件类型
在现实场景中,数据可能以多种文件格式存在,如 PDF、Word 文档、电子表格,甚至是 JSON 或 XML 等结构化数据格式。要处理这些不同的文件类型,可采用以下策略:
文件转换: 有许多库和工具可将不同文件格式转换为纯文本。例如,可使用 pdfplumber 或 tika 从 PDF 中抽取文本,或使用 python-docx 从 Word 文档中抽取文本。
自定义文件加载器 :LangChain 提供了 DocumentLoader 接口,允许您为特定文件类型创建自定义加载器。您可以通过继承 DocumentLoader 并重写 load 方法来处理所需的文件格式。
结构化数据处理: 对于 JSON 或 XML 等结构化数据格式,可使用 pandas 或 lxml 等库进行解析和信息抽取,然后再将其传入知识图谱抽取流水线。
多模态知识图谱抽取 :在某些情况下,输入数据可能是多模态的,既包含文本也包含图像或视频等其他模态。在此情形下,可以探索多模态知识图谱抽取技术,将基于文本的抽取与计算机视觉或其他模态特定方法相结合。
这些策略将帮助您扩展基于知识图谱的 RAG 应用,以处理更复杂和多样化的数据集,以及更广泛的文件类型。
需要注意的是,随着输入数据复杂度的提高,知识图谱抽取过程可能需要更多面向特定领域的定制与调优,以确保结果准确可靠。
挑战
在现实世界中为 RAG 应用搭建知识图谱是一项复杂的工作,面临多重挑战。我们来看看其中的一些:
知识图谱构建
构建高质量的知识图谱是一个复杂且耗时的过程,需要大量领域专业知识与投入。从各类数据源中抽取实体、关系与事实,并将其整合到一致的知识图谱中颇具挑战,尤其是面对大型且多样的数据集。这需要理解领域、识别相关信息,并以能准确捕捉关系与语义的方式对其进行结构化。
数据集成与互操作性
RAG 应用通常需要集成来自多个异构来源的数据,每个来源都有其自身的结构、格式与语义。要确保数据一致性、解决冲突,并在不同数据源之间映射实体与关系并非易事。需要进行细致的数据清洗、转换与映射,以确保知识图谱准确地表达各来源的信息。
知识图谱维护与演化
知识图谱并非静态。随着新信息出现或现有信息变化,它们需要持续更新与维护。让知识图谱随不断演变的数据源保持最新与一致,可能是一项资源密集型工作。这涉及监测数据源中的变化、识别相关更新,并在保持图谱完整性与一致性的前提下,将更新传播到知识图谱中。
可扩展性与性能
随着知识图谱在规模与复杂度上的增长,如何高效地存储、检索与查询图数据将愈发具有挑战。对于具有高查询量的大型 RAG 应用,可能会出现可扩展性与性能问题。优化知识图谱的存储、索引与查询处理技术,对于维持可接受的性能水平至关重要。
查询复杂度与推理
虽然知识图谱擅长表示复杂关系并支持多跳推理,但要构造并执行充分利用这些能力的复杂查询并不容易。开发高效的查询处理与推理算法仍是一个活跃的研究领域。理解所用知识图谱系统的查询语言与推理能力,对于有效发挥其潜力非常重要。
缺乏标准化
目前在知识图谱的表示与查询上缺少被广泛采用的标准,这可能导致互操作性问题与厂商锁定。不同的知识图谱系统可能采用不同的数据模型、查询语言与 API,从而使得在系统间迁移或与其他系统集成变得困难。采用或制定标准有助于促进互操作性并降低厂商锁定风险。
可解释性与透明性
尽管知识图谱能够提供可解释、透明的推理,但要确保推理过程对终端用户来说易于理解仍具挑战,尤其是当查询或推理路径较为复杂时。开发用户友好的界面与解释,清晰传达推理过程及其基本假设,对于赢得用户信任与促进采用很重要。
领域特定挑战
根据不同领域与应用,可能还存在特定挑战,例如处理领域特定术语、本体或数据格式。以医疗领域为例,复杂的医学术语、编码体系以及隐私问题,都会为知识图谱的搭建与使用增加额外难度。
尽管存在这些挑战,知识图谱在 RAG 应用中仍具有显著优势,尤其是在表示结构化知识、支持复杂推理以及提供可解释与透明结果方面。通过合理的知识图谱设计、数据集成策略与高效的查询处理技术来应对这些挑战,是成功实现基于知识图谱的 RAG 应用的关键。
结论
在本教程中,我们探索了知识图谱的力量,以生成更准确、信息量更大、语境更相关的回答。我们从理解知识图谱的基本概念及其在 RAG 应用中的作用开始,随后通过动手示例,从文本数据抽取知识图谱、存入 Neo4j 数据库,并用它来为用户查询检索相关上下文。最后,我们演示了如何利用检索到的上下文,结合图中的结构化知识来生成回答。
如果您想进一步了解 AI 与大语言模型,请查看这个包含六门课程的技能路径:AI Fundamentals 。
希望您觉得本教程有用且有趣,我们下期再见。
编码愉快!
您是否想过,为什么像 Alexa 或 Google Assistant 这样的数字助理能如此准确地回答您的问题?
其背后的魔法叫作检索增强生成(RAG),它将信息检索与语言生成技术结合起来。这个过程中一个关键角色是知识图谱,它帮助这些助理访问庞大的结构化信息池,从而提升回答质量。
在本教程中,我们将探索知识图谱,以及如何用它来构建 RAG 应用,以获得更准确、更相关的回答。
我们将先拆解知识图谱的基础知识及其在 RAG 中的作用。接着与向量数据库进行对比,并了解在什么情况下优先使用哪一种。然后我们将动手从文本数据创建一个知识图谱,将其存入数据库,并用它来为用户查询找到相关信息。我们还会讨论如何将这种方法扩展到处理不同类型的数据和除纯文本外的多种文件格式。
如果您想进一步了解 RAG,请查看这篇关于检索增强生成的文章。
什么是知识图谱?
知识图谱以结构化、互联的形式表示信息。它由实体(节点)以及实体之间的关系(边)组成。实体可以代表现实世界中的对象、概念或想法,而关系描述这些实体是如何相互连接的。
知识图谱背后的直觉是模仿人类理解与推理世界的方式。我们不会将信息存放在孤立的“仓”里,而是会在不同信息之间建立联系,形成丰富而互联的知识网络。
知识图谱通过清晰展示不同实体之间的关系,帮助我们看清实体是如何关联的。探索这些连接可以帮助我们发现新信息,并得出从零散信息中难以推演的结论。
我们来看一个例子。
图 1:在这个可视化表示中,节点以圆形显示,节点间的关系以带标签的箭头连接加以表示。
这个知识图谱有效地刻画了个人 Sarah 和 Michael 与公司 prismaticAI 之间的雇佣关系。在我们的示例中,有三个节点:
总而言之,我们有两个人物节点(Sarah 和 Michael)以及一个公司节点(prismaticAI)。现在,我们来看看这些节点之间的关系(边):
查询与遍历知识图谱
知识图谱的一个强大之处在于,能够查询并遍历实体之间的关系,以提取相关信息或推断新知识。我们用示例知识图谱来演示如何实现这一点。
首先,需要确定我们希望从知识图谱中检索什么信息。例如:
查询 1:Sarah 在哪里工作?
要回答这个查询,我们需要在知识图谱中找到合适的起点。在本例中,我们要从表示 Sarah 的节点开始。
从起点(Sarah 的节点)出发,沿着指向外部的“works for(就职于)”关系边前进。该边将 Sarah 的节点连接到表示 prismaticAI 的节点。通过遍历“works for”关系,我们可以得出结论:Sarah 就职于 prismaticAI。
回答 1:Sarah 就职于 prismaticAI。
再来一个查询:
查询 2:谁在 prismaticAI 工作?
这一次,我们从表示 prismaticAI 的节点开始。
从 prismaticAI 节点出发,沿着“works for(就职于)”关系边反向回溯。这会引导我们找到那些在 prismaticAI 工作的人员节点。通过反向遍历“works for”关系,我们可以识别出 Sarah 和 Michael 都在 prismaticAI 工作。
回答 2:Sarah 和 Michael 在 prismaticAI 工作。
再举一个例子!
查询 3:Michael 是否与 Sarah 在同一家公司工作?
我们可以从 Sarah 的节点或 Michael 的节点任一处开始。这里从 Sarah 的节点开始。
沿着“works for(就职于)”关系到达 prismaticAI 节点。
然后,检查 Michael 是否也有一条通向同一 prismaticAI 节点的“works for”关系。由于 Sarah 和 Michael 都与该 prismaticAI 节点存在“works for”关系,我们可以得出他们在同一家公司工作的结论。
回答 3:是的,Michael 与 Sarah 在同一家公司(prismaticAI)工作。
通过遍历知识图谱中的关系,我们能够提取特定信息,理解实体之间的连接。知识图谱可以变得更为复杂,包含众多节点与关系,从而以结构化、互联的方式表示复杂的现实世界知识。
知识图谱在 RAG 应用中的优势
RAG 应用将信息检索与自然语言生成结合起来,为用户查询或提示提供相关且连贯的回答。知识图谱具备多项优势,使其特别适合于这类应用。下面我们来看看关键收益:
结构化知识表示
正如上一节所述,知识图谱以实体(节点)及其关系(边)的方式来结构化地表示信息。相比非结构化文本数据,这种结构化表示更便于针对特定查询或任务检索相关信息。
在我们的示例知识图谱中,我们可以通过沿着“works for(就职于)”关系,轻松检索出谁在 prismaticAI 工作。
上下文理解
知识图谱捕捉实体之间的关系,从而实现对信息所处语境的更深层理解。对于在 RAG 应用中生成连贯、相关的回答而言,这种上下文理解至关重要。
回到我们的例子,理解 Sarah、Michael 与 prismaticAI 之间的“works for(就职于)”关系,可以让 RAG 应用就他们的雇佣信息给出更契合语境的回答。
推理能力
沿着知识图谱中的关系进行遍历,使 RAG 应用能够进行推断并得出可能未被明示的新知识。这种推理能力提升了生成回答的质量与完整性。
通过遍历关系,RAG 应用可以推断出 Sarah 和 Michael 在同一家公司工作,即使这条信息并未被直接陈述。
知识整合
知识图谱可以整合来自多个来源的信息,使 RAG 应用能够利用多样且互补的知识库。这种整合有助于生成更全面、更周全的回答。
我们可以将不同来源中关于公司、员工及其角色的信息加入示例知识图谱,从而为回答生成提供更完整的图景。
可解释性与透明性
知识图谱以透明的方式呈现用于生成回答的知识。这种透明性是解释生成结果背后推理过程的关键,在许多应用(如问答系统)中尤为重要。
以示例中的回答 3 为例,其解释可以是:是的,Michael 与 Sarah 在同一家公司工作。我先识别到 Sarah 就职于 prismaticAI,然后再验证 Michael 也与 prismaticAI 存在“works for(就职于)”关系。由于他们都与同一公司实体存在该关系,我可以推断他们在同一家公司工作。
这种推理过程的透明性,使用户和开发者能够理解 RAG 应用如何得到其回答,而非将其视作黑箱。同时,这也提升了对系统的信任,因为决策过程清晰可查,并可与知识图谱进行核验。
此外,如果知识图谱中存在任何不一致或缺失信息,解释过程也有助于识别并解决这些问题,从而提升回答的准确性与完整性。
借助知识图谱,RAG 应用能够生成更准确、清晰、易于理解的回答,使其适用于各类自然语言处理任务。
知识图谱 vs. 向量数据库
在构建 RAG 应用时,您可能会遇到两种不同的方法:知识图谱与向量数据库。两者都用于表示和检索信息,但它们在底层数据结构以及处理信息的方式上有所不同。
让我们来看看这两种方法的关键差异:
特性
知识图谱
向量数据库
数据表示
以实体(节点)及实体间的关系(边)组成图结构。
高维向量,每个向量代表一条信息(如文档、句子)。
检索机制
遍历图结构并沿着实体间的关系前进。支持推理与新知识的导出。
基于相似度度量(如余弦相似度)的向量相似性。返回最相似的向量及其关联信息。
可解释性
对人类更可解释的知识表示。图结构与带标签的关系能清晰说明实体连接方式。
由于高维数值表示,对人类不易解释。直接理解检索信息之间的关系或背后推理较具挑战。
知识整合
通过在统一图结构中表示实体与关系来促进整合。若实体与关系映射得当,可实现无缝整合。
更具挑战。需要向量空间对齐或集成方法来合并信息。确保向量兼容性并非易事。
推理能力
通过遍历图结构并利用实体间关系实现推理。可发现隐含连接并导出新洞见。
更受限。依赖向量相似度,可能错过隐式关系或推断。可识别相似信息,但难以像知识图谱那样捕捉复杂关系。
知识图谱与向量数据库各有优势与适用场景,如何选择取决于您的具体应用需求。知识图谱擅长表示与推理结构化知识,而向量数据库更适合高度依赖语义相似性与基于向量表示的信息检索的任务。
您可以在这篇机器学习向量数据库入门中进一步了解向量数据库。此外,亦可查看最受欢迎的五大向量数据库。
如何为 RAG 应用实现知识图谱
本节将介绍如何实现一个知识图谱,以增强 RAG 应用的语言生成过程。
我们将涵盖以下关键步骤:
完成本节后,您将对在 RAG 应用中实现知识图谱有扎实的理解,从而构建更智能、更具上下文感知的语言生成系统。
先决条件
在开始之前,请确保您已安装以下内容:
pip install langchain)pip install llama-index)步骤 1:加载并预处理文本数据
第一步是加载并预处理我们将用于抽取知识图谱的文本数据。在此示例中,我们将使用一段文本,描述一家名为 prismaticAI 的科技公司、其员工及其角色。
我们首先从 LangChain 引入所需的类:
TextLoader与CharacterTextSplitter。TextLoader用于加载文本数据,而CharacterTextSplitter将文本切分为更小的片段,以提升处理效率。接下来,将文本数据定义为多行字符串变量
text。然后使用
TextLoader直接从该变量中加载文本数据。loader.load()方法会返回一个Document对象列表,每个对象包含一段文本片段。为了将文本切分为更小、更易管理的片段,我们创建一个
CharacterTextSplitter实例,设置chunk_size为 200 个字符、chunk_overlap为 20 个字符。chunk_overlap参数确保相邻片段之间存在一定重叠,有助于在知识抽取过程中保持上下文。最后,调用
CharacterTextSplitter的split_documents方法对Document对象进行拆分,得到的更小片段以Document对象列表的形式存储在 texts 变量中。通过这样的预处理,我们就为下一步做好了准备:初始化语言模型,并用它从文本片段中抽取知识图谱。
步骤 2:初始化语言模型并抽取知识图谱
在加载与预处理文本数据之后,下一步是初始化语言模型,并用它从文本片段中抽取知识图谱。在本示例中,我们将使用 LangChain 提供的 OpenAI 语言模型。
首先,从 LangChain 引入所需的类:
OpenAI与LLMGraphTransformer。OpenAI是 OpenAI 语言模型的封装,我们将用它来抽取知识图谱。LLMGraphTransformer是一个将文本数据转换为知识图谱表示的实用类。接着,从环境变量中加载 OpenAI API 密钥。这是避免在代码中硬编码敏感凭据的安全最佳实践。
然后以
temperature为0初始化一个OpenAI语言模型实例。温度参数控制模型输出的随机性,较低的数值会产生更具确定性的结果。初始化语言模型后,创建
LLMGraphTransformer实例,并传入已初始化的llm对象。LLMGraphTransformer会将文本片段(texts)转换为知识图谱表示。最后,调用
LLMGraphTransformer的convert_to_graph_documents方法,并传入 texts 列表。该方法利用语言模型分析文本片段并抽取相关实体、关系以及其他结构化信息,然后以知识图谱的形式表示。结果知识图谱存储在graph_documents变量中。至此,我们已成功初始化语言模型并用它从文本数据中抽取出知识图谱。下一步,我们将把知识图谱存入数据库以便持久化与查询。
步骤 3:将知识图谱存入数据库
从文本数据中抽取出知识图谱后,将其以可持久化、可查询的格式进行存储非常重要。在本教程中,我们将使用 Neo4j 来存储知识图谱。
首先,从 LangChain 引入
Neo4jGraphStore类。该类为与 Neo4j 数据库交互并存储知识图谱提供了便捷接口。接着,通过提供必要的连接信息(Neo4j 数据库 URL、用户名和密码)来创建
Neo4jGraphStore实例。请将"your_neo4j_url"、"your_username"和"your_password"替换为您的 Neo4j 实例的实际值。最后,调用
graph_store实例的write_graph方法,并传入上一步得到的graph_documents列表。该方法会将知识图谱序列化并写入 Neo4j 数据库。将知识图谱存入 Neo4j 数据库,确保其可持久保存,并在需要时便于查询与检索。Neo4j 的图结构非常适合高效表示与遍历知识图谱中复杂的关系与实体。
下一步,我们将设置基于该图检索知识与利用检索上下文生成回答的组件。
需要注意的是,虽然本教程使用 Neo4j 作为图数据库,LangChain 也支持其他图数据库,例如 Amazon Neptune,以及与 TinkerPop 兼容的数据库(如 Gremlin Server)。您可以将
Neo4jGraphStore替换为与所选数据库相对应的图存储实现。步骤 4:为 RAG 检索知识
现在我们已将知识图谱存入数据库,可以设置相关组件,基于用户查询从图中检索相关知识,并利用检索到的上下文生成回答。这是 RAG 应用的核心功能。
首先,从 LlamaIndex 引入所需的类:
RetrieverQueryEngine、KnowledgeGraphRAGRetriever和ResponseSynthesizer。RetrieverQueryEngine是一种查询引擎,它使用检索器从数据源(在此为知识图谱)获取相关上下文,然后基于该上下文综合生成回答。KnowledgeGraphRAGRetriever是专门用于从存储于数据库的知识图谱中检索相关信息的检索器。ResponseSynthesizer负责将检索到的上下文与语言模型结合,生成最终回答。接着,通过传入
graph_store实例的storage_context来创建KnowledgeGraphRAGRetriever实例。该storage_context包含连接与查询我们存储知识图谱的 Neo4j 数据库所需的信息。同时将verbose=True以启用检索过程的详细日志。然后,使用
from_args方法并传入我们的graph_rag_retriever实例来初始化RetrieverQueryEngine。该查询引擎将负责从知识图谱中检索相关上下文并据此生成回答的完整流程。完成这些组件的设置后,我们已准备好查询知识图谱,并利用检索到的上下文生成回答。下一步,我们将看看如何在实践中完成这一过程。
步骤 5:查询知识图谱并生成回答
最后,我们可以查询知识图谱,并利用检索到的上下文生成回答。
在这个示例中,我们定义了三个与文本数据中员工和公司相关的不同查询。对于每个查询,我们使用
query_engine从知识图谱中检索相关上下文,创建一个ResponseSynthesizer实例,并调用其synthesize方法,传入查询与检索到的上下文。ResponseSynthesizer会结合语言模型与检索到的上下文,生成该查询的最终回答,并打印到控制台,结果与本文第一部分中的答案相吻合。现实场景中的知识图谱
尽管本教程用相对简单的文本演示了在 RAG 应用中使用知识图谱,现实世界的场景往往涉及更复杂、多样的数据集。此外,输入数据也可能采用纯文本之外的多种文件格式。本节将探讨如何扩展基于知识图谱的 RAG 应用以处理这类情形。
处理大型与多样化数据集
随着输入数据规模和复杂度的提升,知识图谱抽取过程可能变得更具挑战。以下是一些应对大型与多样化数据集的策略:
处理不同文件类型
在现实场景中,数据可能以多种文件格式存在,如 PDF、Word 文档、电子表格,甚至是 JSON 或 XML 等结构化数据格式。要处理这些不同的文件类型,可采用以下策略:
这些策略将帮助您扩展基于知识图谱的 RAG 应用,以处理更复杂和多样化的数据集,以及更广泛的文件类型。
需要注意的是,随着输入数据复杂度的提高,知识图谱抽取过程可能需要更多面向特定领域的定制与调优,以确保结果准确可靠。
挑战
在现实世界中为 RAG 应用搭建知识图谱是一项复杂的工作,面临多重挑战。我们来看看其中的一些:
知识图谱构建
构建高质量的知识图谱是一个复杂且耗时的过程,需要大量领域专业知识与投入。从各类数据源中抽取实体、关系与事实,并将其整合到一致的知识图谱中颇具挑战,尤其是面对大型且多样的数据集。这需要理解领域、识别相关信息,并以能准确捕捉关系与语义的方式对其进行结构化。
数据集成与互操作性
RAG 应用通常需要集成来自多个异构来源的数据,每个来源都有其自身的结构、格式与语义。要确保数据一致性、解决冲突,并在不同数据源之间映射实体与关系并非易事。需要进行细致的数据清洗、转换与映射,以确保知识图谱准确地表达各来源的信息。
知识图谱维护与演化
知识图谱并非静态。随着新信息出现或现有信息变化,它们需要持续更新与维护。让知识图谱随不断演变的数据源保持最新与一致,可能是一项资源密集型工作。这涉及监测数据源中的变化、识别相关更新,并在保持图谱完整性与一致性的前提下,将更新传播到知识图谱中。
可扩展性与性能
随着知识图谱在规模与复杂度上的增长,如何高效地存储、检索与查询图数据将愈发具有挑战。对于具有高查询量的大型 RAG 应用,可能会出现可扩展性与性能问题。优化知识图谱的存储、索引与查询处理技术,对于维持可接受的性能水平至关重要。
查询复杂度与推理
虽然知识图谱擅长表示复杂关系并支持多跳推理,但要构造并执行充分利用这些能力的复杂查询并不容易。开发高效的查询处理与推理算法仍是一个活跃的研究领域。理解所用知识图谱系统的查询语言与推理能力,对于有效发挥其潜力非常重要。
缺乏标准化
目前在知识图谱的表示与查询上缺少被广泛采用的标准,这可能导致互操作性问题与厂商锁定。不同的知识图谱系统可能采用不同的数据模型、查询语言与 API,从而使得在系统间迁移或与其他系统集成变得困难。采用或制定标准有助于促进互操作性并降低厂商锁定风险。
可解释性与透明性
尽管知识图谱能够提供可解释、透明的推理,但要确保推理过程对终端用户来说易于理解仍具挑战,尤其是当查询或推理路径较为复杂时。开发用户友好的界面与解释,清晰传达推理过程及其基本假设,对于赢得用户信任与促进采用很重要。
领域特定挑战
根据不同领域与应用,可能还存在特定挑战,例如处理领域特定术语、本体或数据格式。以医疗领域为例,复杂的医学术语、编码体系以及隐私问题,都会为知识图谱的搭建与使用增加额外难度。
尽管存在这些挑战,知识图谱在 RAG 应用中仍具有显著优势,尤其是在表示结构化知识、支持复杂推理以及提供可解释与透明结果方面。通过合理的知识图谱设计、数据集成策略与高效的查询处理技术来应对这些挑战,是成功实现基于知识图谱的 RAG 应用的关键。
结论
在本教程中,我们探索了知识图谱的力量,以生成更准确、信息量更大、语境更相关的回答。我们从理解知识图谱的基本概念及其在 RAG 应用中的作用开始,随后通过动手示例,从文本数据抽取知识图谱、存入 Neo4j 数据库,并用它来为用户查询检索相关上下文。最后,我们演示了如何利用检索到的上下文,结合图中的结构化知识来生成回答。
如果您想进一步了解 AI 与大语言模型,请查看这个包含六门课程的技能路径:AI Fundamentals。
希望您觉得本教程有用且有趣,我们下期再见。
编码愉快!