加载数据(摄取)#
在您选择的 LLM 处理您的数据之前,您首先需要处理并加载数据。这与机器学习领域的数据清洗/特征工程管道,或传统数据设置中的 ETL 管道类似。
这个摄取管道通常包含三个主要阶段
- 加载数据
- 转换数据
- 索引和存储数据
我们将在后续章节中介绍索引/存储。在本指南中,我们将主要讨论加载器和转换。
加载器#
在您选择的 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
对象(Document
是 Node
的子类)。转换也可以堆叠和重新排序。
我们提供了用于转换文档的高级和低级 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])