LangChain:数据增强之文本切割器

在Langchain的数据增强模块,数据以 Document 对象和向量形式在各个包装器之间流转。向量形式的数据由向量数据库管理,而被转换为向量之前,数据以 Document 对象的形式存在。

Langchain 提供的文本切割器实际有两个任务,一是把文档切割;二是将切割后的文档转换为 Document 对象数据。这些 Document 对象会被传递给嵌入模型包装器,嵌入包装器再将它们转换为嵌入向量,被存储在向量数据库中,检索器再从向量数据库中检索与用户输入的问题相关的文档内容。

官方资料:LangChain TextSplitter

概述

文档加载器的任务是从各种源加载数据,然后再通过文档切割器将这些文档转换为 Document 对象。Document 对象包含文本及其相关元数据。即将不同格式、不同源的数据统一为 Document 对象。

文档分块通常是诸多应用的关键预处理步骤,其核心目标是将大型文本拆解为更小、可管理的数据单元(有意义的文本块,通常是句子)。该流程具备多重优势:

  • 统一处理能力:确保所有文档处理方式统一、对不同长度的文档实现标准化处理
  • 突破模型限制:多数嵌入模型和语言模型存在最大输入限制,拆分能处理超出限制的长文档。突破输入Token限制(Max Token)。
  • 优化表征质量:长文档的嵌入表征可能因信息过载而失真。拆分后每个片段能获得更聚焦、更准确的表征。
  • 增强检索精度:在信息检索系统中,拆分可提高结果精度,使查询更精准匹配相关文档片段。
  • 优化计算资源:处理小型文本块可提升内存效率,并更好地实现处理任务的并行化。

分块策略呈现多样化特征,主流方法包括固定窗口滑动、语义边界识别等,不同技术方案在计算效率与语义保持度上各有侧重。

关键概念

Text splitters

基于长度切割

最直观的策略是根据文档长度进行拆分。这种简单而有效的方法能确保每个文本块不超过指定的大小限制。基于长度拆分的核心优势包括:

  • 实现简单
  • 文本块大小统一
  • 可灵活适配不同模型需求

具体长度的拆分类型:

  1. 基于词元(Token-based)
    根据词元数量分割文本,适用于语言模型处理场景。
  2. 基于字符(Character-based)
    根据字符数量分割文本,在不同文本类型中表现更稳定。

字符文本切割器CharacterTextSplitter默认的分割符是 \n\n

使用示例CharacterTextSplitter进行基于 Token 的拆分的示例实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from langchain_core.documents import Document
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.document_loaders import TextLoader

loader = TextLoader(file_path="../file/report.txt", encoding="utf-8")
document: list[Document] = loader.load()
text = document[0].page_content

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base", chunk_size=100, chunk_overlap=0
)

split_texts = text_splitter.split_text(text)

for text_block in split_texts:
print(text_block)
print("-" * 50)

代码功能说明

  1. 加载文本文件:使用 TextLoader 加载指定路径的文本文件。
    • 创建一个 TextLoader 实例,用于加载 ../file/example.txt 路径下的文本文件。
    • 调用 load 方法加载文本文件内容,返回一个 Document 对象列表。
  2. 创建文本分割器:使用 CharacterTextSplitter 基于 Tiktoken 编码器按字符分割文本。
    • 创建一个 CharacterTextSplitter 实例,使用 cl100k_base 编码(OpenAI GPT-3.5 和 GPT-4 使用的编码)。
    • chunk_size=100 表示每个文本块包含最多 100 个 token。
    • chunk_overlap=0 表示相邻文本块之间没有重叠。
  3. 分割文本:将加载的文本分割成指定大小的文本块。
    • 将 Document 对象转换为字符串,再调用 split_text 方法将其分割成多个文本块,结果存储在 texts 列表中。
  4. 打印结果:遍历分割后的文本块并打印。

护展阅读

基于文本结构切割

文本天然具有层级化结构(如段落、句子、词语)。利用这种固有结构制定拆分策略,可实现以下优势:

  • 保持语言流畅性
  • 确保拆分块内的语义连贯性
  • 灵活适应不同文本粒度层级

LangChain 的递归字符文本分割器 (RecursiveCharacterTextSplitter) 正是基于此理念:

  • RecursiveCharacterTextSplitter尝试保留完整的较大单元(例如,段落)。
  • 如果一个单元超过分块大小,则降级到下一层级(例如,句子)。
  • 必要时,此过程拆分将继续降级到单词级别。

递归字符文本分割器RecursiveCharacterTextSplitter默认的分割符是 "\n\n", "\n", " ", ""

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import TextLoader

loader = TextLoader(file_path="../file/report.txt", encoding="utf-8")
document: list[Document] = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)
doc_list = text_splitter.split_documents(document)

for doc in doc_list:
print(doc.page_content)
print(doc.metadata)
print("-" * 50)

代码功能说明

  1. 导入必要工具类

    • RecursiveCharacterTextSplitter:这是 LangChain 里用于递归地按字符拆分文本的工具类,能把长文本分割成指定大小的文本块。
    • TextLoader:这是 LangChain 里用于加载文本文件的工具类。
  2. 创建文本加载器

    • TextLoader:创建一个 TextLoader 实例,指定要加载的文件路径为 ../file/report.txt,并设置文件编码为 utf-8(解决中文乱码)。
    • loader.load():调用 load 方法加载文件内容,返回一个包含文档信息的列表。
  3. 创建文本分割器

    • 创建一个 RecursiveCharacterTextSplitter 实例,用于递归地按字符对文本进行分割。设置参数:
    • chunk_size=100 表示每个分割后的文本块最大长度为 100 个字符。
    • chunk_overlap=0 表示分割后的文本块之间没有重叠部分。
  4. 分割文档

    • text_splitter.split_documents(document):调用 split_documents 方法将加载的文档分割成多个文本块,返回一个包含分割后文档的列表。
  5. 遍历分割后的文档并打印信息

    • doc.page_content:打印每个分割后文档的内容。
    • doc.metadata:打印每个分割后文档的元数据,元数据通常包含文档的来源、创建时间等信息。
    • "-" * 50:打印 50 个连字符作为分隔线,用于区分不同的文本块。

API参考RecursiveCharacterTextSplitter

扩展阅读:按字符递归切割文本>recursive text splitting

基于文档结构切割

某些文档具有固有结构(如 HTML、Markdown 或 JSON 文件)。这类文档宜根据其结构进行拆分,因其天然将语义相关的文本分组。基于结构拆分的主要优势包括:

  • 保留文档的逻辑组织架构
  • 维持每个文本块内的上下文关联
  • 对检索或摘要等下游任务更高效

结构化拆分示例

  • Markdown:按标题层级拆分(如 #、##、###)
  • HTML:根据标签进行拆分
  • JSON:按对象或数组元素拆分
  • 代码:根据函数、类或逻辑块拆分

扩展阅读

基于语义的切割

与前述方法不同,基于语义的分割技术会直接分析文本的内容。当其他方法使用文档或文本结构作为语义代理时,但此方法直接分析文本的语义,通过检测文本含义的显著变化实现分割。

其核心实现逻辑如下(以滑动窗口法为例):

  • 生成初始嵌入向量:选取前N个语句生成语义嵌入向量。
  • 滑动窗口比对:移动到下一组句子并生成新的嵌入向量(滑动窗口处理方式)。
  • 识别语义跃迁点:通过向量比较定位显著差异点,该点即为语义段落间的”分割点”。

该技术生成的文本块具备更强的语义连贯性,可显著提升检索、摘要等下游任务质量。

扩展阅读

作者

光星

发布于

2025-05-25

更新于

2025-06-01

许可协议

评论