加载数据(提取)
在我们选择的 LLM 对我们的原始数据进行处理之前,我们首先需要对原始数据进行简单处理并加载原始数据。这个过程类似于 ML 世界中的数据清理/特征工程流程,或传统数据设置中的 ETL 管道。
数据提取流程通常由三个主要阶段组成:
- 加载数据
- 转换数据
- 索引并存储数据
我们将在后续章节中介绍索引/存储。在本小节中,我们主要讨论加载器和转换过程。
加载器
在我们选择的 LLM 对我们的原始数据进行处理之前,我们需要加载原始数据。LlamaIndex 执行此操作的方式是通过 数据连接器(也称为 Reader
)。数据连接器 从不同的数据源提提取数据并将数据格式化为 Document
对象。Document
是数据和有关该数据的元数据的集合。
使用 SimpleDirectoryReader
加载
最容易使用的加载器是 SimpleDirectoryReader
,它可以从给定目录中的 每个文件 创建文档 Document
对象。它内置于 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
。
数据转换
加载数据后,您需要处理和转换数据,然后将其放入存储系统。这些转换包括 分块、提取元数据 和 对每个块提取embedding。这是确保 LLM 能够检索和最佳使用数据所必需的。
转换输入/输出是Node对象(一个 Document
是对应 Node
的子类)。转换也可以堆叠和重新排序。
我们有用于转换文档的高级 API 和低级 API。
高级转换 API
索引有一个 .from_documents()
方法,它接受一个 Document
对象数组,并正确地解析和分块它们。但是,有时你会希望更好地控制文档的拆分方式。
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]
)
低级转换 API
您还可以显式定义这些步骤。
您可以通过使用我们的转换模块(文本分割器、元数据提取器等)作为独立组件来实现这一点,或者在我们的声明性转换流程接口中组合它们。
让我们来看看下面的步骤。
将文档拆分成节点
处理文档的关键步骤是将它们拆分为 “块”/Node
对象。关键思想是将数据处理成可以检索/提供给 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>"},
)
添加嵌入embedding
要将节点插入向量索引,它应该具有嵌入embedding。有关更多详细信息,请参阅我们的提取管道或嵌入指南。
直接创建并传递节点
如果我们愿意,您可以直接创建节点并将节点列表直接传递给索引器: