LangChain文档加载器提供了两种核心加载方式:load()一次性加载全部文档和lazy_load()延迟流式加载文档,后者特别适合处理大型数据集以避免内存溢出问题。
一、文档加载器核心加载方法
两种加载模式详解
load() - 一次性加载模式,将所有文档一次性加载到内存中,返回完整的Document对象列表,适合小型数据集(如单个PDF、小型文本文件)
代码示例:
python
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("./data/small.pdf")
documents = loader.load() # 一次性加载所有页面
print(f"共加载 {len(documents)} 个文档")
lazy_load() - 延迟流式加载模式
按需加载文档,仅在迭代时才实际加载内容
返回一个生成器对象,避免一次性占用大量内存
特别适合大型数据集(如GB级日志文件、大型PDF文档集)
代码示例:
python
from langchain_community.document_loaders import TextLoader
loader = TextLoader("./data/large_log.txt", encoding="utf-8")
for doc in loader.lazy_load(): # 逐块加载,而非一次性加载
print(f"处理文档块:{doc.page_content[:100]}")
# 可在此处进行分块处理、向量化等操作
两种加载方式的底层关系
LangChain的BaseLoader基类中定义了这两种方法的关系:
python
def load(self) -> List[Document]:
"""一次性加载所有文档"""
return list(self.lazy_load())
def lazy_load(self) -> Iterator[Document]:
"""延迟加载文档(生成器)"""
if type(self).load != BaseLoader.load:
return iter(self.load()) # 向后兼容:如果子类实现了load但没实现lazy_load
raise NotImplementedError(f"{self.__class__.__name__} does not implement lazy_load()")
这种设计确保了:
新代码推荐使用lazy_load():更内存友好
旧代码兼容性:如果子类只实现了load(),lazy_load()会自动调用它
灵活性:开发者可以根据数据规模选择合适的加载方式
二、各种文档类型的具体加载方法
1、PDF文档加载
PyPDFLoader(最常用):
python
from langchain_community.document_loaders import PyPDFLoader
# 一次性加载所有页面
loader = PyPDFLoader("./data/document.pdf", mode="page")
pages = loader.load() # 返回每页一个Document对象
# 或使用延迟加载(推荐大型PDF)
for page in loader.lazy_load():
print(f"第 {page.metadata.get('page', '未知')} 页: {len(page.page_content)} 字符")
关键参数说明:
powershell
mode="page"(默认):每页生成一个Document,metadata包含页码
mode="single":将整个PDF作为单个Document对象
password:用于解锁加密PDF
2、文本文件加载
TextLoader(TXT/Markdown等纯文本):
python
from langchain_community.document_loaders import TextLoader
# 一次性加载
loader = TextLoader("./data/sample.txt", encoding="utf-8")
documents = loader.load()
# 延迟加载(推荐大型文件)
loader = TextLoader("./data/large_file.md", encoding="utf-8")
for doc in loader.lazy_load():
print(f"文档内容预览: {doc.page_content[:200]}...")
print(f"来源: {doc.metadata['source']}")
3、目录批量加载
DirectoryLoader(批量处理文件夹):
python
from langchain_community.document_loaders import DirectoryLoader
# 一次性加载所有txt文件
loader = DirectoryLoader(
"./documents/",
glob="**/*.txt",
show_progress=True,
use_multithreading=True
)
documents = loader.load()
# 延迟加载(推荐大型目录)
for doc in loader.lazy_load():
print(f"处理文件: {doc.metadata['source']}")
# 可在此处进行分块、向量化等操作
4、网页内容加载
WebBaseLoader(抓取网页内容):
python
from langchain_community.document_loaders import WebBaseLoader
# 一次性加载
loader = WebBaseLoader("https://example.com")
data = loader.load()
# 延迟加载(推荐抓取多个网页)
urls = ["https://example.com/page1", "https://example.com/page2"]
loader = WebBaseLoader(urls)
for doc in loader.lazy_load():
print(f"网页标题: {doc.metadata.get('title', '未知')}")
print(f"内容长度: {len(doc.page_content)} 字符")
5、结构化数据加载
CSVLoader(表格数据):
python
from langchain_community.document_loaders import CSVLoader
loader = CSVLoader(
file_path="./data/sales.csv",
csv_args={
"delimiter": ",",
"quotechar": '"',
"fieldnames": ["Product", "Sales", "Region"]
}
)
# 一次性加载
data = loader.load()
# 延迟加载(推荐大型CSV)
for row in loader.lazy_load():
print(f"产品: {row.metadata.get('Product', '未知')}")
print(f"销售额: {row.metadata.get('Sales', '未知')}")
JSONLoader(JSON数据):
python
from langchain_community.document_loaders import JSONLoader
loader = JSONLoader(
file_path="./data/products.json",
jq_schema=".products[]",
text_content=False
)
# 一次性加载
data = loader.load()
# 延迟加载
for product in loader.lazy_load():
print(f"产品名称: {product.metadata.get('name', '未知')}")
print(f"描述: {product.page_content}")
三、加载方法选择的最佳实践
何时使用load() vs lazy_load()
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 小型文档(<10MB) | load() |
简单直接,代码简洁 |
| 大型文档(>10MB) | lazy_load() |
避免内存溢出,流式处理更高效 |
| 需要随机访问文档 | load() |
一次性加载后可随机索引 |
| 仅需顺序处理文档 | lazy_load() |
内存效率高,适合管道式处理 |
大文件处理的高级技巧
结合lazy_load()的流式处理管道:
python
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 创建分块器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", "!", "?", ",", "、", ""]
)
# 流式处理大型文档
loader = TextLoader("./data/very_large_file.txt", encoding="utf-8")
for doc in loader.lazy_load():
# 逐块分块处理
chunks = text_splitter.split_documents([doc])
# 将每个块向量化并存入数据库
for chunk in chunks:
vector_db.add_documents([chunk])
使用多线程加速目录加载:
python
from langchain_community.document_loaders import DirectoryLoader
loader = DirectoryLoader(
"./documents/",
glob="**/*.txt",
use_multithreading=True, # 启用多线程
threads_per_worker=4 # 每个worker使用4个线程
)
# 延迟加载结合多线程
for doc in loader.lazy_load():
# 处理文档...
pass
四、常见问题解决方案
内存溢出问题
当处理GB级文件时,即使使用lazy_load()也可能遇到内存问题,解决方案:
- 进一步减小分块大小:将chunk_size从500降低到200-300
- 增加分块重叠度:设置chunk_overlap=100确保语义连贯
- 使用更轻量级的模型:选择小型嵌入模型如BAAI/bge-small-zh-v1.5
中文文档处理技巧
- 指定正确编码:TextLoader(..., encoding="utf-8")
- 自定义分隔符:针对中文文本,使用separators=["\n\n", "\n", "。", "!", "?", ",", "、", ""]
- 启用元素模式:对于Markdown,使用UnstructuredMarkdownLoader(..., mode="elements")
扫描件PDF处理
普通PyPDFLoader无法处理扫描件PDF,需使用OCR方案:
python
from langchain_community.document_loaders import UnstructuredPDFLoader
loader = UnstructuredPDFLoader(
"./data/scanned.pdf",
strategy="ocr", # 启用OCR
mode="page"
)
通过合理选择load()或lazy_load()方法,结合适当的分块策略和处理技巧,您可以高效地加载各种类型的文档,为RAG系统构建坚实的知识库基础。对于大型数据集,强烈推荐使用lazy_load()方法以避免内存问题,并结合流式处理管道实现高效的知识库构建。