RAG 文本数据切割技术

新星杯·14天创作挑战营·第18期 10w+人浏览 308人参与

一、任务概述

RAG(检索增强生成)中的文本数据切割是将原始文本按照特定策略分解为更小、更易处理的片段(chunk)的过程。其核心目标是优化检索效率与问答准确性,使大语言模型能更精准地获取相关上下文信息。

二、背景

随着自然语言处理技术的发展,RAG系统被广泛应用于知识问答、信息检索等场景。原始文本通常具有长度长、结构复杂的特点,直接输入模型会导致:

  • 超出模型上下文窗口限制
  • 关键信息被稀释,检索精度下降
  • 生成回答时上下文关联断裂

因此,合理的文本切割成为RAG系统性能优化的关键环节。

三、在RAG流程中的定位

在RAG系统完整流程中,文本数据切割属于知识预处理阶段的核心环节,具体位置如下:

  1. 数据采集(获取原始文本/文档)→
  2. 文本切割(当前任务)→
  3. 文本嵌入(将切割后的片段转换为向量)→
  4. 向量存储(存入向量数据库)→
  5. 检索阶段(根据用户查询匹配相关片段)→
  6. 生成阶段(结合检索结果生成回答)

文本切割是连接原始数据与后续向量处理的桥梁,直接影响整个RAG系统的效果。

四、作用

  1. 提升检索效率:更小的片段减少检索比对的数据量,加快响应速度
  2. 增强匹配精度:主题更聚焦的片段能提高与查询的相关性匹配
  3. 优化上下文利用:符合模型窗口限制的片段能被更充分地用于生成回答
  4. 保留语义完整性:合理的切割策略可最大程度保留文本内在逻辑关系

五、主要切割方式及实现

1. 通用递归字符切割

基于标点符号和换行符等自然分隔符进行递归分割,适用于无结构化文本。

from langchain_text_splitters import RecursiveCharacterTextSplitter

with open(r'F:\python测试\智谱-langchain\测试数据\test.txt', encoding='utf8') as f:
    text_data = f.read()


'''
chunk_size:块的最大大小,其中大小由length_function决定
chunk_overlap:数据块之间的目标重叠。重叠数据块有助于在数据块之间划分上下文时减少信息丢失。
length_function:确定块大小的函数。
is_separator_regex:分隔符列表是否应解释为正则表达式。
'''

# 递归切割器
# 默认的分隔符:["\n\n", "\n", " ", ""]
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=20,
    length_function=len,
    is_separator_regex=False,
    separators=[
        "\n\n",
        "\n",
        ".",
        "?",
        "!",
        "。",
        "!",
        "?",
        ",",
        ",",
        " "
    ]
)

# chunks_list = text_splitter.split_documents([text_data])
chunks_list = text_splitter.create_documents([text_data])

print(len(chunks_list))

print(chunks_list[0])
print('--------------------------')
print(chunks_list[1])

特点

  • 实现简单,处理速度快
  • 支持多语言标点符号
  • 可通过调整chunk_sizechunk_overlap控制切割粒度
  • 适合处理无明显结构的纯文本

2. 基于语义的智能切割

利用文本嵌入计算句子间语义相似度,在语义断点处分割,保留语义完整性。

import os
from langchain_community.embeddings import BaichuanTextEmbeddings
from langchain_experimental.text_splitter import SemanticChunker

# 1. 环境配置与初始化
# 设置百川API密钥(用于生成文本嵌入)
os.environ['BAICHUAN_API_KEY'] = 'sk-732b2b80be7bd800cb3a1dbc330722b4'
# 初始化百川文本嵌入模型
embeddings = BaichuanTextEmbeddings()

# 读取待分割的文本数据
with open('test.txt', encoding='utf8') as f:
    text_data = f.read()

print("="*80)
print("原始文本长度:", len(text_data))
print("="*80)

# ------------------------------------------------------------------------------
# 模式1: percentile(百分位模式)- 最常用
# 核心逻辑:计算所有相邻句子嵌入的相似度,取N百分位作为阈值
# 当相邻句子相似度低于该百分位阈值时,视为语义断点
# 参数说明:
# - breakpoint_threshold: 百分位数值(0-100),默认20
# ------------------------------------------------------------------------------
print("\n【模式1】breakpoint_threshold_type='percentile'(百分位模式)")
print("模式说明:基于相邻句子相似度的百分位设定断点,适合大多数场景")
text_splitter_percentile = SemanticChunker(
    embeddings=embeddings,
    breakpoint_threshold_type='percentile',
    breakpoint_threshold=20  # 默认值,可调整(值越大,分割越细)
)
docs_percentile = text_splitter_percentile.create_documents([text_data])
print(f"分割后文档数量: {len(docs_percentile)}")
print(f"第1段内容:\n{docs_percentile[0].page_content[:500]}..." if docs_percentile else "无分割结果")
print("-"*60)

# ------------------------------------------------------------------------------
# 模式2: standard_deviation(标准差模式)
# 核心逻辑:以所有相邻句子相似度的均值 ± N倍标准差作为阈值
# 当相似度低于(均值 - N*标准差)时,视为断点(默认N=1)
# ------------------------------------------------------------------------------
print("\n【模式2】breakpoint_threshold_type='standard_deviation'(标准差模式)")
print("模式说明:基于相似度分布的标准差设定断点,适合数据分布较均匀的文本")
text_splitter_std = SemanticChunker(
    embeddings=embeddings,
    breakpoint_threshold_type='standard_deviation',
    breakpoint_threshold=1  # 默认值,可调整
)
docs_std = text_splitter_std.create_documents([text_data])
print(f"分割后文档数量: {len(docs_std)}")
print(f"第1段内容:\n{docs_std[0].page_content[:500]}..." if docs_std else "无分割结果")
print("-"*60)

# ------------------------------------------------------------------------------
# 模式3: interquartile(四分位模式)
# 核心逻辑:基于四分位距(IQR)计算阈值,鲁棒性更强(抗异常值)
# 阈值 = 第一四分位数(Q1) - N*IQR(默认N=1.5)
# ------------------------------------------------------------------------------
print("\n【模式3】breakpoint_threshold_type='interquartile'(四分位模式)")
print("模式说明:基于四分位距设定断点,抗异常值干扰,适合噪声较大的文本")
text_splitter_iqr = SemanticChunker(
    embeddings=embeddings,
    breakpoint_threshold_type='interquartile',
    breakpoint_threshold=1.5  # 默认值,可调整
)
docs_iqr = text_splitter_iqr.create_documents([text_data])
print(f"分割后文档数量: {len(docs_iqr)}")
print(f"第1段内容:\n{docs_iqr[0].page_content[:500]}..." if docs_iqr else "无分割结果")
print("="*80)

特点

  • 基于语义相似度分割,保留完整语义单元
  • 提供三种分割模式,适应不同文本特性
  • 依赖嵌入模型,处理成本相对较高
  • 适合对语义连贯性要求高的场景

3. 基于标题结构的切割

HTML文档切割

利用HTML中的标题标签(h1-h6)进行层级分割,保留文档原生结构。

from langchain_text_splitters import RecursiveCharacterTextSplitter, HTMLHeaderTextSplitter

html_string = """
<!DOCTYPE html>
<html>
<body>
    <div>
        <h1>Foo</h1>

        <p>Some intro text about Foo.</p>
        <div>
            <h2>Bar main section</h2>
            <p>Some intro text about Bar.</p>
            <h3>Bar subsection 1</h3>
            <p>Some text about the first subtopic of Bar.</p>
            <h3>Bar subsection 2</h3>
            <p>Some text about the second subtopic of Bar.</p>
        </div>
        <div>
            <h2>Baz</h2>
            <p>Some text about Baz</p>
        </div>
        <br>
        <p>Some concluding text about Foo</p>
    </div>
</body>
</html>
"""

label_split = [  # 定义章节的结构
    ('h1', '大章节 1'),
    ('h2', '小节 2'),
    ('h3', '章节中的小点 3'),
]

html_splitter = HTMLHeaderTextSplitter(label_split)

docs_list = html_splitter.split_text(html_string)

print('切割之后的结果: -------------------')
print(docs_list)


label_split_2 = [  # 定义章节的结构
    ('h1', '大章节'),
    ('h2', '小节'),
    ('h3', '章节中的小点'),
    ('h4', '小点中的子节点'),
]
html_splitter = HTMLHeaderTextSplitter(label_split_2)

docs_list = html_splitter.split_text_from_url('https://plato.stanford.edu/entries/goedel/')

print(docs_list[0])

print('--------------------')
print('总共有多少个docs: ', len(docs_list))
print('--------------------------------')
print(docs_list[1])

# 由于章节的内容太多,可以切两次


# 默认的分隔符:["\n\n", "\n", " ", ""]
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=600,
    chunk_overlap=20,
    # 长度函数
    length_function=len, # 默认是len
    # 是否使用正则表达式
    is_separator_regex=False,
    # 分隔符
    separators=[
        "\n\n",
        "\n",
        ".",
        "?",
        "!",
        "。",
        "!",
        "?",
        ",",
        ",",
        " "
    ]
)

docs2_list = text_splitter.split_documents(docs_list)
print('---------------------------------')
print('总共有多少个docs: ', len(docs2_list), '\n')
print('---------------------------------')
print(docs2_list[1], '\n')
Markdown文档切割

针对Markdown的标题语法(#、##、###等)进行结构化分割。

from langchain_text_splitters import RecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter

with open(r'F:\python测试\智谱-langchain\测试数据\Foo.md', encoding='utf8') as f:
    text_data = f.read()


label_split = [
    ('#', '大章节'),
    ('##', '小节'),
    ('###', '小点')
]

# strip_headers :是否在内容中删除章节的标题
markdown_splitter = MarkdownHeaderTextSplitter(label_split, strip_headers=False)

docs_list = markdown_splitter.split_text(text_data)

print(docs_list)

特点

  • 保留文档原生结构信息
  • 可通过label_split定义多级标题映射
  • 支持直接从URL读取HTML内容进行分割
  • 适合处理结构化文档,如技术文档、博客文章等

六、组合切割策略

对于长文档,可采用多级切割策略:

  1. 先使用标题分割器按文档结构切割为大章节
  2. 再使用递归字符分割器对过长章节进行二次分割(如上述HTML切割示例中的二次处理)

七、总结

不同切割方式适用于不同场景:

  • 结构化文档(HTML/Markdown)优先使用标题分割器
  • 非结构化文本可选择递归字符分割器
  • 对语义连贯性要求高的场景(如长文档理解)推荐使用语义分割器

实际应用中需根据文档类型、长度及业务需求选择合适的切割策略与参数,以达到最佳的RAG系统性能。

训练数据保存为deep_convnet_params.pkl,UI使用wxPython编写。卷积神经网络(CNN)是一种专门针对图像、视频等结构化数据设计的深度学习模型,在计算机视觉、语音识别、自然语言处理等多个领域有广泛应用。其核心设计理念源于对生物视觉系统的模拟,主要特点包括局部感知、权重共享、多层级抽象以及空间不变性。 **1. 局部感知与卷积操作** 卷积层是CNN的基本构建块,使用一组可学习的滤波器对输入图像进行扫描。每个滤波器在图像上滑动,以局部区域内的像素值与滤波器权重进行逐元素乘法后求和,生成输出值。这一过程能够捕获图像中的边缘、纹理等局部特征。 **2. 权重共享** 同一滤波器在整个输入图像上保持相同的权重。这显著减少了模型参数数量,增强了泛化能力,并体现了对图像平移不变性的内在假设。 **3. 池化操作** 池化层通常紧随卷积层之后,用于降低数据维度并引入空间不变性。常见方法有最大池化和平均池化,它们可以减少模型对微小位置变化的敏感度,同时保留重要特征。 **4. 多层级抽象** CNN通常包含多个卷积和池化层堆叠在一起。随着网络深度增加,每一层逐渐提取更复杂、更抽象的特征,从底层识别边缘、角点,到高层识别整个对象或场景,使得CNN能够从原始像素数据中自动学习到丰富的表示。 **5. 激活函数与正则化** CNN中使用非线性激活函数来引入非线性表达能力。为防止过拟合,常采用正则化技术,如L2正则化和Dropout,以增强模型的泛化性能。 **6. 应用场景** CNN在诸多领域展现出强大应用价值,包括图像分类、目标检测、语义分割、人脸识别、图像生成、医学影像分析以及自然语言处理等任务。 **7. 发展与演变** CNN的概念起源于20世纪80年代,其影响力在硬件加速和大规模数据集出现后真正显现。经典模型如LeNet-5用于手写数字识别,而AlexNet、VGG、GoogLeNet、ResNet等现代架构推动了CNN技术的快速发展。如今,CNN已成为深度学习图像处理领域的基石,并持续创新。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值