LangChain:数据增强之文本切割器
在Langchain的数据增强模块,数据以 Document 对象和向量形式在各个包装器之间流转。向量形式的数据由向量数据库管理,而被转换为向量之前,数据以 Document 对象的形式存在。
Langchain 提供的文本切割器实际有两个任务,一是把文档切割;二是将切割后的文档转换为 Document 对象数据。这些 Document 对象会被传递给嵌入模型包装器,嵌入包装器再将它们转换为嵌入向量,被存储在向量数据库中,检索器再从向量数据库中检索与用户输入的问题相关的文档内容。
概述
文档加载器的任务是从各种源加载数据,然后再通过文档切割器将这些文档转换为 Document 对象。Document 对象包含文本及其相关元数据。即将不同格式、不同源的数据统一为 Document 对象。
文档分块通常是诸多应用的关键预处理步骤,其核心目标是将大型文本拆解为更小、可管理的数据单元(有意义的文本块,通常是句子)。该流程具备多重优势:
- 统一处理能力:确保所有文档处理方式统一、对不同长度的文档实现标准化处理
- 突破模型限制:多数嵌入模型和语言模型存在最大输入限制,拆分能处理超出限制的长文档。突破输入Token限制(Max Token)。
- 优化表征质量:长文档的嵌入表征可能因信息过载而失真。拆分后每个片段能获得更聚焦、更准确的表征。
- 增强检索精度:在信息检索系统中,拆分可提高结果精度,使查询更精准匹配相关文档片段。
- 优化计算资源:处理小型文本块可提升内存效率,并更好地实现处理任务的并行化。
分块策略呈现多样化特征,主流方法包括固定窗口滑动、语义边界识别等,不同技术方案在计算效率与语义保持度上各有侧重。
关键概念
基于长度切割
最直观的策略是根据文档长度进行拆分。这种简单而有效的方法能确保每个文本块不超过指定的大小限制。基于长度拆分的核心优势包括:
- 实现简单
- 文本块大小统一
- 可灵活适配不同模型需求
具体长度的拆分类型:
- 基于词元(Token-based):
根据词元数量分割文本,适用于语言模型处理场景。 - 基于字符(Character-based):
根据字符数量分割文本,在不同文本类型中表现更稳定。
字符文本切割器CharacterTextSplitter默认的分割符是 \n\n
。
使用示例:CharacterTextSplitter进行基于 Token
的拆分的示例实现:
1 | from langchain_core.documents import Document |
代码功能说明:
- 加载文本文件:使用 TextLoader 加载指定路径的文本文件。
- 创建一个
TextLoader
实例,用于加载../file/example.txt
路径下的文本文件。 - 调用
load
方法加载文本文件内容,返回一个 Document 对象列表。
- 创建一个
- 创建文本分割器:使用
CharacterTextSplitter
基于Tiktoken
编码器按字符分割文本。- 创建一个
CharacterTextSplitter
实例,使用cl100k_base
编码(OpenAI GPT-3.5 和 GPT-4 使用的编码)。 chunk_size=100
表示每个文本块包含最多 100 个 token。chunk_overlap=0
表示相邻文本块之间没有重叠。
- 创建一个
- 分割文本:将加载的文本分割成指定大小的文本块。
- 将 Document 对象转换为字符串,再调用
split_text
方法将其分割成多个文本块,结果存储在 texts 列表中。
- 将 Document 对象转换为字符串,再调用
- 打印结果:遍历分割后的文本块并打印。
护展阅读:
- 基于词元的切割使用>token-based。
- 基于字符的切割使用>character-based。
基于文本结构切割
文本天然具有层级化结构(如段落、句子、词语)。利用这种固有结构制定拆分策略,可实现以下优势:
- 保持语言流畅性
- 确保拆分块内的语义连贯性
- 灵活适应不同文本粒度层级
LangChain 的递归字符文本分割器 (RecursiveCharacterTextSplitter
) 正是基于此理念:
RecursiveCharacterTextSplitter
尝试保留完整的较大单元(例如,段落)。- 如果一个单元超过分块大小,则降级到下一层级(例如,句子)。
- 必要时,此过程拆分将继续降级到单词级别。
递归字符文本分割器RecursiveCharacterTextSplitter默认的分割符是 "\n\n", "\n", " ", ""
。
使用示例:
1 | from langchain_text_splitters import RecursiveCharacterTextSplitter |
代码功能说明:
导入必要工具类
RecursiveCharacterTextSplitter
:这是 LangChain 里用于递归地按字符拆分文本的工具类,能把长文本分割成指定大小的文本块。TextLoader
:这是 LangChain 里用于加载文本文件的工具类。
创建文本加载器
TextLoader
:创建一个TextLoader
实例,指定要加载的文件路径为../file/report.txt
,并设置文件编码为utf-8
(解决中文乱码)。loader.load()
:调用load
方法加载文件内容,返回一个包含文档信息的列表。
创建文本分割器
- 创建一个
RecursiveCharacterTextSplitter
实例,用于递归地按字符对文本进行分割。设置参数: chunk_size=100
表示每个分割后的文本块最大长度为 100 个字符。chunk_overlap=0
表示分割后的文本块之间没有重叠部分。
- 创建一个
分割文档
text_splitter.split_documents(document)
:调用split_documents
方法将加载的文档分割成多个文本块,返回一个包含分割后文档的列表。
遍历分割后的文档并打印信息
doc.page_content
:打印每个分割后文档的内容。doc.metadata
:打印每个分割后文档的元数据,元数据通常包含文档的来源、创建时间等信息。"-" * 50
:打印 50 个连字符作为分隔线,用于区分不同的文本块。
API参考 :RecursiveCharacterTextSplitter
扩展阅读:按字符递归切割文本>recursive text splitting
基于文档结构切割
某些文档具有固有结构(如 HTML、Markdown 或 JSON 文件)。这类文档宜根据其结构进行拆分,因其天然将语义相关的文本分组。基于结构拆分的主要优势包括:
- 保留文档的逻辑组织架构
- 维持每个文本块内的上下文关联
- 对检索或摘要等下游任务更高效
结构化拆分示例:
- Markdown:按标题层级拆分(如 #、##、###)
- HTML:根据标签进行拆分
- JSON:按对象或数组元素拆分
- 代码:根据函数、类或逻辑块拆分
扩展阅读:
- Markdown 切割 > Markdown splitting.
- JSON 切割 > Recursive JSON splitting.
- 代码切割 > Code splitting.
- HTML 切割 > HTML splitting.
基于语义的切割
与前述方法不同,基于语义的分割技术会直接分析文本的内容。当其他方法使用文档或文本结构作为语义代理时,但此方法直接分析文本的语义,通过检测文本含义的显著变化实现分割。
其核心实现逻辑如下(以滑动窗口法为例):
- 生成初始嵌入向量:选取前N个语句生成语义嵌入向量。
- 滑动窗口比对:移动到下一组句子并生成新的嵌入向量(滑动窗口处理方式)。
- 识别语义跃迁点:通过向量比较定位显著差异点,该点即为语义段落间的”分割点”。
该技术生成的文本块具备更强的语义连贯性,可显著提升检索、摘要等下游任务质量。
扩展阅读:
- 基于语义的文本切割 > splitting text based on semantic meaning.
- 基于语方切割示例 > Greg Kamradt’s notebook.
LangChain:数据增强之文本切割器
http://blog.gxitsky.com/2025/05/25/AI-LangChain-013-TextSplitter/