Langchain学习(6):文档加载器 - CSV、JSON、PDF与文本处理详解
·
在构建RAG(检索增强生成)系统或处理非结构化数据时,高效、精准地加载文档是关键第一步。LangChain提供了丰富的文档加载器(Document Loaders),针对不同文件格式提供专业解决方案。本文将深入解析四种核心加载器的使用技巧、参数细节与实战代码,帮助应对各类数据加载场景。
CSVLoader:结构化表格数据加载
核心参数解析
| 参数 | 说明 | 关键细节 |
|---|---|---|
file_path |
CSV文件路径 | 支持相对/绝对路径 |
csv_args |
CSV解析参数字典 | delimiter(分隔符)、quotechar(引用符)、fieldnames(自定义表头) |
encoding |
文件编码 | 中文场景务必设为"utf-8" |
source_column |
指定元数据来源列 | 如设为"name",每条文档的metadata会包含该列值 |
metadata_columns |
额外元数据列 | 可传入列表如["age", "gender"] |
两种加载模式对比
| 方法 | 适用场景 | 内存表现 |
|---|---|---|
load() |
小文件(<1万行) | 一次性加载全部文档到内存 |
lazy_load() |
大文件/流式处理 | 生成器模式,逐条返回,防内存溢出首选 |
代码示例
步骤1:生成测试CSV数据
import csv
import random
names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十',
'郑一', '王二', '陈三', '褚四', '卫五', '蒋六', '沈七', '韩八',
'Alice', 'Bob', 'Charlie', 'David', 'Emma', 'Frank', 'Grace', 'Henry',
'Ivy', 'Jack', 'Kate', 'Leo', 'Mia', 'Noah', 'Olivia', 'Paul', 'Quinn']
genders = ['男', '女', '其他']
data = []
selected_names = random.sample(names, 30)
for name in selected_names:
age = random.randint(18, 60)
gender = random.choice(genders)
data.append([name, age, gender])
with open('people.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['name', 'age', 'gender'])
writer.writerows(data)
print('CSV文件生成成功!共30条数据。')
生成文件建议存放至
./csv_data/people.csv(与加载代码路径匹配)
步骤2:加载CSV文档
from langchain_community.document_loaders.csv_loader import CSVLoader
loader = CSVLoader(
file_path="./csv_data/people.csv",
csv_args={
"delimiter": ",", # 指定分隔符
"quotechar": '"', # 指定引用字符
# "fieldnames": ["name", "age", "city"], # 添加一个新表头,如果源文件有表头,则原来的表头会当成数据
},
encoding="utf-8",
)
# document = loader.load()
# print(document)
# 懒加载(推荐大数据场景)
for document in loader.lazy_load():
print(document)
✅ 关键提示:
- 注释掉的
load()适合调试小数据;生产环境大数据建议用lazy_load() - 若CSV无表头,需通过
csv_args["fieldnames"]显式指定列名
JSONLoader:解析JSON数据
环境准备
pip install jq
核心参数解析
| 参数 | 说明 | 使用要点 |
|---|---|---|
jq_schema |
核心参数:jq表达式提取路径 | 决定提取哪些字段(见下方三类示例) |
text_content |
是否将提取内容转为纯文本 | False 保留JSON结构,True 转为字符串 |
json_lines |
是否为JSON Lines格式 | 每行独立JSON对象时设为 True |
三类JSON场景完整示例(代码零修改)
场景1:单个JSON对象(stu.json)
{
"name": "张三",
"age": 18,
"hobby": ["篮球", "足球", "跑步"],
"other": {
"city": "北京",
"phone": "13800000000"
}
}
from langchain_community.document_loaders.json_loader import JSONLoader
loader = JSONLoader(
file_path="./json_data/stu.json",
jq_schema=".", # 提取整个JSON对象
text_content=False,
)
document = loader.load()
print(document)
场景2:JSON数组(stus.json)
[
{"name": "张三", "age": 18,"gender":"男"},
{"name": "李四", "age": 20,"gender":"男"},
{"name": "王五", "age": 22,"gender":"男"}
]
loader = JSONLoader(
file_path="./json_data/stus.json",
jq_schema=".[].name", # 提取每个对象的name字段(返回3个Document)
text_content=False,
)
document = loader.load()
print(document)
场景3:JSON Lines格式(stu_lines.json)
{"name": "张三", "age": 18,"gender":"男"}
{"name": "李四", "age": 20,"gender":"男"}
{"name": "王五", "age": 22,"gender":"男"}
loader = JSONLoader(
file_path="./json_data/stu_lines.json",
jq_schema=".name", # 每行提取name字段
text_content=False,
json_lines=True, # 关键!标识为JSON Lines格式
)
document = loader.load()
print(document)
jq_schema速查:
.→ 整个对象.字段名→ 单字段.[].字段名→ 数组中每个元素的字段.嵌套.字段→ 多层嵌套提取
TextLoader + 文本分割
核心组件说明
| 组件 | 作用 | 关键参数 |
|---|---|---|
TextLoader |
读取纯文本文件 | encoding(中文必设utf-8) |
RecursiveCharacterTextSplitter |
智能分块 | chunk_size, chunk_overlap, separators |
RecursiveCharacterTextSplitter参数精解
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # 单块最大字符数(按length_function计算)
chunk_overlap=0, # 相邻块重叠字符数(缓解语义割裂)
separators=["\n\n", "\n", "。", "!", "?"], # 按优先级尝试分割
length_function=len, # 字符计数函数(可替换为token计数器)
)
分割逻辑:
- 优先在
\n\n(段落)处分割 - 若仍超长,尝试
\n(换行) - 依此类推至标点符号,最大限度保留语义完整性
完整代码
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
loader = TextLoader(
"./text_data/python语法.txt",
encoding="utf-8",
)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=0,
separators=["\n\n", "\n", "。", "!", "?"],
length_function=len,
)
split_docs = text_splitter.split_documents(docs)
print(f"文档分段数: {len(split_docs)}")
for doc in split_docs:
print("=" * 20)
print(doc)
print("=" * 20)
✅ 最佳实践:
- 中文文本务必在
separators中包含中文标点(。!?) chunk_overlap建议设为chunk_size的10%,避免关键信息被割裂
PyPDFLoader:PDF文档加载与分页处理
在处理技术文档、学术论文、企业报告等PDF资源时,精准控制分页粒度是构建高质量知识库的关键。PyPDFLoader作为LangChain最稳定的PDF加载方案,提供灵活的分页策略与流式处理能力,完美适配各类PDF处理场景。
核心参数解析
| 参数 | 说明 | 使用要点 |
|---|---|---|
file_path |
PDF文件路径 | 支持相对/绝对路径,路径含中文需确保系统编码兼容 |
mode |
核心参数:文档分割模式 | "page"(默认):每页独立Document;"single":全文合并为单个Document |
password |
PDF密码(可选) | 加密PDF必填,无密码文档切勿设置此参数 |
extract_images |
是否提取图片(新版本支持) | 默认False,需OCR能力时设为True(需额外配置) |
| 模式 | 适用场景 | Document数量 |
|---|---|---|
"page" |
技术文档/论文/手册 | = PDF总页数 |
"single" |
短文档(<5页)或需全文上下文 | 1 |
为什么推荐
"page"模式?
- 每页独立元数据(含
page字段),便于精准溯源- 避免超长文本导致LLM上下文溢出
- 与向量数据库分块策略天然契合
- 流式加载时内存占用稳定(每页处理完即释放)
环境依赖
pip install pypdf # PyPDFLoader底层依赖库
# 如需处理加密PDF:pip install pycryptodome
代码示例
from langchain_community.document_loaders.pdf import PyPDFLoader
loader = PyPDFLoader(
file_path="./pdf_data/introduction.pdf", # 要加载的PDF文件路径
mode="page", # 加载模式,"page"表示每页作为一个文档;"single"表示整个文档作为一个文档
# password="password", # PDF文件密码,没有密码就无需此参数
)
page_idx = 0
for doc in loader.lazy_load():
page_idx += 1
print(f"Page {page_idx} {'=' * 30}")
print(doc)
重要注意事项
| 问题类型 | 现象 | 解决方案 |
|---|---|---|
| 扫描版PDF | page_content 为空 |
需OCR预处理(推荐:unstructured库 + Tesseract) |
| 加密PDF | 报FileNotDecryptedError |
通过password参数传入正确密码 |
| 页码偏移 | metadata中page值与实际不符 |
注意:page字段从0开始计数(第1页=0) |
| 表格/公式丢失 | 复杂排版内容提取不全 | 结合pdfplumber等专业库后处理 |
选型决策树
核心价值:
PyPDFLoader将PDF的物理结构(页) 与语义结构(文本块) 解耦----先按页精准切分保留上下文边界,再通过TextSplitter进行语义级优化,
为RAG系统提供高质量、可溯源的文档基石。
总结与选型指南
| 加载器 | 适用场景 | 关键技巧 |
|---|---|---|
| CSVLoader | 表格数据(用户信息、日志、结构化记录) | 大文件必用 lazy_load();中文设 encoding="utf-8";无表头时指定 fieldnames |
| JSONLoader | API响应、配置文件、嵌套数据 | 精准编写 jq_schema;JSON Lines设 json_lines=True;需预装 jq 库 |
| TextLoader+Splitter | 纯文本长文档(手册、脚本、文章) | 中文需含 ["。","!","?"] 的 separators;chunk_overlap 建议设10%~15% |
| PyPDFLoader | PDF文档(论文、技术手册、报告) | 首选 mode="page" + lazy_load();页码元数据从0开始;扫描版需OCR预处理 |
核心思想:
文档加载不是“读取文件”,而是 “将原始数据转化为LLM可理解的语义单元”。
- CSV → 每行即语义单元(含列名元数据)
- JSON → 按jq_schema提取关键字段
- 文本 → 按语言特性智能分块
- PDF → 按物理页精准切分 + 页码溯源
更多推荐


所有评论(0)