SemanticChunker 是一种基于语义连贯性的智能文本分块策略,借助嵌入模型深入理解文本含义,能够精准识别语义边界,从而显著提升 RAG(检索增强生成)系统在信息检索中的准确度与回答质量。本教程将带你系统掌握 SemanticChunker 的核心原理、实际操作方法、参数调优技巧及典型应用场景,帮助你在项目中做出最优选择。
1. SemanticChunker 的主要用途与优势
SemanticChunker 是一款基于语义相似度进行智能切分的文本分割器(text splitter),其核心优势在于能够自动识别文本中的语义边界,广泛应用于以下场景:
- 保持语义连贯性:当你需要将长文本分割为多个片段,同时希望避免破坏内容的自然衔接,使分块既不过于零碎,又能充分体现上下文关联时。
- 优化 RAG 检索:作为 Embedding 或向量检索前的理想预处理环节,生成语义完整的文本块,有助于提高后续检索与生成任务的精准度。
- 智能识别主题变化:当你需要自动检测文本中语义不连续的位置(即语义“断点”),例如新话题的开启或上下文的显著转变时。
- 超越简单切割:与依赖固定字符数或分隔符的传统方法相比,它能根据内容的语义“跳跃”程度动态确定分割点,实现更符合人类阅读习惯的智能分块。
小提示: 如果你的文本结构规整统一(如法律条文、技术规格书),传统分块器可能效率更高;但对于新闻报道、学术论文、小说等主题多变的长文本,SemanticChunker 的优势更为突出。
2. 核心原理:基于语义连贯性的文本分块策略
SemanticChunker 的工作流程主要包含以下几个步骤:
- 先按句子拆:使用正则表达式将文本按句号、问号、感叹号等标点切分为单个句子。
- 把每句前后几句组合在一起:根据
buffer_size参数,将相邻的若干句子组合成一个小窗口。 - 对每一组句子做 embedding:调用传入的嵌入模型,将每个窗口转换为向量表示。
- 计算前后组合句子的语义差异:具体采用余弦距离来衡量相邻窗口之间的语义变化程度。
- 根据语义差异的“跳跃”位置来分段:当相邻窗口的语义差异超过设定阈值时,即认为此处发生了主题切换,便在该位置断开文本。
- 分段方式支持几种选择:
- 百分位数(percentile)
- 均值 + 标准差(standard_deviation)
- 均值 + 四分位距(interquartile)
- 梯度百分位(gradient)

常见问题:为什么 SemanticChunker 不直接使用句子级别的 embedding,而要组合相邻句子?
单独一个句子的语义往往过于单薄,难以准确判断主题是否发生变化。通过组合前后若干句子(buffer),可以有效捕捉局部上下文,使语义差异的计算更加稳健,从而精准识别主题切换点。
3. SemanticChunker 的使用
3.1 初始化参数详解
semantic_splitter = SemanticChunker(
embeddings, # 必需: 嵌入模型实例
buffer_size=1, # 可选: 组合句子时的上下文窗口大小
add_start_index=False, # 可选: 是否在元数据中添加起始索引
breakpoint_threshold_type="percentile", # 断点阈值类型
breakpoint_threshold_amount=None, # 断点阈值数值
number_of_chunks=None, # 可选: 期望的分块数量
sentence_split_regex=r"(?<=[.?!])\s+", # 句子分割正则
min_chunk_size=None # 可选: 最小分块大小
)
注意: 默认的句子分割正则对中文支持不佳,需要进行自定义调整,例如:sentence_split_regex=r"(?<=[。?!])\s*"
3.2 断点阈值类型对比
| 类型 | 计算方式 | 适用场景 | 默认值 |
|---|---|---|---|
| percentile | 百分位数(默认95%) | 通用场景 | 95 |
| standard_deviation | 均值 + N倍标准差 | 正态分布数据 | 3 |
| interquartile | 均值 + N倍四分位距 | 有离群值的数据 | 1.5 |
| gradient | 距离变化率的百分位数 | 关注语义突变点 | 95 |
小提示: 如果文本主题变化较为剧烈(如包含多个独立章节),建议使用 percentile 并搭配较低阈值(如90%);若文本主题呈现渐进式演变,standard_deviation 可能是更合适的选择。
3.3 完整使用示例
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings
# 创建OpenAI嵌入实例
embeddings = OpenAIEmbeddings(openai_api_key="hk-iwtbie91e427",
model="text-embedding-3-large",
base_url="https://api.openai-hk.com/v1")
# 读取示例文本
with open('example_text_2.txt', 'r', encoding='utf-8') as file:
text = file.read()
# 创建两种分块器
recursive_splitter = RecursiveCharacterTextSplitter(
chunk_size=300,
separators=["\n\n", "\n", "。", ",", " ", ""]
)
semantic_splitter = SemanticChunker(
embeddings=embeddings,
sentence_split_regex=r"(?<=[。?!])\s*",
breakpoint_threshold_type = "percentile",
breakpoint_threshold_amount=95
)
# 使用递归分块器处理文本
print("RecursiveCharacterTextSplitter的分块结果:")
recursive_chunks = recursive_splitter.split_text(text)
for i, chunk in enumerate(recursive_chunks, 1):
print(f"\n块 {i}:")
print(chunk)
print("-" * 80)
# 使用语义分块器处理文本
print("\nSemanticChunker的分块结果:")
semantic_chunks = semantic_splitter.split_text(text)
for i, chunk in enumerate(semantic_chunks, 1):
print(f"\n块 {i}:")
print(chunk)
print("-" * 80)
# 输出分块数量的比较
print(f"\n分块数量比较:")
print(f"RecursiveCharacterTextSplitter: {len(recursive_chunks)} 块")
print(f"SemanticChunker: {len(semantic_chunks)} 块")
分块结果:
RecursiveCharacterTextSplitter的分块结果:
块 1:
技术发展的三个维度
编程语言的演进历程
从最早的机器语言开始,编程语言经历了汇编语言、高级语言的发展阶段。20世纪50年代,FORTRAN等早期高级语言的出现,大大提高了编程效率。随后,面向对象编程范式兴起,C++、Ja va等语言引领了软件开发的新方向。近年来,Python、Go等现代语言的流行,反映了开发者对简洁性、高效性的追求。函数式编程的回归和新型编程范式的出现,预示着编程语言仍在不断创新。
--------------------------------------------------------------------------------
块 2:
Web技术的变革之路
互联网技术的发展始于简单的HTML页面。Web 1.0时代,静态网页是主流,用户只能被动接收信息。Web 2.0带来了交互革命,AJAX技术让动态交互成为可能,社交媒体和用户生成内容改变了互联网的面貌。如今的Web 3.0时代,语义网技术和去中心化应用正在重塑网络空间,区块链等创新技术为Web世界带来了新的可能。
--------------------------------------------------------------------------------
块 3:
云计算的发展趋势
云计算技术经历了从传统主机到虚拟化,再到现代云服务的演变。IaaS、PaaS、SaaS等服务模式的出现,为企业提供了灵活的IT解决方案。容器技术和微服务架构的普及,推动了应用部署和扩展的革新。边缘计算的兴起补充了传统云计算的不足,而混合云战略则满足了企业对灵活性和安全性的双重需求。未来,云原生技术将继续引领数字化转型的方向。
--------------------------------------------------------------------------------
SemanticChunker的分块结果:
块 1:
技术发展的三个维度
编程语言的演进历程
从最早的机器语言开始,编程语言经历了汇编语言、高级语言的发展阶段。 20世纪50年代,FORTRAN等早期高级语言的出现,大大提高了编程效率。 随后,面向对象编程范式兴起,C++、Ja va等语言引领了软件开发的新方向。 近年来,Python、Go等现代语言的流行,反映了开发者对简洁性、高效性的追求。 函数式编程的回归和新型编程范式的出现,预示着编程语言仍在不断创新。 Web技术的变革之路
互联网技术的发展始于简单的HTML页面。 Web 1.0时代,静态网页是主流,用户只能被动接收信息。 Web 2.0带来了交互革命,AJAX技术让动态交互成为可能,社交媒体和用户生成内容改变了互联网的面貌。 如今的Web 3.0时代,语义网技术和去中心化应用正在重塑网络空间,区块链等创新技术为Web世界带来了新的可能。 云计算的发展趋势
云计算技术经历了从传统主机到虚拟化,再到现代云服务的演变。
--------------------------------------------------------------------------------
块 2:
IaaS、PaaS、SaaS等服务模式的出现,为企业提供了灵活的IT解决方案。 容器技术和微服务架构的普及,推动了应用部署和扩展的革新。 边缘计算的兴起补充了传统云计算的不足,而混合云战略则满足了企业对灵活性和安全性的双重需求。 未来,云原生技术将继续引领数字化转型的方向。
--------------------------------------------------------------------------------
分块数量比较:
RecursiveCharacterTextSplitter: 3 块
SemanticChunker: 2 块
常见问题:为什么 SemanticChunker 只分出了2块,而 RecursiveCharacterTextSplitter 分出了3块?
因为 SemanticChunker 通过语义分析发现“编程语言的演进历程”、“Web技术的变革之路”、“云计算的发展趋势”三个主题之间的语义差异并未超过预设阈值(95%百分位),因此它们被合并到了一个块中。而 RecursiveCharacterTextSplitter 仅依据字符数和换行符进行强制切分,导致了物理上的分割。这说明 SemanticChunker 更注重保持主题的连贯性,但生成的块大小可能相对较大。
4. 优缺点分析
优点
- 分块更加智能,能够有效维护语义的完整性
- 特别适合处理复杂的长文本内容
- 分块结果更贴近人类的自然理解方式
缺点
- 需要调用嵌入模型,处理成本相对较高
- 处理速度相比传统方法较慢
- 依赖外部API服务(如 OpenAI)
选择建议
- 如果项目对文本理解的准确性有较高要求,且具备预算支持,建议优先考虑 SemanticChunker
- 如果项目需要快速处理大量文本,或者文本结构比较规整,可以选择 RecursiveCharacterTextSplitter
- 在实际应用中,可以根据具体场景的需求灵活选择合适的分块器
5. 总结
文本分块是优化 RAG 性能的关键环节。SemanticChunker 利用嵌入模型理解语义,智能地保持内容连贯性,非常适合处理复杂、主题多变的长文本,但成本相对较高且依赖外部 API。RecursiveCharacterTextSplitter 基于字符和分隔符进行递归分割,速度快、成本低、可离线运行,适用于结构化文本或需要快速处理的场景,但可能破坏原有的语义结构。
选择哪种分块器取决于项目对准确性、预算、处理速度和文本特性的具体需求。特别注意: SemanticChunker 提供了多种阈值计算方式(如百分位数、标准差等),需要根据文本类型仔细调优参数才能达到最佳效果。建议先用少量样本测试不同阈值,观察分块结果是否符合预期。
深入理解不同分块器的原理与适用场景,有助于构建更高效、更精准的 RAG 系统。
进阶小提示: 如果需要同时兼顾处理速度与语义质量,不妨尝试“混合策略”:先用 RecursiveCharacterTextSplitter 快速切分成较大的块,再借助 SemanticChunker 对每个大块进行二次精细分割。这样既能减少嵌入调用的次数,又能有效保留语义边界。
