标签:LangChain、RAG、文本分割、RecursiveCharacterTextSplitter、MarkdownHeaderTextSplitter、TokenTextSplitter、语义分块、代码分块、HTML 分块、最佳实践
🔥 前言:为什么 "切分" 是 RAG 的 "灵魂"?
在 RAG(检索增强生成)系统中,文档切割(Chunking) 是决定最终效果的核心环节,没有之一。
- 切得太粗:单个块太长,超出模型上下文窗口,检索时会混入大量无关信息,导致 "噪音过大"
- 切得太碎:语义被强行割裂,上下文丢失,检索结果不完整,大模型无法理解整体逻辑
- 切得不对:无视文档结构,比如把 Markdown 的标题和正文分开、把代码的函数拆成两半,直接导致语义断裂
可以说,没有高质量的切割,就没有高质量的 RAG。本文将系统梳理 LangChain 中 8 大主流文档切割技术,从原理、选型、实战代码到避坑指南,一次性讲透,让你看完就能上手!
一、环境准备:LangChain 文本分割器安装与基础配置
1.1 依赖安装(适配新版 LangChain)
LangChain 0.2 + 版本已将文本分割器独立为langchain-text-splitters包,旧版导入方式已废弃,先执行安装:
bash
运行
# 安装核心依赖(虚拟环境内执行)
pip install -U langchain langchain-text-splitters langchain-community tiktoken python-dotenv
1.2 基础工具导入(统一导入,后续所有代码通用)
python
运行
python
# 统一导入所有核心分割器,避免重复导入
from langchain_text_splitters import (
RecursiveCharacterTextSplitter, # 递归字符分割器(通用首选)
CharacterTextSplitter, # 简单字符分割器
MarkdownHeaderTextSplitter, # Markdown标题分割器
PythonCodeTextSplitter, # Python代码分割器
TokenTextSplitter, # Token数量分割器
HTMLHeaderTextSplitter, # HTML标签分割器
SentenceTransformersTokenTextSplitter, # 语义Token分割器
Language # 多语言分割器枚举
)
from langchain.schema import Document # 文档对象,部分场景需要
from typing import List # 类型提示
import tiktoken # Token计数工具
二、核心技术选型:8 大主流文档切割技术详解
2.1 技术选型对比表(速查)
表格
| 分割器类型 | 核心原理 | 适用场景 | 优点 | 缺点 | 推荐指数 |
|---|---|---|---|---|---|
| RecursiveCharacterTextSplitter | 按优先级递归尝试多种分隔符切割 | 通用文本、TXT/Word/ 通用文档 | 兼顾结构与长度,语义保留最好 | 对结构化文档(Markdown/HTML)适配一般 | ⭐⭐⭐⭐⭐ |
| CharacterTextSplitter | 按单一固定分隔符切割 | 结构简单的纯文本 | 实现简单,速度快 | 无视语义,易切断句子 / 段落 | ⭐⭐ |
| MarkdownHeaderTextSplitter | 按 Markdown 标题层级切割 | Markdown 文档、技术文档 | 完美保留标题 - 正文结构,语义完整 | 仅支持 Markdown 格式,不处理超长段落 | ⭐⭐⭐⭐ |
| PythonCodeTextSplitter | 按 Python 语法结构(函数 / 类 / 注释)切割 | Python 代码文件 | 不破坏代码结构,避免语法断裂 | 仅支持 Python 代码,通用性差 | ⭐⭐⭐⭐ |
| TokenTextSplitter | 按模型 Token 数量切割 | 对 Token 限制敏感的场景(如 GPT-3.5/4) | 严格控制 Token 数,适配模型上下文 | 无视语义结构,易切断句子 | ⭐⭐⭐ |
| HTMLHeaderTextSplitter | 按 HTML 标签层级切割 | HTML 网页、爬取的结构化文档 | 保留 HTML 结构,提取标题层级 | 仅支持 HTML 格式 | ⭐⭐⭐ |
| SentenceTransformersTokenTextSplitter | 基于语义相似度切割 | 长文本、语义连贯性要求高的场景 | 按语义边界切割,上下文保留最好 | 速度慢,依赖额外模型 | ⭐⭐⭐⭐ |
| 自定义语义分割器 | 结合向量相似度 / 聚类切割 | 复杂文档、非结构化文本 | 语义保留最优 | 实现复杂,计算成本高 | ⭐⭐⭐ |
三、实战代码详解:8 大分割器从入门到精通
3.1 RecursiveCharacterTextSplitter:通用首选,万能分割器
3.1.1 核心原理
这是 LangChain 官方推荐的通用场景首选分割器 ,它会按优先级递归尝试多种分隔符(如段落\n\n、换行\n、空格、字符"")切割,直到块大小符合要求,在保留语义和控制长度之间取得了最佳平衡。
3.1.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
chunk_size |
单个文本块的最大字符数(或 Token 数,取决于length_function) |
500~1500(根据模型上下文调整) |
chunk_overlap |
相邻块之间的重叠字符数,防止语义断裂 | chunk_size的 10%~20% |
separators |
切割优先级列表,按顺序尝试切割 | ["\n\n", "\n", " ", ""] |
length_function |
计算文本长度的函数,默认len,可改为tiktoken计数 |
len(通用场景)/ tiktoken(Token 敏感场景) |
add_start_index |
是否在metadata中添加块的起始索引 |
True(调试 / 溯源时推荐) |
3.1.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备测试文本(模拟通用文档,包含段落、换行、句子)
# --------------------------
sample_text = """
人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。人工智能可以对人的意识、思维的信息过程的模拟。人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。
人工智能是一门极富挑战性的科学,从事这项工作的人必须懂得计算机知识、心理学和哲学。人工智能包括十分广泛的科学,它由不同的领域组成,如机器学习、计算机视觉等。
总的来说,人工智能研究的一个主要目标是使机器能够胜任一些通常需要人类智能才能完成的复杂工作。不同时代、不同的人对这种"复杂工作"的理解是不同的。
"""
# --------------------------
# 2. 初始化递归字符分割器(核心配置)
# --------------------------
splitter = RecursiveCharacterTextSplitter(
chunk_size=300, # 单个块最大字符数:300字(会被切成多块)
chunk_overlap=50, # 块间重叠50字,避免上下文断裂
separators=[ # 切割优先级:先段落→再换行→再空格→最后强制切
"\n\n", # 优先级1:按段落分割
"\n", # 优先级2:按换行分割
" ", # 优先级3:按空格分割(单词/句子)
"" # 兜底:强制按字符分割(防止无法切割)
],
length_function=len, # 用len()计算文本长度(通用场景)
add_start_index=True # 为每个块添加起始索引(方便调试溯源)
)
# --------------------------
# 3. 执行文本切割
# --------------------------
# 方式1:直接切割字符串文本(最常用,无需Document对象)
chunks = splitter.split_text(sample_text)
# 方式2:切割Document对象(和LangChain文档加载器配合使用)
# from langchain_community.document_loaders import TextLoader
# loader = TextLoader("sample.txt", encoding="utf-8")
# docs = loader.load()
# chunks_with_metadata = splitter.split_documents(docs)
# --------------------------
# 4. 输出切割结果
# --------------------------
print(f"✅ 切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 块(起始索引:{splitter._get_start_index(chunk, sample_text) if splitter.add_start_index else '无'})")
print(chunk)
print("-" * 80)
3.1.4 运行结果与说明
- 文本会被切成多块,每块长度≤300 字,块间重叠 50 字
- 切割会优先按段落边界进行,只有段落过长时才会按换行 / 空格切割,最大限度保留语义
- 适合绝大多数通用场景,是 LangChain 中使用最广泛的分割器
3.2 CharacterTextSplitter:简单粗暴的固定分隔符分割
3.2.1 核心原理
这是 LangChain 中最基础的文本分割器,仅支持按单一固定分隔符(如换行、逗号、句号)切割,不做递归尝试,实现简单但语义保留效果差。
3.2.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
chunk_size |
单个文本块的最大字符数 | 300~1000 |
chunk_overlap |
相邻块之间的重叠字符数 | chunk_size的 10% |
separator |
固定分隔符,如\n\n(段落)、\n(换行)、。(句号) |
\n\n(段落) |
3.2.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备测试文本(按段落分隔)
# --------------------------
sample_text = """
人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。
"""
# --------------------------
# 2. 初始化简单字符分割器
# --------------------------
splitter = CharacterTextSplitter(
chunk_size=200, # 单个块最大字符数:200字
chunk_overlap=30, # 块间重叠30字
separator="\n\n", # 按段落分割(固定分隔符)
length_function=len
)
# --------------------------
# 3. 执行切割与输出
# --------------------------
chunks = splitter.split_text(sample_text)
print(f"✅ 切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 块")
print(chunk)
print("-" * 80)
3.2.4 优缺点与适用场景
- ✅ 优点:实现简单,速度快,适合结构非常规整的文本(如按段落分隔的文档)
- ❌ 缺点:不做递归尝试,若单个段落超过
chunk_size,会直接切断句子,语义断裂严重 - 适用场景:结构极其简单的纯文本、批量处理低质量文档(如爬虫原始文本)
3.3 MarkdownHeaderTextSplitter:结构化 Markdown 文档专用分割器
3.3.1 核心原理
专门为 Markdown 文档设计的分割器,会按 Markdown 的标题层级 (如# 一级标题、## 二级标题、### 三级标题)切割,自动将标题与对应的正文绑定,保留文档的层级结构,完美解决 Markdown 文档的语义保留问题。
3.3.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
headers_to_split_on |
定义要切割的标题层级列表,格式为[(分隔符, 元数据键名)] |
[("#", "Header 1"), ("##", "Header 2"), ("###", "Header 3")] |
return_each_line |
是否将每一行单独作为一个块(默认 False) | False(推荐) |
strip_headers |
是否在块内容中移除标题文本(默认 True) | False(保留标题,方便溯源) |
3.3.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备Markdown格式测试文本(包含多级标题)
# --------------------------
sample_markdown = """
# 人工智能简介
人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。
## 核心分支
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。
### 主要研究方向
该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
## 发展前景
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。
"""
# --------------------------
# 2. 初始化Markdown标题分割器
# --------------------------
# 定义要处理的标题层级:一级、二级、三级标题
headers_to_split_on = [
("#", "Header 1"), # 一级标题,元数据键名设为Header 1
("##", "Header 2"), # 二级标题,元数据键名设为Header 2
("###", "Header 3") # 三级标题,元数据键名设为Header 3
]
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=headers_to_split_on,
strip_headers=False # 保留标题文本,块内容中会包含标题
)
# --------------------------
# 3. 执行切割与输出(会返回Document对象,包含标题元数据)
# --------------------------
chunks = splitter.split_text(sample_markdown)
print(f"✅ 切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 块(标题层级:{chunk.metadata})")
print(chunk.page_content)
print("-" * 80)
3.3.4 运行结果与说明
- 每个块会自动包含标题层级的元数据,比如
{"Header 1": "人工智能简介", "Header 2": "核心分支", "Header 3": "主要研究方向"} - 切割会严格按标题边界进行,正文会和对应的标题绑定,不会出现标题与正文分离的情况
- 适合 Markdown 格式的技术文档、笔记、API 文档,是结构化文本 RAG 的首选分割器
3.4 PythonCodeTextSplitter:代码文件专用分割器
3.4.1 核心原理
专门为 Python 代码文件设计的分割器,会按 Python 的语法结构(如函数、类、注释、换行)切割,避免将一个函数 / 类拆成两半,同时控制块的大小,是代码库 RAG 的必备工具。
3.4.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
chunk_size |
单个代码块的最大字符数 | 500~1000(根据代码复杂度调整) |
chunk_overlap |
相邻块之间的重叠字符数 | chunk_size的 10%~20% |
language |
代码语言,可通过Language枚举指定(如Language.PYTHON) |
Language.PYTHON |
3.4.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备Python代码测试文本(包含函数、类、注释)
# --------------------------
sample_code = """
class Calculator:
\"\"\"简单计算器类,支持加减乘除运算\"\"\"
def __init__(self):
self.result = 0
def add(self, a, b):
\"\"\"加法运算:返回a + b\"\"\"
self.result = a + b
return self.result
def subtract(self, a, b):
\"\"\"减法运算:返回a - b\"\"\"
self.result = a - b
return self.result
def multiply(self, a, b):
\"\"\"乘法运算:返回a * b\"\"\"
self.result = a * b
return self.result
def greet(name):
\"\"\"打招呼函数,返回问候语\"\"\"
return f"Hello, {name}!"
# 主程序入口
if __name__ == "__main__":
calc = Calculator()
print(calc.add(5, 3))
print(greet("LangChain"))
"""
# --------------------------
# 2. 初始化Python代码分割器
# --------------------------
splitter = PythonCodeTextSplitter(
chunk_size=300, # 单个代码块最大字符数:300字
chunk_overlap=50, # 块间重叠50字,避免函数被切断
length_function=len
)
# --------------------------
# 3. 执行切割与输出
# --------------------------
chunks = splitter.split_text(sample_code)
print(f"✅ 代码切割完成!共生成 {len(chunks)} 个代码块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 个代码块")
print(chunk)
print("-" * 80)
3.4.4 运行结果与说明
- 代码会按函数 / 类的边界切割,不会出现函数被拆成两半的情况
- 块间重叠会包含函数的开头 / 结尾,避免上下文丢失
- 适合 Python 代码库的 RAG 场景,比如代码问答助手、API 文档检索
3.5 TokenTextSplitter:按模型 Token 数量切割(适配 GPT-3.5/4)
3.5.1 核心原理
按模型 Token 数量切割文本,而不是按字符数,严格控制每个块的 Token 数不超过模型上下文限制,避免超出模型输入长度导致报错,是对 Token 敏感场景的必备工具。
3.5.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
chunk_size |
单个文本块的最大 Token 数 | 200~1000(根据模型上下文调整,如 GPT-3.5/4 推荐 512) |
chunk_overlap |
相邻块之间的重叠 Token 数 | chunk_size的 10%~20% |
encoding_name |
Token 编码名称,如cl100k_base(GPT-3.5/4 使用) |
cl100k_base |
3.5.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备测试文本(通用长文本)
# --------------------------
sample_text = """
人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。人工智能可以对人的意识、思维的信息过程的模拟。人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。
人工智能是一门极富挑战性的科学,从事这项工作的人必须懂得计算机知识、心理学和哲学。人工智能包括十分广泛的科学,它由不同的领域组成,如机器学习、计算机视觉等。
"""
# --------------------------
# 2. 初始化Token分割器(适配GPT-3.5/4的cl100k编码)
# --------------------------
splitter = TokenTextSplitter(
chunk_size=100, # 单个块最大Token数:100(适配GPT-3.5/4的上下文限制)
chunk_overlap=20, # 块间重叠20个Token
encoding_name="cl100k_base" # 使用GPT-3.5/4的Token编码
)
# --------------------------
# 3. 执行切割与输出(附带Token数统计)
# --------------------------
chunks = splitter.split_text(sample_text)
print(f"✅ Token切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
# 加载GPT-3.5/4的Token编码器,统计每个块的实际Token数
encoding = tiktoken.get_encoding("cl100k_base")
for idx, chunk in enumerate(chunks):
token_count = len(encoding.encode(chunk))
print(f"📦 第 {idx+1} 块(Token数:{token_count})")
print(chunk)
print("-" * 80)
3.5.4 运行结果与说明
- 每个块的 Token 数严格控制在
chunk_size以内,不会超出模型上下文限制 - 适合使用 GPT-3.5/4 等对 Token 数敏感的模型的 RAG 场景,避免因块过大导致模型报错
- 缺点是无视语义结构,可能会切断句子,需结合语义边界优化
3.6 HTMLHeaderTextSplitter:HTML 网页专用分割器
3.6.1 核心原理
专门为 HTML 网页设计的分割器,会按 HTML 的标题标签层级 (如<h1>、<h2>、<h3>)切割,自动将标签内容与对应的层级绑定,保留网页的结构信息,适合爬取的结构化网页文档。
3.6.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
headers_to_split_on |
定义要切割的 HTML 标签层级列表,格式为[(标签名, 元数据键名)] |
[("h1", "Header 1"), ("h2", "Header 2"), ("h3", "Header 3")] |
return_each_line |
是否将每一行单独作为一个块(默认 False) | False(推荐) |
3.6.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备HTML格式测试文本(包含多级标题标签)
# --------------------------
sample_html = """
<html>
<body>
<h1>人工智能简介</h1>
<p>人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。</p>
<h2>核心分支</h2>
<p>人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。</p>
<h3>主要研究方向</h3>
<p>该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。</p>
<h2>发展前景</h2>
<p>人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。</p>
</body>
</html>
"""
# --------------------------
# 2. 初始化HTML标题分割器
# --------------------------
# 定义要处理的HTML标题标签层级:h1、h2、h3
headers_to_split_on = [
("h1", "Header 1"), # 一级标题标签
("h2", "Header 2"), # 二级标题标签
("h3", "Header 3") # 三级标题标签
]
splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
# --------------------------
# 3. 执行切割与输出(会返回Document对象,包含标签元数据)
# --------------------------
chunks = splitter.split_text(sample_html)
print(f"✅ HTML切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 块(标题层级:{chunk.metadata})")
print(chunk.page_content)
print("-" * 80)
3.6.4 运行结果与说明
- 每个块会自动包含 HTML 标题标签的元数据,比如
{"Header 1": "人工智能简介", "Header 2": "核心分支", "Header 3": "主要研究方向"} - 切割会严格按标题标签边界进行,段落内容会和对应的标题绑定,不会出现标题与正文分离的情况
- 适合爬取的 HTML 网页文档、结构化网页数据的 RAG 场景
3.7 SentenceTransformersTokenTextSplitter:语义 Token 分割器(进阶)
3.7.1 核心原理
基于 Sentence-Transformers 模型的 Token 分割器,会按语义边界切割文本,同时控制 Token 数量,兼顾语义连贯性和模型上下文限制,是进阶 RAG 场景的优化方案。
3.7.2 核心参数详解
表格
| 参数 | 作用 | 推荐值 |
|---|---|---|
chunk_size |
单个文本块的最大 Token 数 | 200~512 |
chunk_overlap |
相邻块之间的重叠 Token 数 | chunk_size的 10% |
model_name |
Sentence-Transformers 模型名称,如all-MiniLM-L6-v2 |
all-MiniLM-L6-v2(轻量高效) |
3.7.3 实战代码(超详细注释版)
python
运行
python
# --------------------------
# 1. 准备测试文本(通用长文本)
# --------------------------
sample_text = """
人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。人工智能可以对人的意识、思维的信息过程的模拟。人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。
"""
# --------------------------
# 2. 初始化语义Token分割器(需提前安装sentence-transformers)
# --------------------------
splitter = SentenceTransformersTokenTextSplitter(
chunk_size=100, # 单个块最大Token数:100
chunk_overlap=20, # 块间重叠20个Token
model_name="all-MiniLM-L6-v2" # 轻量语义模型,适合中文/英文
)
# --------------------------
# 3. 执行切割与输出
# --------------------------
chunks = splitter.split_text(sample_text)
print(f"✅ 语义Token切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 块")
print(chunk)
print("-" * 80)
3.7.4 优缺点与适用场景
- ✅ 优点:兼顾语义连贯性和 Token 数控制,比普通 Token 分割器更适合语义检索
- ❌ 缺点:速度较慢,依赖额外的 Sentence-Transformers 模型,计算成本较高
- 适用场景:对语义连贯性要求高的进阶 RAG 场景、长文本检索优化
3.8 自定义语义分割器:结合向量相似度的进阶方案(拓展)
3.8.1 核心原理
结合文本向量化和相似度计算,按语义边界切割文本,将语义相关的句子合并为一个块,最大限度保留语义连贯性,是当前 RAG 领域的进阶优化方案。
3.8.2 实战代码(超详细注释版,基于 LangChain 实现)
python
运行
python
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import TextSplitter
from langchain.schema import Document
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# --------------------------
# 1. 自定义语义分割器类(基于向量相似度)
# --------------------------
class SemanticTextSplitter(TextSplitter):
def __init__(self, chunk_size: int = 500, similarity_threshold: float = 0.7):
"""
初始化语义分割器
:param chunk_size: 单个文本块的最大字符数
:param similarity_threshold: 语义相似度阈值,低于该值则分割
"""
super().__init__()
self.chunk_size = chunk_size
self.similarity_threshold = similarity_threshold
# 加载轻量向量化模型
self.embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
def split_text(self, text: str) -> List[str]:
"""按语义相似度切割文本"""
# 第一步:按句子分割文本(简单按句号分割,可根据语言调整)
sentences = [s.strip() for s in text.split("。") if s.strip()]
if not sentences:
return []
# 第二步:对每个句子生成向量
sentence_embeddings = self.embeddings.embed_documents(sentences)
sentence_embeddings = np.array(sentence_embeddings)
# 第三步:按相似度合并句子
chunks = []
current_chunk = sentences[0]
current_embedding = sentence_embeddings[0]
for i in range(1, len(sentences)):
next_sentence = sentences[i]
next_embedding = sentence_embeddings[i]
# 计算当前块与下一个句子的余弦相似度
similarity = cosine_similarity([current_embedding], [next_embedding])[0][0]
# 如果相似度低于阈值,或合并后超过chunk_size,则分割
if similarity < self.similarity_threshold or len(current_chunk + next_sentence) > self.chunk_size:
chunks.append(current_chunk)
current_chunk = next_sentence
current_embedding = next_embedding
else:
# 合并句子,更新当前块的向量(取平均值)
current_chunk += "。" + next_sentence
current_embedding = (current_embedding + next_embedding) / 2
# 添加最后一个块
if current_chunk:
chunks.append(current_chunk)
return chunks
# --------------------------
# 2. 准备测试文本(通用长文本)
# --------------------------
sample_text = """
人工智能(AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的"容器"。人工智能可以对人的意识、思维的信息过程的模拟。人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。
"""
# --------------------------
# 3. 初始化并执行自定义语义分割器
# --------------------------
splitter = SemanticTextSplitter(
chunk_size=500,
similarity_threshold=0.7 # 相似度低于0.7则分割
)
chunks = splitter.split_text(sample_text)
print(f"✅ 自定义语义切割完成!共生成 {len(chunks)} 个文本块")
print("=" * 80)
for idx, chunk in enumerate(chunks):
print(f"📦 第 {idx+1} 块")
print(chunk)
print("-" * 80)
3.8.3 优缺点与适用场景
- ✅ 优点:语义保留效果最优,能将语义相关的句子合并为一个块,大幅提升检索质量
- ❌ 缺点:实现复杂,计算成本高,速度较慢,依赖向量化模型
- 适用场景:对检索质量要求极高的进阶 RAG 场景、长文本语义检索优化
四、实战避坑指南:常见问题与解决方案
4.1 坑点 1:切割后块的 Token 数超出模型上下文限制
- 问题:用
RecursiveCharacterTextSplitter按字符数切割,但模型按 Token 数限制,导致块过大报错 - 解决方案:改用
TokenTextSplitter,或自定义length_function为len(encoding.encode(chunk)),按 Token 数控制块大小
python
运行
python
# 自定义length_function,按GPT-3.5/4的Token数控制块大小
from langchain_text_splitters import RecursiveCharacterTextSplitter
import tiktoken
encoding = tiktoken.get_encoding("cl100k_base")
def tiktoken_length(text: str) -> int:
return len(encoding.encode(text))
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
length_function=tiktoken_length # 用Token数控制块大小
)
4.2 坑点 2:Markdown/HTML 文档切割后结构丢失,标题与正文分离
- 问题:用普通分割器切割 Markdown/HTML 文档,导致标题和正文被分开,语义断裂
- 解决方案:改用
MarkdownHeaderTextSplitter或HTMLHeaderTextSplitter,按标题层级切割,保留结构元数据
4.3 坑点 3:代码文件切割后函数 / 类被拆成两半,无法被正确检索
- 问题:用普通分割器切割 Python 代码,导致函数被切断,检索时只能匹配到部分代码
- 解决方案:改用
PythonCodeTextSplitter,按 Python 语法结构切割,避免破坏代码结构
4.4 坑点 4:块间重叠设置不当,导致上下文丢失或冗余
- 问题:
chunk_overlap设置为 0,相邻块无重叠,导致句子 / 段落被切断;设置过大,导致块间冗余严重,检索效率低 - 解决方案:
chunk_overlap设置为chunk_size的 10%~20%,兼顾语义连贯性和检索效率
4.5 坑点 5:非结构化文本切割效果差,语义断裂严重
- 问题:爬虫文本、OCR 文本等非结构化文档,用普通分割器切割效果差,语义断裂严重
- 解决方案:先用
UnstructuredLoader清洗文本,再用RecursiveCharacterTextSplitter或自定义语义分割器切割
五、实战组合方案:不同场景的最优切割策略
5.1 通用场景(TXT/Word/ 通用文档)
- 推荐组合:
RecursiveCharacterTextSplitter+ 按 Token 数控制chunk_size - 配置建议:
chunk_size=500~1000,chunk_overlap=50~100,separators=["\n\n", "\n", " ", ""]
5.2 Markdown 技术文档场景
- 推荐组合:
MarkdownHeaderTextSplitter+RecursiveCharacterTextSplitter(二次切割超长段落) - 配置建议:先按标题层级切割,再对超过
chunk_size的段落用递归分割器二次切割
5.3 代码库场景(Python/Java 等)
- 推荐组合:
PythonCodeTextSplitter(或对应语言的分割器) +TokenTextSplitter(按 Token 数二次控制) - 配置建议:
chunk_size=500~1000,chunk_overlap=50~100,避免函数 / 类被切断
5.4 长文本 / 语义敏感场景
- 推荐组合:
SentenceTransformersTokenTextSplitter或 自定义语义分割器 - 配置建议:
chunk_size=200~512,similarity_threshold=0.6~0.8,兼顾语义和 Token 数
六、进阶优化:切割效果评估与调参技巧
6.1 切割效果评估指标
- 语义连贯性:块内句子是否完整,无明显语义断裂
- 块大小一致性:所有块的长度 / Token 数是否在目标范围内,无过大 / 过小的块
- 元数据完整性:结构化文档的标题 / 标签元数据是否完整保留
- 检索准确率:切割后的块在向量数据库中检索时,是否能返回完整的上下文
6.2 调参技巧
- 先小批量测试:用少量文档测试不同
chunk_size和chunk_overlap的效果,避免全量数据返工 - 结合模型上下文:根据使用的模型调整
chunk_size,如 GPT-3.5/4 推荐chunk_size=512~1024,避免超出上下文限制 - 针对文档类型调整:Markdown/HTML 文档优先用结构化分割器,通用文本用递归分割器
- 逐步优化:先使用默认配置,再根据检索结果调整
chunk_overlap和separators
七、结语:从 "会用" 到 "用好",切割是 RAG 的第一道门槛
文档切割看似简单,实则是 RAG 系统中影响检索质量的核心环节。LangChain 提供了丰富的分割器工具,从通用的递归字符分割器,到结构化的 Markdown/HTML 分割器,再到进阶的语义分割器,覆盖了绝大多数场景的需求。
但工具只是基础,真正的 "用好" 需要结合业务场景、文档类型和模型特性,选择合适的分割策略,甚至自定义分割器。只有做好了切割这一步,后续的向量化、检索、生成环节才能发挥出最佳效果。
**👉 关注我!点赞 + 收藏 + 评论 "想要",私信我即可免费领取!**后续还会持续更新 LangChain 进阶、向量数据库优化、大模型微调等干货内容,带你从 0 到 1 搭建企业级 RAG 系统,再也不用为 "切分差、检索不准、生成胡说八道" 发愁!你的三连是我持续输出干货的最大动力!