目录
LLM私域数据训练问题
LLM在人类和数据之间提供自然语言界面。广泛可用的模型是根据大量公开数据(如维基百科、邮件列表、教科书、源代码等)进行预先训练的。
然而,虽然LLM接受了大量数据的培训,但他们并没有接受您的数据的培训,这些数据可能是私有的或特定于您试图解决的问题。它隐藏在 API 后面、SQL 数据库中,或者隐藏在 PDF 和幻灯片中。
什么是LlamaIndex
LlamaIndex 通过连接到多种数据源并将您的数据添加到 LLM 已有的数据中来解决外部数据训练问题。这通常称为检索增强生成(RAG)。RAG 使您能够使用 LLM 来查询数据、转换数据并生成新的见解。您可以询问有关数据的问题、创建聊天机器人、构建半自治代理等等。
提供的工具
-
数据连接器从其本机源和格式获取现有数据。这些可以是 API、PDF、SQL 等等。
-
数据索引以中间表示形式构建数据,这些中间表示形式对于LLM来说既简单又高效。
-
引擎提供对数据的自然语言访问。例如: - 查询引擎是用于知识增强输出的强大检索接口。聊天引擎是用于与数据进行多消息、“来回”交互的对话界面。
-
数据代理是由 LLM 提供支持的知识工作者,并通过工具进行增强,从简单的辅助函数到 API 集成等等。
-
应用程序集成将 LlamaIndex 重新融入生态系统的其余部分。这可以是 LangChain、Flask、Docker、ChatGPT,或者……其他任何东西!
如何使用
pip install llama-index
PyPi:
LlamaIndex: llama-index · PyPI.
GPT Index (duplicate): gpt-index · PyPI.
NPM (Typescript/Javascript):
- LlamaIndex community:
- Twitter: https://twitter.com/llama_index
- Discord https://discord.gg/dGcwcsnxhU
一些核心术语
-
Document 是任何数据源的通用容器 - 例如,PDF、API 输出或从数据库检索的数据。它们可以手动构建,也可以通过我们的数据加载器自动创建。默认情况下,文档存储文本以及一些其他属性。下面列出了其中一些。
metadata
- 可附加到文本的注释字典。
relationships
- 包含与其他文档/节点的关系的字典。
-
Node:对应于文档中的一大块文本。LlamaIndex接受Document对象,并在内部将它们解析/块化为Node对象。
-
Response Synthesis:你可以认为是一个放置你选择Node的购物车,它会完成合成,然后处理后续的响应。
工作过程
为了便于理解,我们可以将节点视为大约1k个单词的文本块,而响应合成则是通过查看相关节点(文本块)来给出问题答案(响应)的LLM。可以参考《最详细的文本分块(Chunking)方法,直接影响LLM应用效果》。
Llamaindex提供不同类型的索引,以便更好地组织和检索相关信息,并使用Embeddings和LLM高效地运行查询。
LlamaIndex中的索引分类
对于 LlamaIndex 来说,Indexes
是检索增强生成 (RAG) 用例的核心基础。
在高层次上,Indexes
是从Documents构建的。它们用于构建查询引擎和聊天引擎 ,从而可以通过数据进行问答和聊天。
在底层,Indexes
将数据存储在Node
对象中(代表原始文档的块),并公开支持额外配置和自动化的Retriever接口。
迄今为止最常见的索引是VectorStoreIndex
,对于其他索引,请查看我们关于每个索引如何工作的指南,以帮助您决定哪个索引适合您的用例。
LlamaIndex提供了各种不同的索引类型,每种类型都有自己的优缺点。特定任务的最佳索引类型将取决于任务的特定需求。
Summary Index(汇总索引)
Summary Index(以前叫List Index)是一个简单的数据结构,它将文档存储为节点序列。在索引构建期间,文档文本被分块、转换为节点并存储在一个列表中。这使得它成为检索包含特定关键字或短语的文档的非常有效的索引。

在查询的过程中发生了什么?
在查询期间,如果没有指定其他查询参数,LlamaIndex只是将列表中的所有节点加载到响应合成模块中。
当用户输入关键字或短语时,查询列表索引。然后,索引扫描节点列表以查找包含关键字或短语的文档。然后将匹配查询的文档返回给响应合成模块:
使用Summary Index的缺点或问题:
对于大型数据集,Summary Index可能会变得低效,这是因为它需要扫描整个节点列表来查找与查询匹配的文档。
TREE Index(树索引)
Tree Index也是一种索引类型,它将文档的文本存储在树状结构中。树中的每个节点表示其子文档的摘要。我相信看这篇文章的朋友应该多少都接触过树的数据结构,通过遍历树并查找与查询相关的节点,树索引可用于查找与给定查询相关的文档。

在查询过程中发生了什么?
-
查询树索引时,需要提供查询字符串。首先处理查询字符串以识别与查询相关的关键字。
-
然后索引遍历树,从根节点开始(也可以是其他地方开始)。在每个节点上,索引检查查询中的关键字是否出现在节点的摘要中。如果是,则索引下降到节点的子节点。如果不是,则索引移动到下一个节点。
-
这个过程一直持续到索引到达一个叶子节点,或者直到它耗尽树中的所有节点。到达的叶节点是最有可能与查询相关的文档。
-
根据原始文档:查询树索引需要从根节点向下遍历到叶节点。默认情况下,(
child_branch_factor=1
),查询在给定父节点的情况下选择一个子节点。如果child_branch_factor=2
,查询将在每个级别选择两个子节点。
使用树索引的优点:
-
树索引对于查找相关文档非常有效,这是因为树结构允许索引快速地将搜索范围缩小到可能与查询相关的少量文档。
-
树索引也非常可扩展,它们可以用于索引包含数百万甚至数十亿个文档的大型数据集,不管数据量大小,性能相对稳定。
-
树索引相对容易创建,一旦有了文档,就可以通过手动或自动将文档分组到相关的集群中来创建树形结构。
使用树索引的缺点:
-
树索引可能比其他类型的索引(如向量索引)更难创建。这是因为需要手动或自动地将文档分组到相关的集群中。
-
树索引在查找与查询“无关”的文档时效率较低(也就是空转的效率较低)。这是因为索引需要遍历整个树,即使查询只与少量文档相关。
-
树索引可能比其他类型的索引更难理解。这是因为树形结构不是人类可以直接解释的。
总的来说,树索引是索引和查询大型文本数据集的强大工具。它们对于查找相关文档非常有效,可伸缩,并且相对容易创建。但是,它们比其他类型的索引更难创建,并且在空转查询时效率较低
Keyword Table Index(关键词表索引)
关键字表索引是一种将文档的关键字存储在表中的索引,我觉得这更加类似Map<k,v>或者字典的结构。表中的每一行代表一个关键字,每一列代表一个文档。通过在表中查找关键字,可以使用表索引来查找包含给定关键字的文档。

看看查询的过程:
查询关键字表索引时,需要提供关键字。然后索引在表中查找关键字并返回包含该关键字的所有文档。
总的来说,关键字表索引是索引和查询大型文本数据集的强大工具。它们对于查找包含特定关键字、可伸缩且相对容易创建的文档非常有效。但是,它们在查找包含多个关键字的文档时效率较低,在查找包含大量关键字的文档时可伸缩性较差,在查找包含同义词或相关关键字的文档时准确性较差。
Vector Store Index(向量存储索引)
向量索引是一种将文档文本转化为向量的索引,向量通常是由编码器transformer模型(如Bert等)生成的,它们也被称为Embeddings模型(参考大模型应用中大部分人真正需要去关心的核心——Embedding)。向量表示文本的含义,可以根据用户的查询来查找相关文档。
使用LlamaIndex来创建向量Index是非常简单,可以从文档中直接提取文本建立索引,可以看下面这段代码:
from llama_index import Document, VectorStoreIndex
text_list = [text1, text2, ...]
documents = [Document(text=t) for t in text_list]
# build index
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]
# parse nodes
parser = SimpleNodeParser.from_defaults()
nodes = parser.get_nodes_from_documents(documents)
# build index
index = VectorStoreIndex(nodes)
使用向量索引的优点:
-
向量索引对于查找类似文档非常有效。这是因为向量可以直接进行比较,而无需进行任何文本处理。
-
向量索引扩展相对容易,它们可以用于索引包含数百万甚至数十亿个文档的大型数据集。
-
向量索引创建相对容易,拥有Embedding模型(中文常用的包括m3e、bge等)之后,就可以为文档生成向量,并将它们存储在向量索引中。
我们看看向量索引在查询的时候发生了什么:
-
当您查询向量索引时,您提供一个查询字符串。查询字符串首先由相同的Embedding模型处理以生成向量。
-
然后将向量与索引中所有文档的向量进行匹配,具有最相似(可以设置top_k)向量的文档将作为查询的结果返回。
-
我们还可以定义返回top-k最相似的节点,并将它们传递到我们的响应合成模块。
总的来说,向量索引与传统查询的索引相比,更具备语义属性,可以让我们根据语义来检索,而不仅仅是按关键词匹配等字面意思来搜索。而且向量索引使用高效、可扩展能力强,且易于创建。当然了,它也有不好的一方面,就是如果您使用的不是本地embedding模型,而是使用OpenAI的text-embedding-ada-003
、通义千问的embedding模型等,那么是需要成本的,而且量大的话可能很昂贵,即使使用免费的BGE、m3e等本地模型,也是需要一些硬件资源的。对了,说一点开心的,本地的embedding模型的话,我们自己是可以微调训练的,可以参考《手工微调embedding模型》。
KnowledgeGraphIndex(知识图谱索引)
# 根据环境变量设置 OpenAI API 密钥
os.environ["OPENAI_API_KEY"] = "INSERT OPENAI KEY"
# 配置日志记录,设置为 INFO 级别并输出到标准输出流
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
# 知识图谱构建和查询的相关导入
from llama_index import (
SimpleDirectoryReader,
ServiceContext,
KnowledgeGraphIndex,
)
from llama_index.graph_stores import SimpleGraphStore
from llama_index.llms import OpenAI
from IPython.display import Markdown, display
# 读取文件夹中的文本数据作为文档
documents = SimpleDirectoryReader(
"../../../../examples/paul_graham_essay/data"
).load_data()
# 定义一个 LLM,设置为 OpenAI 的 text-davinci-002 模型
llm = OpenAI(temperature=0, model="text-davinci-002")
# 创建服务上下文,设置 LLM 和分块大小
service_context = ServiceContext.from_defaults(llm=llm, chunk_size=512)
# 创建存储上下文,使用简单图形存储
graph_store = SimpleGraphStore()
storage_context = StorageContext.from_defaults(graph_store=graph_store)
# 构建知识图谱索引,将文档转换为三元组,并存储
index = KnowledgeGraphIndex.from_documents(
documents,
max_triplets_per_chunk=2,
storage_context=storage_context,
service_context=service_context,
)
# 将索引转换为查询引擎,设置查询模式和是否包含文本信息
query_engine = index.as_query_engine(
include_text=False, response_mode="tree_summarize"
)
# 执行查询,获取关于 "Interleaf" 的信息
response = query_engine.query(
"Tell me more about Interleaf",
)
## create graph
from pyvis.network import Network
#可视化展示知识图谱
g = index.get_networkx_graph()
net = Network(notebook=True, cdn_resources="in_line", directed=True)
net.from_nx(g)
net.show("example.html")
Llama_index
封装了知识图谱构建和查询功能的库,它允许用户从文本数据中创建知识图谱,并使用自然语言查询这些图谱。这种方式对于处理大量非结构化数据,提取信息并以结构化方式访问这些信息特别有用。
评估RAG的的框架
Ragas 是一个框架,可帮助您评估检索增强生成 (RAG) 管道。RAG 表示一类使用外部数据来增强 LLM 背景的 LLM 申请。现有的工具和框架可以帮助您构建这些管道,但对其进行评估并量化管道性能可能很困难。这就是 Ragas(RAG 评估)发挥作用的地方。
Ragas 为您提供基于最新研究的工具,用于评估 LLM 生成的文本,让您深入了解 RAG 管道。Ragas 可以与您的 CI/CD 集成,以提供持续检查以确保性能。
from ragas import evaluate
from datasets import Dataset
import os
os.environ["OPENAI_API_KEY"] = "your-openai-key"
# prepare your huggingface dataset in the format
# Dataset({
# features: ['question', 'contexts', 'answer', 'ground_truths'],
# num_rows: 25
# })
dataset: Dataset
results = evaluate(dataset)
# {'ragas_score': 0.860, 'context_precision': 0.817,
# 'faithfulness': 0.892, 'answer_relevancy': 0.874}
总结
我们讨论了5种类型的索引,它们如何存储数据,在查询时如何工作,以及每种索引的优缺点。因此,您可以根据自己的要求和约束条件选择最适合的Index。有一些高级类型的索引,如知识图谱索引等,后面再单独讲,需要结合知识图谱本身的一些概念。
引用
LlamaIndex官方文档:Indexing - LlamaIndex 🦙 0.9.21