一、RAG文本分割

        RAG(Retrieval-Augmented Generation,检索增强生成)模型是一种结合了检索 和生成能力的自然语言处理模型。 它通过检索相关的文档片段,并将这些信息作为生成过程的上下文,以提高生成质量 和准确性。

        在RAG模型中,文本分割是一个非常关键的步骤。合理地分割文档文本, 不仅能够提高检索的效率,还能更有效地将检索到的信息提供给生成模型,使生成内 容更加连贯和准确。

文本分割优点: 

        提升检索效率: 文本分割的首要原因是为了提高检索的效率。对于较长的文档,直接检索整篇文 档可能会导致信息冗余或者重要信息丢失。因此,合理的文本分割将长文档分成 多个段落或片段,这样每个片段可以单独进行检索,从而提高检索的精度和速 度。

        更好的信息匹配: 当文档被合理地分割后,检索算法可以更加精确地匹配用户查询和文档片段。这 样不仅能够减少噪声,还可以确保检索到的内容更加相关,生成模型在使用这些 片段进行回答时能够生成更加相关和有意义的内容。

        增强生成质量: 检索增强生成模型依赖检索到的内容作为生成输入的一部分。如果检索到的文档 片段不准确或上下文不完整,生成的结果可能会偏离用户的期望。文本分割可以 确保每个文档片段足够独立,且能够提供完整的上下文信息,从而提高生成的准 确性和上下文连贯性。

        降低计算复杂度: 长文本的直接处理会大大增加模型的计算量和时间开销,甚至有些大模型并不支 持超长文本的输入。通过将文本分割成多个较小的片段,可以只针对特定的片段 进行处理,从而减少计算量,提高响应速度。这不仅优化了模型的性能,还减少 了生成结果时的延迟。 

二、文本分割方法 

2.1、字符分割

        字符分割是最基础的文本分割方式,按照指定的分隔符进行分割。chunk_size 指的 是每个分割片段(chunk)的长度。chunk_overlap 指的是每个分割片段之间的重叠 部分。

注意: split_text 和 split_documents 不同:

        split_text:处理单纯的字符串。

        split_documents:处理包含元数据的文档对象。 

# 导入LangChain的字符文本分割器
from langchain.text_splitter import CharacterTextSplitter

# 定义要分割的中文文本
text = "在西天取经的几百年前黑风山上有一只黑熊精占山为王,自称黑风大王。"

# 创建字符文本分割器实例
# 参数说明:
# chunk_size=15: 每个文本块的最大字符数
# chunk_overlap=2: 相邻文本块之间的重叠字符数
# separator="": 分割符设为空字符串(按字符分割)
splitter = CharacterTextSplitter(
    chunk_size=15,
    chunk_overlap=2,
    separator=""
)

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

# 打印分割结果
print(chunks)
['在西天取经的几百年前黑风山上有', '上有一只黑熊精占山为王,自称黑', '称黑风大王。']

2.2、递归字符文本分割

        递归字符文本分割是字符分割的升级版,它以字符分割为基础,但在分割时引入了递 归的机制。 在初步分割之后,再对一些不完整或冗长的片段进行进一步细分,从而获得更加细粒 度的分割。

        这个方法比简单的字符分割更加灵活,可以通过递归深度来控制分割的粒度。 RecursiveCharacterTextSplitter不设置separators时,默认的separators参数为 ["\n\n", "\n", " ", ""]:将按不同的字符递归地分割(按照这个优先级["\n\n", "\n", " ", ""]),文本分割器首先在"\n\n"处尝试分割,如果分出的块过大(大于 chunk_size),则找到"\n"处尝试分割以此类推,若都不满足则按照字符划分。

# 导入LangChain的递归字符文本分割器
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 定义要分割的中文文本
text = "在西天取经的几百年前黑风山上有一只黑熊精占山为王,这里只是为了占位没什么用,自称黑风大王。"

# 创建递归字符文本分割器实例
# 参数说明:
# chunk_size=15: 每个文本块的最大字符数
# chunk_overlap=3: 相邻文本块之间的重叠字符数
# separators=[...]: 分割符优先级列表(按顺序尝试分割)
splitter = RecursiveCharacterTextSplitter(
    chunk_size=15,  # 每个分块最大15个字符
    chunk_overlap=3,  # 分块间重叠3个字符
    separators=[
        "\n\n",  # 双换行(最高优先级)
        "\n",    # 单换行
        " ",      # 空格
        ".",      # 英文句号
        ",",      # 英文逗号
        ",",     # 中文逗号
        "。",     # 中文句号
        ""        # 最后按字符分割(最低优先级)
    ]
)

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

# 打印分割结果
print(chunks)
['在西天取经的几百年前黑风山上有', '山上有一只黑熊精占山为王', ',这里只是为了占位没什么用', ',自称黑风大王。']

递归分割机制:

        会按照separators列表中的顺序,优先尝试用高级别的分隔符

        如果高级别分隔符无法满足chunk_size要求,会降级使用更低级别的分隔符

参数特点:

        chunk_overlap=3确保分块之间有3个字符的重叠,保持上下文连贯

        中文标点","和"。"被明确列为分隔符,确保在标点处自然分割

分割策略:

        优先在段落(\n\n)、句子(。)级别分割

        其次在短语(,)和词语(空格)级别分割

        最后才会按单个字符分割

中文适配:

        专门添加了中文标点作为分隔符

        确保中文文本能在语义合理的边界处分割

2.3、特定文档分割(以markdown为例):

        特定文档分割是基于文档结构对文本进行分割的一种方式。不同的文档类型通常有各 自的结构化信息,例如书籍中的章节和段落、网页中的HTML标签等。 利用这些预定义的结构化信息,可以更加自然地分割文本,保证片段的上下文连贯 性。

# 导入Markdown标题文本分割器
from langchain.text_splitter import MarkdownHeaderTextSplitter

# 定义包含Markdown标题的文本内容
text = """
# 第一章
在西天取经的几百年前,黑风山上。\n\n在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。
# 第二章
测试。
"""

# 定义需要分割的标题级别和对应的元数据名称
# 格式: [(标题标记, 元数据字段名), ...]
headers_to_split_on = [
    ("#", "Header 1"),   # 一级标题,保存到Header 1元数据字段
    ("##", "Header 2"),  # 二级标题,保存到Header 2元数据字段
]

# 创建Markdown标题分割器实例
splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=headers_to_split_on  # 传入标题配置
)

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

# 打印分割结果
print(chunks)
# 预期输出结构:
# [
#     {
#         'content': '在西天取经的几百年前...',  # 正文内容
#         'metadata': {'Header 1': '第一章'}  # 标题元数据
#     },
#     {
#         'content': '测试。',
#         'metadata': {'Header 1': '第二章'}
#     }
# ]
[Document(metadata={'Header 1': '第一章'}, page_content='在西天取经的几百年前,黑风山上。  \n在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。在西天取经的几百年前,黑风山上。'), Document(metadata={'Header 1': '第二章'}, page_content='测试。')]

2.4、实例

# 导入必要的库
from langchain_community.document_loaders import TextLoader  # 文本加载器
from langchain.text_splitter import RecursiveCharacterTextSplitter  # 递归字符分割器

# 1. 加载TXT文档
# 创建TextLoader实例,指定文件路径和编码格式
text_loader = TextLoader("黑悟空.txt", encoding="UTF-8")
# 加载文档内容,返回Document对象列表
documents = text_loader.load()

# 2. 定义递归字符分割器
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,  # 每个分块的最大字符数
    chunk_overlap=20,  # 相邻分块间的重叠字符数
    separators=["\n\n", "\n", " ", ".", ",", ",", "。", ""]  # 分割符优先级列表
    # 分割符优先级说明:
    # 1. 首先尝试用双换行符(\n\n)分割
    # 2. 然后尝试单换行符(\n)
    # 3. 接着是空格、英文标点
    # 4. 最后是中文标点
    # 5. 如果以上都不适用,则按单个字符分割
)

# 3. 执行文档分割
# 对加载的文档进行分割,返回分割后的Document对象列表
splits_docs = text_splitter.split_documents(documents)

# 4. 打印分割结果
# 遍历所有分块,打印序号和内容
for i, chunk in enumerate(splits_docs):
    print(f"分块 {i+1}: \n{chunk}\n")  # 打印分块编号和内容
    # 每个chunk是一个Document对象,包含page_content和metadata属性

# 补充说明:
# 1. 适合处理包含中文标点的文本
# 2. 会尽量在段落、句子边界处进行分割
# 3. 重叠部分(chunk_overlap)确保上下文连贯性
# 4. 输出结果保留了原始文档的结构信息

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐