RAG 应用之 LlamaIndex——介绍各种索引及优缺点

原文地址 www.luxiangdong.com

80 后,退役码农,非专业产品经理

最近一直和小明在搞 RAG,我们认为这对于大部分公司和个人来说,就是大模型的未来,有应用才能更好推动大模型发展,至少近三年内应该是。前面也输出了一些 RAG 方面的文章,也有了一套精确度相对较高的技术产品。但是你知道的,RAG 领域也在不断发展,而且我们确实也还面临着一些实际的问题,所以最近开始细细研究 LlamaIndex——我觉得适用于 RAG 领域的话,可能会比 LangChain 更优秀。今天我们先来看看 LlamaIndex 的索引。

这是我自己列的一个结构图,当然是按我自己的理解画的,您只做参考吧,哈哈。

LlamaIndex 是一个大型语言模型 (大语言模型) 的数据框架,提供以下工具:

LlamaIndex 是为初学者和高级用户设计的。高级 API 允许初学者使用 LlamaIndex 在 5 行代码中摄取和查询他们的数据。低级 api 允许高级用户自定义和扩展任何模块 (数据连接器、索引、检索器、查询引擎、重新排序模块),以满足他们的需求。

以下是使用 LlamaIndex 的一些好处:

LlamaIndex 中的索引是一种数据结构,它允许您从大量文本语料库中快速搜索和检索数据。它的工作原理是在语料库中的关键字或短语与包含这些关键字或短语的文档之间创建映射。这种映射允许您快速找到包含特定关键字或短语的所有文档,即使语料库非常大。

索引对于各种任务都很有用,例如:

LlamaIndex 提供了各种不同的索引类型,每种类型都有自己的优缺点。特定任务的最佳索引类型将取决于任务的特定需求。

Llamaindex 提供的结构或组织数据的索引类型:

让我们先了解一些术语。根据 Llamaindex 的官方文件:

为了便于理解,我们可以将节点视为大约 1k 个单词的文本块,而响应合成则是通过查看相关节点 (文本块) 来给出问题答案 (响应) 的 LLM。这里大家也可以回看我之前的文章《最详细的文本分块 (Chunking) 方法,直接影响 LLM 应用效果》。

Llamaindex 提供不同类型的索引,以便更好地组织和检索相关信息,并使用 Embeddings 和 LLM 高效地运行查询。我们将逐一查看主要 Index:

List Index :

List Index 是一个简单的数据结构,它将文档存储为节点序列。在索引构建期间,文档文本被分块、转换为节点并存储在一个列表中。这使得它成为检索包含特定关键字或短语的文档的非常有效的索引。

使用列表索引的优点

在查询的过程中发生了什么

在查询期间,如果没有指定其他查询参数,LlamaIndex 只是将列表中的所有节点加载到响应合成模块中。

当用户输入关键字或短语时,查询列表索引。然后,索引扫描节点列表以查找包含关键字或短语的文档。然后将匹配查询的文档返回给响应合成模块:

使用 List Index 的缺点或问题:

向量索引是一种将文档文本转化为向量的索引,向量通常是由编码器 transformer 模型 (如 Bert 等) 生成的,它们也被称为 Embeddings 模型(参考前面关于 embedding 的文章《Embedding——从入门到生产使用》)。向量表示文本的含义,可以根据用户的查询来查找相关文档。

使用 LlamaIndex 来创建向量 Index 是非常简单,可以从文档中直接提取文本建立索引,可以看下面这段代码:

from llama_index import Document, VectorStoreIndex

text_list = [text1, text2, ...]
documents = [Document(text=t) for t in text_list]


index = VectorStoreIndex.from_documents(documents)

或者我们也可以从先生成 Node,才建立索引,我推荐这种方式,因为后面更好管理:

from llama_index import Document, VectorStoreIndex
from llama_index.node_parser import SimpleNodeParser

text_list = [text1, text2, ...]
documents = [Document(text=t) for t in text_list]


parser = SimpleNodeParser.from_defaults()
nodes = parser.get_nodes_from_documents(documents)


index = VectorStoreIndex(nodes)

使用向量索引的优点:

我们看看向量索引在查询的时候发生了什么:

总的来说,向量索引与传统查询的索引相比,更具备语义属性,可以让我们根据语义来检索,而不仅仅是按关键词匹配等字面意思来搜索。而且向量索引使用高效、可扩展能力强,且易于创建。当然了,它也有不好的一方面,就是如果您使用的不是本地 embedding 模型,而是使用 OpenAI 的text-embedding-ada-003、通义千问的 embedding 模型等,那么是需要成本的,而且量大的话可能很昂贵,即使使用免费的 BGE、m3e 等本地模型,也是需要一些硬件资源的。对了,说一点开心的,本地的 embedding 模型的话,我们自己是可以微调训练的,可以参考我之前的文章《手工微调 embedding 模型》。

Tree Index 也是一种索引类型,它将文档的文本存储在树状结构中。树中的每个节点表示其子文档的摘要。我相信看这篇文章的朋友应该多少都接触过树的数据结构,通过遍历树并查找与查询相关的节点,树索引可用于查找与给定查询相关的文档。

为什么用树?我们通过和数组、链表的比较,使用大学知识简单复习一下树的优点:

使用树索引的优点:

在查询过程中发生了什么?

使用树索引的缺点:

总的来说,树索引是索引和查询大型文本数据集的强大工具。它们对于查找相关文档非常有效,可伸缩,并且相对容易创建。但是,它们比其他类型的索引更难创建,并且在空转查询时效率较低。

关键字表索引是一种将文档的关键字存储在表中的索引,我觉得这更加类似 Map<k,v> 或者字典的结构。表中的每一行代表一个关键字,每一列代表一个文档。通过在表中查找关键字,可以使用表索引来查找包含给定关键字的文档。

使用关键字表索引的优点:

看看查询的过程:

使用关键字 Index 的缺点或问题:

总的来说,关键字表索引是索引和查询大型文本数据集的强大工具。它们对于查找包含特定关键字、可伸缩且相对容易创建的文档非常有效。但是,它们在查找包含多个关键字的文档时效率较低,在查找包含大量关键字的文档时可伸缩性较差,在查找包含同义词或相关关键字的文档时准确性较差。

我们讨论了 5 种类型的索引,它们如何存储数据,在查询时如何工作,以及每种索引的优缺点。因此,您可以根据自己的要求和约束条件选择最适合的 Index。有一些高级类型的索引,如知识图谱索引等,后面再单独讲,需要结合知识图谱本身的一些概念。

对 LlamaIndex 的研究是因为它确实很优秀,很多理念也给了我们极大启发。就像小明说的,他想好好学习 LlamaIndex,然后用 Java 也写一个简化版,因为他要拯救广大面对 AI 大浪而处于彷徨中的 Java 程序员,哈哈。

1.Different types of indexes in LlamaIndex to improve your RAG system:https://uttu-parashar.medium.com/different-types-of-indexes-in-llamaindex-to-improve-your-rag-system-fa9c49f40559

2.LlamaIndex 官方文档:https://docs.llamaindex.ai/en/stable/core_modules/data_modules/documents_and_nodes/root.html