📝 本章学习目标:彻底掌握 LangChain 文档切割全流程,能独立完成纯文本、PDF、Markdown、代码、长文档的智能分割,适配 RAG 系统,解决大模型上下文超限、语义断裂、检索不准问题。
一、引言:为什么文档切割是 RAG 必学核心
在大模型应用爆发的今天,RAG(检索增强生成) 已成为落地私有知识库的标准方案。而文档切割(Text Splitting) 是 RAG pipeline 中最关键、最容易踩坑的一环。
1.1 背景与意义
- 大模型有严格上下文窗口限制(GPT-3.5 4k/16k、GPT-4 8k/32k、国产模型多在 4k--8k),长文本直接输入必报错。
- 切割质量直接决定:检索准确率、回答相关性、 hallucination(幻觉)率、系统响应速度。
- 好的切割 = 语义完整 + 长度合规 + 无冗余断裂 + 可复现可调试。
据社区统计,60% 以上 RAG 效果差,根源不在模型 / 向量库,而在文档切割不合理。
1.2 本章结构概览
plaintext
环境搭建 → 核心概念 → 分割器原理 → 多场景实战代码 → 调优策略 → 常见坑 → 面试/工程最佳实践
二、核心概念解析
2.1 基本定义
- Document :LangChain 统一文档对象,含
page_content(文本)+metadata(元信息,页码 / 来源 / 时间等)。 - Chunk:切割后的文本片段,是向量入库与检索的最小单元。
- Chunk Size:单块最大长度(字符 / Token)。
- Chunk Overlap:块间重叠长度,保证上下文连贯。
- Separator:分隔符(换行、句号、空格、正则等)。
- Length Function :长度计算方式(
len字符数 /tiktokenToken 数)。
2.2 关键术语
- 递归分割:按层级优先分割(段落→句子→词→字符),最大保留语义。
- Token 感知分割:按模型真实 Token 数切割,避免窗口溢出。
- 语言专属分割:对 Python/JS/HTML/Java 等代码按语法结构分割。
- 语义保留:不把一句话、一个概念、一个代码块强行切断。
2.3 文档切割标准架构
plaintext
┌─────────────────────────────────┐
│ 文档加载(Loader) │
│ TXT/PDF/MD/DOCX/HTML/DB/爬取 │
├─────────────────────────────────┤
│ 文本清洗(预处理) │
│ 去空行/去多余空格/统一换行/去噪 │
├─────────────────────────────────┤
│ 文本分割(Splitter) │
│ 递归字符 / Token / 代码 / 语义 │
├─────────────────────────────────┤
│ 块校验与增强 │
│ 长度统计/元数据注入/去重/过滤 │
└─────────────────────────────────┘
三、环境搭建(一步到位)
3.1 安装依赖
bash
运行
python
# 核心分割器
pip install -U langchain-text-splitters
# 文档加载器
pip install -U langchain-community pypdf python-docx unstructured markdown
# Token 计算(OpenAI 系)
pip install -U tiktoken
# 环境变量
pip install python-dotenv
3.2 基础导入模板(所有案例通用)
python
运行
python
import os
import re
import tiktoken
from dotenv import load_dotenv
from langchain_core.documents import Document
from langchain_text_splitters import (
RecursiveCharacterTextSplitter,
CharacterTextSplitter,
Language
)
# 加载环境变量
load_dotenv()
# ======================
# 全局工具函数
# ======================
def tiktoken_len(text: str, encoding_name: str = "cl100k_base") -> int:
"""
计算文本的 Token 数量(适配 GPT3.5/4/Claude 等)
:param text: 输入文本
:param encoding_name: 编码名,cl100k_base 适配 most
:return: token 数量
"""
encoding = tiktoken.get_encoding(encoding_name)
return len(encoding.encode(text))
def print_chunks(chunks: list[Document], max_show: int = 5):
"""
友好打印切割结果
"""
print(f"📦 总块数:{len(chunks)}")
print("=" * 80)
for i, chunk in enumerate(chunks[:max_show]):
print(f"【第 {i+1} 块】")
print(f"字符数:{len(chunk.page_content)}")
print(f"Token 数:{tiktoken_len(chunk.page_content)}")
print(f"内容:{chunk.page_content[:150]}...")
print(f"元数据:{chunk.metadata}")
print("-" * 80)
四、最核心:RecursiveCharacterTextSplitter 递归分割(90% 场景首选)
4.1 原理
按层级分隔符 依次尝试分割,不满足长度再下钻,最大程度保留段落 / 句子完整性,是通用最强分割器LangChain。
默认分隔符(英文):
plaintext
["\n\n", "\n", " ", ""]
中文优化分隔符(强烈推荐):
python
运行
python
separators_cn = [
"\n\n", # 段落
"\n", # 行
"。", "!", "?", # 句子结束
";", # 分句
",", "、", # 短语
" ", # 空格
"" # 兜底
]
4.2 基础实战:纯中文文本切割
python
运行
python
# ======================
# 1. 准备长文本(示例:长篇文章)
# ======================
long_text = """
人工智能(AI)是一门旨在使计算机系统能够模拟、延伸和扩展人类智能的技术科学。
它包含机器学习、自然语言处理、计算机视觉、专家系统等多个分支。
近年来,随着大模型技术的飞速发展,AI 已经深入渗透到医疗、金融、教育、交通、工业制造等各行各业。
在自然语言处理领域,RAG(检索增强生成)技术有效解决了大模型幻觉、知识滞后等问题,成为企业落地的主流方案。
文档切割作为 RAG 的第一步,直接决定了后续检索精度与生成质量。
合理的切割策略能让模型精准定位知识点,输出稳定可靠的答案。
"""
# ======================
# 2. 初始化分割器(中文专用)
# ======================
splitter = RecursiveCharacterTextSplitter(
chunk_size=300, # 单块最大字符数
chunk_overlap=50, # 重叠长度,保证上下文连贯
separators=separators_cn,# 中文分隔符
length_function=len, # 按字符长度计算
is_separator_regex=False # 非正则
)
# ======================
# 3. 执行切割
# ======================
# 方式1:直接切割字符串 → 返回字符串列表
text_chunks = splitter.split_text(long_text)
# 方式2:切割为 Document 对象(推荐,保留元数据)
docs = [Document(page_content=long_text, metadata={"source": "demo_text"})]
splitted_docs = splitter.split_documents(docs)
# ======================
# 4. 查看结果
# ======================
print_chunks(splitted_docs)
4.3 核心参数详解
表格
| 参数 | 说明 | 推荐值 |
|---|---|---|
| chunk_size | 单块最大长度 | 300--800 字符 / 200--500 Token |
| chunk_overlap | 重叠长度 | 50--100 字符 / 30--80 Token |
| separators | 分隔符优先级 | 中文用上面 separators_cn |
| length_function | 长度计算 | len(简单)/tiktoken_len(精准) |
| is_separator_regex | 是否正则分隔 | False(稳定) |
五、Token 感知切割(工程级必用)
5.1 为什么要用
- 字符数 ≠ Token 数(中文 1 字≈1--2 Token)。
- 按字符切割容易实际 Token 超限,导致 API 报错。
- 按真实 Token 切割 = 100% 安全。
5.2 实战代码:按 Token 切割
python
运行
python
# ======================
# 1. 基于 Token 的分割器
# ======================
token_splitter = RecursiveCharacterTextSplitter(
chunk_size=400, # 最大 400 Token
chunk_overlap=80, # 重叠 80 Token
separators=separators_cn,
length_function=tiktoken_len, # 核心:用 Token 计算长度
is_separator_regex=False
)
# ======================
# 2. 切割并验证
# ======================
token_chunks = token_splitter.split_documents(docs)
print("🔍 按 Token 切割结果:")
print_chunks(token_chunks)
# 验证每块 Token 不超限
for i, chunk in enumerate(token_chunks):
token_num = tiktoken_len(chunk.page_content)
if token_num > 400:
print(f"⚠️ 第 {i+1} 块超限:{token_num}")
else:
print(f"✅ 第 {i+1} 块合规:{token_num}")
5.3 快捷方式:from_tiktoken_encoder
python
运行
python
# ======================
# 直接用封装好的 Token 分割器
# ======================
token_quick_splitter = CharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base", # GPT 系列编码
chunk_size=400,
chunk_overlap=80
)
quick_chunks = token_quick_splitter.split_documents(docs)
print_chunks(quick_chunks)
六、多格式文档实战(PDF/Markdown/DOCX/ 代码)
6.1 实战 1:PDF 文档切割(最常用)
python
运行
python
from langchain_community.document_loaders import PyPDFLoader
# ======================
# 1. 加载 PDF
# ======================
pdf_path = "人工智能技术白皮书.pdf"
loader = PyPDFLoader(pdf_path)
pdf_docs = loader.load() # 列表,每个元素是一页 PDF → Document
# ======================
# 2. 切割(保留页码元数据)
# ======================
pdf_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=100,
separators=separators_cn,
length_function=tiktoken_len
)
pdf_splitted = pdf_splitter.split_documents(pdf_docs)
# ======================
# 3. 查看(页码自动保留在 metadata)
# ======================
print_chunks(pdf_splitted)
6.2 实战 2:Markdown 切割(按标题层级)
python
运行
python
from langchain_community.document_loaders import UnstructuredMarkdownLoader
# ======================
# 1. 加载 MD(按结构解析:标题/段落/列表)
# ======================
md_path = "LangChain实战教程.md"
md_loader = UnstructuredMarkdownLoader(md_path, mode="elements")
md_docs = md_loader.load()
# ======================
# 2. 分割
# ======================
md_splitter = RecursiveCharacterTextSplitter(
chunk_size=400,
chunk_overlap=50,
separators=["\n#", "\n##", "\n###", "\n\n", "\n", "。", " "]
)
md_chunks = md_splitter.split_documents(md_docs)
print_chunks(md_chunks)
6.3 实战 3:代码切割(Python/JS/HTML/Java)
适合代码库、技术文档、接口说明,按语法结构切割,不破坏函数 / 类 / 代码块LangChain。
python
运行
python
# ======================
# 1. 示例代码
# ======================
python_code = """
def rag_pipeline(doc_path: str, question: str) -> str:
# 加载文档
loader = PyPDFLoader(doc_path)
docs = loader.load()
# 切割文档
splitter = RecursiveCharacterTextSplitter(chunk_size=300)
chunks = splitter.split_documents(docs)
# 向量化
embeddings = OpenAIEmbeddings()
db = Chroma.from_documents(chunks, embeddings)
# 检索
retriever = db.as_retriever(search_kwargs={"k": 3})
relevant_docs = retriever.get_relevant_documents(question)
# 生成答案
chain = RetrievalQA.from_chain_type(llm=ChatOpenAI(), chain_type="stuff", retriever=retriever)
return chain.run(question)
# 调用
if __name__ == "__main__":
ans = rag_pipeline("test.pdf", "什么是RAG?")
print(ans)
"""
# ======================
# 2. 代码专用分割器
# ======================
code_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON,
chunk_size=300,
chunk_overlap=30
)
# ======================
# 3. 切割代码
# ======================
code_docs = [Document(page_content=python_code)]
code_chunks = code_splitter.split_documents(code_docs)
print("🐍 Python 代码切割结果:")
print_chunks(code_chunks)
支持语言:
- Python / JavaScript / TypeScript
- HTML / CSS / Java / Go / PHP / C++ / C#
6.4 实战 4:Word(DOCX)切割
python
运行
python
from langchain_community.document_loaders import Docx2txtLoader
# 加载 Word
docx_loader = Docx2txtLoader("企业知识库.docx")
docx_docs = docx_loader.load()
# 切割
docx_splitter = RecursiveCharacterTextSplitter(
chunk_size=400,
chunk_overlap=80,
separators=separators_cn,
length_function=tiktoken_len
)
docx_chunks = docx_splitter.split_documents(docx_docs)
print_chunks(docx_chunks)
七、高级功能:自定义分割、清洗、增强
7.1 自定义正则分割(精准控制)
python
运行
python
# ======================
# 按【章节】【条目】【问题】等正则切割
# ======================
regex_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=[r"\n第[\d一二三四五六七八九十]+章", r"\n\d+\.", "。", " "],
is_separator_regex=True # 开启正则
)
# 带章节的文本
book_text = """
第1章 人工智能概述
1.1 AI的定义
人工智能是模拟人类智能的技术...
1.2 AI发展历史
从图灵测试到大模型...
第2章 RAG技术原理
2.1 检索增强生成流程
2.2 文档切割最佳实践
"""
regex_chunks = regex_splitter.split_text(book_text)
for i, c in enumerate(regex_chunks):
print(f"第{i+1}章块:\n{c}\n{'-'*50}")
7.2 文本预处理清洗(提升切割质量)
python
运行
python
def clean_text(text: str) -> str:
"""
文本清洗:去多余空格、空行、特殊符号
"""
# 去多余空行
text = re.sub(r"\n+", "\n", text)
# 去多余空格
text = re.sub(r" +", " ", text)
# 去首尾空格
text = text.strip()
return text
# 使用
raw_text = " 我 是 空 格 怪 \n\n\n 文档切割实战教程 "
cleaned = clean_text(raw_text)
print("清洗前:", repr(raw_text))
print("清洗后:", repr(cleaned))
7.3 块增强:自动添加元数据、过滤短块
python
运行
python
def enhance_chunks(chunks: list[Document], min_len: int = 50) -> list[Document]:
"""
块增强:
1. 过滤过短的无效块
2. 自动添加序号、时间戳元数据
"""
enhanced = []
for idx, chunk in enumerate(chunks):
content = chunk.page_content
# 过滤过短
if len(content) < min_len:
continue
# 新增元数据
chunk.metadata["chunk_id"] = idx + 1
chunk.metadata["char_length"] = len(content)
chunk.metadata["token_length"] = tiktoken_len(content)
enhanced.append(chunk)
return enhanced
# 调用
enhanced_chunks = enhance_chunks(splitted_docs)
print_chunks(enhanced_chunks)
八、工程最佳实践(直接复制到生产)
8.1 通用切割函数(生产级封装)
python
运行
python
def split_document(
file_path: str,
chunk_size: int = 400,
chunk_overlap: int = 80,
use_token: bool = True
) -> list[Document]:
"""
通用文档切割入口,支持 TXT/PDF/MD/DOCX
:param file_path: 文件路径
:param chunk_size: 块大小
:param chunk_overlap: 重叠
:param use_token: 是否按 Token 切割
:return: 切割后的 Document 列表
"""
# 1. 自动选择 Loader
ext = os.path.splitext(file_path)[-1].lower()
if ext == ".pdf":
loader = PyPDFLoader(file_path)
elif ext == ".docx":
loader = Docx2txtLoader(file_path)
elif ext == ".md":
loader = UnstructuredMarkdownLoader(file_path)
elif ext == ".txt":
loader = UnstructuredMarkdownLoader(file_path)
else:
raise ValueError(f"不支持文件类型:{ext}")
# 2. 加载文档
docs = loader.load()
# 3. 选择长度函数
length_func = tiktoken_len if use_token else len
# 4. 初始化分割器
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=separators_cn,
length_function=length_func
)
# 5. 切割 + 增强
splits = splitter.split_documents(docs)
final_chunks = enhance_chunks(splits)
return final_chunks
# ======================
# 一行调用
# ======================
if __name__ == "__main__":
final = split_document("人工智能白皮书.pdf")
print(f"✅ 最终有效块:{len(final)}")
print_chunks(final)
8.2 不同场景推荐参数
表格
| 场景 | chunk_size | chunk_overlap | 分割器 |
|---|---|---|---|
| 通用文章 | 300--500 字符 | 50--100 | 递归中文 |
| 技术文档 | 400--600 Token | 80--120 | Token 递归 |
| 代码文件 | 200--300 字符 | 20--40 | 语言专属 |
| 法律 / 合同 | 500--800 字符 | 100--150 | 正则 + 递归 |
| 新闻 / 对话 | 200--300 字符 | 30--50 | 短句优先 |
九、常见问题与避坑指南
9.1 高频问题
Q1:切割后句子被截断怎么办?
- 增大
chunk_overlap - 调整
separators,把句子结束符放更前面 - 适当增大
chunk_size
Q2:按字符切割,Token 还是超限?
- 必须改用
tiktoken_len按 Token 切割 - 模型不同编码不同,不要估算字符→Token
Q3:PDF 切割乱码、内容错乱?
- 用
PyPDFLoader而非UnstructuredPDFLoader - 先清洗文本,再切割
- 检查 PDF 是否是图片版(需 OCR)
Q4:块太多 / 太少,检索不准?
- 太多:调大
chunk_size - 太少:调小
chunk_size - 配合向量库
search_kwargs={"k":3--5}使用
9.2 经典错误代码对比
❌ 错误:无重叠、无清洗、按字符硬切
python
运行
bad_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=0)
✅ 正确:中文分隔符 + Token 计算 + 合理重叠
python
运行
good_splitter = RecursiveCharacterTextSplitter(
chunk_size=400,
chunk_overlap=80,
separators=separators_cn,
length_function=tiktoken_len
)
十、未来趋势与职业发展
- 语义切割:基于 embedding 自动聚类语义块,未来主流。
- 自适应切割:根据内容复杂度自动调整块大小。
- 多模态切割:文本 + 图片 + 表格统一结构化分割。
- 端侧切割:浏览器 / 移动端本地切割,保护隐私。
学习路径:
- 入门:掌握递归字符分割 → 1 周
- 进阶:Token 切割 + 多格式文档 → 2 周
- 专家:自定义分割 + 工程 pipeline + 调优 → 1 个月
十一、本章小结
本章从原理→环境→基础→多格式→高级→工程 完整覆盖 LangChain 文档切割,提供可直接复制到生产的代码,解决 RAG 最核心痛点。
核心记住三句话:
- 90% 场景用 RecursiveCharacterTextSplitter + 中文分隔符
- 生产环境必须按 Token 切割,不要按字符估算
- 切割质量 = 语义完整 + 长度合规 + 元数据齐全
💖 看完点赞 + 关注,下期更硬核!
我是专注 RAG 大模型落地 的实战派博主,持续输出:✅ LangChain 全栈教程 ✅ RAG 优化调优 ✅ 私有知识库搭建 ✅ 大模型应用开发
点赞 + 收藏 + 关注,持续更新不迷路~