你必须要认识到真实世界的文档加载难度,不仅要会加载文档,更要理解文档如何成为 Agent 的“记忆”或“知识库”,支撑工具调用、RAG、长期记忆等关键能力
LangChain 的文档加载就是:把不同格式的文件,变成统一的 Document 对象
DocumentDocumentDocument 文档有两个字段:
Document(
page_content="文本内容……",
metadata={"source": "..."}
)
-
page_content- 存储文件的全部文本内容
- 类型:字符串(str)
- 包含文件中的所有文本,保留原始格式
-
metadata- 存储文件的元数据信息
- 类型:字典(dict)
- 默认包含:
source: 文件路径
- 可以包含其他自定义元数据
1、文档加载的本质
LangChain v1.0+ 的文档处理链路是:
文件 → Document 对象 → 文本切片 → 检索 & RAG → Agent
可以粗浅地理解为:
Document 是 LangChain 世界的“人民币”,所有组件靠它传递信息
2、文档加载器的核心模块
2.1、Document_loaders 文档加载器
在LangChain中,Document Loaders 是构建AI应用的"第一道工序"。它们负责将各种格式的文档转换为统一的Document对象,让后续的文本处理、向量化、检索等工作变得简单高效,没有它,我们就像没有刀的厨师,再好的食材也做不出美味佳肴。
2.2、常用加载器详解与示例:
1、TXT 文件加载器:
-
**用途:**加载 .txt 纯文本文件到一个Document对象的page_content中
-
代码示例:
from langchain_community.document_loaders import TextLoader # 加载文档 loader = TextLoader("文件路径", encoder = "指定文件编码格式") # 执行文件加载操作 # 调用load()方法读取文件内容 # 返回一个包含 Document 对象的列表 documents = loader.load()
2、PDF 文件加载器:PyPDFLoader
-
**用途:**加载PDF文件(每页转换为一个DocumentDocumentDocument)
-
代码示例:
from langchain_community.document_loaders import PyPDFLoader loader = PyPDFLoader("文件路径") documents = loader.load() # 查看第一页的内容和元数据 first_page = documents[0] print(f"Page content: {first_page.page_content[:200]}...") # 预览前200个字符 print(f"Metadata: {first_page.metadata}") # 通常包含 'source' 和 'page'
3、MarkDown 文件加载器:UnstructuredMarkdownLoader
-
用途:专门加载Markdown文件(.md)
-
参数解析:
- **
file_path:**Markdown 文件的路径 - **
mode:**关键参数,决定文档结构- “single” (默认):将整个 Markdown 文件作为一个完整的
Document加载 - “elements”:将文件解析为结构化的元素(如
Title、NarrativeText、ListItem),每个元素成为一个独立的Document对象,并包含丰富的元数据(如category)
- “single” (默认):将整个 Markdown 文件作为一个完整的
strategy:解析策略- 可选
"hi_res"(高精度,保留更多结构) "fast"(快速模式)
- 可选
- **
-
代码示例:
from langchain_community.document_loaders import UnstructuredMarkdownLoader # 模式1: 作为单个文档加载 loader_single = UnstructuredMarkdownLoader("文件路径") data_single = loader_single.load() # 模式2: 作为元素加载 (保留文档结构) loader_elements = UnstructuredMarkdownLoader( file_path='文件路径', mode='elements', strategy='fast' # 选择快速解析策略 ) data_elements = loader_elements.load() # 查看元素的类型 if data_elements: print(f"Element category: {data_elements[0].metadata['category']}") print(f"Element content: {data_elements[0].page_content}")
4、HTML文件加载器:UnstructuredHTMLLoader
-
用途:加载HTML文件,提取文本内容
-
**参数解析:**file_path
-
代码示例:
from langchain_community>document_loaders import UnstructuredHTMLLoader loader = UnstructuredHTMLLoader("文件路径") data = loader.load() # 查看加载的文档内容 html_doc = data[0] print(f"HTML content: {html_doc.page_content}") print(f"Source: {html_doc.metadata['source']}")
5、Office文档加载器:UnstructuredWordDocunmentLoader
-
用途:加载Word文档(.docx)
-
参数解析:
file_path: 文档路径model: 处理模式,决定文档结构保留方式single:将整个文档作为一个 Document 进行处理elements:按文档元素进行分割,返回包含标题、段落、列表等结构化元素的 Document 列表
-
示例代码:
from langchain_community.document_loaders import UnstructuredWordDocumentLoader # 使用 elements 模式保留文档结构 loader = UnstructuredWordDocumentLoader("./example.docx", mode="elements") documents = loader.load() print(f"加载了 {len(documents)} 个文档元素") for i, doc in enumerate(documents[:3]): # 查看前3个元素 print(f"元素 {i+1}:") print(f" 类型: {doc.metadata.get('category', 'Unknown')}") print(f" 内容: {doc.page_content[:100]}...") print(f" 元数据: {doc.metadata}") print("---")
6、UnstructuredExcelLoader Excel文档加载器
-
**用途:**加载Excel文件
-
参数解析:
file_path: Excel 文件路径 (.xlsx)mode: 处理模式(同 Word 加载器)
-
代码示例:
from langchain_community.document_loaders import UnstructuredExcelLoader loader = UnstructuredExcelLoader("./data.xlsx") documents = loader.load() # Excel 加载器的特殊处理 print(f"加载了 {len(documents)} 个工作表或单元格区域") for doc in documents: print(f"内容: {doc.page_content[:200]}...") print(f"元数据: {doc.metadata}") print("---")
7、PPT 文档加载器:UnstructuredPowerPointLoader
-
用途:加载PPT文档(.pptx)
-
核心参数:
file_path: PowerPoint 文件路径 (.pptx)mode: 处理模式
-
示例代码:
from langchain_community.document_loaders import UnstructuredPowerPointLoader loader = UnstructuredPowerPointLoader("./presentation.pptx", mode="elements") documents = loader.load() print(f"PPT 包含 {len(documents)} 个幻灯片元素") for doc in documents: slide_num = doc.metadata.get('page_number', 'Unknown') element_type = doc.metadata.get('category', 'Unknown') print(f"幻灯片 {slide_num} - {element_type}: {doc.page_content[:100]}...")
8、目录加载器:DirectoryLoader
-
**用途:**加载整个目录中的所有文档(自动识别文件类型)
-
参数解析:
path: 目录路径glob: 文件匹配模式loader_cls或loader_map: 指定文件类型对应的加载器recursive: 是否递归搜索子目录silent_errors:是否忽略加载错误的文件show_progress: 是否显示进度条use_multithreading: 是否使用多线程
-
特点:支持递归加载,可以指定文件类型,懒加载优化性能
-
示例代码:
from langchain_community.document_loaders import ( DirectoryLoader, TextLoader, PyPDFLoader, UnstructuredWordDocumentLoader ) # 方法1:使用 loader_cls(单一文件类型) loader1 = DirectoryLoader( "./documents/", glob="*.txt", # 只加载txt文件 loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"}, show_progress=True, recursive=False # 不搜索子目录 ) # 方法2:使用 loader_map(多种文件类型) loader_map = { '.txt': TextLoader, '.pdf': PyPDFLoader, '.docx': lambda path: UnstructuredWordDocumentLoader(path, mode="elements") } loader2 = DirectoryLoader( "./documents/", glob="**/*.*", # 递归匹配所有文件 loader_map=loader_map, recursive=True, # 递归搜索子目录 use_multithreading=True, show_progress=True ) documents = loader2.load() print(f"总共加载了 {len(documents)} 个文档") # 统计不同文件类型的文档数量 from collections import Counter file_types = [doc.metadata.get('source', '').split('.')[-1] for doc in documents] print(f"文件类型分布: {Counter(file_types)}")
9、CSV文档加载器: CSVLoader
-
**功能:**从CSV加载文档
-
核心参数:
file_path: CSV 文件路径source_column: 指定作为来源的列名csv_args: 自定义 CSV 读取参数
-
代码示例:
from langchain_community.document_loaders import CSVLoader loader = CSVLoader( file_path="./data.csv", source_column="id", # 指定元数据中的来源列 encoding="utf-8", csv_args={ 'delimiter': ',', 'quotechar': '"' } ) documents = loader.load() print(f"CSV 包含 {len(documents)} 行数据") for doc in documents[:2]: # 查看前2行 print(f"内容: {doc.page_content}") print(f"元数据: {doc.metadata}") print("---")
10、JSONLoader:
-
用途:从JSON数据加载文档
-
核心参数:
file_path: JSON 文件路径jq_schema: jq 查询语法,用于提取文本内容text_key: 指定包含文本内容的字段content_key: 同 text_key
-
代码示例:
from langchain_community.document_loaders import JSONLoader # 示例1:简单数组结构 loader1 = JSONLoader( file_path='./data.json', jq_schema='.[]', # 遍历数组中的每个对象 text_key='content' ) # 示例2:复杂嵌套结构 loader2 = JSONLoader( file_path='./articles.json', jq_schema='.articles[].body', # 提取 articles 数组中每个对象的 body 字段 content_key='body' ) documents = loader2.load() print(f"从 JSON 中提取了 {len(documents)} 个文档") for doc in documents[:2]: print(f"内容: {doc.page_content[:100]}...") print(f"元数据: {doc.metadata}")
11、WebBaseLoader
-
功能:
-
核心参数:
-
web_paths或url: 网页URL -
bs_kwargs: BeautifulSoup 解析参数 -
requests_kwargs: 请求参数
-
-
代码示例:
from langchain_community.document_loaders import WebBaseLoader # 加载单个网页 loader1 = WebBaseLoader("https://example.com") # 加载多个网页 urls = [ "https://example.com/page1", "https://example.com/page2" ] loader2 = WebBaseLoader(urls) # 自定义请求参数 loader3 = WebBaseLoader( "https://example.com", requests_kwargs={ 'headers': {'User-Agent': 'Mozilla/5.0'}, 'timeout': 10 }, bs_kwargs={'features': 'lxml'} ) documents = loader3.load() print(f"从网页加载了 {len(documents)} 个文档") for doc in documents: print(f"网页标题: {doc.metadata.get('title', 'N/A')}") print(f"内容预览: {doc.page_content[:200]}...") print(f"来源: {doc.metadata.get('source', 'N/A')}") print("---")
3、错误处理(仅供参考)
- 单文件类型版本
# 导入必要的库和模块
from langchain_community.document_loaders import DirectoryLoader # 导入目录加载器,用于批量加载文档
from langchain_community.document_loaders import TextLoader # 导入文本加载器,用于加载txt文件
import os # 导入操作系统接口模块,用于文件路径操作
import glob # 导入glob模块,用于文件模式匹配
def safe_load_document(directory, glob_pattern="*.*",loader_cls=TextLoader):
"""
安全加载文档的函数,能够处理文件加载过程中的常见错误
参数:
directory (str): 要加载的文档目录路径
glob_pattern (str): 文件匹配模式,默认为所有文件
loader_cls (class): 文档加载器类,默认为TextLoader
返回:
list: 包含成功加载的所有Document对象的列表
"""
documents = [] # 初始化一个空列表,用于存储成功加载的文档
error_files = [] # 记录加载失败的文件
# 检查目录是否存在
if not os.path.exists(directory):
print(f"错误: 目录 {directory} 不存在")
return documents, error_files
# 使用glob模式匹配目录中符合条件的所有文件路径
# os.path.join() 用于安全地拼接目录路径和文件模式
try:
for file_path in glob.glob(os.path.join(directory, glob_pattern)):
try:
# 检查文件是否为空
if os.path.getsize(file_path) == 0:
print(f"警告: 文件 {file_path} 为空,跳过")
error_files.append(file_path)
continue
loader = loader_cls(file_path, encoding="utf-8")
loaded_docs = loader.load()
# 检查是否成功加载到内容
if loaded_docs and len(loaded_docs) > 0:
documents.extend(loaded_docs)
print(f"成功: 加载文件 {file_path},获得 {len(loaded_docs)} 个文档")
else:
print(f"警告: 文件 {file_path} 没有加载到内容")
error_files.append(file_path)
except Exception as e:
print(f"错误: 加载文件 {file_path} 失败 - {str(e)}")
error_files.append(file_path)
continue
except Exception as e:
print(f"错误: 遍历目录时发生异常 - {str(e)}")
return documents, error_files # 返回成功和失败的文件信息
# 使用示例:调用安全加载函数
# 加载指定目录下所有.txt文件
documents, errors = safe_load_documents("./documents/", glob_pattern="*.txt")
# 打印加载结果统计信息
print(f"成功加载 {len(documents)} 个文档,{len(errors)} 个文件加载失败")
- 多文件类型的版本
from langchain_community.document_loaders import PyPDFLoader, UnstructuredWordDocumentLoader
def safe_load_multiple_types(directory):
"""
支持多种文件类型的安全加载函数
"""
documents = []
# 定义文件类型与对应加载器的映射
loader_map = {
'.txt': (TextLoader, {'encoding': 'utf-8'}),
'.pdf': (PyPDFLoader, {}),
'.docx': (UnstructuredWordDocumentLoader, {'mode': 'elements'})
}
for file_path in glob.glob(os.path.join(directory, "*.*")):
# 获取文件扩展名
file_ext = os.path.splitext(file_path)[1].lower()
# 检查是否有对应的加载器
if file_ext in loader_map:
loader_class, loader_kwargs = loader_map[file_ext]
try:
loader = loader_class(file_path, **loader_kwargs)
documents.extend(loader.load())
print(f"成功加载: {file_path}")
except Exception as e:
print(f"加载失败: {file_path} - {e}")
else:
print(f"跳过不支持的文件类型: {file_path}")
return documents
4、懒加载机制:
懒加载(Lazy Loading)是一种程序设计优化技术,核心思想是延迟初始化对象,直到真正需要使用时才创建
DirectoryLoader的懒加载实现
from langchain_community.document_loaders import DirectoryLoader
from langchain_community.document_loaders import PyPDFLoader
import time
# 创建DirectoryLoader实例(默认启用懒加载)
loader = DirectoryLoader(
"./large_documents/", # 包含大量PDF文件的目录
glob="*.pdf", # 匹配所有PDF文件
loader_cls=PyPDFLoader, # 指定PDF加载器
show_progress=True # 显示加载进度条
)
print("创建加载器完成,但还没有真正读取任何文件...")
print(f"加载器类型: {type(loader)}")
print("---")
# 方法1:一次性加载所有文档(触发实际读取)
print("开始使用load()方法加载文档...")
start_time = time.time()
documents = loader.load() # 这时才真正开始读取所有文件
end_time = time.time()
print(f"共加载了 {len(documents)} 个文档")
print(f"加载耗时: {end_time - start_time:.2f} 秒")
print("---")
# 方法2:使用懒加载迭代器(推荐处理大文件)
print("开始使用lazy_load()方法逐个处理文档...")
start_time = time.time()
processed_count = 0
for doc in loader.lazy_load(): # 返回生成器,按需加载
# 模拟文档处理
processed_count += 1
print(f"正在处理第 {processed_count} 个文档: {doc.metadata['source']}")
# 这里可以添加实际的文档处理逻辑
# 例如:文本分析、向量化、存储到数据库等
# 每处理10个文档显示一次进度
if processed_count % 10 == 0:
print(f"已处理 {processed_count} 个文档...")
end_time = time.time()
print(f"懒加载处理完成,总共处理 {processed_count} 个文档")
print(f"处理耗时: {end_time - start_time:.2f} 秒")
lazy_load() 方法深度解析
lazy_load() 是 DirectoryLoader 类中的一个方法,它返回一个生成器(Generator),能够按需逐个加载和处理文档,而不是一次性加载所有文件到内存中
load()方法将会立即加载所有文档到内存lazy_load()方法只在迭代时加载当前文件, 生成一个文档后立即暂停,等待下一次请求
性能对比结果分析
我这里处理1000个PDF文件,性能对比结果如下:
| 指标 | 一次性加载 | 懒加载 | 优势 |
|---|---|---|---|
| 初始响应时间 | 20秒 | 0.5秒 | 40倍提升 |
| 内存占用峰值 | 2GB | 50MB | 40倍降低 |
| 首个结果时间 | 20秒后 | 立即 | 实时响应 |
| 错误处理 | 全部失败 | 部分失败 | 容错性更好 |
| 用户体验 | 长时间等待 | 即时反馈 | 体验更佳 |
5、 文档加载性能优化技巧:
from langchain_community.document_loaders import DirectoryLoader, TextLoader
import os
import glob
class OptimizedDocumentLoader:
"""优化文档加载器"""
def __init__(self, base_directory):
self.base_directory = base_directory
def multi_threaded_loading(self, file_pattern="*.txt", recursive=True):
"""
多线程加载文档
参数:
file_pattern: 文件匹配模式
recursive: 是否递归搜索子目录
"""
loader = DirectoryLoader(
self.base_directory,
glob=file_pattern,
loader_cls=TextLoader,
loader_kwargs={"encoding": "utf-8", "autodetect_encoding": True},
use_multithreading=True, # 启用多线程加速
silent_errors=True, # 静默处理错误文件
recursive=recursive, # 递归搜索
show_progress=True # 显示进度条
)
return loader.load()
def batch_loading(self, file_pattern="*.txt", batch_size=100, recursive=True):
"""
分批加载文档,适用于超大目录
参数:
file_pattern: 文件匹配模式
batch_size: 每批处理的文件数量
recursive: 是否递归搜索
"""
all_documents = []
# 构建搜索模式
if recursive:
search_pattern = os.path.join(self.base_directory, "**", file_pattern)
else:
search_pattern = os.path.join(self.base_directory, file_pattern)
# 获取所有文件
file_list = glob.glob(search_pattern, recursive=recursive)
total_files = len(file_list)
print(f"找到 {total_files} 个文件,开始分批加载(每批 {batch_size} 个文件)...")
for batch_index, i in enumerate(range(0, total_files, batch_size)):
batch_files = file_list[i:i + batch_size]
batch_documents = []
for file_path in batch_files:
try:
loader = TextLoader(file_path, encoding="utf-8")
documents = loader.load()
batch_documents.extend(documents)
except Exception as e:
print(f" 加载失败: {os.path.basename(file_path)} - {str(e)}")
continue
all_documents.extend(batch_documents)
# 进度报告
processed_files = min(i + batch_size, total_files)
progress = (processed_files / total_files) * 100
print(f" 批次 {batch_index + 1}: 处理 {len(batch_files)} 个文件 → 获得 {len(batch_documents)} 个文档 "
f"({progress:.1f}%)")
# 内存优化:清理批处理数据
del batch_documents
print(f" 加载完成: 总共 {len(all_documents)} 个文档")
return all_documents
def lazy_batch_processing(self, file_pattern="*.txt", recursive=True):
"""
懒加载 + 分批处理(内存最优方案)
"""
loader = DirectoryLoader(
self.base_directory,
glob=file_pattern,
loader_cls=TextLoader,
loader_kwargs={"encoding": "utf-8"},
recursive=recursive,
use_multithreading=True
)
# 返回生成器,实现真正的流式处理
return loader.lazy_load()
# 使用示例
def demo_optimized_loading():
"""演示优化后的加载方法"""
loader = OptimizedDocumentLoader("./documents/")
print("=== 方法1: 多线程加载 ===")
documents1 = loader.multi_threaded_loading("*.txt")
print(f"多线程加载结果: {len(documents1)} 个文档")
print("\n=== 方法2: 分批加载 ===")
documents2 = loader.batch_loading("*.txt", batch_size=50)
print(f"分批加载结果: {len(documents2)} 个文档")
print("\n=== 方法3: 懒加载流式处理 ===")
processed_count = 0
for document in loader.lazy_batch_processing("*.txt"):
# 在这里处理每个文档
processed_count += 1
if processed_count % 10 == 0:
print(f"已流式处理 {processed_count} 个文档...")
print(f"流式处理完成: {processed_count} 个文档")
# 运行演示
if __name__ == "__main__":
demo_optimized_loading()

被折叠的 条评论
为什么被折叠?



