RAG之语义块切分semantic chunking

复制代码
Semantic Chunking(语义分块)是基于文本的语义关联性、逻辑结构、主题一致性,将长文本切分成若干 “语义完整的独立单元(Chunk)” 的技术。
  • 核心目标:让每个分块内部语义紧密、逻辑完整,分块之间语义边界清晰;
  • 核心区别:和 "按字符数 / 句子 / 段落的机械分块" 不同,语义分块不依赖固定规则,而是靠语义理解判断 "哪里该切分";
  • 通俗比喻:把一篇长文拆成 "有独立意思的小段落",比如把 "可解释 AI 的定义 + 重要性" 拆成一个块,而不是把 "可解释 AI + 人工智能伦理" 混在一个块里。

二、为什么需要 Semantic Chunking?(核心价值)

  1. 适配大模型上下文窗口:多数开源模型(如 Llama3-8B)上下文窗口有限(4k/8k),语义分块能让长文本适配窗口,避免截断;
  2. 提升语义检索精度:你之前遇到的 "检索结果怪异" 问题,核心原因之一就是分块没做好(XAI 内容被切散),语义分块能让检索时精准匹配核心内容;
  3. 提升大模型理解效率:分块后模型只需处理 "相关的语义单元",不用解析整段无关文本,推理更快、回答更精准;
  4. 避免语义断裂:机械分块可能把 "可解释 AI 的定义" 切到两个块里,语义分块能完整保留核心信息。

三、Semantic Chunking 的主流实现方法

方法 1:规则驱动的语义分块(入门级,易实现)

核心思路 :基于文本的结构化特征 + 简单语义规则分块,比如 "按标题层级 / 段落 / 标点 + 关键词边界" 切分,不用模型推理,速度快。

  • 适用场景:结构化文本(论文、文档、手册)、低配设备快速验证;
  • 核心规则(中文适配):① 优先按标题 / 章节 切分(如 "1.1 可解释 AI 定义" 作为块边界);② 按语义关键词 切分(如遇到 "伦理""岗位流失" 等和当前主题无关的关键词,就切分);③ 按段落 + 标点兜底(中文用 "。!?;" 分割基础单元,再合并成语义块)。
方法 2:嵌入驱动的语义分块(主流级,精度高)

核心思路 :先将文本切分成 "小基础单元(句子 / 短句)",用嵌入模型(如 bge-large-zh-v1.5)生成每个单元的语义向量,计算相邻单元的余弦相似度,相似度低于阈值时即为 "语义边界",在此处切分。

  • 适用场景:非结构化文本(网文、对话、自由文本)、高精度语义检索;
  • 核心优势:不依赖规则,纯靠语义判断边界,适配所有文本类型;
  • 关键参数:相似度阈值(中文推荐 0.6~0.7)、基础单元大小、分块最大长度。

先拆成单句→生成向量算相邻相似度→找相似度骤降的语义边界→边界处切分→合并边界内的同主题句子,形成语义块

复制代码
def compute_breakpoints(similarities, method="percentile", threshold=90):
    """
    根据相似度下降计算分块的断点。

    Args:
        similarities (List[float]): 句子之间的相似度分数列表。
        method (str): 'percentile'(百分位)、'standard_deviation'(标准差)或 'interquartile'(四分位距)。
        threshold (float): 阈值(对于 'percentile' 是百分位数,对于 'standard_deviation' 是标准差倍数)。

    Returns:
        List[int]: 分块的索引列表。
    """
    # 根据选定的方法确定阈值
    if method == "percentile":
        #计算相似度分数的第X百分位数
        threshold_value = np.percentile(similarities,threshold)
    elif method ==  "standard_deviation":
        # 计算相似度分数的均值和标准差。
        mean = np.mean(similarities)
        std_dev = np.std(similarities)
        # 将阈值设置为均值减去 X 倍的标准差
        threshold_value = mean - (threshold * std_dev)
    elif method == "interquartile":
        #计算第一和第三四位分位数(Q1和Q3)
        q1, q3 = np.percentile(similarities,[25,75])
        # 使用 IQR 规则(四分位距规则)设置阈值
        threshold_value = q1 - 1.5 * (q3 - q1)
    else:
        # 如果提供了无效的方法,则抛出异常
        raise ValueError("Invalid method. Choose 'percentile', 'standard_deviation', or 'interquartile'.")

    # 找出相似度低于阈值的索引
    return [i for i, sim in enumerate(similarities) if sim < threshold_value]

你想搞懂这个函数里percentile(百分位)方法是如何确定语义分块断点的,核心是通过 "相似度分数的百分位数" 设定阈值,把低于这个阈值的位置判定为语义边界(断点)。我会用「通俗解释 + 分步拆解 + 结合你的 XAI 场景举例」,把这个逻辑讲透,包括计算过程、阈值含义、断点筛选的完整流程。

先明确核心概念:百分位数(Percentile)

在这个方法里,threshold参数(比如你传 90)表示 "第 90 百分位数",先给你一个通俗定义:

把所有相似度分数从小到大排序后,第 90 百分位数 是这样一个值:有 90% 的分数 ≤ 这个值,10% 的分数 > 这个值(反过来也可以理解为:只有 10% 的分数比这个值小)。👉 你的逻辑是:只有那些 "极小的相似度分数"(前 10%)才是语义边界,因为这些位置的句子相似度骤降,是主题切换的地方。

关键细节:threshold参数的调整会影响断点数量

你传的threshold(百分位数)越大,阈值越高,断点越多;越小,阈值越低,断点越少。比如你把threshold从 90 改成 75:

  • 计算第 75 百分位数:排序后列表[0.45,0.82,0.85,0.92,0.95],第 75 百分位数是 0.92;
  • 筛选低于 0.92 的索引:[0,1,2](只有这 3 个位置);👉 实际使用中,中文语义分块推荐把 percentile 设为 80~90(筛选出 10~20% 的低相似度位置,刚好是核心语义边界)。

为什么这个方法比 "固定阈值(比如 0.7)" 更智能?

固定阈值(比如 0.7)的问题是:不同文本的相似度分布不同(比如有的文本整体相似度高,有的低),固定值可能漏判 / 误判;而percentile方法是自适应阈值

  • 不管文本的相似度整体高低,只选 "相对最低的 10%(或 20%)" 作为边界;
  • 比如:
    • 高相似度文本(所有相似度≥0.8):第 90 百分位数可能是 0.95,只筛出<0.95 的位置;
    • 低相似度文本(所有相似度≤0.7):第 90 百分位数可能是 0.65,只筛出<0.65 的位置;👉 适配不同文本的相似度分布,更通用。

总结

percentile方法确定断点的核心逻辑:

  1. 把相邻句子的相似度从小到大排序;
  2. 计算第 N 百分位数(N = 你传的 threshold)作为阈值;
  3. 所有低于这个阈值的相似度位置,都是 "语义边界(断点)";
  4. 本质是选相对最低的一批相似度位置作为切分点,自适应不同文本的相似度分布
相关推荐
chillxiaohan2 小时前
GO学习记录——动态创建测试http接口
学习·http·golang
了一梨2 小时前
SQLite3学习笔记2:SQL 基础语法
笔记·学习·sqlite
子夜江寒2 小时前
OpenCV 学习:文档扫描与视频运动检测与跟踪
opencv·学习·计算机视觉·音视频
爱喝可乐的老王2 小时前
神经网络的学习
人工智能·神经网络·学习
阿蒙Amon2 小时前
TypeScript学习-第2章:基础类型
javascript·学习·typescript
charlie1145141912 小时前
现代嵌入式 C++——自定义删除器(Custom Deleter)
开发语言·c++·笔记·学习·嵌入式
QiZhang | UESTC2 小时前
学习日记day70
学习
星期五不见面3 小时前
嵌入式学习!(一)C++学习-STL(21)-26/1/27
开发语言·c++·学习
知识分享小能手3 小时前
Oracle 19c入门学习教程,从入门到精通,Oracle系统调优 —— 内存结构与参数优化详解(15)
数据库·学习·oracle