跳到内容

加载数据(摄取)#

在您选择的 LLM 处理您的数据之前,您首先需要处理并加载数据。这与机器学习领域的数据清洗/特征工程管道,或传统数据设置中的 ETL 管道类似。

这个摄取管道通常包含三个主要阶段

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

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

加载器#

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

使用 SimpleDirectoryReader 加载#

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

from llama_index.core import SimpleDirectoryReader

documents = SimpleDirectoryReader("./data").load_data()

使用来自 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 上有数百个连接器可供使用!

直接创建 Document#

除了使用加载器,您还可以直接使用 Document。

from llama_index.core import Document

doc = Document(text="text")

转换#

数据加载后,您需要在将其放入存储系统之前对其进行处理和转换。这些转换包括分块、提取元数据以及嵌入每个块。这对于确保数据可以被检索并被 LLM 最佳地使用是必要的。

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

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

高级转换 API#

索引有一个 .from_documents() 方法,它接受一个 Document 对象数组,并会正确解析和分块。然而,有时您可能需要更精细地控制文档如何分割。

from llama_index.core import VectorStoreIndex

vector_index = VectorStoreIndex.from_documents(documents)
vector_index.as_query_engine()

在底层,这将您的 Document 分割成 Node 对象,Node 对象与 Document 类似(它们包含文本和元数据),但与它们的父 Document 存在关系。

如果您想通过这种抽象定制核心组件,例如文本分割器,您可以传入自定义的 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]
)

低级转换 API#

您也可以显式定义这些步骤。

您可以通过将我们的转换模块(文本分割器、元数据提取器等)用作独立组件,或者在我们的声明式 转换管道接口 中组合它们来完成此操作。

让我们逐步了解以下步骤。

将文档分割成 Node#

处理文档的一个关键步骤是将其分割成“块”/Node 对象。核心思想是将您的数据处理成适合检索/馈送给 LLM 的小片段。

LlamaIndex 支持多种 文本分割器,范围从基于段落/句子/token 的分割器到基于文件的分割器,如 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)

添加元数据#

您还可以选择为文档和 Node 添加元数据。这可以手动完成,也可以使用自动元数据提取器完成。

这里是关于 1) 如何定制 Document 和 2) 如何定制 Node 的指南。

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

添加嵌入#

要将 Node 插入向量索引,它应该具有嵌入。有关更多详细信息,请参阅我们的摄取管道或我们的嵌入指南

直接创建和传递 Node#

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

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])