LLM 快速构建实用知识图谱指南

快速构建知识图谱不再是难题!本文教你如何利用LLM,结合Langchain和Neo4J,轻松提取信息并构建实用知识图谱。

原文标题:几分钟掌握!用 LLM 快速构建实用知识图谱

原文作者:图灵编辑部

冷月清谈:

本文介绍了如何利用大语言模型 (LLM) 快速构建知识图谱,并探讨了其在检索增强生成 (RAG) 中的应用。文章首先解释了知识图谱相较于向量存储在信息检索方面的优势,尤其是在处理复杂查询和跨数据源推理方面的能力。然后,文章以 Langchain 的 LLMGraphTransformer 和 Neo4J Aura 图数据库为例,演示了如何用几行代码将非结构化文本数据转换为知识图谱。最后,文章讨论了如何通过控制图谱提取过程和预处理文本数据来优化知识图谱的构建,使其更适用于企业级应用场景,例如指定实体类型和关系、处理文本中信息不一致等问题。

怜星夜思:

1、除了 Neo4J,还有哪些图数据库适合与 Langchain 结合使用,它们各自的优缺点是什么?
2、文中提到的预处理方法对于提高知识图谱的质量至关重要,除了预处理,还有哪些方法可以提升 LLM 提取信息的准确性?
3、文章中提到的 GraphRAG,除了知识图谱,还有什么其他方式可以优化 RAG 的检索策略?

原文内容

我曾经尝试过构建知识图谱,结果以失败告终——那时候还没有 LLM 这样的工具!

照片由 Unsplash 上的 detait 拍摄

最初听到“知识图谱”这个词,感觉有点吓人——倒不是因为它的原理复杂,而是构建过程看起来非常繁琐。

我以前试过自己动手构建知识图谱,结果失败了。

图是表达复杂关系的最佳方式之一,被广泛应用在推荐系统、欺诈检测等领域。但让我最感兴趣的是它在信息检索上的应用潜力。

后来,我开始尝试利用知识图谱来改进 RAG(检索增强生成,Retrieval-Augmented Generation)。

事实上,构建 RAG 不一定非得用知识图谱,甚至不需要数据库。只要能从大量信息中提取出相关内容,传递给 LLM,就可以实现 RAG 的功能。

比如,你可以通过网页搜索作为信息检索策略,也可以用向量数据库的语义搜索功能来提升效果。

如果你用图数据库来检索信息,那么这种方式被称为 GraphRAG,它是知识图谱在 RAG 中的具体应用。

这篇文章并不是专门介绍 GraphRAG 的,而是讨论如何用 LLM 构建知识图谱。但既然提到,还是有必要简单说说为什么知识图谱可以作为内容存储,帮助改进 RAG(Retrieval-Augmented Generation)。

为什么 RAG 需要知识图谱?

知识图谱提供了更智能的信息检索方式,而单靠向量存储有时无法满足所有需求。

从向量存储中获取信息的主要方法是通过编码文本的语义相似度。具体流程是这样的:

我们使用一个向量嵌入模型,例如 OpenAI 的 text-embedding-3,将文本转换为向量表示。即使 “Apple” 和 “Appam”(一种印度食物)在字母上有很多相同之处,它们的向量表示仍然大不相同。这些向量随后会被存储在像 Chroma 这样的向量数据库中。

在检索阶段,我们使用同样的嵌入模型对用户输入进行编码,然后通过计算距离矩阵(比如余弦相似度)从向量存储中检索信息。

这种方法是我们从向量存储中检索信息的唯一方式。如你所猜测,嵌入模型的选择在检索准确性中起着关键作用。而数据库的类型通常对准确性影响不大,但可能会涉及并发、速度等其他问题。

举个例子:

假设你有一份关于各大公司领导团队的大型文档。

如果问题是“John Doe 先生是哪个公司 CEO?”这种简单的事实性问题,向量嵌入系统可以轻松处理,因为答案通常可以直接从嵌入的文档片段中找到。

但如果问题变成“John Doe 先生和哪些人在多个董事会里一起担任董事?”这种更复杂的问题,就会比较难处理。

向量相似性检索依赖于知识库中的明确提及,只有明确提到的信息才会被检索出来。而知识图谱则能通过整体数据来推理出更多信息。

例如,最近邻搜索就需要依赖知识库中的直接提及。如果缺少这种直接总结,基于向量嵌入的系统就难以跨越多个数据源进行推理或整合信息。

相比之下,知识图谱可以在整个数据集的层面进行推理。例如,它能把“国家节点”和“战略节点”按关系靠近分组,运行一个简单的查询就能得到我们需要的信息。

现在我们理解了知识图谱的重要性,接下来让我们来看看构建一个知识图谱时会面临哪些挑战。

构建知识图谱曾经是个难题(但现在不再是了)

几年前,一位同事向我介绍了知识图谱的概念。他希望为我们所有的项目创建一个统一、可搜索的知识图谱。

在花了一个周末学习 Neo4J 后,我觉得这个工具有很大的潜力。

但当时的难点在于如何从大量的 PDF、PPT 和 Word 文档中提取节点和边(即实体和关系)。

我们尝试过一些方法,但效果不理想。我们只能手动将这些非结构化的文档转化为图数据模型。

我们曾经试图用 PyPDF2 来读取 PDF 文件并进行关键字搜索,但并没有取得很好的效果。最终,我们只能放弃这个方法,认为它“不值得花时间”。

但随着 LLM(大语言模型)的广泛应用,情况发生了变化。

在接下来的部分,我们将借助 LLM 来构建一个简单的(或许是最简单的)知识图谱。

几分钟内构建知识图谱

现在,从文本和图像中提取信息不再像过去那么困难了。

虽然处理非结构化数据还可以进一步改进,但过去几年,尤其是大语言模型(LLM)的发展,给我们带来了很多新机会。

在这一部分,我们将介绍如何使用 LLM 来构建一个简单的知识图谱,并讨论如何进一步优化,让它可以应用于企业级场景。

我们将使用 Langchain 的实验功能 LLMGraphTransformer,同时采用 Neo4J Aura 作为图数据库的云端存储解决方案。

如果你使用的是 LlamaIndex,可以尝试它的 KnowledgeGraphIndex,这是一个与我们使用的工具类似的 API。当然,你也可以选择其他图数据库,像 Neo4J 一样使用。

接下来,我们先来安装必要的依赖包。

pip install neo4j langchain-openai langchain-community langchain-experimental

在这个例子中,我们将把一份包含高管和他们所属组织等信息的列表映射到图数据库。如果你想跟着一起操作,可以在这里找到我使用的示例数据。这个数据是我自己创建的虚拟数据(当然,使用了 AI 技术)。

接下来是将非结构化文档转化为知识图谱的简单代码,实际上,这段代码非常简洁:

import os

from langchain_neo4j import Neo4jGraph
from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import TextLoader
from langchain_experimental.graph_transformers import LLMGraphTransformer

graph = Neo4jGraph(
    url=os.getenv("NEO4J_URL"),
    username=os.getenv("NEO4J_USERNAME""neo4j"),
    password=os.getenv("NEO4J_PASSWORD"),
)

# ------------------- Important --------------------
llm_transformer = LLMGraphTransformer(
    llm= ChatOpenAI(temperature=0, model_name="gpt-4-turbo")
)
# ------------------- Important --------------------

document = TextLoader("data/sample.txt").load()

graph_documents = llm_transformer.convert_to_graph_documents(document)

graph.add_graph_documents(graph_documents)

这段代码非常简单明了。

我特别强调了最关键的部分:如何构建图数据库。LLMGraphTransformer 类使用我们传入的 LLM,从文档中提取图谱数据。

你现在可以将任何类型的 Langchain 文档传入 convert_to_graph_documents 方法来提取知识图谱。数据源可以是文本、Markdown 文件、网页内容,甚至是从其他数据库查询的结果。

如果是手动操作,这项任务几年前可能需要几个月时间才能完成。

你还可以访问 Aura db 控制台来查看生成的图谱,它看起来可能是这样的:

Neo4J Aura 云端通过 LLMGraphTransformer 模块生成的图谱 — 作者截图

在后台,API 使用 LLM 来提取相关信息,并构建 Neo4J 的 Python 对象来表示节点和边。

正如我们所看到的,使用提取器 API 构建知识图谱已经变得非常简单。接下来,我们讨论一下如何将其优化,做到企业级应用。

如何让知识图谱适应企业级需求

曾经我们放弃了构建知识图谱的想法,因为它太复杂了。如今,借助 LLM 的帮助,我们能够更快速、低成本地构建知识图谱。然而,刚刚创建的这个图谱并不适合用于稳定的实际应用。

虽然构建知识图谱的效率得到了极大提升,但初步生成的图谱通常还不足以满足企业级应用的需求。以下是两个关键问题及其解决方案:

1. 更好地控制图谱提取过程

如果你按照这个示例操作,你会注意到生成的图谱只包含“人物”和“组织”类型的节点。实际上,提取的内容仅限于这些人物及其所担任的公司董事职位。

注意:使用 LLM 提取图谱是一种概率性技术,结果可能与你的不同。

不过,我们可以从文本文件中提取更多信息。例如,我们可以查明每位高管曾就读的大学以及他们的工作经历。

那么,我们能否指定需要提取的实体类型和它们之间的关系呢?幸运的是,LLMGraphTransformer 类支持这一功能。

以下是另一种启动实例的方式:

llm_transformer = LLMGraphTransformer(
    llm=llm,
    allowed_nodes=["Person""Company""University"],
    allowed_relationships=[
        ("Person""CEO_OF""Company"),
        ("Person""CFO_OF""Company"),
        ("Person""CTO_OF""Company"),
        ("Person""STUDIED_AT""University"),
    ],
    node_properties=True,
)

在上面的版本中,我们明确告诉 Transformer 要查找“人物”、“公司”和“大学”类型的实体,并指定它们之间可能的关系。这是帮助 LLM 提取信息的关键步骤。

另外,第三个参数 node_properties 让 Transformer 可以获取那些没有关系的实体的所有属性。

通过明确指定节点和关系来构建的知识图谱通常更完整、准确。不过,为了确保提取的关键信息更精准,接下来的一些方法可能会有所帮助。

2. 在图谱转换前进行预处理(Propositioning)

文本本身就是一种复杂的数据形式,而编写这些文本的人思维方式更为复杂。

有时候,我们并不会把所有的内容直接表达出来。即使是正式或技术性的写作,也常常会在不同地方提到相同的概念。比如,在这篇文章中,我多次使用了“Knowledge Graph”和“KG”这两个词。

这种方式让 LLM 很难准确理解上下文。

实际上,Graph Transformer 在后台会将文本分割成多个小块,并在每一块内独立处理。因此,文本中的其他部分信息无法在分块后关联到当前的块。

例如,文章开头提到某人的职位是“首席投资官(CIO)”,但在分割文本时,这个定义可能会在后续块中丢失。此时,LLM 无法理解“CIO”中的“I”究竟是指投资、信息还是其他。

为了解决这个问题,我们使用了预处理。在对文本进行分块或处理之前,我们先进行预处理,确保每一块都能被正确理解。

下面是实现这一目标的方法。

obj = hub.pull("wfh/proposal-indexing")

# You can explore the prompt template behind this by running the following:
# obj.get_prompts()[0].messages[0].prompt.template

llm = ChatOpenAI(model="gpt-4o")

# A Pydantic model to extract sentences from the passage
class Sentences(BaseModel):
    sentences: List[str]

extraction_llm = llm.with_structured_output(Sentences)

# Create the sentence extraction chain
extraction_chain = obj | extraction_llm

# Test it out
sentences = extraction_chain.invoke(
    """
    On July 20, 1969, astronaut Neil Armstrong walked on the moon . 
    He was leading the NASA's Apollo 11 mission. 
    Armstrong famously said, "
That's one small step for man, one giant leap for mankind" as he stepped onto the lunar surface.
    """
)

>>['
On July 20, 1969, astronaut Neil Armstrong walked on the moon.',
 "Neil Armstrong was leading NASA'
s Apollo 11 mission.",
 'Neil Armstrong famously said, "
That\'s one small step for man, one giant leap for mankind" as he stepped onto the lunar surface.']
)

>>['On July 20, 1969, astronaut Neil Armstrong walked on the moon.',
 "Neil Armstrong was leading NASA's Apollo 11 mission.",
 'Neil Armstrong famously said, "That\'s one small step for man, one giant leap for mankind" as he stepped onto the lunar surface.']

这段代码使用了 Langchain 提供的提示(prompt)模板。从结果来看,每个文本块都是自我解释的,即使不参考其他文本块,LLM 也能独立理解。

在创建知识图谱之前先进行这种预处理,能够帮助 LLM 避免因失去参考信息而丢失节点或关系。

最后的思考

我曾经尝试过构建知识图谱,但没有成功。对企业或团队而言,构建知识图谱的好处远远不值付出的巨大努力。不过,那时 LLM 还没有出现。

当我得知 LLM 可以从纯文本中提取图谱信息,并将其存储到像 Neo4J 这样的数据库时,我非常震惊。但这些实验性的功能仍然不够完善。

我认为它们目前还不适合直接用于生产环境,至少需要进行一些调整和优化。

在这篇文章中,我介绍了两种帮助我提升知识图谱构建质量的技术。希望对你也有所帮助!

学习技术不孤单,扫一扫入群,一起进步~

提升 LLM 提取信息的准确性,除了预处理,还可以尝试以下几种方法:1. 使用更强大的 LLM 模型,例如 GPT-4;2. 提供更清晰的提示词,明确告诉 LLM 想要提取什么信息;3. 对 LLM 的输出进行后处理,例如实体消歧、关系规范化等;4. 使用多模型融合的方法,结合不同 LLM 的输出结果。

优化 RAG 检索策略,还可以考虑使用一些高级的搜索技术,例如基于 Transformer 的模型、语义搜索、模糊匹配等等。还可以根据具体的应用场景,对检索结果进行排序和过滤,例如根据时间、相关性、权威性等指标进行排序。

我个人比较推荐 NebulaGraph,它是一款开源的分布式图数据库,性能很强,而且支持多种查询语言。跟 Langchain 集成也很方便,有一些现成的工具和教程可以参考。不过运维成本会比 Neo4J 高一些,需要一定的技术储备。

对于“除了知识图谱,还有什么其他方式可以优化 RAG 的检索策略?”这个问题,我觉得可以考虑结合向量数据库和关键词搜索,形成一种混合检索策略。先用关键词搜索快速筛选出候选文档,再用向量数据库进行语义匹配,提高检索的准确性和效率。

除了 Neo4J,还有很多图数据库可以与 Langchain 结合使用,比如 Amazon Neptune、JanusGraph、ArangoDB 等等。Neo4J 的优点是社区活跃,文档丰富,成熟度高;缺点是商业版价格较高。JanusGraph 支持分布式部署,扩展性好,但学习曲线较陡峭。ArangoDB 是一个多模型数据库,支持图数据库、文档数据库和键值数据库,比较灵活,但性能可能不如专门的图数据库。

针对“除了知识图谱,还有什么其他方式可以优化 RAG 的检索策略?”这个问题,还可以考虑引入用户反馈机制,根据用户的点击、评价等信息,不断优化检索模型和策略,提高检索的个性化和用户满意度。不妨试试强化学习。

我觉得 fine-tuning LLM 也是一个不错的选择,可以用特定领域的数据对 LLM 进行微调,提高它在该领域的提取能力。不过需要一定的数据量和计算资源。

选图数据库要看具体场景吧。如果数据量不大,对性能要求不高,Neo4J 社区版就足够用了,上手也比较简单。如果数据量很大,需要高并发和高可用性,可以考虑分布式的图数据库,比如 JanusGraph 或者 NebulaGraph。另外,还要考虑与现有系统的兼容性,以及团队的技术栈等等。