想象你是餐厅后厨的备菜师傅。采购回来的不是一颗颗洗净的青菜,而是整只鸡、整块冬瓜、一整扇排骨。顾客——也就是大语言模型——嘴就那么大,一次能咽下的分量有限(专业上叫“上下文窗口”),而且他点的是“宫保鸡丁”,不是“一整只鸡”。你若把整只鸡丢进锅里,锅放不下;你若整只端上桌,顾客咬不动。于是你需要“改刀”:把食材切成一口大小的小份,每一份都方便顾客夹取、入味。这一步,就是 RAG 里的文档分块(Chunking)——把长文档切成小块,再向量化存入知识库,供检索时精确定位。 切法五花八门,最主流的三套刀法:固定分块像切黄瓜,一刀一刀等长切,快但不管纹理;语义分块像庖丁解牛,沿着骨节缝隙下刀,慢但肉块完整;递归分块像整鸡分装,先拆大件、再细切小件,先后有序。这篇文章,就是带你把这三种刀法学明白,再学会根据自家菜式(业务场景)挑一套趁手好用的。

岗位关联

分块策略直接决定 RAG 的检索质量:同样的知识库,切法不同,问答准确率可能相差数倍。对 AI 从业者而言,这是投入产出比最高的优化环节之一。

目录
  1. 可视化演示
  2. 一、分块必要性
  3. 二、固定分块
  4. 三、语义分块
  5. 四、递归分块
  6. 五、参数调优
  7. 六、场景选型
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示文档分块策略三种方案的核心机制,通过架构/数据/状态/性能四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

文档分块策略三种方案:固定分块 固定分块策略与实现方法 语义分块原理与切分技术 核心机制可视化 文档分块策略三种方案整体架构与关键组件

一、分块必要性

后厨有条铁规矩:再好的食材,进冰箱前都要先按部位分装。五花肉、里脊、排骨各放一格,顾客点菜时才能秒找到“那一片”。RAG 系统也一样——文档不切块,整个塞进向量库,检索时就等于把一只整鸡丢进冰箱:你问“鸡腿在哪儿”,它只能说“鸡在冰箱里”。

为什么非切不可?两个硬约束。第一,大语言模型有上下文窗口——它一次能读入的 token 数有限(token 是模型读写文本的最小单位,大致相当于半个到两个汉字或三四个字母),常见规格是 8K 到 128K,但一份几十万字的技术文档动辄几十万 token,整篇塞不进去。第二,检索粒度:一条内容会被压缩成一个嵌入向量(相当于内容的风味标签),如果这一块里装了十个主题,标签就会互相稀释,跟“什么都像”其实就等同于“什么都不像”。

所以切块不只是“为了放得下”,更是“为了搜得准”。我们可以用一个简单估算来理解约束:假设检索返回 k 个块,每块平均 S 个 token,模型生成回答还需要预留 L 个 token,三者加起来不能超过窗口总容量 W。

所以“切多大”不是口感问题,是能不能下锅、顾客吃不吃得到肉的问题。确定了要切,接下来就看三套刀法怎么选了。

k×S+Lout≤W\displaystyle k \times S + L_{\text{out}} \le W
意思是:送进模型的内容 = 检索到的块 + 要生成的答案,总长度不能超过“嘴巴”的容量。
  1. 检索块数量 k这是检索器返回的块数,比如 Top-5 就是 k=5。块越多,喂给模型的信息越全,但也越占窗口。
    kk
  2. 单块长度 S这是每个块平均的 token 数,也是分块策略的主旋钮——你切多大,直接决定左边的乘积多大。
    k×Sk \times S
  3. 输出预留 L_out这是留给模型生成答案的长度。若不留余量,模型写到一半被硬截断,就像服务员端着菜正要上桌却被门框卡住。
    k×S+Loutk \times S + L_{\text{out}}
  4. 窗口上限 W上下文窗口总容量。总和一旦超过 W,超出部分会被静默截断,信息就丢在门缝里了。
    ≤W\le W

二、固定分块

要做拍黄瓜,第一步是把黄瓜切成等距圆片。不看纹理,不计长短,快刀一落,大小整齐——追求的是“均匀”,而不是“合理”。固定分块(Fixed-size Chunking)就是这套刀法:设定好块大小,从头一刀一刀等长切下去。

实现极简:给定块大小 S(按 token 或字符数计)和重叠 O,从文档开头以固定步长滑窗切割。你可以想象一把标尺在文档上爬:量到 S 就落一刀,然后往回退 O 的距离继续量。为什么要退那一下?为了防止一句话正好被拦腰切断——有了重叠,跨边界的句子至少能在相邻的某一块里完整出现。

具体能切出多少块?设文档总长为 L,那么块数 N 由下面的公式给出。

这套刀法最大的优点是简单、快、可预测,特别适合日志、固定格式报表这类本身没有强语义结构的数据。缺点也一眼可见:它完全无视语义,很可能把一句“小王昨天提交了代码”切成“小王昨天提交了”和“代码”两块——主语在左边,宾语在右边,检索时两边都匹配不上。黄瓜段看着整齐,但若纹理里长了筋,横切一刀照样硌牙。

N=⌈L−OS−O⌉\displaystyle N = \left\lceil \frac{L - O}{S - O} \right\rceil
文档长度减去重叠后,除以每次实际前进的步长,再向上取整——最后剩半截黄瓜也得算一段。
  1. 文档总长 L整篇文档的 token 或字符总数,就是案板上那根黄瓜的总长度。
    L−OL - O
  2. 重叠长度 O相邻两块共享的长度。它让边界信息不至于断成两截,但也意味着同样的内容会被存两遍,是有代价的。
    S−OS - O
  3. 滑动步长每切一块,切刀起始点只前进 S−O。这保证了相邻块的重叠部分恰好是 O。
    L−OS−O\frac{L - O}{S - O}
  4. 向上取整⌈⌉ 表示最后剩的不足一块也算作一块,避免“有内容没处放”。
    ⌈⋅⌉\left\lceil \cdot \right\rceil

三、语义分块

庖丁解牛的秘诀是“以无厚入有间”:顺着筋骨间的空隙下刀,刀刃不损,肉块完整。语义分块(Semantic Chunking)就是给句子找“关节”——在话题自然切换的地方下刀,而不是按刻度硬切。

关节怎么找?把每句话送入嵌入模型,得到一个向量(句子的“风味标签”),再用余弦相似度衡量相邻两句的亲疏。相似度高,说明还在聊同一个话题;突然跌到阈值以下,说明话题切换了——这里就是关节,该下刀了。

具体流程是四步:先按句号、问号等把文档断成句子;再逐句生成嵌入向量;然后计算相邻句对的相似度;最后遇到低于阈值的位置就切开。相邻句子的相似度这样算:

语义分块切出的块内部话题自洽,检索时“句句有着落”,质量通常明显好于固定分块。代价是:嵌入计算耗时、需要额外调阈值,而且对本来就只有一两句的短文本,收益几乎为零。庖丁解牛慢,但刀用得久,肉也卖得上价——语义分块贵,但检索精度常常值得这个价。

sim(a,b)=a⃗⋅b⃗∣a⃗∣ ∣b⃗∣\displaystyle \text{sim}(a,b) = \frac{\vec{a} \cdot \vec{b}}{|\vec{a}| \, |\vec{b}|}
两个句子的向量越“同向”,夹的角越小,相似度越接近 1;夹角越大,越接近 0 甚至负数。低于阈值,就是话题断开的信号。
  1. 两个句子向量相邻两句分别被嵌入模型映射为高维向量,a 和 b。向量的每一维可以理解为句子在某个潜在主题上的响应强度。
    a⃗,b⃗\vec{a}, \vec{b}
  2. 向量点积点积衡量两个向量方向的一致性。方向越接近,点积越大;方向相反,点积为负。这是“亲疏”的原始度量。
    a⃗⋅b⃗\vec{a} \cdot \vec{b}
  3. 模长归一化除以两个向量的模长,消除句子长短的影响。两句再长再短,相似度都落在同一把尺子上,可比性才成立。
    ∣a⃗∣ ∣b⃗∣|\vec{a}| \, |\vec{b}|
  4. 阈值判断sim 的取值范围是 [-1, 1]。设置一个阈值 θ(如 0.3),当相邻相似度低于 θ 就在此处切分。θ 越高越敏感,块切得越碎。
    sim<θ\text{sim} < \theta

四、递归分块

整鸡分装讲究顺序:先卸腿、卸翅、卸胸,这是大结构;鸡胸再切条,条再切丁,这是细节。递归分块(Recursive Chunking)就是这套“先粗后细”的刀法——每一层只解决一个问题:块太大?换更细的分隔符再切。

它维护一个分隔符优先级列表,从大到小排列:段落(\n\n)、换行(\n)、句号、逗号、空格……先按最大的分隔符切,切出来的块如果仍然超过大小上限 M,就降级用下一级分隔符继续切,直到所有块都“瘦身”到可接受范围。LangChain 里的 RecursiveCharacterTextSplitter 就是这套思路的代表实现。

整个切分过程的终止条件可以写成一句话:所有最终块的长度都不超过上限 M。

递归分块的好处是两头兼顾:既尊重了段落、句子这类自然边界,又严格控制了块的大小,不会像语义分块那样完全放飞。它的哲学和整鸡分装一样:先保证大结构不断,再解决细节尺寸——大多数厨房都这么干,大多数 RAG 项目也适用。

∀c∈C:  ∣c∣≤M\displaystyle \forall c \in \mathcal{C}: \; |c| \le M
递归切分什么时候停?当且仅当集合里的每个块都满足“长度 ≤ M”。这是递归的出口,也是质量的底线。
  1. 最终块集合 C递归切分结束后,所有产出块的集合。它可能是第一次切的结果,也可能经历了几轮细化。
    C\mathcal{C}
  2. 任意一个块 c∀ 是“任意”的意思——不是说整体差不多就行,而是每一个块都要单独达标。
    ∀c∈C\forall c \in \mathcal{C}
  3. 块长度 |c|每个块实际包含的字符或 token 数,是触达递归条件的量尺。
    ∣c∣|c|
  4. 大小上限 M只要有一个块 |c|>M,就继续对它换下一级分隔符切分;直到全部达标才收刀。
    ∣c∣≤M|c| \le M

五、参数调优

一口多大才算“一口”?吃凉面要一筷头,喝汤要一小勺,没有放之四海皆准的尺寸。聪明的后厨会让顾客试吃、收集反馈,再调整刀法。分块参数也一样,没法拍脑袋定,得靠评测说话。

最常见的两个旋钮:块大小(chunk_size)和重叠度(overlap)。块大小可以从 200-800 token 起步试探,重叠一般取 10%-20%,只需足够覆盖常见“跨块句”的长度。它们的组合效果会直接体现在检索指标上,其中最常用的是 Recall@K:看检索返回的前 K 个块里,命中了多少真正相关的块。

实操上建议用控制变量法:先固定 overlap,把 chunk_size 从 200 扫到 800,画出 Recall@K 曲线找峰值;再固定这个 size,扫 overlap。别忘了同时观察端到端问答质量和延迟成本——召回不是唯一指标。试吃是最朴素的真理,参数是调出来的,不是查表查出来的。自家菜式、自家食客,试过才知道火候。

Recall@K=∣Crel∩CK∣∣Crel∣\displaystyle \text{Recall@}K = \frac{|C_{\text{rel}} \cap C_K|}{|C_{\text{rel}}|}
相关块被“抓回来”的比例。Recall@K 越高,说明切块方式越能让检索器一眼相中正确的内容。
  1. 相关块集合 C_rel这是人工标注的“标准答案”——回答某个问题真正需要的那些块。它是试吃的依据。
    CrelC_{\text{rel}}
  2. 返回块集合 C_K检索器对某个问题返回的前 K 个块。K 越大,召回越容易高,但噪声也越多。
    CKC_K
  3. 两者交集既在标准答案里、又被检索器捞上来的块,就是“命中”。
    Crel∩CKC_{\text{rel}} \cap C_K
  4. 归一化比值命中数除以总相关数,得到 0 到 1 的召回率。1.0 意味着相关块全数归案。
    ∣Crel∩CK∣∣Crel∣\frac{|C_{\text{rel}} \cap C_K|}{|C_{\text{rel}}|}

六、场景选型

刀法跟着菜式走:拍黄瓜要均匀圆片,选固定分块;白切鸡要骨肉分离,选语义分块;佛跳墙食材繁杂、各有脾气,就得递归分块这类分层处理的刀法。没有哪把刀天下无敌,只有合不合适。

对照现实场景:固定分块适合日志、监控流水这类格式统一、本身无强语义结构的文本,图一个便宜大碗;语义分块适合学术论文、深度长文这类话题层层递进、语义边界明显的文档,图一个精准;递归分块适合混合格式的文档——Markdown 里嵌着代码块,合同里套着条款,它用分隔符层级保留了结构,是大多数项目的稳妥起点。

真要纠结,可以给候选方案打个分。用一个简单的加权公式综合考虑:

所以,选型没有标准答案,只有标准流程:先摸清食材(文档结构),再让评测数据替你选择。做 RAG 和做菜一个道理——刀法可以换,案板上的功夫不能省。

Score=αR+βQ−γT\displaystyle \text{Score} = \alpha R + \beta Q - \gamma T
把召回率 R、语义完整度 Q 这两个“收益项”用权重放大,再减去时延 T 这个“成本项”,得分最高的方案就是当下最合适的刀法。
  1. 召回率 R由 Recall@K 等指标衡量,是检索系统的基本盘——相关的东西都没找回来,后面再精致也白搭。
    RR
  2. 语义完整度 Q块内信息是否自洽、是否经得起“断章取义”的考验。可以人工抽评,也可以让 LLM 打分。
    QQ
  3. 处理时延 T分块与嵌入的计算耗时。语义分块在这项上明显吃亏,海量文档场景下尤其心疼。
    TT
  4. 权重配置α、β、γ 按业务口味调节。比如问答精度优先,就把 β 调大;日志系统追求吞吐,就把 γ 调大。
    αR+βQ−γT\alpha R + \beta Q - \gamma T

AI 应用场景

企业知识库客服问答

阶段:离线文档预处理与索引构建

解决的问题:HR 政策、产品手册动辄几百页,直接整篇入库会导致检索命中混乱,客户问“年假怎么算”时经常返回整章制度,用户翻半天找不到答案。采用固定分块加适量重叠,把长条款切成 300 token 左右的小块,再配合重叠保住条款边界,问答命中率明显提升。

具体案例:某公司给客服机器人接入员工手册,原先整章入库的 Recall@K(K=5)只有 0.42;改成固定分块(size=300, overlap=50)后提升到 0.63,单个问题的平均响应块数也从 3.2 降到 1.1,回答更聚焦。

学术论文语义检索

阶段:检索召回优化

解决的问题:论文每个章节话题独立,用固定分块会把“方法论”切得七零八落,检索“实验设置”却召回一堆“结论”段落。用语义分块沿话题边界切分,让每个块对应一个完整的观点或步骤。

具体案例:一个科研问答助手对 200 篇论文做语义分块:先按句切分并用 embedding 模型编码,相邻句相似度低于 0.35 处断开。上线后“方法-结果”类问题的命中准确率提升了 27%,代价是索引构建时间增加了约 1.8 倍,团队评估后认为值得。

混合格式代码仓库文档

阶段:索引前的文档清洗与结构拆分

解决的问题:GitHub 仓库的 Markdown 里嵌着代码块,README 里混着表格和列表。固定分块会拦腰切断代码函数,语义分块又难以识别缩进层级。递归分块按 \n\n\n、\n\n、\n 逐层切,既保住标题结构,又保证代码块完整。

具体案例:某团队给内部代码库做问答,用 RecursiveCharacterTextSplitter(chunk_size=500, overlap=50)处理 3000 个文档,代码相关问题的检索准确率比固定分块高 19%,且每块都能对应到明确的文件与行号。

Python 演示

python86 行
# -*- coding: utf-8 -*-"""三种分块策略的极简实现, 无需第三方库, 仅供教学演示.""" import math  def char_tokens(text):    """用字符二元组模拟词元切分, 便于计算相似度."""    t = ''.join(ch.lower() for ch in text if ch.isalnum())    return [t[i:i + 2] for i in range(len(t) - 1)]  def count_vec(tokens):    """把词元列表转成词频向量, 相当于简化版词袋."""    vec = {}    for tk in tokens:        vec[tk] = vec.get(tk, 0) + 1    return vec  def cos_sim(a, b):    """计算两个句子的余弦相似度, 值域 [-1, 1]."""    va = count_vec(char_tokens(a))    vb = count_vec(char_tokens(b))    common = set(va) & set(vb)    dot = sum(va[k] * vb[k] for k in common)    na = math.sqrt(sum(v * v for v in va.values()))    nb = math.sqrt(sum(v * v for v in vb.values()))    return dot / (na * nb) if na * nb else 0.0  def fixed_chunk(text, size=60, overlap=8):    """固定分块: 按字符数等长切分, 带重叠."""    step = max(size - overlap, 1)    return [text[i:i + size] for i in range(0, len(text), step)]  def recursive_chunk(text, max_size=80, seps=("\n\n", "\n", ". ", " ")):    """递归分块: 按分隔符优先级逐层切分, 超过上限就换细一级."""    def split_by(txt, levels):        if len(txt) <= max_size or not levels:            return [txt] if txt else []        out = []        for piece in txt.split(levels[0]):            out.extend(split_by(piece, levels[1:]))        return out     chunks = []    buf = ""    for seg in split_by(text, seps):        if buf and len(buf) + len(seg) > max_size:            chunks.append(buf)            buf = seg        else:            buf += seg    if buf:        chunks.append(buf)    return chunks  def semantic_chunk(sentences, threshold=0.3):    """语义分块: 相邻句子相似度跌破阈值处切分."""    if len(sentences) <= 1:        return list(sentences)    chunks = []    buf = sentences[0]    for i in range(1, len(sentences)):        if cos_sim(sentences[i - 1], sentences[i]) < threshold:            chunks.append(buf)            buf = sentences[i]        else:            buf += sentences[i]    if buf:        chunks.append(buf)    return chunks  if __name__ == "__main__":    doc = ("The RAG system needs chunking. Fixed chunking is fast and simple. "           "Semantic chunking uses embeddings to find natural boundaries. "           "Recursive chunking splits by separators layer by layer. "           "Engineers should tune parameters for their own data.")    sents = [doc[i:i + 24] for i in range(0, len(doc), 24)]    print("fixed:", fixed_chunk(doc))    print("recursive:", recursive_chunk(doc))    print("semantic:", semantic_chunk(sents))
目的:用纯 Python 实现固定、递归、语义三种分块,演示同一篇文档在不同刀法下的切分差异,方便你理解每种策略的输入输出形态。
  1. def fixed_chunk(text, size=60, overlap=8):固定分块入口,size 和 overlap 是两个可以直接调的主旋钮。
  2. step = max(size - overlap, 1)每次前进的步长等于块大小减重叠,保证相邻块有共享内容。
  3. return [text[i:i + size] for i in range(0, len(text), step)]从 0 开始以固定步长切片,生成一组等长重叠块。
  4. def split_by(txt, levels):递归分块的核心函数:一层层换更细的分隔符。
  5. for piece in txt.split(levels[0]):先用当前最“大”的分隔符切开,再看每块是否达标。
  6. out.extend(split_by(piece, levels[1:]))块仍太大就降级到下一级分隔符,这就是“递归”二字的由来。
  7. if cos_sim(sentences[i - 1], sentences[i]) < threshold:相邻句相似度跌破阈值,就在这里下刀。
  8. chunks.append(buf)把累积的句子作为一块写进结果,然后清空缓冲区开始下一块。

常见误区

误区我总担心块太小信息不够,于是把 chunk_size 调到 2000 甚至更大,觉得块越大上下文越全,检索肯定更准。

正解块太大会稀释语义——一块里装三四个主题,嵌入向量被平均成“四不像”,检索时跟什么都沾边、又跟什么都不贴。而且大块容易超出上下文窗口被截断。块大小是平衡题,通常从 200-800 token 起步,用 Recall@K 实测为准。就像一块牛排切太大,一口咬不下,味道也混在一起;切太小又尝不出滋味。

为何常见:来自“信息多=效果好”的直觉,忽略了检索匹配靠的是全局相似度,主题混杂会互相抵消。

误区固定分块最简单,反正 embedding 能理解语义,切成啥样都能搜到,没必要用复杂方法。

正解embedding 不是万能的。一个句子被拦腰切断,向量就变成“半个意思”,与查询的相似度明显下降。固定分块适合日志这类无强结构的文本,对强语义长文,固定切分会让召回率明显下滑。黄瓜段切得再整齐,断了筋的段落煮出来也是两截。

为何常见:固定分块零成本实现,在小规模 demo 上问题不明显,容易让人误以为“复杂方法都不必要”。

误区语义分块最智能,肯定全面吊打固定和递归,我的项目直接无脑上语义分块。

正解语义分块要额外做嵌入、调阈值,计算和延迟成本明显更高;对本来就短的文本,收益趋近于零;阈值设得不好,还会切得支离破碎或者一整段不切。它是“精准但贵”的刀法,适合长文强语义场景。庖丁解牛是好,但洗一把葱也用不着庖丁。

为何常见:源于“越智能越好”的直觉,忽略了成本-收益和场景匹配才是工程决策的核心。

误区重叠越多,信息重复覆盖,上下文肯定越全,所以我把 overlap 设成 chunk_size 的一半以上。

正解重叠过大的代价是:相邻块高度重复,索引体量膨胀、检索噪声增加,同一内容在多个块里反复出现,反而会稀释相关块的权重。overlap 一般取 10%-20%,只需覆盖常见“跨块句”的长度即可。冰箱里同样的食材放三份,找的时候反而不知道该拿哪份。

为何常见:把“防切碎”的初衷误当成“多多益善”,意识不到冗余本身也是成本。

误区上线前调一次参数,以后就一直是这套配置,省得每次改。

正解文档分布会变——新文档的格式、长度、语言都可能不同;模型升级也会改变 token 化方式。分块策略应当纳入评测迭代:每次大版本更新后,用标注问答对重测 Recall@K,必要时重调 chunk_size、overlap 和阈值。季节不同菜就不同,同一把刀也要常换磨刀石。

为何常见:工程上“能用就不动”的惯性,加上缺少自动化评测管道,导致参数慢慢腐朽而不自知。

面试题

Q1. 固定分块的实现方式是什么?

单选题 · easy

  • A.按固定字符数切成等长小块← 正确答案
  • B.按句子语义相似度切分
  • C.用正则先粗后细切分
  • D.基于 token 嵌入聚类切分

答案:A。固定分块的核心就是按设定的块大小机械等长切分,像切黄瓜一样只认刻度。B 是语义分块,C 是递归分块的思路,D 则属于嵌入聚类类方法,都不符合“固定”二字。

Q2. 固定分块中设置重叠 overlap 的主要作用是什么?

单选题 · easy

  • A.避免切断上下文信息← 正确答案
  • B.减少块的总数量
  • C.提高切分速度
  • D.降低存储文件大小

答案:A。重叠让相邻块共享一部分内容,跨边界的句子至少能在某一块完整出现,避免关键信息被拦腰截断。它不会减少块数,反而会增加一点,也不能提速或省空间,所以 B、C、D 都不对。

Q3. 语义分块判断切分点的核心依据是什么?

单选题 · mid

  • A.相邻句子嵌入余弦相似度← 正确答案
  • B.字符串出现频次统计
  • C.标点符号的位置分布
  • D.字符长度均匀切分

答案:A。语义分块把句子变成向量,看相邻两句的余弦相似度是否跌破阈值——就像牛骨关节处的缝隙。频次统计、标点位置、等长切分都不是语义方法,自然无法定位“话题切换”的位置。

Q4. 下列哪些是语义分块的缺点?

多选题 · hard

  • A.需要额外的嵌入计算开销← 正确答案
  • B.对短文本效果提升有限← 正确答案
  • C.完全不需要任何参数
  • D.天然比固定分块更快

答案:AB。语义分块要逐句嵌入、算相似度,计算开销高,这是“贵”;对只有一两句话的短文本,没有话题边界可找,收益趋近于零。它恰恰需要阈值参数,而且比固定分块慢得多,所以 C 和 D 是错误的。

Q5. 递归分块属于什么分块思想?

单选题 · easy

  • A.按分隔符优先级层层切分← 正确答案
  • B.一次性等长切分全文
  • C.随机抽取若干段落
  • D.只按词频最高处切分

答案:A。递归分块维护一个从大到小的分隔符列表,先按大分隔符切,块还太大就换下一级继续切,像整鸡先拆大件再细切。B 是固定分块,C 和 D 都与递归分块的层次逻辑无关。

Q6. 递归分块相对于纯固定分块的优势有哪些?

多选题 · hard

  • A.在自然语义边界处断开← 正确答案
  • B.避免大段文本被硬切← 正确答案
  • C.保证每个块字节数相同
  • D.可保留代码等结构化层级← 正确答案

答案:ABD。递归分块按段落、换行、句号等自然边界逐层切,所以不会把语义完整的段落硬生生劈开,也能保留代码块、标题这类结构。它不保证等长——那是固定分块的特征,所以 C 错误。

Q7. chunk 过小会导致检索效果变差,主要原因是?

单选题 · mid

  • A.单个块携带语义信息过少← 正确答案
  • B.块的数量减少效率提高
  • C.向量维度会自动降低
  • D.嵌入模型输出空向量

答案:A。块太小,每个块只剩只言片语,嵌入向量缺少上下文,检索时难以与查询内容对齐——好比肉丁切得太碎,一夹就散、一尝没味。块过小反而块数变多,也不会改变向量维度或输出空向量。

Q8. 块重叠 overlap 的合理作用有哪些?

多选题 · mid

  • A.衔接跨块边界的信息← 正确答案
  • B.防止关键句被切碎丢失← 正确答案
  • C.让所有块内容完全相同
  • D.完全消除检索噪声

答案:AB。重叠的本质是给边界信息上“双保险”:同一句话在相邻两块里都有完整版本,哪块被检索到都不亏。但它不会让块内容变得一样(只是部分重叠),更不可能消除所有噪声,所以 C、D 错误。

Q9. 固定分块最典型的优点是什么?

单选题 · mid

  • A.实现简单且计算开销低← 正确答案
  • B.能精准保持语义完整
  • C.无需设置任何参数
  • D.自动适应文本结构

答案:A。固定分块按刻度等长切,不需要额外嵌入计算,速度最快、实现最直接,适合海量日志类数据。它恰恰会破坏语义,需要设置 size 和 overlap 参数,也不会自适应文本结构,所以 B、C、D 均不正确。

Q10. 语义分块的阈值设置对切分结果的影响是什么?

单选题 · hard

  • A.阈值越高越容易切出更多块← 正确答案
  • B.阈值越高块数量越少
  • C.阈值与切分结果完全无关
  • D.阈值只能取整数区间

答案:A。切分的条件是“相似度低于阈值就切开”。阈值越高,绝大多数句对都满足“不够相似”,下刀越频繁,块就越多越碎;阈值越低则越少切。阈值显然是核心参数,也取小数而非整数区间,所以 B、C、D 皆错。