用大模型构建企业级知识图谱真的太简单了!


一开始听到“知识图谱(Knowledge Graph)”这个词,确实有点让人望而生畏——不是概念本身,而是构建它的过程。


我之前尝试过做一个知识图谱,但失败了。


图这种数据结构,确实是表达复杂关系最好的方式之一,广泛应用于推荐系统、欺诈检测等等。但最吸引我兴趣的,其实是信息检索。


于是我开始探索,如何利用知识图谱来构建更强大的RAG系统。


当然,RAG并不一定非得依赖知识图谱,它甚至都不需要数据库。只要你能从海量信息中提取出相关内容,并传递给大语言模型(LLM)的上下文,RAG就可以正常工作。


比如你可以用网页搜索作为RAG的检索手段,也可以用向量数据库来进行语义搜索。

如果你选择用图数据库来检索上下文信息,那我们通常会称之为“GraphRAG”。


不过本文并不是要讲GraphRAG(也许将来会专门写一篇),而是聚焦在:如何利用LLM来构建知识图谱。当然,在这之前我们还是得提一下,为什么知识图谱能让RAG更强大。



为什么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 Auro(一个云托管的图数据库)来存储图数据。


如果你用的是 LlamaIndex,可以看看它提供的 KnowledgeGraphIndex 接口,功能也类似。当然,Neo4j 也不是唯一选择,其他图数据库也可以胜任。


我们先从安装必要的依赖包开始……


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


在这个例子中,我们会将一组商业领袖及其所属组织等信息映射到图数据库中。如果你想跟着一起操作,可以查看我使用的示例数据——这是一个我用AI生成的虚拟数据集。


下面是一个从非结构化文档中生成知识图谱的代码示例,简单得出乎意料:



上面的代码非常直观明了。


其中最关键的部分是构建图数据库的过程。我已经特别标出了这一段。LLMGraphTransformer 类会使用我们传入的 LLM,从文档中抽取出图结构信息。


现在可以将任何 Langchain 的 Document 类型传递给 convert_to_graph_documents 方法,用来提取知识图谱。这个源文件可以是纯文本、Markdown 文件、网页内容,甚至是另一个数据库查询的返回结果。


如果这项工作靠人工来完成,可能得花上几个月的时间——而几年前我们确实是这么做的。


你可以登录 Aura 的图数据库控制台来可视化这个图谱,呈现效果可能会像下面这样:



在这个过程中,底层的 API 实际上是调用了一个 LLM,自动从文本中提取出相关信息,并构建了 Neo4J 所需的 Python 对象(用于表示节点和边)。


现在我们已经知道使用 extractor API 构建知识图谱是件轻松的事,接下来就该讨论,如何让知识图谱真正达到企业级应用的标准




如何让知识图谱达到企业可用的标准?  



曾经,我们放弃构建知识图谱,是因为这件事太复杂了。如今,构建过程的确简单了不少,但我们刚刚生成的这个图谱,离“可用于可靠业务”的程度还有距离。


我发现了几个明显的缺陷,并对其中两个做了改进,这里值得重点讲讲:


1. 提高对图谱提取过程的控制力


如果你跟着例子实际跑了一遍,可能会注意到,自动生成的图谱中,只有 Person 和 Organization 两类节点。本质上,这个提取过程仅识别了人物及其所在的公司。

注意:用 LLM 来提取图谱本质上是一个“概率性”的过程。你的结果未必和我一样。

但实际上,我们是可以从文本中提取出更多信息的。比如某个高管毕业于哪所大学,或者他们过去的工作经历等。


那能不能提前告诉系统我们要提取哪些实体类型和关系呢?幸运的是,LLMGraphTransformer 类是支持这项功能的。


你可以通过如下方式初始化:



在这个版本中,我们明确告诉 transformer 去识别三类实体:人物、公司、大学;并指定它们之间可能存在的关系。这个信息对 LLM 提取实体关系是非常关键的。


此外node_properties=True 这一参数,会让系统尽可能提取节点的各种属性(即使它们没有明确的关联关系)。


通过明确设定实体类型和关系,构建出来的知识图谱通常更完整、更精准。但如果我们希望尽可能“确保”所有重要信息都能被提取出来,还可以配合下面这个方法:


2. 图谱转换前进行“命题化”处理(Propositioning)


文本是一种“有点混乱”的数据形式,而人类写出来的文本往往更混乱。


我们不会总是把所有信息集中说出来,哪怕是在正式的技术文档里,也常常是前后分散表达。比如在这篇文章中,我用过 “Knowledge Graph” 和 “KG” 两种表达方式。

这种“信息散落在多个位置”的现象,会让 LLM 难以正确理解上下文。


而 LLMGraphTransformer 在内部会先对文本进行分块(chunk),然后每个 chunk 独立处理。这样一来,不同 chunk 之间的信息联系就会被打断。


举个例子,假设文章开头提到某人是“CIO”(首席信息官),但这个解释只出现在文本的前一部分。那么在分块之后,后面的 chunk 再次提到“CIO”时,LLM 就可能不清楚这个缩写指的是“信息”还是“投资”或别的含义。


为了解决这个问题,我们可以先进行“命题化”处理(propositioning),让每个 chunk 自包含必要的上下文信息。


具体做法如下:



这个代码用的是 Langchain 的 Prompt Hub 里的一个提示词。从结果可以看出,每一个句子都是独立完整、易于理解的,不再依赖其他上下文信息。


在构建知识图谱前做这样的处理,可以极大降低节点或关系遗漏的风险。



最后的思考  



我曾经尝试构建知识图谱,但失败了。那时候构建图谱的投入远远大于它带来的价值。但这还都是在 LLM 出现之前。


直到我发现 LLM 可以从纯文本中提取出图谱结构,并存入 Neo4J 这样的数据库时,我非常震撼。当然,这项技术目前还不够成熟。


我不认为这些功能已经准备好用于生产环境——除非你愿意加点“修补”。


本文提到的两个方法,是我在实际操作中用来提升知识图谱质量的有效手段。希望它们对你也有帮助。


👀 如果你曾因复杂度而放弃构建知识图谱,是时候重新出发了!


https://medium.com/data-science/enterprise-ready-knowledge-graphs-96028d863e8c


本文数据集:

https://raw.githubusercontent.com/thuwarakeshm/knowledge-graph-example/refs/heads/main/sample.txt






(文:PyTorch研习社)

欢迎分享

发表评论