图谱驱动的大语言模型 Llama Index
如何利用图谱构建更好的 In-context Learning 大语言模型应用。
注:本文是我最初以英文撰写的,然后麻烦 ChatGPT 帮我翻译成了英文,翻译的 prompt 是:
In this thread, you are a Chinese Tech blogger to help translate my blog in markdown from English into Chinese, the blog style is clear, fun yet professional. I will paste chapters in markdown to you and you will send back the translated and polished version.
1 LLM 应用的范式
作为认知智能的一大突破,LLM 已经改变了许多行业,以一种我们没有预料到的方式进行自动化、加速和启用。每天都会看到新的 LLN 应用被创建出来,我们仍然在探索如何利用这种魔力的新方法和用例。
将 LLM 引入流程的最典型模式之一是要求 LLM 根据专有的/特定领域的知识理解事物。目前,我们可以向 LLM 添加两种范式以获取这些知识:微调——fine-tune和上下文学习—— in-context learning。
微调是指对 LLM 模型进行附加训练,以增加额外的知识;而上下文学习是在查询提示中添加一些额外的知识。我们目前观察到,由于其简单性,上下文学习比微调更受欢迎。
在本博客中,我将分享我们在上下文学习方法方面所做的工作。
2 Llama Index:数据与 LLM 之间的接口
2.1 上下文学习
上下文学习的基本思想是使用现有的 LLM(未更新)来处理特定知识数据集的特殊任务。
例如,要构建一个可以回答关于某个人的任何问题,甚至扮演一个人的数字化化身的应用程序,我们可以将上下文学习应用于一本自传书籍和 LLM。在实践中,应用程序将使用用户的问题和从书中"搜索"到的一些信息构建提示,然后查询 LLM 来获取答案。
┌───────┐ ┌─────────────────┐ ┌─────────┐
│ │ │ Docs/Knowledge │ │ │
│ │ └─────────────────┘ │ │
│ User │─────────────────────────────────────▶ LLM │
│ │ │ │
│ │ │ │
└───────┘ └─────────┘
在这种搜索方法中,实现从文档/知识(上述示例中的那本书)中获取与特定任务相关信息的最有效方式之一是利用嵌入(Embedding)。
2.2 嵌入(Embedding)
嵌入通常指的是将现实世界的事物映射到多维空间中的向量的方法。例如,我们可以将图像映射到一个(64 x 64)维度的空间中,如果映射足够好,两个图像之间的距离可以反映它们的相似性。
嵌入的另一个例子是 word2vec 算法,它将每个单词都映射到一个向量中。例如,如果嵌入足够好,我们可以对它们进行加法和减法操作,可能会得到以下结果:
vec(apple) + vec(pie) =~ vec("apple apie")
或者向量测量值 vec(apple) + vec(pie) - vec("apple apie")
趋近于0:
|vec(apple) + vec(pie) - vec("apple apie")| =~ 0
类似地,“pear” 应该比 “dinosaur” 更接近 “apple”:
|vec(apple) - vec(pear)| < |vec(apple) - vec(dinosaur)|
有了这个基础,理论上我们可以搜索与给定问题更相关的书籍片段。基本过程如下:
- 将书籍分割为小片段,为每个片段创建嵌入并存储它们
- 当有一个问题时,计算问题的嵌入
- 通过计算距离找到与书籍片段最相似的前 K 个嵌入
- 使用问题和书籍片段构建提示
- 使用提示查询 LLM
┌────┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │
├────┴────┴────┴────┤
│ Docs/Knowledge │
┌───────┐ │ ... │ ┌─────────┐
│ │ ├────┬────┬────┬────┤ │ │
│ │ │ 95 │ 96 │ │ │ │ │
│ │ └────┴────┴────┴────┘ │ │
│ User │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─▶ LLM │
│ │ │ │
│ │ │ │
└───────┘ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └─────────┘
│ ┌──────────────────────────┐ ▲
└────────┼▶│ Tell me ....., please │├───────┘
└──────────────────────────┘
│ ┌────┐ ┌────┐ │
│ 3 │ │ 96 │
│ └────┘ └────┘ │
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
2.3 Llama Index
Llama Index 是一个开源工具包,它能帮助我们以最佳实践去做 in-context learning:
- 它提供了各种数据加载器,以统一格式序列化文档/知识,例如 PDF、维基百科页面、Notion、Twitter 等等,这样我们可以无需自行处理预处理、将数据分割为片段等操作。
- 它还可以帮助我们创建嵌入(以及其他形式的索引),并以一行代码的方式存储嵌入(在内存中或向量数据库中)。
- 它内置了提示和其他工程实现,因此我们无需从头开始创建和研究,例如,用4行代码在现有数据上创建一个聊天机器人。
3 文档分割和嵌入的问题
嵌入和向量搜索在许多情况下效果良好,但在某些情况下仍存在挑战,其中之一是可能丢失全局上下文/跨节点上下文。
想象一下,当查询"请告诉我关于作者和 foo 的事情",在这本书中,假设编号为 1、3、6、19~25、30~44 和 96~99 的分段都涉及到 foo 这个主题。则在这种情况下,简单地搜索与书籍片段相关的前 k 个嵌入可能效果不尽人意,因为这时候只考虑与之最相关的几个片段(比如 k = 3),从而丢失了许多上下文信息。
┌────┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │
├────┴────┴────┴────┤
│ Docs/Knowledge │
│ ... │
├────┬────┬────┬────┤
│ 95 │ 96 │ │ │
└────┴────┴────┴────┘
而解决、缓解这个问题的方法,在 Llama Index 工具的语境下,就是创建组合索引和综合索引。
其中,向量存储(VectorStore)只是其中的一部分。除此之外,我们可以定义一个摘要索引和/或树形索引等,以将不同类型的问题路由到不同的索引,从而避免在需要全局上下文时丧失它。
然而,借助知识图谱,我们可以采取更有意思的方法:
4 知识图谱
知识图谱这个术语最初由谷歌在2012年5月提出,作为其增强搜索结果和向用户提供更多上下文信息的努力的一部分。知识图谱旨在理解实体之间的关系,并直接提供查询的答案,而不仅仅返回相关网页的列表。
知识图谱是一种以图形格式组织和连接信息的方式,其中节点表示实体,边表示实体之间的关系。图形结构允许高效地存储、检索和分析数据。
它的结构如下图所示:
那么知识图谱到底能怎么帮到我们呢?
5 嵌入和知识图谱的结合
这里的基本思想是,作为信息的精炼格式,知识图谱可以以比我们对原始数据/文档进行的分割更小的粒度进行查询/搜索。因此,通过不替换大块的数据,而是将两者结合起来,我们可以更好地搜索需要全局/跨节点上下文的查询。
请看下面的图示,假设问题是关于 x
的,所有数据片段中有20个与它高度相关。现在,除了获取主要上下文的前3个文档片段(比如编号为 1、2 和 96 的文档片段),我们还从知识图谱中对 x
进行两次跳转查询,那么完整的上下文将包括:
- 问题:“Tell me things about the author and x”
- 来自文档片段编号 1、2 和 96 的原始文档,在 Llama Index 中,它们被称为节点 1、节点 2 和节点 96。
- 包含 “x” 的知识图谱中的 10 个三元组,通过对
x
进行两层深度的图遍历得到:- x -> y(来自节点 1)
- x -> a(来自节点 2)
- x -> m(来自节点 4)
- x <- b-> c(来自节点 95)
- x -> d(来自节点 96)
- n -> x(来自节点 98)
- x <- z <- i(来自节点 1 和节点 3)
- x <- z <- b(来自节点 1 和节点 95)
┌──────────────────┬──────────────────┬──────────────────┬──────────────────┐
│ .─. .─. │ .─. .─. │ .─. │ .─. .─. │
│( x )─────▶ y ) │ ( x )─────▶ a ) │ ( j ) │ ( m )◀────( x ) │
│ `▲' `─' │ `─' `─' │ `─' │ `─' `─' │
│ │ 1 │ 2 │ 3 │ │ 4 │
│ .─. │ │ .▼. │ │
│( z )─────────────┼──────────────────┼──────────▶( i )─┐│ │
│ `◀────┐ │ │ `─' ││ │
├───────┼──────────┴──────────────────┴─────────────────┼┴──────────────────┤
│ │ Docs/Knowledge │ │
│ │ ... │ │
│ │ │ │
├───────┼──────────┬──────────────────┬─────────────────┼┬──────────────────┤
│ .─. └──────. │ .─. │ ││ .─. │
│ ( x ◀─────( b ) │ ( x ) │ └┼▶( n ) │
│ `─' `─' │ `─' │ │ `─' │
│ 95 │ │ │ 96 │ │ │ 98 │
│ .▼. │ .▼. │ │ ▼ │
│ ( c ) │ ( d ) │ │ .─. │
│ `─' │ `─' │ │ ( x ) │
└──────────────────┴──────────────────┴──────────────────┴──`─'─────────────┘
显然,那些(可能很宝贵的)涉及到主题 x
的精炼信息来自于其他节点以及跨节点的信息,都因为我们引入知识图谱的步骤,而能够被包含在 prompt 中,用于进行上下文学习,从而克服了前边提到的问题。
6 Llama Index 中的知识图谱进展
最初,William F.H.将知识图谱的抽象概念引入了 Llama Index,其中知识图谱中的三元组与关键词相关联,并存储在内存中的文档中,随后Logan Markewich还增加了每个三元组的嵌入。
最近的几周中,我一直在与社区合作,致力于将 “GraphStore” 存储上下文引入 Llama Index,从而引入了知识图谱的外部存储。首个实现是使用我自从 2021 年以来一直在开发的开源分布式图数据库 NebulaGraph。
在实现过程中,还引入了遍历图的多个跳数选项以及在前 k 个节点中收集更多关键实体的选项(用于在知识图谱中搜索以获得更多全局上下文),我们仍在对这些变更进行完善。
引入 GraphStore 后,还可以从现有的知识图谱中进行上下文学习,并与其他索引结合使用,这也非常有前景,因为知识图谱被认为具有比其他结构化数据更高的信息密度。
在接下来的几周里,我将在本博客中更新有关 Llama Index 中的知识图谱相关工作的内容,然后在 PR 合并后,分享端到端的演示项目和教程。请继续关注!