跳转到内容

加载数据(数据摄取)

在您选择的LLM能够处理您的数据之前,您首先需要对数据进行处理和加载。这与机器学习领域中的数据清洗/特征工程流程,或传统数据环境中的ETL流程有相似之处。

该数据摄取管道通常包含三个主要阶段:

  1. 加载数据
  2. 转换数据
  3. 索引并存储数据

我们将在后续章节中介绍索引/存储相关内容。本指南主要讨论加载器和转换操作。

在您选择的LLM能够处理您的数据之前,您需要先加载数据。LlamaIndex实现这一点的方式是通过数据连接器,也称为Reader。数据连接器从不同的数据源摄取数据,并将数据格式化为Document对象。一个Document是数据(目前是文本,未来将包括图像和音频)以及关于该数据的元数据的集合。

最容易使用的阅读器是我们的SimpleDirectoryReader,它能够将给定目录中的每个文件转换为文档。该阅读器内置于LlamaIndex中,能够读取多种格式,包括Markdown、PDF、Word文档、PowerPoint演示文稿、图像、音频和视频。

from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader("./data").load_data()

使用来自LlamaHub的读取器

Section titled “Using Readers from LlamaHub”

由于存在众多可能的数据来源,它们并未全部内置。相反,您可以从我们的数据连接器注册表LlamaHub中下载它们。

在这个示例中,LlamaIndex下载并安装名为DatabaseReader的连接器,该连接器对SQL数据库执行查询,并将结果的每一行作为Document返回:

from llama_index.core import download_loader
from llama_index.readers.database import DatabaseReader
reader = DatabaseReader(
scheme=os.getenv("DB_SCHEME"),
host=os.getenv("DB_HOST"),
port=os.getenv("DB_PORT"),
user=os.getenv("DB_USER"),
password=os.getenv("DB_PASS"),
dbname=os.getenv("DB_NAME"),
)
query = "SELECT * FROM users"
documents = reader.load_data(query=query)

LlamaHub 上有数百个连接器可供使用!

除了使用加载器,你也可以直接使用文档。

from llama_index.core import Document
doc = Document(text="text")

数据加载完成后,在将其存入存储系统之前,您需要对数据进行处理和转换。这些转换包括分块、提取元数据以及对每个数据块进行嵌入处理。这对于确保数据能够被检索并被大型语言模型优化使用至关重要。

转换输入/输出是 Node 对象(DocumentNode 的子类)。转换也可以堆叠和重新排序。

我们提供了高级和低级两种API用于文档转换。

索引具有一个 .from_documents() 方法,该方法接受一个文档对象数组,并能正确解析和分块处理它们。然而,有时您可能希望对文档的分割方式拥有更大的控制权。

from llama_index.core import VectorStoreIndex
vector_index = VectorStoreIndex.from_documents(documents)
vector_index.as_query_engine()

在底层实现中,这会将您的文档拆分为节点对象,这些对象类似于文档(包含文本和元数据),但与它们的父文档存在关联关系。

如果你想自定义核心组件,比如文本分割器,通过这个抽象层你可以传入一个自定义的 transformations 列表或应用到全局的 Settings

from llama_index.core.node_parser import SentenceSplitter
text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=10)
# global
from llama_index.core import Settings
Settings.text_splitter = text_splitter
# per-index
index = VectorStoreIndex.from_documents(
documents, transformations=[text_splitter]
)

您也可以明确定义这些步骤。

您可以通过两种方式实现:要么将我们的转换模块(文本分割器、元数据提取器等)作为独立组件使用,要么在我们的声明式转换管道接口中组合它们。

让我们按照以下步骤进行操作。

处理文档的一个关键步骤是将它们分割成“块”/节点对象。核心思想是将数据处理成可检索/输入给LLM的小片段。

LlamaIndex 支持多种文本分割器,从基于段落/句子/标记的分割器到基于文件的分割器(如HTML、JSON)。

这些可以单独使用或作为数据摄取管道的一部分

from llama_index.core import SimpleDirectoryReader
from llama_index.core.ingestion import IngestionPipeline
from llama_index.core.node_parser import TokenTextSplitter
documents = SimpleDirectoryReader("./data").load_data()
pipeline = IngestionPipeline(transformations=[TokenTextSplitter(), ...])
nodes = pipeline.run(documents=documents)

您也可以选择为您的文档和节点添加元数据。这可以通过手动方式或使用自动元数据提取器来完成。

以下是关于 1) 如何自定义文档 和 2) 如何自定义节点 的指南。

document = Document(
text="text",
metadata={"filename": "<doc_file_name>", "category": "<category>"},
)

要将节点插入向量索引,它应具有嵌入向量。详情请参阅我们的数据摄取流水线嵌入向量指南

如果您愿意,可以直接创建节点并将节点列表直接传递给索引器:

from llama_index.core.schema import TextNode
node1 = TextNode(text="<text_chunk>", id_="<node_id>")
node2 = TextNode(text="<text_chunk>", id_="<node_id>")
index = VectorStoreIndex([node1, node2])