大家好,我是工藤学编程 🦉 一个正在努力学习的小博主,期待你的关注
实战代码系列最新文章😉 C++实现图书管理系统(Qt C++ GUI界面版)
SpringBoot实战系列🐷 【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案
分库分表 分库分表之实战-sharding-JDBC分库分表执行流程原理剖析
消息队列 深入浅出 RabbitMQ-RabbitMQ消息确认机制(ACK)
AI大模型 零基础学AI大模型之RAG系统链路构建:文档切割转换全解析

前情摘要
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实战
21、零基础学AI大模型之RAG系统链路构建:文档切割转换全解析

本文章目录

零基础学 AI 大模型之 LangChain 文本分割器实战:CharacterTextSplitter 与 RecursiveCharacterTextSplitter 全解析

在上一篇文章中,咱们搞定了LangChain的Document Loaders模块,成功实现了PDF、网页、Word等多种文档的加载。但加载后的文档往往存在一个问题——文本太长!大模型都有固定的输入长度限制(比如GPT-3.5-Turbo默认4k token),直接把整篇文档喂进去会报错;更重要的是,长文本会导致大模型抓不住重点,检索时匹配精度大幅下降。

这时候就需要「文本分割器(Text Splitter)」登场了!它就像一把精准的“剪刀”,能把长文档按照合理的规则切成一个个大小适中的文本块(chunk),既满足大模型的输入限制,又能最大程度保留文本的语义完整性。

今天咱们就聚焦LangChain中最常用的两个分割器:CharacterTextSplitter(基础字符分割器)RecursiveCharacterTextSplitter(递归字符分割器),从核心原理、实战案例、参数调优到避坑指南,一次性讲透!

请添加图片描述

一、为什么需要文本分割器?先搞懂3个核心原因

在动手实战前,先明确文本分割的必要性,避免盲目使用:

  1. 适配大模型输入限制:所有大模型都有最大token长度限制(比如GPT-4 Turbo支持128k token,但普通模型多为4k/8k),超过限制会直接拒绝处理;
  2. 提升检索精度:RAG系统中,分割后的小文本块能更精准地与用户查询匹配(比如查询“数据库连接错误”,直接匹配到日志中的对应片段,而不是整个日志文件);
  3. 减少语义丢失:合理的分割规则能避免把完整的语义单元(比如一个段落、一个句子)切断,让大模型理解更连贯。

简单说:Loaders负责“把文档拿进来”,Splitter负责“把文档切好”,这两步是RAG系统的基础,缺一不可!

二、CharacterTextSplitter:基础字符分割器实战

2.1 核心特点:简单直接的“固定长度切割”

CharacterTextSplitter是LangChain中最基础的文本分割器,核心逻辑很简单:按照指定的分隔符,把文本切成固定字符长度的块

它的优势在于:

  • 速度极快(时间复杂度O(n)),内存消耗极低;
  • 精确控制块长度,适合结构规整的文本;
    局限性也很明显:
  • 不考虑语义结构,可能切断完整句子/段落;
  • 对无规律文本处理效果差。

2.2 核心参数详解

参数 类型 默认值 关键说明
separator str “\n\n” 切割文本的分隔符(比如空格、换行、句号)
chunk_size int 4000 每个文本块的最大字符数(核心参数)
chunk_overlap int 200 相邻文本块的重叠字符数(用于保留上下文,必须小于chunk_size)
strip_whitespace bool True 是否清除文本块首尾的空格(推荐开启,避免多余空白)
is_separator_regex bool False 是否将分隔符视为正则表达式(比如用\s+匹配任意空白字符)

2.3 实战案例1:处理长文本(按空格分割)

场景:有一段混合中英文的长文本,需要按空格分割,每个块不超过50个字符,相邻块重叠10个字符。

# 导入分割器
from langchain.text_splitter import CharacterTextSplitter

# 待分割的长文本
text = """是一段 需要被分割的 长文本示例....,每个文本块的最大长度(字符数或token数)
Document loaders are designed to load document objects. LangChain has 
hundreds of integrations with various data sources to load data from: 
Slack, Notion, Google Drive"""

# 初始化分割器
splitter = CharacterTextSplitter(
    separator=" ",  # 按空格分割
    chunk_size=50,  # 每个块最大50个字符
    chunk_overlap=10,  # 相邻块重叠10个字符
    strip_whitespace=True  # 清除首尾空格
)

# 执行分割
chunks = splitter.split_text(text)

# 输出结果
print(f"分割后共得到 {len(chunks)} 个文本块:")
for i, chunk in enumerate(chunks, 1):
    print(f"\n块{i}(长度:{len(chunk)}):{chunk}")

2.4 运行结果与分析

分割后共得到 4 个文本块:

块1(长度:49):是一段 需要被分割的 长文本示例....,每个文本块的最大长度(字符数或token数)

块2(长度:49):Document loaders are designed to load document objects. LangChain has

块3(长度:48):has hundreds of integrations with various data sources to load data

块4(长度:24):from: Slack, Notion, Google Drive

关键观察:

  • 相邻块(比如块2和块3)有重叠的“has”(对应chunk_overlap=10),保留了上下文;
  • 分割严格按照空格执行,未考虑句子边界(比如块2结尾切断了“LangChain has”)。

2.5 实战案例2:处理日志文件(按换行分割)

在这里插入图片描述

场景:日志文件每行是一个独立的日志条目,结构规整,需要按换行分割,避免切断单条日志。

from langchain.text_splitter import CharacterTextSplitter

# 模拟日志数据
log_data = """
[ERROR] 2026-03-15 14:22:35 - Database connection failed
[INFO] 2026-03-15 14:23:10 - Retrying connection...
[WARNING] 2026-03-15 14:23:45 - High memory usage detected
[ERROR] 2026-03-15 14:24:20 - Connection timeout after 3 attempts
[INFO] 2026-03-15 14:25:05 - Connection restored successfully
"""

# 初始化分割器(按换行分割)
log_splitter = CharacterTextSplitter(
    separator="\n",  # 按换行符分割(每条日志一行)
    chunk_size=60,  # 每个块最大60字符
    chunk_overlap=20,  # 重叠20字符
    strip_whitespace=True
)

# 分割并输出
log_chunks = log_splitter.split_text(log_data)
print(f"日志分割后共 {len(log_chunks)} 块:")
for chunk in log_chunks:
    print(f"→ {chunk}")

2.6 运行结果与分析

日志分割后共 3 块:
→ [ERROR] 2026-03-15 14:22:35 - Database connection failed
[INFO] 2026-03-15 14:23:10 - Retrying connection...
→ [INFO] 2026-03-15 14:23:10 - Retrying connection...
[WARNING] 2026-03-15 14:23:45 - High memory usage detected
→ [WARNING] 2026-03-15 14:23:45 - High memory usage detected
[ERROR] 2026-03-15 14:24:20 - Connection timeout after 3 attempts
[INFO] 2026-03-15 14:25:05 - Connection restored successfully

工藤小贴士:处理日志、CSV等结构化文本时,用separator="\n"(按行分割)能完美保留每条记录的完整性,这是CharacterTextSplitter的最佳使用场景!

三、RecursiveCharacterTextSplitter:通用递归分割王者

3.1 核心特点:智能递归的“多级分割”

RecursiveCharacterTextSplitter是LangChain中使用最广泛的分割器,堪称“万能分割器”。它的核心逻辑是:按优先级顺序尝试多种分隔符,大粒度分割失败就用小粒度分割

默认分隔符优先级:["\n\n", "\n", " ", ""](先按段落分割→再按行→再按空格→最后按字符硬分割)。

优势很突出:

  • 语义保持能力强,优先保留自然边界(段落、句子);
  • 适配复杂文本(比如学术论文、混合格式文档);
  • 多语言支持友好(可自定义中文分隔符如“。”“?”)。

3.2 核心参数详解(新增关键参数)

除了继承CharacterTextSplitter的chunk_sizechunk_overlap等参数,还新增2个关键参数:

参数 类型 默认值 关键说明
separators list [“\n\n”, “\n”, " ", “”] 优先级递减的分隔符列表(可自定义)
keep_separator bool False 是否在文本块中保留分隔符(比如保留句号、换行符)
length_function callable len 长度计算函数(默认按字符数,可改为按token数)

3.3 实战案例1:基础测试(保留语义边界)

场景:一段英文长文本,需要分割为最大20字符的块,重叠4字符,优先保留句子完整性。

# 注意:LangChain v0.1.10+ 推荐从 langchain_text_splitters 导入
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 待分割文本
text = """I Love English hello world, how about you? If you're looking to get 
started with chat models, vector stores, or other LangChain components from a 
specific provider, check out our supported integrations"""

# 初始化递归分割器
splitter = RecursiveCharacterTextSplitter(
    chunk_size=20,  # 每个块最大20字符
    chunk_overlap=4,  # 重叠4字符
    separators=["\n\n", "\n", " ", ""],  # 默认优先级:段落→行→空格→字符
    keep_separator=False  # 不保留分隔符
)

# 分割并输出
chunks = splitter.split_text(text)
print(f"分割后共 {len(chunks)} 块:")
for i, chunk in enumerate(chunks, 1):
    print(f"块{i}(长度:{len(chunk)}):{chunk}")

3.4 运行结果与分析

分割后共 8 块:
块1(长度:17):I Love English hello world
块2(长度:16):world, how about you?
块3(长度:16):you? If you're looking
块4(长度:16):looking to get started
块5(长度:16):started with chat models
块6(长度:16):models, vector stores, or
块7(长度:16):or other LangChain components
块8(长度:19):components from a specific provider

关键观察:

  • 分割器优先按空格分割,避免切断单词(比如“world”没有被切成“wor”和“ld”);
  • 相邻块重叠4字符(比如块1的“world”和块2的“world”重叠),保留上下文。

3.5 实战案例2:处理学术论文(中文支持)

场景:一段中文学术论文文本,包含多个段落,需要分割为最大50字符的块,重叠10字符,优先按段落→句子分割。

from langchain_text_splitters import RecursiveCharacterTextSplitter

# 模拟学术论文文本
paper_text = """
引言 机器学习近年来取得突破性进展,在计算机视觉、自然语言处理等领域广泛应用。本研究聚焦大模型在文本处理中的优化策略。
方法 我们提出新型网络架构,结合注意力机制与迁移学习,提升小样本场景下的性能。实验验证了该架构的有效性。
实验 在ImageNet数据集上进行对比测试,结果显示准确率比基线模型提升12.5%,推理速度提升20%。
"""

# 初始化分割器(自定义中文分隔符)
splitter = RecursiveCharacterTextSplitter(
    chunk_size=50,
    chunk_overlap=10,
    separators=["\n\n", "\n", "。", ",", " ", ""],  # 中文优先级:段落→行→句号→逗号→空格→字符
    keep_separator=True  # 保留分隔符(比如保留句号)
)

# 分割并输出
chunks = splitter.split_text(paper_text)
print(f"分割后共 {len(chunks)} 块:")
for i, chunk in enumerate(chunks, 1):
    print(f"块{i}(长度:{len(chunk)}):{chunk.strip()}")

3.6 运行结果与分析

分割后共 3 块:
块1(长度:49):引言 机器学习近年来取得突破性进展,在计算机视觉、自然语言处理等领域广泛应用。
块2(长度:48):领域广泛应用。本研究聚焦大模型在文本处理中的优化策略。方法 我们提出新型网络架构,
块3(长度:49):网络架构,结合注意力机制与迁移学习,提升小样本场景下的性能。实验验证了该架构的有效性。
块4(长度:48):架构的有效性。实验 在ImageNet数据集上进行对比测试,结果显示准确率比基线模型提升12.5%,
块5(长度:21):推理速度提升20%。

工藤小贴士:处理中文文本时,一定要在separators中加入“。”“,”等中文标点,这样能避免把完整句子切断,大幅提升语义保持能力!

3.7 避坑指南:分隔符顺序不能乱

RecursiveCharacterTextSplitter的分隔符顺序直接影响分割效果,错误的顺序会导致过早分割,破坏语义结构。

# 错误示范:先按空格分割,再按换行分割(顺序颠倒)
bad_splitter = RecursiveCharacterTextSplitter(
    separators=[" ", "\n"],  # 错误:空格优先级高于换行
    chunk_size=500
)

# 正确示范:从大结构到小结构(段落→行→句子→单词→字符)
good_splitter = RecursiveCharacterTextSplitter(
    separators=["\n\n", "\n", "。", "?", "!", " ", ""],  # 正确顺序
    chunk_size=500
)

错误顺序会导致:明明有完整的段落/行,却被空格切成零散的单词,语义完全断裂!

四、分割器核心参数深度解析

4.1 chunk_size与chunk_overlap:最关键的两个参数

  • chunk_size:每个文本块的最大长度(默认按字符数,可改为按token数);
    • 建议值:通用文本500-1000字符,密集文本(论文)1000-2000字符,松散文本(对话)200-500字符;
  • chunk_overlap:相邻文本块的重叠长度,用于保留上下文;
    • 建议值:chunk_size的10%-20%(比如chunk_size=1000时,overlap=100-200);
    • 必须满足:chunk_overlap < chunk_size,且为正整数。

4.2 为什么重叠不生效?3个常见原因

很多同学会遇到“设置了chunk_overlap,但分割后没有重叠”的问题,核心原因有3个:

原因1:文本总长度不足

当输入文本长度 ≤ chunk_size时,不会触发分割,自然没有重叠:

from langchain_text_splitters import CharacterTextSplitter

text = "这是一个非常短的测试文本。"  # 长度仅15字符
splitter = CharacterTextSplitter(
    chunk_size=100,  # 远大于文本长度
    chunk_overlap=20,
    separator="。"
)
chunks = splitter.split_text(text)
print(chunks)  # 输出:['这是一个非常短的测试文本。'](无分割,无重叠)
原因2:递归分割优先保证块大小

当无法找到合适的分隔符时,递归分割器会强制按字符硬分割,此时重叠仍会生效,但可能不明显:

from langchain_text_splitters import RecursiveCharacterTextSplitter

# 无标点的超长文本
text = "这是一段没有标点的超长文本需要被分割成多个块但是因为没有分隔符所以分割器会尝试按字符递归分割直到满足块大小要求"

splitter = RecursiveCharacterTextSplitter(
    chunk_size=30,
    chunk_overlap=10,
    separators=["", " "]  # 无有效分隔符,按字符分割
)

chunks = splitter.split_text(text)
for i, chunk in enumerate(chunks, 1):
    print(f"块{i}(长度:{len(chunk)}):{chunk}")

运行结果(重叠部分明显):

块1(长度:30):这是一段没有标点的超长文本需要被分割成多个块但是因为没有分隔
块2(长度:30):个块但是因为没有分隔符所以分割器会尝试按字符递归分割直到满足
块3(长度:15):字符递归分割直到满足块大小要求

(块1末尾的“个块但是因为没有分隔”与块2开头重叠10字符)

原因3:分隔符强制分割导致无法重叠

当分隔符切割后的文本块正好等于chunk_size时,无法形成重叠:

from langchain_text_splitters import CharacterTextSplitter

text = "abcdefg.hijkllm.nopqrst.uvwxyz"  # 按句号分割后,每个块7字符
splitter = CharacterTextSplitter(
    chunk_size=7,  # 与分割后的块长度一致
    chunk_overlap=3,
    separator="."
)
chunks = splitter.split_text(text)
print(chunks)  # 输出:['abcdefg', 'hijkllm', 'nopqrst', 'uvwxyz'](无重叠)

五、常见问题与避坑指南

5.1 问题1:分割后文本块语义模糊,检索匹配不准

  • 表现:用户查询某一知识点时,返回的文本块不相关或仅部分相关;
  • 原因:chunk_size过大,单个块包含多个无关主题;或chunk_overlap过小,上下文丢失;
  • 解决方案:缩小chunk_size(比如从2000减到1000),增加chunk_overlap(比如从100增至200)。

5.2 问题2:文本块过短,大模型回答缺乏连贯性

  • 表现:大模型基于文本块生成的回答逻辑断裂,无法形成完整观点;
  • 原因:chunk_size过小,切割后的块无法包含完整的语义单元;
  • 解决方案:增大chunk_size,或使用ParentDocumentRetriever(将细粒度块与父文档关联,保留整体上下文)。

5.3 问题3:中文文本分割混乱(切断句子)

  • 表现:中文句子被切成“半句话”,比如“机器学习近年来取得突破性”和“进展,在计算机视觉领域”;
  • 原因:未自定义中文分隔符,使用了默认的英文分隔符;
  • 解决方案:在separators中加入中文标点,如["\n\n", "\n", "。", "?", "!", ",", " ", ""]

六、最佳实践:不同场景参数调优建议

6.1 通用文本处理(如新闻、博客)

  • 参数建议:chunk_size=500-1000,chunk_overlap=100-200(约为chunk_size的15%);
  • 分隔符:["\n\n", "\n", "。", "?", "!", " ", ""]
  • 案例:处理技术博客时,用该参数能保留完整段落和句子,检索时精准匹配知识点。

6.2 代码文件分割(如Python、Java代码)

  • 参数建议:使用RecursiveCharacterTextSplitter.from_language(),自动识别代码结构;
  • 实战代码:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter

# 自动识别Python代码结构(函数、类、注释)
python_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON,
    chunk_size=200,
    chunk_overlap=50
)

# 分割Python代码
code = """
def add(a, b):
    \"\"\"两数相加\"\"\"
    return a + b

class Calculator:
    def __init__(self):
        self.result = 0
    
    def multiply(self, a, b):
        self.result = a * b
        return self.result
"""
code_chunks = python_splitter.split_text(code)
print("代码分割结果:")
for chunk in code_chunks:
    print(f"→ {chunk.strip()}")

6.3 结构化文档分割(如Markdown、HTML)

  • 参数建议:使用MarkdownHeaderTextSplitter按标题层级分割,保留元数据;
  • 实战代码:
from langchain_text_splitters import MarkdownHeaderTextSplitter

# 定义要分割的标题层级(# 为一级标题,## 为二级标题)
headers_to_split_on = [
    ("#", "Header 1"),
    ("##", "Header 2"),
]

# 初始化Markdown分割器
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)

# 待分割的Markdown文本
markdown_text = """
# 引言
机器学习近年来发展迅速。

## 研究背景
随着算力提升,大模型应用场景不断扩大。

## 研究目标
本研究旨在优化大模型推理速度。

# 方法
提出基于量化的优化策略。
"""

# 分割(返回带元数据的Document对象)
docs = markdown_splitter.split_text(markdown_text)
for doc in docs:
    print(f"标题:{doc.metadata}")
    print(f"内容:{doc.page_content}\n")

运行结果(保留标题元数据):

标题:{'Header 1': '引言', 'Header 2': '研究背景'}
内容:随着算力提升,大模型应用场景不断扩大。

标题:{'Header 1': '引言', 'Header 2': '研究目标'}
内容:本研究旨在优化大模型推理速度。

标题:{'Header 1': '方法'}
内容:提出基于量化的优化策略。

七、CharacterTextSplitter vs RecursiveCharacterTextSplitter 对比

最后用一张表格总结两个分割器的核心差异,帮你快速选择:

特性 CharacterTextSplitter RecursiveCharacterTextSplitter
分隔符策略 单级固定分隔符 多级优先级递归分隔符
语义保持能力 ★★☆☆☆ ★★★★☆
处理速度 ★★★★★ ★★★★☆
适用文本 结构化文本(日志、CSV、代码) 通用文本(论文、邮件、网页、多语言)
配置难度 简单(仅需指定分隔符) 中等(需调整分隔符顺序)
推荐场景 需精确控制块大小、文本结构规整 需保留语义完整性、文本结构复杂

总结与下期预告

今天咱们从实战角度吃透了LangChain的两个核心文本分割器:CharacterTextSplitter适合“结构化文本+精确控制”,RecursiveCharacterTextSplitter适合“通用场景+语义保持”。记住:分割器的核心是“平衡块大小与语义完整性”,没有绝对最优的参数,需要根据具体文本类型调整。

如果觉得本文对你有帮助,欢迎点赞、收藏、关注!有任何问题,评论区留言交流~ 👋

请添加图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐