数据加载(摄取):LlamaIndex中的数据处理与加载
在选择的LLM能够处理你的数据之前,你首先需要处理和加载数据。这类似于机器学习世界中的数据清洗/特征工程管道,或传统数据设置中的ETL管道。
这个摄取管道通常包括三个主要阶段:
- 加载数据
- 转换数据
- 索引和存储数据
我们将在后续章节中讨论索引/存储。在本指南中,我们将主要讨论加载器和转换。
加载器
在选择的LLM能够处理你的数据之前,你需要加载它。LlamaIndex通过数据连接器(也称为Reader)来实现这一点。数据连接器从不同的数据源摄取数据,并将数据格式化为Document对象。Document是数据的集合(目前是文本,未来还会有图像和音频)以及关于该数据的元数据。
使用SimpleDirectoryReader加载
最简单的Reader是我们内置的SimpleDirectoryReader,它从给定目录中的每个文件创建文档。它可以读取多种格式,包括Markdown、PDF、Word文档、PowerPoint幻灯片、图像、音频和视频。
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader("./data").load_data()
使用LlamaHub中的Reader
由于有太多可能的数据来源,它们并不都是内置的。相反,你可以从我们的数据连接器注册表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对象,这些对象类似于Document(包含文本和元数据),但与它们的父Document有关系。
如果你想通过这个抽象自定义核心组件,比如文本分割器,你可以传递一个自定义的转换列表或应用到全局的Settings:
from llama_index.core.node_parser import SentenceSplitter
text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=10)
# 全局
from llama_index.core import Settings
Settings.text_splitter = text_splitter
# 每个索引
index = VectorStoreIndex.from_documents(
documents, transformations=[text_splitter]
)
低级转换API
你也可以显式地定义这些步骤。
你可以通过使用我们的转换模块(文本分割器、元数据提取器等)作为独立组件,或者在我们的声明式Transformation Pipeline接口中组合它们来实现这一点。
让我们逐步进行以下操作。
将文档分割成节点
处理文档的关键步骤是将它们分割成“块”/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)如何自定义Documents和2)如何自定义Nodes的指南。
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])
通过LlamaIndex,我们不仅提供了一个强大的工具集,还构建了一个充满活力的社区,致力于推动LLMs在各种应用中的潜力。无论你是初学者还是经验丰富的开发者,LlamaIndex都为你提供了探索和实现上下文增强LLM应用的途径。加入我们,一起解锁LLMs的无限可能!