← 返回博客

本文属于主题:企业知识库怎么建:从分块、检索到评测

语义分块值不值得做?先量它的天花板

从「长文本怎么分块」到一个判决性实验:给「完美语义分块」伪造一份语料,量出它的理论上限——边界增益只有 ±2 个百分点,收益全部来自话题标题进入上下文头。再追两档 LLM 生成版,模型跨档而结果纹丝不动。

语义分块,指按话题边界而不是固定字数切分文档。这篇用量化实验回答它值不值得做:完美语义边界带来的边界增益只有 ±2 个百分点,收益几乎全部来自话题标题进入上下文头。

「你们的分块是按什么策略做的?」——这个问题看代码就能回答。「这个策略好吗?」——看代码就不够了。「能不能改成按语义分块?」——这个问题最麻烦,因为它在问一个还不存在的东西值不值得做。

上一篇文章里我给琅嬛的检索系统造了一把尺子,它抓出过一条死掉的 FTS 通道、证伪过一轮分块参数调优。但那把尺子有个盲区:它量的是维基百科——结构良好、标题齐全,恰好是现有分块策略的主场。而这篇文章要回答的问题链,终点落在分块策略的弱势主场:没有任何结构的连续长文本。会议转写、访谈录音、口述材料,用户天天往知识库里扔的这类东西。

这条路我走了一整轮:先看现状,再找语料,造了第二个评测轨道,然后做了一个判决性实验,把「语义分块」这个方向正式关掉了——同时又打开了另一扇门,再亲手把那扇门也关到只剩一条缝。全程零产品代码改动,所有结论都有同指纹的对照数据。

先把现状说清楚:琅嬛的分块是什么

给没读过前篇的读者一页纸交代。琅嬛的分块不是「纯滑窗切字」,而是结构优先、滑窗兜底:

  • 文档解析后得到结构化块(段落/标题/表格),标题策略优先沿标题节切分——一个标题节一个分段;
  • 没有标题的文本用启发式策略识别伪章节开头(「第X章」「1.」「1、」、分隔线、全大写标题行);
  • 都不行就退化为纯滑窗:按字符计数的滑动窗口,窗口内优先在段落边界 > 换行 > 中英文句末标点处落刀;
  • 默认开父子块:384 字的子块做向量/全文检索,4096 字的父块负责命中后返回完整上下文;
  • 每个块带一条「文档标题 > 一级标题 > 二级标题 > …」的上下文头,拼进向量化文本但不进返回正文。

这套东西好不好?上一轮在维基百科上的对照实验已经给过一半答案:父块翻倍、子块缩小,指标都在噪声区间里晃——分块参数不是检索质量的杠杆。但那是在有标题的语料上。没标题的语料,从来没人量过。

无结构语料的分块现状:先做免费的观察

第一步不花钱:找一批无结构连续文本,跑真实的解析器和分块器,看切点落在哪里。

数据集是 VCSUM:239 场真实中文会议(B 站视频,230+ 小时 ASR 转写),MIT 许可。它最珍贵的地方不是转写本身,而是人工标注的话题切分——标注员标出了每场会议的话题切换点。这相当于「人类共识的语义边界」金标准,正好是无结构语料版的答案卷。

把前 30 场会议按两种真实入库形态(逐发言成段 / 全文连排)跑了一遍真实链路,观察结果分成两半:

好的那一半:99.3% 的切点落在句末标点或段落边界上——中文口语转写句子短、标点密,边界回退几乎总能命中。「滑窗会把句子切成两半」这个直觉担忧,在这个语料上几乎不存在。

坏的那一半:约 9% 的子块横跨两个人工话题(边界两侧各超 30 字),约 22% 的话题切换点在 50 字内没有任何块边界。启发式策略在会议文本上等于没生效——2029 个发言的首句里只有 2 个命中「第X章」这类模式,实际就是纯滑窗。

到此为止,故事符合直觉:无结构文本上,切点是按位置切的,不是按语义切的,「9% 的块混着两个话题」听起来就很伤检索。语义分块似乎有戏。

但「听起来会伤」和「实测伤了」之间,隔着一整个实验。

把尺子接过来:VCSUM 检索评测轨道

观察只看分块,下一步量检索。VCSUM 的构造比 MIRACL 那轮多了一屽数据工程:

  • 对齐校验:只有「人工话题切分」与数据集逐句段记录完全一致的会议才入选——239 场里 227 场通过,12 场整场剔除,不做修补。评测语料的完整性不能靠猜。
  • 双轨语料:1297 个人工话题段,一段一文档做短文档轨(隔离分块变量);227 场完整会议做长文档轨(全链路)。
  • Query 集:139 条人工撰写的问题,取前 30 场会议的每个话题段一问,基于该段的人工议题与摘要改写成自然问句。这个 query 集作为资产进了仓库——它是 benchmark 定义的一部分,改它要在 PR 里说明理由。
  • 其余全部复用上一轮的尺子:通道矩阵(纯向量 / 纯 FTS / 混合 / 混合+rerank)、文本重叠命中、阈值敏感性、未命中归因。

基线跑出来(139 条 query,bge-m3 + bge-reranker-v2-m3,下文数字均为 recall@10):

轨道 纯向量 纯 FTS 混合 混合+rerank
话题段(隔离分块) 0.9640 0.5468 0.9640 0.9640
会议长文档(全链路) 0.8849 0.2014 0.8921 0.9424

三个读数值得停下来看:

rerank 在无结构长文本上是最大的单点增益。 不开 rerank,全链路损耗约 8 个百分点(0.964 → 0.885);开了之后损耗收窄到 2.2 个百分点(0.964 → 0.942)。rerank 一个组件吃掉了四分之三的全链路损耗。

未命中归因指向分块边界。 16 个未命中里 15 个是「gold 会议已召回、但命中块与标准段落的文本重叠不足」——目标文档找到了,是块切得不对齐。这与 9% 跨话题块的观察方向一致。

FTS 在这个语料上远强于维基百科场景(0.55 vs 0.13):query 是话题描述型、简体一致,没有疑问句虚词和繁简混杂的坑。这反过来验证了上篇的归因——FTS 弱在问句与繁简,不弱在关键词场景本身。

顺手又跑了一组参数对照(子块 384→512):混合通道 +2.9 个百分点、rerank 通道 −2.9 个百分点,互相抵消。分块参数在无结构语料上依然不是杠杆——这是第三次证伪,也是最后一次需要证伪。

判决性实验:给「完美语义分块」伪造一份语料

现在回到最初的问题:该不该做语义分块?

直接实现一个语义分块器再看效果,是最贵的一条路。更聪明的做法是先问:语义分块的理论上限是多少? 一个完美的语义分块器,做到极致也就是把切点放在人类标注的话题边界上——任何真实实现(embedding 相似度断点、LLM 判边界)都只能逼近人工标注,不可能超越。

而 VCSUM 恰好把人工标注给了我们。于是有个近乎作弊的做法:在每个话题边界注入一个 Markdown 标题。琅嬛的 markdown 解析器遇到 ## 会产出标题块,chunker 的标题策略遇到标题块就沿标题切分,标题自动进入每块的标题路径和上下文头——零产品代码改动,切点就与人工话题边界完全对齐了。前提验证也做了:注入后跨话题子块从 9% 降到 0,oracle 条件严格成立。

但这里有个陷阱:注入标题同时改变了两件事——切分边界和每块的上下文头内容。如果只跑一版「注入真实标题」的语料,指标涨了,你不知道该归功给谁。所以实验必须拆成两臂:

  • Oracle-B(中性标题):注入 ## 话题段3 这种无信息量标题。边界完全对齐,但标题不含任何语义——纯量「边界对齐」的效果;
  • Oracle-A(真实标题):注入人工话题标题(如 ## 元宇宙的生态发展需完善)。边界对齐 + 话题标题进入上下文头。

语料除标题 passage 外与基线逐字节一致,归因干净。判读规则提前写死(预注册,防止事后找理由):B 相对基线若在 ±2 个百分点内,语义分块正式排除;若 +5 个百分点以上,立项做可实现版本。

结果一:边界不是损耗的主因,语义分块排除

会议长文档 recall@10 基线 Oracle-B(纯边界对齐) Oracle-A(边界+标题)
纯向量 0.8849 0.8993(+1.4pp) 0.9640(+7.9pp)
纯 FTS 0.2014 0.2014(±0) 0.5683(+36.7pp)
混合 0.8921 0.9065(+1.4pp) 0.9640(+7.2pp)
混合+rerank 0.9424 0.9353(−0.7pp) 0.9640(+2.2pp)

Oracle-B 三条通道全部落在预注册的 ±2 个百分点噪声带内。把切点精确对齐到人工话题边界——这是一切语义分块实现的理论上限——在检索指标上不产生任何实际收益。 之前观察到的「9% 跨话题块」听起来很伤,实测不伤。分块的确定性和默认参数不用动,「能不能按语义分块」这个问题可以永久关闭了。

一个假设被干净利落地杀死,和做出一个功能同样值钱——它让「不做」有了证据。

结果二:收益全在上下文头,而且有个构造性解释

真正的爆点在 Oracle-A:向量 +7.9 个百分点、FTS +36.7 个百分点,长文档轨完全追平了隔离分块的短文档轨(双双 0.9640),未命中从 16 个降到 5 个——正好是短文档轨固有的那 5 个。也就是说,无结构长文本的全链路损耗,可以被「每个块知道自己属于什么话题」完全消除。

A 与 B 的唯一差别是标题内容,增益却差出一个数量级。机理用一个便宜的统计就看清了:把 query 做字符二元组分解,统计它们被什么覆盖——

  • 被段正文覆盖:平均 57.9%;
  • 被人工标题覆盖:平均 49.3%——注意标题平均只有十个字,信息密度是两千字正文的百倍量级;
  • 9.8% 的 query 用词只在标题里、正文里根本没有,41% 的 query 这个缺口超过 10%。

缺口里的词是什么?「发展计划」「展望」「措施」——提问者用的抽象概括词。口语转写里没人这么说话,正文里就不存在这些词,FTS 的 AND 匹配被卡死在缺失词上。人工标题是提问视角对内容的重新命名,正好补上这座桥。

这个统计还顺带判处了「零成本规则版」死刑:首句、高频词这类抽取式规则只能产出正文已有的词,而增益恰恰来自正文没有的词。抽取规则在构造上就不可能复制 oracle 的收益——不是我试了不行,是结构性地不行。

结果三:LLM 生成版——模型跨档,结果不动

Oracle-A 用的是人工金标标题,产品里不可能有。可实现版是让 LLM 从段正文生成标题,拼进每块的上下文头。于是有了第三组对照(同样的注入机制,同样的评测):

先试本地 qwen2.5:7b(温度 0、全文输入、按段哈希缓存,1297 段全部生成):标题内容质量出乎意料地好——「电影产业与资本的对话」对人工「资本对电影的驱动」,不少段比人工标题更具体。但检索指标:向量通道零增益,FTS +4.3 个百分点,只吃到上限的 12%。

于是换云端 DeepSeek-V4-Flash 重造一整套标题:质量肉眼更贴人工框架(「乡村教育关键在于校长」对人工「中国乡村教育的发展关键」,query 问的正是「关键是什么」)。指标:

会议长文档 recall@10 基线 7B 本地 DeepSeek-V4-Flash 人工上限
纯向量 0.8849 0.8849(±0) 0.8921(+0.7pp) 0.9640
纯 FTS 0.2014 0.2446(+4.3pp) 0.2518(+5.0pp) 0.5683
混合+rerank 0.9424 0.9281(−1.4pp) 0.9281(−1.4pp) 0.9640

生成模型跨了一个档位,结果几乎纹丝不动。这个「不动」本身是最有信息量的读数:瓶颈不是模型能力,是「内容概括措辞」与「提问措辞」的本质错位。 任何只看正文做摘要的生成器——7B 也好云端旗舰也好——都会复用正文的词汇组织标题;而增益恰恰来自提问者视角的抽象词。摘要和提问是两种话语方向,这条生成路线到头了。

按预注册规则(向量通道 ≥ +4 个百分点才立项):两档模型,两次不立项。

诚实的边界:这把尺子自己也有偏差

这轮调查的最后一块拼图,是发现 benchmark 自身带着一处系统性偏差。

139 条 query 当初是基于人工议题标题和摘要撰写的——query 的用词天然锚定人工标题的措辞。统计上它直接可见:query 二元组被人工标题覆盖 49.3%,被 LLM 标题只覆盖 16~17%。后果是双向的:

  • Oracle-A 偏高:它的标题和 query 同源,词面重合被双重计入;
  • LLM 版偏低:LLM 换一种说法,而考卷恰好考人工那种说法。

真实用户既不锚定人工标题也不锚定 LLM 措辞,真实收益介于两者之间——区间很宽(向量通道 0 到 +7.9 个百分点),所以「LLM 上下文头」这个方向没有被彻底关闭,只是当前证据不足以支撑投入。要把这个问题真正判死或救活,前提是先造一套只看正文、不接触任何标题撰写的 query 集,把偏差摘掉再量。这个前提已写进改进路线,在那之前不值得再往里花算力。

对自己的尺子保持怀疑和对外部榜单保持怀疑,是同一种美德。

沉淀

这轮调查动了几千行评测代码、跑了七份同指纹报告,产品代码一行没改。回头看,比结论更可复用的是方法论:

先量天花板,再决定盖不盖楼。 想引入一个不存在的能力(语义分块)时,先用它无法超越的理论上限(人工标注边界)做一次 oracle 实验。上限都不够高的方向,任何实现都不值得做——这次上限是 ±2 个百分点,方向当天关闭,节省的是几周的开发和一个大概率负优化的版本。

一次干预只动一个变量,动不了就拆成两臂。 「注入标题」同时改了边界和上下文头,拆成中性标题/真实标题两臂之后,收益的真实来源(上下文头)和无效来源(边界)才各归各位。不拆的对照实验,经常是在同时验证两个纠缠的假设。

判读规则预注册。 ±2 个百分点排除、+5 个百分点立项,标准写在跑实验之前。没有预注册,人几乎必然会在结果出来后把标准挪到对自己有利的位置——尤其是投入了几小时算力之后。

机理统计比指标归因更便宜也更硬。 「9.8% 的 query 词只在标题里」这一个统计,同时解释了 oracle 增益的来源、判处了规则版死刑、预言了摘要式 LLM 的上限。指标告诉你哪里不对,机理统计告诉你为什么、以及接下来什么必然不行。

阴性结果是链条,不是终点。 这轮的结论链:分块参数不是杠杆(第三次证伪)→ 边界不是杠杆(排除语义分块)→ 上下文头是真实杠杆(上限 +7.9pp)→ 但摘要式生成兑现不了(两档模型证伪)→ 剩下的是措辞对齐问题和尺子自身的锚定偏差。每一环都是下一环的路标。「不做」的证据一路攒下来,最后剩下的那件该做的事(rerank 已交付,繁简归一化排队中)反而无比清晰。

回到最初的问题链。「分块按什么策略?」——结构优先、滑窗兜底、父子两级、上下文头随行,这篇文章第一节。「这个策略好吗?」——好在它不是瓶颈:参数、边界都不是检索质量的杠杆,别在这上面花时间。「能不能按语义分块?」——能,但不值得:完美语义边界的实测增益在噪声区间里。真正值得追逐的是那 2.2 个百分点的残差和提问视角的措辞鸿沟——前者有 rerank 兜着,后者在等一把没有偏差的尺子。

完整的数据、方法与判读记录在琅嬛仓库的检索评测报告(§4.4–§4.6),七份报告带全指纹可复现。至于「RAG 要不要学」的行业之争,我的立场写在《「RAG 可以不学了」?做知识库的人不同意》里:替代不掉的是人工的知识清洗,评测是其中之一。上一篇文章见《给检索系统造一把尺子》。