在本文中,我将分享一个 Python 库——Graph Maker。它可以根据给定的本体从文本语料库创建知识图。 Graph Maker 使用 Llama3、Mistral、Mixtral 或 Gemma 等开源 LLM 来提取 KG。
简要回顾
我们可能应该从“为什么要使用图表”开始。
这是一个很好地总结了知识图谱思想的例子。
要创建 KG,我们需要两条信息。
有了这两条信息,我们就可以根据提及人物和地点的文本构建知识图谱。然而,假设我们的知识库是关于处方药及其相互作用的临床研究。我们可能会使用不同的本体,其中化合物、用法、效果、反应等可以构成我们的本体。
虽然这种方法缺乏生成 KG 的传统方法的严格性,但它有其优点。它可以比传统方法更轻松地使用非结构化数据生成知识图谱。从某种意义上说,它生成的知识图谱也是非结构化的。然而,它们更容易构建并且信息更丰富。它们非常适合 GRAG(图形检索增强生成)之类的应用程序。
为什么选择图表制作工具?
它将帮助我们了解与法学硕士一起创建 KG 的挑战。让我们使用维基百科对指环王书籍的摘要。毕竟,人们不可能不爱指环王!
有意义的实体
如果自由运行,LLM提取的实体在其类别中可能过于多样化。它错误地将抽象概念标记为实体。例如,在文本“Bilbo Baggins庆祝他的生日并将戒指留给Frodo”中,LLM可以提取“Bilbo Baggins庆祝他的生日”或“庆祝他的生日”作为“动作”。但如果将“生日”提取为“事件”,可能会更有用。
解析中的弹性
从本质上讲,LLM 的输出是不确定的。要从大型文档中提取 KG,我们必须将语料分割成较小的文本块,然后为每个文本块生成子图。为了构建一致的图,LLM 必须按照给定的模式为每个子图一致地输出 JSON 对象。哪怕漏掉一个,都可能对整个图的连通性产生不利影响。
尽管 LLM 在响应格式良好的 JSON 对象方面做得越来越好,但仍远非完美。具有有限上下文窗口的 LLM 也可能生成不完整的响应。
实体分类
LLM 在识别实体时可能会出现大量错误。如果上下文是特定领域的,或者实体不是以标准英语命名,问题就会更大。NER 模型在这方面可以做得更好,但它们也受限于所训练的数据。此外,它们也无法理解实体之间的关系。
强制 LLM 与类别保持一致是及时工程中的一门艺术。
图表制作器
我在这里分享的图形制作库改进了之前的方法,在严谨与简便之间游走,在结构与缺乏结构之间游走。
在前一种方法中,LLM 可以自由地自行发现本体,而图制作者则试图强迫 LLM 使用用户定义的本体。
下面是它的工作原理,分为 5 个简单步骤。
1. 定义图的本体
本体库理解以下本体模式。在幕后,本体是一个迂腐的模型。
ontology = Ontology(
# labels of the entities to be extracted. Can be a string or an object, like the following.
labels=[
{"Person": "Person name without any adjectives, Remember a person may be referenced by their name or using a pronoun"},
{"Object": "Do not add the definite article 'the' in the object name"},
{"Event": "Event event involving multiple people. Do not include qualifiers or verbs like gives, leaves, works etc."},
"Place",
"Document",
"Organisation",
"Action",
{"Miscellaneous": "Any important concept can not be categorised with any other given label"},
],
# Relationships that are important for your application.
# These are more like instructions for the LLM to nudge it to focus on specific relationships.
# There is no guarantee that only these relationships will be extracted, but some models do a good job overall at sticking to these relations.
relationships=[
"Relation between any pair of Entities",
],
)
我对提示进行了调整,使其产生的结果与给定的本体一致。我认为它在这方面做得相当不错。不过,它仍然不是 100% 准确的。准确度取决于我们选择生成图的模型、应用、本体和数据质量。
2. 将文本分割成块。
我们可以使用尽可能大的文本语料库来创建大型知识图谱。但是,目前 LLM 的上下文窗口有限。因此,我们需要对文本进行适当的分块,然后一次创建一个图。我们应该使用的块大小取决于模型的上下文窗口。本项目中使用的提示会占用大约 500 个文本块。上下文的其余部分可分为输入文本和输出图形。根据我的经验,200 到 500 个 token 的较小块会生成更详细的图形。
3. 将这些语块转换成文档。
文档是一个具有以下模式的迂腐模型
## Pydantic document model
class Document(BaseModel):
text: str
metadata: dict
在这里,我们添加到文档中的元数据会标记到从文档中提取出来的每个关系中。
我们可以在元数据中添加关系的上下文,例如页码、章节、文章名称等。通常情况下,每个节点对在多个文档中都有多种相互关系。元数据有助于将这些关系上下文化。
4. 运行图表制作工具。
图形生成器直接获取文档列表,并对每个文档进行迭代,为每个文档创建一个子图。最终输出是所有文档的完整图。
下面是一个如何实现这一功能的简单示例。
from graph_maker import GraphMaker, Ontology, GroqClient
## -> Select a groq supported model
model = "mixtral-8x7b-32768"
# model ="llama3–8b-8192"
# model = "llama3–70b-8192"
# model="gemma-7b-it" ## This is probably the fastest of all models, though a tad inaccurate.
## -> Initiate the Groq Client.
llm = GroqClient(model=model, temperature=0.1, top_p=0.5)
graph_maker = GraphMaker(ontology=ontology, llm_client=llm, verbose=False)
## -> Create a graph out of a list of Documents.
graph = graph_maker.from_documents(docs)
## result: a list of Edges.
print("Total number of Edges", len(graph))
## 1503
图形创建器通过 LLM 运行每个文档,并解析响应以创建完整的图形。最终的图形是一个边列表,其中每条边都是一个 pydantic 模型,如下所示。
class Node(BaseModel):
label: str
name: str
class Edge(BaseModel):
node_1: Node
node_2: Node
relationship: str
metadata: dict = {}
order: Union[int, None] = None
我对提示进行了调整,现在它们生成的 JSON 格式相当一致。如果 JSON 响应无法解析,图形创建器还会尝试手动将 JSON 字符串拆分成多个边串,然后尝试挽救任何可能的结果。
5. 保存到 Neo4j
我们可以将模型保存到 Neo4j 中,以便创建 RAG 应用程序、运行网络算法,或者使用 Bloom
from graph_maker import Neo4jGraphModelimport Neo4jGraphModel
create_indices = False
neo4j_graph = Neo4jGraphModel(edges=graph, create_indices=create_indices)
neo4j_graph.save()
图形的每条边都会作为事务保存到数据库中。如果你是第一次运行此代码,请将 `create_indices` 设置为 true。这将通过设置节点的唯一性约束来准备数据库。
5.1 可视化
在上文中,我们使用 networkx 和 pyvis 库将图可视化。在这里,由于我们已经将图保存到 Neo4J 中,因此可以直接利用 Bloom 将图可视化。
为了避免重复,让我们生成不同的可视化效果。
比方说,我们想看看书中人物之间的关系是如何演变的。
我们可以通过跟踪图制作者在遍历这本书的过程中,如何将边逐步添加到图中来实现这一点。为了实现这一点,"边缘 "模型有一个名为 "顺序 "的属性。该属性可用于为图表添加时间或年代维度。
在我们的示例中,图形生成器会自动将文档列表中出现特定文本块的序列号添加到从该文本块提取的每一条边上。因此,要想了解字符之间的关系是如何演变的,我们只需按照边的顺序对图进行横切即可。
下面是这些横截面的动画演示。
图形和 RAG
这种 KG 的最佳应用可能是在 RAG 中。Medium 上有大量文章介绍如何使用图形来增强 RAG 应用程序。
从本质上讲,图形提供了大量不同的知识检索方式。根据我们设计图形和应用程序的方式,其中一些技术可能比简单的语义搜索更强大。
最基本的,我们可以在节点和关系中添加嵌入向量,然后根据向量索引运行语义搜索进行检索。不过,我认为,当我们将赛弗(Cypher)查询和网络算法与语义搜索结合在一起时,RAG 应用程序中的图形才能发挥真正的威力。