大家好,我是工藤学编程 🦉 | 一个正在努力学习的小博主,期待你的关注 |
|---|---|
实战代码系列最新文章😉 | C++实现图书管理系统(Qt C++ GUI界面版) |
SpringBoot实战系列🐷 | 【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案 |
分库分表 | 分库分表之实战-sharding-JDBC分库分表执行流程原理剖析 |
消息队列 | 深入浅出 RabbitMQ-RabbitMQ消息确认机制(ACK) |
AI大模型 | 零基础学AI大模型之LangChain WebBaseLoader与Docx2txtLoader实战 |
前情摘要 1、零基础学AI大模型之读懂AI大模型 2、零基础学AI大模型之从0到1调用大模型API 3、零基础学AI大模型之SpringAI 4、零基础学AI大模型之AI大模型常见概念 5、零基础学AI大模型之大模型私有化部署全指南 6、零基础学AI大模型之AI大模型可视化界面 7、零基础学AI大模型之LangChain 8、零基础学AI大模型之LangChain六大核心模块与大模型IO交互链路 9、零基础学AI大模型之Prompt提示词工程 10、零基础学AI大模型之LangChain-PromptTemplate 11、零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战 12、零基础学AI大模型之LangChain链 13、零基础学AI大模型之Stream流式输出实战 14、零基础学AI大模型之LangChain Output Parser 15、零基础学AI大模型之解析器PydanticOutputParser 16、零基础学AI大模型之大模型的“幻觉” 17、零基础学AI大模型之RAG技术 18、零基础学AI大模型之RAG系统链路解析与Document Loaders多案例实战 19、零基础学AI大模型之LangChain PyPDFLoader实战与PDF图片提取全解析 20、零基础学AI大模型之LangChain WebBaseLoader与Docx2txtLoader实战
大家好,我是工藤学编程 🦉 ,一个专注AI大模型实战的小博主~ 上一篇我们详细拆解了RAG系统的文档加载环节,用PyPDFLoader、WebBaseLoader等工具搞定了PDF、网页、Word等多源数据的加载。但加载后的原始文档往往存在「长度超标」「格式混乱」「信息零散」等问题——500页的法律合同直接喂给模型会超token限制,网页文本混着广告导航栏,产品手册的关键参数散在不同页面……这时候就需要RAG链路中的核心环节:文档切割转换来“提纯”数据。
今天这篇就带大家吃透LangChain中的文档转换器(Document Transformers),从「为什么要做」到「核心参数怎么调」,再到「不同场景实战」,手把手教你做好RAG的数据预处理第一步~

上一篇加载后的文档只是“原始素材”,直接用于向量化和检索会踩3个大坑,这也是文档切割转换的核心价值所在:
核心痛点 | 具体影响 | 解决思路 |
|---|---|---|
模型输入token限制 | GPT-4最大32k tokens、Claude 3最高200k,长文档(如500页合同)直接输入会API报错,或被截断导致信息丢失 | 按模型上下文窗口合理分块,确保每个文本块长度合规 |
信息密度不均 & 语义断裂 | 关键信息(如合同条款、产品参数)分散在长文本中,粗暴分割会把完整语义(如一个句子、一个功能模块)拆碎 | 按自然语义边界(段落、句子)分割,保留上下文连贯性 |
格式混乱 & 噪音干扰 | 网页文本含广告/导航栏、代码文档混着Markdown格式、PDF有乱码特殊字符,会降低向量检索精度 | 文本清洗去噪 + 格式标准化,提取纯净有效内容 |
简单说:文档切割转换的本质是「数据提纯+结构化」——把杂乱的原始文档变成「长度合规、语义完整、无噪音、带上下文元数据」的标准化文本块,为后续向量化和检索筑牢基础。
LangChain中的Document Transformers是处理文档流水线的“数据加工厂”,核心围绕3件事展开,缺一不可:
核心任务 | 具体操作 | 最终效果 |
|---|---|---|
文本分块 | 按「固定长度+语义边界」分割文本(优先用段落、句子分隔符) | 避免截断完整语义,适配模型token限制 |
去噪处理 | 移除特殊字符、乱码、HTML标签、广告内容、多余空格 | 提升文本信息密度,减少噪音对向量化的干扰 |
元数据增强 | 为每个文本块注入来源(如“XX合同第3章”)、页码、时间戳、加载器类型等上下文 | 检索时可追溯信息源头,提高答案可信度 |
所有文档切割逻辑都基于langchain_text_splitters.TextSplitter抽象类实现——它定义了分块的核心接口,但不直接实现分割逻辑,需通过子类(如RecursiveCharacterTextSplitter、CharacterTextSplitter)按具体策略执行。
先看核心源码结构(关键参数带场景解读):
from langchain_text_splitters import TextSplitter
from abc import ABC, abstractmethod
from typing import Callable, List, Union
class TextSplitter(BaseDocumentTransformer, ABC):
"""Interface for splitting text into chunks."""
def __init__(
self,
chunk_size: int = 4000, # 文本块最大长度(默认字符数,部分子类支持token数)
chunk_overlap: int = 200, # 相邻块重叠长度(保留上下文)
length_function: Callable[[str], int] = len, # 长度计算函数(默认字符数,可改用token计数)
keep_separator: Union[bool, Literal["start", "end"]] = False, # 是否保留分隔符(如句号、换行)
add_start_index: bool = False, # 是否添加文本块在原始文档中的起始索引
strip_whitespace: bool = True, # 是否去除文本块前后空格
) -> None:
...
@abstractmethod
def split_text(self, text: str) -> List[str]:
"""基础文本分割方法,子类必须实现"""
...TextSplitter的三个核心方法各有分工,很多新手会混淆,用表格一次性讲清:
方法 | 输入类型 | 输出类型 | 元数据处理 | 典型使用场景 |
|---|---|---|---|---|
split_text() | 单个字符串 | List[str](纯文本块列表) | ❌ 不保留 | 仅需分割纯文本(如无格式的TXT文件),无需上下文信息 |
create_documents() | 字符串列表 + 可选元数据列表 | List[Document](文档对象列表) | ✅ 需手动传递 | 从纯文本构建带元数据的文档(如给网页文本添加“来源URL”元数据) |
split_documents() | List[Document](加载后的文档对象) | List[Document](分割后的文档对象) | ✅ 自动继承 | 处理已加载的文档(如PyPDFLoader加载的PDF、WebBaseLoader加载的网页),无需手动管元数据 |
调用逻辑小技巧:实际开发中优先用split_documents()——它会自动继承原始文档的元数据(如PDF的页码、网页的URL),避免后续检索时“找不到信息来源”。
TextSplitter的3个核心参数(chunk_size、chunk_overlap、separators)直接决定分块质量,新手最容易在这里踩坑,下面结合场景讲透:
length_function改为token数)实战案例:分割产品手册文本
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 加载后的产品手册文本(假设已用PyPDFLoader加载为Document对象)
product_manual_doc = [
Document(
page_content="深度学习需要大量数据和计算资源。卷积神经网络(CNN)在图像处理中表现优异,常用于图像分类、目标检测等场景。循环神经网络(RNN)则更适合序列数据,如自然语言处理、时间序列预测。",
metadata={"source": "产品手册.pdf", "page": 5}
)
]
# 设置chunk_size=100(字符数),适配中等上下文窗口模型
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=20,
strip_whitespace=True
)
# 分割文档(自动继承元数据)
split_docs = text_splitter.split_documents(product_manual_doc)
# 输出结果(2个文本块,均含元数据)
for doc in split_docs:
print(f"文本块:{doc.page_content}")
print(f"元数据:{doc.metadata}\n")
# 输出:
# 文本块:深度学习需要大量数据和计算资源。卷积神经网络(CNN)在图像处理中表现优异,常用于图像分类、
# 元数据:{'source': '产品手册.pdf', 'page': 5}
#
# 文本块:计算资源。卷积神经网络(CNN)在图像处理中表现优异,常用于图像分类、目标检测等场景。循环神经网络(RNN)则更适合序列数据,
# 元数据:{'source': '产品手册.pdf', 'page': 5}chunk_size的10%-20%(如chunk_size=1000时,chunk_overlap=100-200);经典案例:长文本序列分割计算 假设chunk_size=1024,chunk_overlap=128,处理长度为2560的文本:
["\n\n", "\n", " ", ""](先按段落分割,再按换行,最后按空格)"。"“;”“,”(如["\n\n", "。", ";", ",", " "]);"\n\n", "\n", "{", "}", ";", " "(避免拆碎代码块);"## "“### ”(按标题分割,保持章节完整性)。实战案例:中文法律文本自定义分隔符
# 法律合同文本(加载后的Document对象)
legal_doc = Document(
page_content="第一条 合同双方:甲方(供应商):XX科技有限公司;乙方(采购方):XX制造有限公司。第二条 采购标的:甲方为乙方提供AI服务器10台,型号为XX-2024,单价5万元/台,总金额50万元。第三条 交货时间:乙方支付预付款后30个工作日内交货。",
metadata={"source": "采购合同.pdf", "page": 1}
)
# 自定义中文分隔符(优先按段落→条款→分号→句号分割)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
separators=["\n\n", "第[一二三四五六七八九十]条", ";", "。", " "] # 正则匹配中文条款
)
split_docs = text_splitter.split_documents([legal_doc])
for doc in split_docs:
print(f"法律文本块:{doc.page_content}\n")
# 输出(按条款分割,语义完整)
# 法律文本块:第一条 合同双方:甲方(供应商):XX科技有限公司;乙方(采购方):XX制造有限公司。
#
# 法律文本块:第二条 采购标的:甲方为乙方提供AI服务器10台,型号为XX-2024,单价5万元/台,总金额50万元。
#
# 法律文本块:第三条 交货时间:乙方支付预付款后30个工作日内交货。如果觉得这篇文章有帮助,别忘了点赞关注~ 有任何文档切割的踩坑问题,欢迎在评论区交流!咱们下一篇见~ 🚀