几个月之前,基于知识的问答(KBQA)还是一种新奇的事物。现在,对于任何AI爱好者来说,带有检索增强生成(RAG)的KBQA已经变得非常简单。看到随着大型语言模型(LLMs)的出现,自然语言处理(NLP)的可能性空间如此迅速地扩展,真是令人着迷。而且它每天都在变得越来越好,这真是令人惊叹。
在我的上一篇文章中,我分享了一种递归的检索与生成(RAG)方法,用于实现多跳推理的问答功能,以便基于大量文本回答复杂问题。
研究代理:应对复杂问题的挑战我制作了一个自主AI研究代理,它可以进行深层次的多跳推理来回答复杂的问题谢谢大家的反馈,有许多人试用后给出了反馈。我整理了这些反馈,并对代码做了一些调整,以解决原代码中的某些问题。我打算写一篇专门的文章来谈谈这些改动。
本文想分享另一个想法,当与递归的RAG结合时,可能会帮助创建一个超级研究助手。这个想法源于我对使用较小的模型进行递归RAG实验,以及我在这篇文章中读到的几个其他想法——特别是其中一个,即增强生成的知识图谱。
摘要知识图谱(KG)或任何图都由节点和边构成。知识图谱中的每个节点代表一个概念,每条边表示两个节点之间的关系。在这篇文章里,我会分享一种将任何文本集转换成概念图的方法。我会交替使用“概念图”(GC)和“知识图谱”(KG)这两个术语,以便更好地说明我的演示内容。
我在这个项目中使用的所有组件都可以在本地安装和配置,因此这个项目可以轻松地在个人电脑上运行。我选择不使用GPT的方法,因为我相信小型开源模型的力量。我使用了出色的Mistral 7B OpenOrca Instruct和Zephyr模型。这些模型可以通过Ollama在本地进行安装和配置。
像 Neo4j 这样的数据库让存储和检索图数据变得简单。我使用了内存中的 Pandas 数据框和 NetworkX Python 库,为了简化操作。
我们的目标是将任何文本语料库转换为概念图(GC),并像本文的精美横幅图像那样对其进行可视化。我们甚至可以与网络图进行互动,移动节点和边,放大、缩小,并根据我们的喜好调整图形的物理特性。这是展示我们正在构建的结果的GitHub页面链接。
访问链接:https://rahulnyk.github.io/knowledge_graph/。
但是首先,让我们先来看看知识图的基本概念以及我们为什么需要它们。如果你已经了解这个概念,可以直接跳过下面的部分。
知识图请看下面这段文字。
玛丽有一只小羊,/ 你或许已经听过这个故事;/ 然而她又多吃了一些,/ 因为她把盘子递给了别人。
希望孩子们没看到这条 😝,他们要是看到了就尴尬了。
这里展示了一种可能的知识图谱表示方法。
这张图是用draw.io绘制的
以下来自IBM的文章很好地解释了知识图的基本概念。
什么是知识图谱?| IBM了解什么是知识图谱,这是一种语义元数据网络图,用于表示一组相关的实体及其之间的关系。引用文章中的一个段落来概括这个观点:
为什么知识图谱?知识图谱,又称语义网,表示现实世界中的实体——如对象、事件、情境或概念——之间的关系网络,并展示了它们之间的关系。这些信息通常存储在图数据库中并以图形结构进行可视化,因此得名“知识图谱”。
知识图谱在多种场景下都非常有用。我们可以计算任何节点的中心性,了解每个概念的重要性。我们可以分析关联或不关联的概念集,并找出概念社区,从而更好地理解主题。我们还能发现看似不相关的概念之间的联系。
我们还可以使用知识图谱来实现图检索增强生成(GRAG 或 GAG)技术,并与我们的文档进行对话。这会比原始的 RAG 技术提供更佳的结果,而原始版本的 RAG 存在一些缺点。例如,用简单的语义相似度检索来获取最相关的信息并不总是有效。特别是当查询未能提供足够的信息来明确其真正意图时,或者当相关上下文分散在大量文本中时。
例如,看看这个查询
能告诉我这本书中何塞·阿卡迪奥·布恩迪亚的家谱吗?
这本书记录了7代的_何塞·阿卡迪奥·布恩迪亚_家族,其中一半的角色都叫_何塞·阿卡迪奥·布恩迪亚_这个名字。用简单的RAG管道来回答这个问题可能很困难,甚至可能根本无法做到。
RAG的另一个不足是,它不会告诉你该问什么。问对问题很多时候比得到正确的答案更重要。
图增强生成(GAG)技术能部分弥补RAG的这些不足。此外,我们可以通过灵活组合,构建一个图增强检索增强生成流水线,以实现两者优势的最大化。
所以现在我们知道这些图表很有趣,它们不仅非常有用,还很美观。
创建概念地图如果你问GPT怎么做,如何从给定文本中构建一个知识地图?它可能会给出如下这样的步骤。
- 从文本内容中提取概念和实体。这些是节点。
- 提取概念之间的关系。这些是边。
- 在图数据结构或图数据库中填充节点(概念)和边(关系)。
- 可视化,至少是为了某种艺术上的享受。
步骤3和4听起来没问题,但你又是怎么做到步骤1和2的呢?
这里是一个流程图展示,展示了我设计的一种方法,用于从任意文本语料库中提取概念。这个方法与前面提到的方法大致相同,但有一些细微的差别。
使用 draw.io 画的图表,由某某创建
- 将文本语料库分成若干块。给每个块分配一个chunk_id。
- 对于每个文本块,使用大模型提取概念及其关联。给这种关联赋予权重W1。同一对概念之间可能存在多种关联。每种关联都表示概念对之间的一条边。
- 考虑到出现在同一块中的概念因为它们在上下文中接近也相互关联。给这种关联赋予权重W2。需要注意的是,同一对概念可能出现在多个块中。
- 将相似的对进行汇总,将它们的权重相加,并将它们的关联合并。现在我们只能找到一个连接不同概念的边。这条边具有一个权重值,以及一个由这些关联组成的名称列表。
你可以在我的GitHub仓库中查看此方法的Python代码实现,我在这篇文章中分享的GitHub仓库里。接下来的几个部分会简要介绍实现的关键点。
为了在此示例中演示该方法,我引用了发表在PubMed/Cureus上的一篇综述文章。该文章根据知识共享署名许可协议进行分发。在本文结尾,感谢所有作者。
印度应对医疗人力资源挑战的机会印度的健康指标虽然最近有所改善,但仍不及同侪国家。……详情请见 www.cureus.com Mistral 和提示第一步非常简单,如上图所示。Langchain提供了很多文本分割工具,我们可以使用这些工具将文本分成小段。
从第2步开始,真正的乐趣才真正开始。为了提取概念及其关系,我用的是Mistral 7B模型。在找到最适合我们需求的模型变体之前,我尝试了以下几种。
Mistral Instruct
Mistral OpenOrca,以及
Zephyr (Hugging Face版本的Mistral衍生模型)
我用的是这些模型的4位量化(即4-bit)版本——这样我的Mac就不会开始对我发脾气了——并通过Ollama在本地托管。
在本地运行大型语言模型,上手Ollama这些模型都是针对指令进行了调优的模型,都包含系统提示和用户提示。它们都能很好地遵循指令,并当需要时将答案格式化为整洁的JSON格式。
经过几轮摸索和尝试后,我最终选择了Zephyr模型并使用了以下提示。
SYS_PROMPT = (
"你是一个网络图制作者,从给定的上下文中提取术语及其关系。你将获得一个上下文段(用```分隔)。你的任务是从给定的上下文中提取术语的本体。这些术语应代表该上下文中提到的关键概念。\n"
"思考1:在遍历每个句子时,考虑其中提到的关键术语。\n"
"\t术语可能包括物体、实体、地点、组织、人物、\n"
"\t状况、缩写、文件、服务、概念等。\n"
"\t术语应尽可能具体和单一\n\n"
"思考2:考虑这些术语之间可能存在一对一的关系。\n"
"\t出现在同一句子或同一段落中的术语通常彼此相关。\n"
"\t一个术语可以与多个其他术语相关。\n\n"
"思考3:找出每一对相关术语之间的具体关系。\n\n"
"以JSON列表格式输出结果。列表中的每个元素包含一对术语及其关系,如下所示:\n"
"[\n"
" {\n"
' "node_1": "从提取的本体中获得的一个概念",\n'
' "node_2": "从提取的本体中获得的一个相关概念",\n'
' "edge": "两个概念之间的关系,用一两句话描述node_1和node_2之间的联系"\n'
" }, {...}\n"
"]"
)
USER_PROMPT = f"上下文:```{input}```\n输出:"
如果这个提示不符合我们儿歌的标准,结果会怎样,如下所示。
[
{
"node_1": "玛丽",
"node_2": "绵羊",
"edge": "属于"
},
{
"node_1": "盘子",
"node_2": "食物",
"edge": "装着"
}, . . .
]
它甚至猜到了“食物”这一概念,而文本中并没有明确提到。这不是很厉害吗?
如果我们对示例文章中的每个文本块进行处理,并将 json 转换为 Pandas 数据帧,结果将会是这样。
每一行在这里表示一对概念之间的关系。每一行代表图中两个节点之间的一条边,同一对概念之间可以有多条边,表示多种关系。上面数据框中的数字4是我任意设定的权重值。
语境相似性我认为在文本语料库中彼此靠近的概念可能有某种关联。我们可以把这种关系叫做“上下文相近性”。
为了计算上下文邻近性边,我们需要将数据框融化,使得 node_1 和 node_2 合并成一列。然后,我们使用 chunk_id 作为键将该数据框自连接。这样,具有相同 chunk_id 的节点会相互配对,形成新的行。
但这同时也表示每个概念都会与其自身配对。这叫作自环,即一条边的起点和终点是同一个节点的结构。为了移除这些自环,我们将从数据框中删除所有node_1和node_2相同的行。
最后,我们得到一个与原来非常相似的 dataframe。
这里的计数列表示节点_1和节点_2共同出现的块(chunk)的数量。列, chunk_id, 则列出了所有这些块(chunk)。
所以我们现在有两个数据框,一个包含语义关系,另一个包含文本中提到的概念的上下文接近性。我们可以通过合并它们来形成我们的网络图表。
我们已经完成了文本的概念图构建。但如果仅止于此,会是一个相当令人失望的过程。我们的目标是像文章开头那样,把这个图可视化出来,我们离目标已经很近了。
建立概念网NetworkX 是一个 Python 库,让你处理网络图超级简单。如果你还不了解这个库,点击下面的图标了解更多。
NetworkX - 网络X文档 NetworkX 是一个用于创建、操作和研究网络的结构、动态和功能的 Python 包……networkx.org把我们的DataFrame加到NetworkX图谱里,只需要几行代码。
G = nx.Graph()
## 向图中添加节点
for node in nodes:
G.add_node(str(node))
## 向图中添加边
for index, row in dfg.iterrows():
G.add_edge(
str(row["node_1"]),
str(row["node_2"]),
title=row["edge"],
weight=row['count']
)
这里就是我们开始利用网络图力量的地方。NetworkX 提供了大量的网络算法,我们可以直接使用。这里有一个链接,链接到我们可以对图运行的算法列表。
算法 - NetworkX 3.2.1 文档在这里,我使用了一种社区检测算法给节点上色。社区是由那些彼此之间连接更紧密的节点组成的群体,比它们与图中其他部分的连接更紧密。概念的社区可以让我们更好地理解文本中讨论的主要话题。
例如,吉文-纽曼算法在我们正在处理的综述文章中发现了17个概念社群。这里有一个这样的社群。
[
'数字技术',
'EVIN',
'医疗器材',
'在线培训管理系统',
'可穿戴追踪技术'
]
这立即让我们对综述论文中讨论的健康技术有了一个大致的概念,并使我们能够提出一些问题,然后用我们的RAG Pipeline来回答。这不是很酷吗?
我们也可以计算图中每个概念的度。节点的度是指它连接的边的数量。所以,在我们的情况下,概念的度越高,它在我们文本主题中的位置就越重要。我们将使用度作为可视化中节点大小的依据。
图可视化可视化是这项练习里最有趣的部分。它有一种特别的感觉,能给你带来一种艺术享受。
我在使用Pyvis库来创建交互式图表。Pyvis是一个用于网络可视化的Python库。这里有一个链接,介绍了一篇文章,展示了这个库的易用性和强大功能及表现力。
仅需几行代码即可用Python可视化交互式网络图 Pyvis——大数据科技
Pyvis 自带一个将 NetworkX 图转换为 PyVis 的工具。所以我们再也不用写代码了……太棒了!!
记得,我们已经计算了每条边的权重以确定边的厚度,节点的社区以确定它们的颜色,以及节点的度以确定它们的大小。
所以,有了这么多花里胡哨的东西,这就是我们的图表。
作者生成的 GIF,使用了本文中讨论的项目。
点击这里查看互动图。
我们可以随意缩放和移动节点和连线。页面底部还有一个滑块,可以用来调整图的物理特性。看看这个图是如何帮助我们提出恰当的问题并更好地理解主题的!
我们可以进一步讨论图如何助力我们构建图增强检索技术,以及这如何帮助我们构建更好的RAG系统。不过我们已经完成了本文的目标!留待下次再说。
Github 仓库页面 GitHub - rahulnyk/knowledge_graph: 将任何文本转化为知识图谱。这可以用于图增强生成或知识图谱问答。……github.com欢迎贡献和建议,多多益善。
我用过下面这篇文章来展示我的代码。
Saxena S G, Godfrey T (2023年6月11日发布) 印度应对医疗人力资源挑战的机会。Cureus 15(6): e40274 DOI 10.7759/cureus.40274
感谢各位作者所做的精彩工作,并将它在知识共享署名许可下发布。
关于我这点
我是一名学习建筑技术(这里的建筑是指技术而非实物建筑)的学生或爱好者。过去,我从事过半导体模型制作、数字电路设计与开发、电子接口设计和建模以及物联网技术方面的工作。目前,我在沃尔玛健康与保健部门从事数据互操作性和健康数据仓库架构设计的工作。