数据清洗与预处理(Data Cleaning & Preprocessing)
将原始混乱数据转化为干净、结构化、模型可用格式的系统化过程
将长文本切成小块供向量检索使用,是 RAG 系统的必备预处理环节。
内容摘要
文本分割(Text Splitting / Chunking)做的事情很直白:把一篇长文档切成若干小块,每块单独送去做向量嵌入和检索。在 RAG(Retrieval-Augmented Generation,检索增强生成)系统中,你不可能把整本书一次塞给 LLM,必须先切块、再检索相关片段、最后把片段喂给模型生成回答。切得好不好,直接决定检索质量——切太大,检索不精准;切太小,上下文丢失。
文本分割(Text Splitting / Chunking)做的事情很直白:把一篇长文档切成若干小块,每块单独送去做向量嵌入和检索。在 RAG(Retrieval-Augmented Generation,检索增强生成)系统中,你不可能把整本书一次塞给 LLM,必须先切块、再检索相关片段、最后把片段喂给模型生成回答。切得好不好,直接决定检索质量——切太大,检索不精准;切太小,上下文丢失。
LangChain 提供的 langchain-text-splitters 是目前最主流的文本分割工具库,内置了多种分割策略,从最简单的固定长度切割到基于语义相似度的智能切割都有覆盖。
| 要素 | 作用 |
|---|---|
| 分割策略(Splitter) | 决定在哪里下刀——按字符数、按段落层级递归、按语义边界等 |
| 分块大小(chunk_size) | 每块的最大长度上限,通常 256-512 个 token,直接影响检索粒度 |
| 重叠区(chunk_overlap) | 相邻块之间的重复部分,防止关键信息正好被切断 |
LangChain 内置了多种分割器,各有适用场景:
| 分割器 | 一句话说明 | 适用场景 |
|---|---|---|
CharacterTextSplitter | 按单一分隔符(如换行符)切割 | 结构简单的纯文本 |
RecursiveCharacterTextSplitter | 按段落→句子→词逐级递归切割 | 通用推荐,大多数场景首选 |
TokenTextSplitter | 按 LLM 实际 token 数切割 | 需要精确控制 token 数的场景 |
MarkdownHeaderTextSplitter | 按 Markdown 标题层级切割 | Markdown 文档 |
HTMLHeaderTextSplitter | 按 HTML 标签结构切割 | 网页内容 |
| 语义分割(Semantic Chunking) | 用嵌入模型计算句子相似度,在语义转折处切割 | 高质量知识库、学术文档 |
RecursiveCharacterTextSplitter 是官方推荐的通用选择。它的切割逻辑是:先尝试在段落处(\n\n)切,如果单段太长就降级到句子(\n),再不行就按空格切,最后才逐字符切。这样能最大程度保留语义完整性。
分块大小是最影响 RAG 效果的参数。实践中的推荐值:
重叠区的作用是防止关键句子正好被切断。推荐设置为 chunk_size 的 10%-20%。例如 chunk_size=500 时,chunk_overlap 设为 50-100。
安装依赖:
pip install langchain-text-splitters>=0.3.0
最小可运行示例(基于 langchain-text-splitters==0.3.8 验证,截至 2026-03):
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 模拟一段 Agent 开发文档
document = """
RAG 是检索增强生成的缩写,核心思路是先检索再生成。
系统收到用户问题后,先从知识库中检索相关片段,再把片段和问题一起交给 LLM 生成回答。
RAG 的优势在于:不需要重新训练模型就能让 LLM 获取最新知识。
企业可以把内部文档灌进向量数据库,员工提问时自动检索相关内容。
文本分割是 RAG 的第一步。把文档切成小块后分别做嵌入,
检索时只取最相关的几块喂给模型,既省 token 又提高准确率。
分块大小的选择很关键。太大的块检索不精准,太小的块缺乏上下文。
一般推荐 300-500 个 token,重叠 10%-20%。
""" * 3 # 重复 3 次模拟更长的文本
# 创建递归字符分割器(通用推荐)
splitter = RecursiveCharacterTextSplitter(
chunk_size=200, # 每块最多 200 字符
chunk_overlap=30, # 相邻块重叠 30 字符
separators=["\n\n", "\n", "。", " ", ""] # 中文优化的分割优先级
)
# 执行分割
chunks = splitter.split_text(document)
# 查看结果
print(f"原始文档长度: {len(document)} 字符")
print(f"分割后块数: {len(chunks)}")
print()
for i, chunk in enumerate(chunks[:3]):
print(f"--- 块 {i+1}({len(chunk)} 字符)---")
print(chunk)
print()
预期输出:
原始文档长度: 918 字符
分割后块数: 7
--- 块 1(198 字符)---
RAG 是检索增强生成的缩写,核心思路是先检索再生成。
系统收到用户问题后,先从知识库中检索相关片段,再把片段和问题一起交给 LLM 生成回答。
RAG 的优势在于:不需要重新训练模型就能让 LLM 获取最新知识
--- 块 2(186 字符)---
企业可以把内部文档灌进向量数据库,员工提问时自动检索相关内容。
文本分割是 RAG 的第一步。把文档切成小块后分别做嵌入,
检索时只取最相关的几块喂给模型,既省 token 又提高准确率
--- 块 3(183 字符)---
分块大小的选择很关键。太大的块检索不精准,太小的块缺乏上下文。
一般推荐 300-500 个 token,重叠 10%-20%。
...
Markdown 文档分割示例:
from langchain_text_splitters import MarkdownHeaderTextSplitter
md_doc = """
# Agent 框架概述
Agent 是能自主执行任务的 AI 系统。
## LangChain
LangChain 是最流行的 Agent 开发框架,生态丰富。
### 核心组件
包括 Chain、Agent、Memory、Retriever 四大组件。
## LangGraph
LangGraph 用有向图编排 Agent 流程,支持循环和分支。
"""
# 按标题层级切割,自动保留层级信息作为元数据
md_splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[
("#", "h1"),
("##", "h2"),
("###", "h3"),
]
)
md_chunks = md_splitter.split_text(md_doc)
for chunk in md_chunks:
print(f"内容: {chunk.page_content[:40]}...")
print(f"元数据: {chunk.metadata}")
print()
预期输出:
内容: Agent 是能自主执行任务的 AI 系统。...
元数据: {'h1': 'Agent 框架概述'}
内容: LangChain 是最流行的 Agent 开发框架,生态丰富。...
元数据: {'h1': 'Agent 框架概述', 'h2': 'LangChain'}
内容: 包括 Chain、Agent、Memory、Retriever 四大组件。...
元数据: {'h1': 'Agent 框架概述', 'h2': 'LangChain', 'h3': '核心组件'}
内容: LangGraph 用有向图编排 Agent 流程,支持循环和分支。...
元数据: {'h1': 'Agent 框架概述', 'h2': 'LangGraph'}
Markdown 分割器的特点:切出来的每块自动带上所属的标题层级作为元数据,检索时可以利用这些元数据做过滤。
| 维度 | LangChain Text Splitters | LlamaIndex NodeParser | Semantic Text Splitter |
|---|---|---|---|
| 核心定位 | 通用文本分割工具库 | RAG 框架内置的文档解析器 | 专注语义边界检测的分割器 |
| 最擅长 | 多种策略开箱即用,生态最大 | 与 LlamaIndex 深度集成 | 基于嵌入的高精度语义切割 |
| 学习曲线 | 低,API 简洁直观 | 中,需要理解 LlamaIndex 体系 | 中,需要配置嵌入模型 |
| 适合人群 | 大多数 RAG 开发者 | 已使用 LlamaIndex 的团队 | 对分块质量有极高要求的场景 |
核心区别:
| 误区 | 准确理解 |
|---|---|
| 分块越小检索越精准 | 块太小会丢失上下文,模型拿到的片段可能不够理解问题。推荐 256-512 token |
| 所有文档用同一套参数 | 代码、文章、表格特性不同,应该用不同的分割策略和参数 |
| 重叠设得越大越安全 | 重叠过大导致大量冗余存储和重复检索结果,10%-20% 足够 |
| 分割只需要做一次 | 分割策略需要根据下游检索效果持续调优,不是一劳永逸的 |
| 优势 | 劣势 |
|---|---|
| 开箱即用,几行代码完成分割 | 固定规则分割无法理解真正的语义边界 |
| 策略丰富,覆盖纯文本/代码/Markdown/HTML | 中文场景下默认分隔符需要手动调整 |
| 与 LangChain 生态无缝集成 | 语义分割依赖嵌入模型,增加计算成本 |
| 轻量级,无重型依赖 | 参数调优(chunk_size、overlap)需要实验摸索 |
参考答案:
CharacterTextSplitter 只按单一分隔符(如 \n\n)切割,碰到一个超长段落就无能为力——整段超出 chunk_size 也只能硬切。
RecursiveCharacterTextSplitter 用多级分隔符递归切割:先尝试按段落切,段落太长就降级到句子,再不行降级到词。这样能在满足大小限制的同时最大化保留语义完整性,所以是通用场景的推荐选择。
参考答案:
中文文档的默认英文分隔符不太好用,建议改为:["\n\n", "\n", "。", ";", ",", " ", ""]。
理由:中文句子以句号(。)结尾而非英文句点(.),分号(;)标记并列关系的断句,逗号(,)是最小的语义停顿。按这个优先级递归,能在中文语境下更好地保留语义边界。
参考答案:
找最优值的方法:以 256-512 token 为起点,在实际 RAG 系统中用评测集做 A/B 测试,比较不同 chunk_size 下的检索召回率和最终回答质量(如 F1 分数),选效果最好的。没有放之四海而皆准的数值,需要根据具体文档和任务实验确定。
优先展示同分类且标签更接近的内容,方便继续串联学习。
将原始混乱数据转化为干净、结构化、模型可用格式的系统化过程
LangChain 官方可观测性与评估平台,提供端到端追踪、自动化评估和生产监控。
用视觉语言大模型直接"看图识字",不只提取字符,还能理解文档结构和语义。