在构建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计数器)
)

分割逻辑

  1. 优先在 \n\n(段落)处分割
  2. 若仍超长,尝试 \n(换行)
  3. 依此类推至标点符号,最大限度保留语义完整性

完整代码

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等专业库后处理

选型决策树

文字版

>20页

扫描版/图片

<5页

PDF类型?

文档长度?

PyPDFLoader + mode=“page” + lazy_load

接TextSplitter二次分块

先用OCR转文字

再用PyPDFLoader处理

PyPDFLoader + mode=“single”

核心价值
PyPDFLoader将PDF的物理结构(页)语义结构(文本块) 解耦----先按页精准切分保留上下文边界,再通过TextSplitter进行语义级优化,
为RAG系统提供高质量、可溯源的文档基石。

总结与选型指南

加载器 适用场景 关键技巧
CSVLoader 表格数据(用户信息、日志、结构化记录) 大文件必用 lazy_load();中文设 encoding="utf-8";无表头时指定 fieldnames
JSONLoader API响应、配置文件、嵌套数据 精准编写 jq_schema;JSON Lines设 json_lines=True;需预装 jq
TextLoader+Splitter 纯文本长文档(手册、脚本、文章) 中文需含 ["。","!","?"]separatorschunk_overlap 建议设10%~15%
PyPDFLoader PDF文档(论文、技术手册、报告) 首选 mode="page" + lazy_load();页码元数据从0开始;扫描版需OCR预处理

核心思想
文档加载不是“读取文件”,而是 “将原始数据转化为LLM可理解的语义单元”

  • CSV → 每行即语义单元(含列名元数据)
  • JSON → 按jq_schema提取关键字段
  • 文本 → 按语言特性智能分块
  • PDF → 按物理页精准切分 + 页码溯源
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐