LlamaIndex - 01 DataLoader (文档加载)
LlamaIndex 文档加载完全指南
文档加载是 LlamaIndex 构建 RAG 应用的第一步,也是最基础的一步。本文将全面介绍 LlamaIndex 中文档加载的各种方式、核心概念以及高级自定义技巧。
一、核心概念:Document
在 LlamaIndex 中,Document(文档)是对原始数据源的标准化封装,是整个 RAG 流程的数据入口。它不仅仅指传统的文本文档,而是涵盖所有可被加载的结构化/非结构化数据的抽象载体。
1. Document 的核心属性
每个 Document 对象包含以下关键属性:
| 属性 | 类型 | 说明 |
|---|---|---|
text | str | 核心属性,存储文档的原始文本内容 |
metadata | dict | 元数据字典,记录文档的上下文信息(文件名、路径、创建时间等) |
id_ / doc_id | str | 唯一标识符,用于区分不同 Document |
2. Document 的关键特性
- 多源适配性:LlamaIndex 提供 100+ 内置 Data Loader,可将不同数据源统一为 Document 对象
- 不可变性:原始 Document 加载后内容不会被修改(分割操作会生成新的 Node)
- 编码保障:加载中文文档时需通过
encoding="utf-8"指定编码
二、文档加载的三种方式
方式一:使用 SimpleDirectoryReader(最常用)
SimpleDirectoryReader 是最简单易用的加载器,可以将指定目录中的文件批量加载为 Document 对象:
from llama_index.core import SimpleDirectoryReader
# 基本用法:加载目录下所有文件
documents = SimpleDirectoryReader("./data").load_data()
# 指定编码(处理中文文档)
documents = SimpleDirectoryReader("./data", encoding="utf-8").load_data()
# 查看加载结果
print(f"加载文档数量:{len(documents)}")
print(f"第一个文档内容长度:{len(documents[0].text)}字符")
print(f"文档元数据:{documents[0].metadata}")支持的文件格式:Markdown、PDF、Word 文档、PowerPoint 演示文稿、图像、音频和视频等。
方式二:使用 LlamaHub 的数据加载器
LlamaHub 是 LlamaIndex 的数据连接器注册表,提供了数百种连接器,支持从各种数据源加载数据:
from llama_index.core import download_loader
from llama_index.readers.database import DatabaseReader
# 示例:从 SQL 数据库加载数据
reader = DatabaseReader(
scheme="postgresql",
host="localhost",
port=5432,
user="myuser",
password="mypassword",
dbname="mydb",
)
query = "SELECT * FROM users"
documents = reader.load_data(query=query)方式三:手动构造 Document
你也可以手动创建 Document 对象:
from llama_index.core import Document
# 从文本列表创建
text_list = ["文本1内容", "文本2内容", "文本3内容"]
documents = [Document(text=t) for t in text_list]
# 创建单个文档
document = Document(text="这是文档的原始文本内容")
# 快速创建示例文档(用于原型开发)
example_doc = Document.example()三、元数据(Metadata)管理
元数据是 Document 的重要组成部分,用于记录文档的上下文信息,对回答溯源和多文档管理至关重要。
1. 设置元数据
方式一:在构造函数中设置
document = Document(
text="文档内容",
metadata={
"filename": "important_doc.pdf",
"category": "技术文档",
"author": "张三",
"creation_date": "2024-01-15"
}
)方式二:创建后设置
document = Document(text="文档内容")
document.metadata = {"filename": "doc.txt", "category": "指南"}方式三:使用 SimpleDirectoryReader 自动设置
from llama_index.core import SimpleDirectoryReader
# 定义元数据生成函数
filename_fn = lambda filename: {"file_name": filename, "source": "local"}
documents = SimpleDirectoryReader(
"./data",
file_metadata=filename_fn
).load_data()2. 自定义文档 ID
文档 ID 用于在索引中高效管理和刷新文档:
# 自动将文件路径作为 ID
documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data()
# 手动设置 ID
document.doc_id = "my_custom_document_id"3. 高级元数据自定义
默认情况下,元数据会被同时注入到 Embedding 模型和 LLM 中。但你可以分别控制:
from llama_index.core import Document
from llama_index.core.schema import MetadataMode
document = Document(
text="这是一个需要处理的文档",
metadata={
"file_name": "secret_document.txt", # 文件名可能包含敏感信息
"category": "finance",
"author": "LlamaIndex"
},
# 排除 LLM 可见的元数据字段
excluded_llm_metadata_keys=["file_name"],
# 排除 Embedding 可见的元数据字段
excluded_embed_metadata_keys=["file_name"],
)
# 查看 LLM 实际看到的内容
print("LLM 看到的内容:")
print(document.get_content(metadata_mode=MetadataMode.LLM))
# 查看 Embedding 模型实际看到的内容
print("Embedding 模型看到的内容:")
print(document.get_content(metadata_mode=MetadataMode.EMBED))4. 自定义元数据格式
你可以控制元数据在文本中的呈现格式:
document = Document(
text="文档内容",
metadata={"key1": "value1", "key2": "value2"},
metadata_seperator=" | ", # 键值对之间的分隔符,默认为 "\n"
metadata_template="{key}: {value}", # 每个键值对的格式,默认为 "{key}: {value}"
text_template="元数据:{metadata_str}\n---\n内容:{content}" # 最终模板
)四、批量加载与高级用法
1. 批量加载目录
from llama_index.core import SimpleDirectoryReader
# 加载整个目录
documents = SimpleDirectoryReader(
input_dir="./docs",
recursive=True, # 递归读取子目录
required_exts=[".pdf", ".txt"], # 只加载特定扩展名
exclude=["temp", "draft"] # 排除特定目录
).load_data()2. 处理大文档
对于大型文档,建议在加载时进行流式处理或设置合适的 chunk 大小:
from llama_index.core import Settings
from llama_index.core.node_parser import SentenceSplitter
# 全局设置 chunk 大小
Settings.chunk_size = 512
# 或使用自定义解析器
documents = SimpleDirectoryReader("./data").load_data()
parser = SentenceSplitter(chunk_size=512, chunk_overlap=20)
nodes = parser.get_nodes_from_documents(documents)3. 使用 DocStore 管理多个索引
你可以将文档存储在 Document Store 中,供多个索引重用,避免数据重复:
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, SummaryIndex
from llama_index.core.storage.docstore import SimpleDocumentStore
from llama_index.core import StorageContext
from llama_index.core.node_parser import SentenceSplitter
# 加载并解析文档
documents = SimpleDirectoryReader("./data").load_data()
nodes = SentenceSplitter().get_nodes_from_documents(documents)
# 创建文档存储
docstore = SimpleDocumentStore()
docstore.add_documents(nodes)
storage_context = StorageContext.from_defaults(docstore=docstore)
# 多个索引共享同一个文档存储
vector_index = VectorStoreIndex(nodes, storage_context=storage_context)
summary_index = SummaryIndex(nodes, storage_context=storage_context)
# 验证:两个索引使用相同的底层节点
print(f"文档存储中的节点数:{len(storage_context.docstore.docs)}")五、完整示例:从加载到索引
以下是一个完整的文档加载到索引构建的示例:
from llama_index.core import (
SimpleDirectoryReader,
VectorStoreIndex,
Settings
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.llms.openai import OpenAI
# 1. 配置 LLM(可选)
Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0)
# 2. 加载文档
documents = SimpleDirectoryReader(
"./data",
encoding="utf-8",
filename_as_id=True # 使用文件名作为文档 ID
).load_data()
print(f"成功加载 {len(documents)} 个文档")
# 3. 查看文档信息
for doc in documents[:3]: # 显示前3个
print(f"文档ID: {doc.doc_id}")
print(f"文件名: {doc.metadata.get('file_name', 'Unknown')}")
print(f"内容长度: {len(doc.text)} 字符")
print("-" * 50)
# 4. 设置文本分割
Settings.chunk_size = 512
Settings.chunk_overlap = 20
# 5. 构建索引
index = VectorStoreIndex.from_documents(documents)
# 6. 查询测试
query_engine = index.as_query_engine()
response = query_engine.query("你的问题在这里")
print(response)六、常见问题与最佳实践
1. 中文编码问题
加载中文文档时,务必指定 encoding="utf-8",否则可能导致乱码:
documents = SimpleDirectoryReader("./chinese_docs", encoding="utf-8").load_data()2. 元数据最佳实践
- 保留文件路径和文件名,便于溯源
- 对敏感元数据使用
excluded_llm_metadata_keys排除 - 保持元数据值类型简单(str、float、int),以便向量数据库兼容
3. 性能优化
- 对于大型文档集,合理设置
chunk_size(通常 512-1024) - 使用
recursive=False避免不必要的深层遍历 - 考虑使用
SimpleDirectoryReader的file_metadata回调函数批量添加元数据
4. 文档刷新策略
通过设置 filename_as_id=True,可以方便地检测文档变化并刷新索引:
# 设置文件名作为 ID,便于检测变化
documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data()
# 后续可以使用索引的 refresh() 方法更新总结
LlamaIndex 的文档加载机制灵活而强大,核心要点包括:
- Document 是核心抽象:统一表示各种数据源的标准化容器
- SimpleDirectoryReader 是主力工具:覆盖大部分本地文件加载需求
- 元数据是关键:合理设置元数据可大幅提升 RAG 效果
- LlamaHub 提供扩展:数百种数据连接器满足各种场景需求
- DocStore 支持多索引共享:避免数据冗余,提升效率
掌握这些文档加载技巧,将为后续的索引构建和智能问答打下坚实基础。