文档中的文字加载后,就要向量化存在向量数据库里,提供给后面的业务逻辑使用,但是在这之前还需要对文本进行分割,分割后的结果在进行向量化,今天主要讲一讲langchain常用的几种文本分割。
LangChain 文本分割:从基础到进阶的实战指南
在基于大模型构建知识库、RAG 等应用时,文本分割是核心前置步骤 ------ 不合理的分割会导致语义断裂、模型理解偏差,而精准的分割能大幅提升检索和回答质量。本文结合实战场景,拆解 LangChain 中 几 种常用的文本分割方法,从原理到应用场景逐一讲透,帮你快速掌握适配不同场景的分割策略。
一、文本分割的核心逻辑与关键参数
无论哪种分割方法,核心都是通过参数控制文本块的大小和关联性,先理清这几个核心参数,后续方法理解会事半功倍:
- chunk_size:单个文本块的最大长度(字符 / Token 数),核心作用是适配大模型上下文窗口,避免单块内容过长;
- chunk_overlap:相邻文本块的重叠长度,通常设为 chunk_size 的 10%-20%,目的是保证语义连续,避免分割后上下文断裂;
- separators:分割符列表(优先级从高到低),决定文本 "从哪里拆",支持普通字符(如。、\n)或正则表达式;
- length_function:长度计算方式,默认按字符数(len),也可自定义为按 Token 数计算,适配不同模型需求。
二、5 种常用分割方法:场景化选型指南
1. 纯句子分割(适配中文语义)
这是最贴合中文表达习惯的分割方式,以中文句子结束符(。!?)为核心分割依据,优先保证每个文本块是完整的句子或句子组。
- 核心特点:按语义单位拆分,避免切断完整句子,适合新闻、文章、对话等以句子为核心语义单元的文本;
- 参数技巧:中文场景下 chunk_overlap 可设为 5-10 个字符,既保证关联又不冗余;is_separator_regex 设为 False,避免正则解析干扰普通分隔符匹配。
2. 按段落分割(适配结构化文本)
以空行、换行符(\n)为分割依据,优先保留完整段落语义,适合有明确段落划分的文本(如文档、论文、排版规整的文案)。
- 核心特点:保留段落完整性,分割粒度比句子大,适合对上下文完整性要求高的场景;
- 参数技巧:chunk_overlap 建议设为 20% 左右,因为段落间语义关联度通常更高,需更多重叠保证衔接。
3. 递归字符分割(推荐:通用最优解)
这是 LangChain 官方推荐的通用方法,本质是 "多优先级分层分割"------ 先按段落(\n)拆,拆不开再按句子(。!?)拆,还拆不开再按字符拆。
- 核心特点:兼顾 "语义完整" 和 "长度限制",适配 90% 以上的通用场景,尤其是无固定格式的长文本;
- 分割优先级:段落符 → 句子符 → 普通字符,最大程度保留语义完整性的同时满足长度要求。
4. 按 Token 分割(精准适配大模型)
直接按 Token 数分割(而非字符数),是适配大模型的精准方案 ------ 因为大模型的上下文窗口是按 Token 计算的,字符数无法精准对应模型处理能力。
- 核心特点:精准匹配模型 Token 限制,避免因字符 / Token 换算偏差导致的超限问题;
- 实用技巧:中文场景下可通过 "字符数 ×1.5" 近似估算 Token 数,正式使用时需指定编码(如 cl100k_base)保证精准度。
5. 固定字符长度分割(兜底方案)
无特定分割符,强制按固定字符数拆分,是所有分割方式的 "兜底选项"。
- 核心特点:简单粗暴,完全不考虑语义,仅保证文本块长度符合要求;
- 适用场景:无固定格式的杂乱文本(如日志、无标点的纯数据文本),或需要严格控制文本块长度的场景。
三、实战选型建议
- 中文通用场景(文章、文档、知识库):优先选递归字符分割,兼顾语义和长度;
- 追求精准语义(问答、摘要):选纯句子分割,保证每个块是完整语义单元;
- 结构化文本(论文、排版文案):选按段落分割,保留段落级上下文;
- 大模型落地(RAG、对话):选按 Token 分割,精准适配模型上下文窗口;
- 无格式杂乱文本:选固定字符长度分割,保证长度合规即可。
四、避坑指南
- 分割符优先级:列表中越靠前的分割符优先级越高,需按 "大粒度→小粒度" 排序(如先段落再句子);
- is_separator_regex 参数:中文普通分隔符(。!?)建议设为 False,避免正则转义导致匹配失败;
- 重叠长度控制:chunk_overlap 不宜超过 chunk_size 的 20%,否则会导致文本块冗余,增加处理成本。
总结
- 文本分割的核心是平衡语义完整性 和长度限制,优先选择能保留语义的分割方式(递归字符 / 句子分割);
- 不同场景需匹配不同分割策略:中文优先句子 / 递归分割,大模型落地优先 Token 分割,结构化文本优先段落分割;
- 关键参数需根据文本类型调整:chunk_overlap 设为 chunk_size 的 10%-20%,中文分隔符匹配时关闭正则解析。
看看代码如何实现:
# -*- coding: utf-8 -*-
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import (
CharacterTextSplitter,
RecursiveCharacterTextSplitter,
TokenTextSplitter
)
# ===================== 1. 加载文本(容错处理) =====================
loader = TextLoader("./txt/1.txt", encoding="utf8")
docs = loader.load()
raw_text = docs[0].page_content
print("✅ 文本加载成功!")
print("======= 原始文本(前300字符)=======")
print(raw_text[:300], "...\n")
# ===================== 2. “按句子分割”(核心修复) =====================
# 方法1:纯句子分割(仅按。!?拆分)
# 1. separators:分割符列表(优先级从高到低)
# 作用:指定文本拆分的依据,按列表顺序优先匹配
# 取值:字符串/正则表达式(需配合is_separator_regex使用)
# 本场景:仅用中文句子结束符(。!?)作为分割依据
# 2. chunk_size:单个分割块的最大字符数
# 作用:限制每个文本块的长度,避免块过大(适配大模型上下文窗口)
# 取值:正整数,单位为“字符数”(中文/英文均按1个字符计算)
# 本场景:每个句子块最多150个字符,超过则继续拆分
# 3. chunk_overlap:相邻分割块之间的重叠字符数
# 作用:保证分割后相邻块有部分内容重叠,避免语义断裂
# 取值:0 ~ chunk_size的20%(推荐),本场景设为5个字符重叠
# 注意:句子分割时可设为0,段落/长文本分割建议设为10%-20%
# 4. length_function:计算文本长度的函数
# 作用:指定如何计算文本块的长度(字符数/Token数等)
# 取值:默认len(按字符数计算),也可自定义函数(如按Token数)
# 本场景:用内置len函数,按字符数统计长度
# 5. is_separator_regex:是否将separators视为正则表达式
# 核心说明:
# - True:separators中的字符串会被当作正则表达式解析(如r"。\n?"匹配“句号+可选换行”)
# - False(默认):separators中的字符串会被当作“普通字符串”精确匹配
# 本场景:设为False,仅精确匹配“。”“!”“?”这三个普通字符,不解析正则
# 方法1:纯句子分割(仅按。!?拆分)
sentence_splitter = RecursiveCharacterTextSplitter(
separators=["。", "!", "?"], # 仅用中文句子分隔符
chunk_size=150, # 每个句子块最大字符数
chunk_overlap=5, # 块间重叠字符
length_function=len,
is_separator_regex=False
)
sentence_chunks = sentence_splitter.split_text(raw_text)
print("======= 按句子分割结果=======")
for idx, chunk in enumerate(sentence_chunks):
print(f"句子块 {idx+1}(字符数:{len(chunk)}):")
print(chunk.strip())
print("-" * 60)
# ===================== 3. 其他分割方法(全版本兼容) =====================
# 方法2:按段落分割(空行\n\n分隔)
paragraph_splitter = CharacterTextSplitter(
separator="\n",
chunk_size=150,
chunk_overlap=20,
is_separator_regex=False
)
para_chunks = paragraph_splitter.split_text(raw_text)
print("\n======= 按段落分割结果 ========")
for idx, chunk in enumerate(para_chunks):
print(f"段落块 {idx+1}:{chunk.strip()[:100]}...")
# # 方法3:递归字符分割(推荐,段落→句子→字符优先级)
recursive_splitter = RecursiveCharacterTextSplitter(
separators=["\n", "。", "!", "?", "\n"], # 拆分优先级
chunk_size=150,
chunk_overlap=15
)
recur_chunks = recursive_splitter.split_text(raw_text)
print("\n======= 递归字符分割结果(推荐)=======")
for idx, chunk in enumerate(recur_chunks[:2]):
print(f"递归块 {idx+1}:{chunk.strip()[:80]}...")
# 方法4:按Token分割(适配大模型)
token_splitter = TokenTextSplitter(
encoding_name="cl100k_base",
chunk_size=100,
chunk_overlap=10
)
token_chunks = token_splitter.split_text(raw_text)
print("\n======= 按Token分割结果 ========")
for idx, chunk in enumerate(token_chunks[:2]):
approx_tokens = len(chunk) * 1.5 # 中文近似Token数
print(f"Token块 {idx+1}(近似Token数:{approx_tokens:.0f}):{chunk.strip()[:80]}...")
# 方法5:固定字符长度分割
fixed_splitter = CharacterTextSplitter(
separator="", # 无分隔符,强制按字符数拆分
chunk_size=80,
chunk_overlap=5
)
fixed_chunks = fixed_splitter.split_text(raw_text)
print("\n======= 固定字符长度分割结果 ========")
for idx, chunk in enumerate(fixed_chunks[:2]):
print(f"固定块 {idx+1}(字符数:{len(chunk)}):{chunk.strip()}")
# chunk_size=1 chunk_overlap=0 强制分隔符分割
print("\n======= 强制按照分隔符分割 ========")
sentence_splitter = RecursiveCharacterTextSplitter(
separators=["。", "!", "?"], # 仅用中文句子分隔符
chunk_size=1, # 每个句子块最大字符数
chunk_overlap=0, # 块间重叠字符
length_function=len,
is_separator_regex=False
)
sentence_chunks = sentence_splitter.split_text(raw_text)
print("======= 按句子分割结果=======")
for idx, chunk in enumerate(sentence_chunks):
print(f"句子块 {idx+1}(字符数:{len(chunk)}):")
print(chunk.strip())
print("-" * 60)
结果输出:
✅ 文本加载成功!
======= 原始文本(前300字符)=======
文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落。
常见的切割方式包括,按标点符号切割、按关键词切割、按固定长度切割三种。
按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割则需要提前设定核心关键词,当文本中出现该关键词时进行切割,适合针对性提取特定内容;按固定长度切割则不考虑文本语义,仅根据设定的字符数或字数进行拆分,适用于对文本长度有明确要求的场景。
无论是哪种切割方式,核心目的都是为了降低文本处理的难度,方便后续的文本分析、语义理解、数据提取等操 ...
======= 按句子分割结果=======
句子块 1(字符数:94):
文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落。
常见的切割方式包括,按标点符号切割、按关键词切割、按固定长度切割三种
句子块 2(字符数:147):
。
按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割则需要提前设定核心关键词,当文本中出现该关键词时进行切割,适合针对性提取特定内容;按固定长度切割则不考虑文本语义,仅根据设定的字符数或字数进行拆分,适用于对文本长度有明确要求的场景
句子块 3(字符数:80):
。
无论是哪种切割方式,核心目的都是为了降低文本处理的难度,方便后续的文本分析、语义理解、数据提取等操作,广泛应用于智能客服、文本检索、机器翻译等领域。
======= 按段落分割结果 ========
段落块 1:文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落。
常见的切割方式包括,按标点符号切割、按关键词切割、按固定长度切割三种。...
段落块 2:按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割则需要提前设定核心关键词,当文本中出现该关键词时进行切割,适合针对性提取特定内容;按固定长度切割则...
段落块 3:无论是哪种切割方式,核心目的都是为了降低文本处理的难度,方便后续的文本分析、语义理解、数据提取等操作,广泛应用于智能客服、文本检索、机器翻译等领域。...
======= 递归字符分割结果(推荐)=======
递归块 1:文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落。
常见的切割方式包括,按标点符号切割、按关...
递归块 2:按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割则需要提前设定核心关键词,当文本中出现该关键词时进行切割,...
======= 按Token分割结果 ========
Token块 1(近似Token数:138):文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落。
常见的切割方式包括,按标点符号切割、按关...
Token块 2(近似Token数:135):�切割、按固定长度切割三种。
按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割则需要提前设定核心关...
======= 固定字符长度分割结果 ========
固定块 1(字符数:76):文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落。
常见的切割方式包括,按标点符号切
固定块 2(字符数:80):标点符号切割、按关键词切割、按固定长度切割三种。
按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割
======= 强制按照分隔符分割 ========
======= 按句子分割结果=======
句子块 1(字符数:58):
文本切割是自然语言处理中的基础操作,主要用于将较长的文本内容拆解为更小的、可处理的单元,比如句子、短语或段落
句子块 2(字符数:40):
。
常见的切割方式包括,按标点符号切割、按关键词切割、按固定长度切割三种
句子块 3(字符数:147):
。
按标点符号切割是最常用的方式,通常以句号、问号、感叹号作为切割节点,适用于大多数通用文本;按关键词切割则需要提前设定核心关键词,当文本中出现该关键词时进行切割,适合针对性提取特定内容;按固定长度切割则不考虑文本语义,仅根据设定的字符数或字数进行拆分,适用于对文本长度有明确要求的场景
句子块 4(字符数:79):
。
无论是哪种切割方式,核心目的都是为了降低文本处理的难度,方便后续的文本分析、语义理解、数据提取等操作,广泛应用于智能客服、文本检索、机器翻译等领域
句子块 5(字符数:1):
。
更多学习资料尽在 老虎网盘资源