🎯 课程主题
学习 LangChain 中除递归字符切分(RecursiveCharacterTextSplitter)之外的多种 TextSplitter:基于 Token 数切分、语义分块、HTML/代码/Markdown 切分。
📝 核心知识点
1. TokenTextSplitter — 按 Token 数切分
- 为何按 Token 切分:LLM 的输入输出上限和计费标准均以 Token 为基本单位,按 Token 切分能统一度量标准。
- 编码器(Encoder)的作用:字符数与 Token 数需要转换映射,因此必须指定编码器(如 OpenAI 的
tiktoken)。 - 语义兼顾:实际操作中发现,TokenTextSplitter 有一定的回溯机制,能兼顾自然语言边界,不会粗暴地截断句子。
- 使用场景:需要精确控制 Token 数的场景。常规文本处理仍推荐优先使用递归字符切分。
2. 基于 CharacterTextSplitter 的 Token 切分
CharacterTextSplitter.from_tiktoken_encoder() 同样可以按 Token 数切分,只需指定编码器即可。
3. SemanticChunker — 语义分块
原理:通过 Embedding 模型判断句子间的语义相似度,在相似度"断崖"处切分。
劣势:需要额外引入 Embedding 模型进行向量化,成本较高、速度较慢。
核心参数:
参数 含义 breakpoint_threshold_type临界类型: percentile(百分位数)、standard_deviation(标准差)、interquartile(四分位距)、gradient(梯度)breakpoint_threshold阈值,超过则切分。值越小→切分越多→碎片化严重;值越大→切分越少→文档块越大 阈值类型选择建议:
- 百分位数(percentile):常规报告文档
- 标准差(standard_deviation):内容剧烈变化的技术文档
- 梯度(gradient):长文档
工作流程:先用正则(句号、问号、感叹号等)拆分为独立句子 → 计算句子间相似度 → 低于阈值则切一刀。
4. 其他专用 Splitter
| Splitter | 用途 |
|---|---|
| HTMLHeaderTextSplitter | 按 HTML 标题层级切分页面 |
| RecursiveCharacterTextSplitter (Code) | 按代码结构切分,支持 Python 等主流语言 |
| MarkdownHeaderTextSplitter | 按 Markdown 标题层级切分 |
🏗️ 架构与工作流
原始文本
│
├── TokenTextSplitter(chunk_size=33, chunk_overlap=0, encoding_name="cl100k_base")
│ └── 按 Token 数切分 → List[str]
│
├── SemanticChunker(embedding_model, breakpoint_threshold_type="percentile", breakpoint_threshold=95)
│ └── 按语义相似度切分 → List[str]
│
├── HTMLHeaderTextSplitter → 按标题层级切分
├── CodeTextSplitter → 按代码结构切分
└── MarkdownHeaderTextSplitter → 按 Markdown 标题切分
💻 代码实战
TokenTextSplitter 示例
from langchain_text_splitters import TokenTextSplitter
text = "在人工智能领域,自然语言处理是核心研究方向之一..."
token_splitter = TokenTextSplitter(
chunk_size=33,
chunk_overlap=0,
encoding_name="cl100k_base" # OpenAI 编码器
)
chunks = token_splitter.split_text(text)
# 结果会兼顾语义边界,不完全按 33 token 硬截断
CharacterTextSplitter 的 Token 变体
from langchain_text_splitters import CharacterTextSplitter
splitter = CharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base",
chunk_size=33,
chunk_overlap=0
)
chunks = splitter.split_text(text)
SemanticChunker 示例
from langchain_text_splitters import SemanticChunker
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings(
model="text-embedding-3-small",
api_key="sk-xxx",
base_url="https://api.openai.com/v1"
)
semantic_splitter = SemanticChunker(
embeddings=embedding,
breakpoint_threshold_type="percentile",
breakpoint_threshold=95
)
# 加载文档
with open("data/sample.txt", "r", encoding="utf-8") as f:
text = f.read()
chunks = semantic_splitter.split_text(text)
print(f"共切分成 {len(chunks)} 个块")
CodeTextSplitter 示例
from langchain_text_splitters import RecursiveCharacterTextSplitter
python_splitter = RecursiveCharacterTextSplitter.from_language(
language="python",
chunk_size=200,
chunk_overlap=20
)
code_chunks = python_splitter.split_text(python_code)
⚠️ 常见问题与避坑指南
- TokenTextSplitter 的 chunk_size 指 Token 数而非字符数,切勿与字符切分混淆。
- SemanticChunker 必须指定
embeddings参数,否则无法计算语义相似度。 - 语义分块阈值调优:阈值设太小会导致碎片化严重,太大则几乎不切。建议根据文档类型选择对应的
breakpoint_threshold_type策略。 - 费用注意:语义分块会对全文进行 Embedding 调用,文档量大时注意 API 费用。
💡 个人总结与延伸
- 优先推荐递归字符切分(RecursiveCharacterTextSplitter),它最贴近人类文本的自然边界,大多数场景够用。
- Token 切分适用于需要精确控制 Token 数的场景(如拼接 Prompt 时做预算控制)。
- 语义分块理论上最理想,但实践中成本和速度是主要瓶颈,适合对切分质量要求极高的场景。
- 代码/HTML/Markdown 专用切分器在实际 RAG 项目中非常实用,能保留文档结构信息。