切成小块 — 五种切法,以及每一种会在哪里翻车
这一章讲三件事: 为什么非切不可;五种切法各自在哪儿失手; 以及那条唯一的判据——一块 = 一个完整的意思。 位置:入库线的第二步。前面四章讲「读进来」,从这一章开始讲「怎么收拾」。 这是 全书篇幅最大、也最有实操价值的一章。
1. 先看现象:同一份新闻页,切法不同,搜出来的东西差很多
书里用的例子特别好懂:一个新闻聚合页,上面依次是政治、体育、医疗三块内容。
用户问:「昨天那场比赛的比分是多少?」
- 切法 A(数着字数硬切): 某一块的前半截是政治新闻的结尾,后半截是体育新闻的开头。 这块被搜出来了,里面一半内容跟比赛无关;
- 切法 B(顺着段落切): 政治归政治、体育归体育,搜出来的那块干干净净。
书里对切法 A 的评价没留情面:它根本不考虑文档的结构, 从句子和段落的中间生生切开;
这么切,撕开的不只是句子和段落,还有文字的整个意思—— 作者为了把文档组织好所付出的一切努力,就此报废。1
这一章讲的就是:怎么下刀。
2. 顶层全景:五种切法排成一条阶梯
① 数着字数硬切 ── 只看长度 ── 最快最笨,会拦腰截断
② 顺着结构切 ── 优先在空行、换行、标点处断 ── 默认选它
③ 认得格式再切 ── 懂 Markdown / 代码 / 网页的写法 ── 源文件有格式时选它
④ 按意思切 ── 用嵌入判断上下句还是不是一回事 ── 文档没结构时选它
⑤ 让模型读一遍再切 ── 模型把内容改写成一条条独立陈述 ── 最贵,内容互相牵连时才值
图说:从上到下越来越聪明,也越来越慢越来越贵。书里的立场很明确——
②是默认答案,往下走要有具体理由。
书里在第 2 章开头就把这条阶梯的选择规则写清楚了: 最简单的是定长切;但更好的做法是考虑文档结构、在段落或标题处 断开; 对付录音转写、聊天记录这类没有结构的文档,试按意思切或让模型来切, 只是这两种比顺着结构切更复杂也更贵2。
先说清一个词:「块」(英文 chunk)就是切出来的那一小段文字, 它是入库和检索的最小单位——一块算一串数,搜也是按块搜回来的。
3. 为什么必须切:两个理由,分量不一样
理由一:嵌入模型一次吃不下太多
书里给的理由:把长文本拆成小块,是为了让文本嵌入模型消化得了3。
这是硬约束。举个书里给的具体数字:OpenAI 的 text-embedding-3-small
这个模型一次最多吃 8191 个标记,超了就得先切4。
(标记见第 01 章:模型切分文字的最小单 位,英文里大致 4 个字符算一个。)
8191 个标记是多少? 按 4 个字符算一个,大约 3 万 2 千个英文字符, 差不多一篇长报告的篇幅;而下一节要推荐的常用块大小是 1000–2000 个标记, 只占它的八分之一到四分之一——也就是说,这个上限平时并不紧,真正决定块大小的是别的理由。
理由二(更重要):块太大,搜出来的东西就不精准
这个理由书里没有直说,但整章都在暗示。书里那句直接相关的话是:
块越大,发给模型的提示就越大,会拖慢响应、抬高运行成本4。
我们把这条推到底:
一块 = 整章(5000 字) → 这一块的「一串数」代表整章的平均意思 → 搜什么都有点像,搜什么都不够准
一块 = 一句话 → 每句话的意思很精确 → 但答案要用的上下文被切没了
图说:块大小是一个两头都疼的取舍。这就是为什么书里给的是一个区间,不是一个数。
4. 切多大:书里唯一给了数字的地方
这一节是全章最实用的几行,值得抄下来。
书里的建议4:
| 项 | 书里的说法 |
|---|---|
| 常用块大小 | 1000–2000 个标记,约合 4000–8000 个字符(英文) |
| 换算 | 英文里 1 个标记 ≈ 4 个字符 |
| 上限 | 别超过你那个嵌入模型的上限(书里的例子是 8191 个标记) |
| 代价 | 块越大 → 提示越大 → 越慢越贵 |
书里的示例代码故意用了 100 个字符,那是为了在书页上看得见效果,不是推荐值5。
切分工具干活之前,要你交待给它几个数,这几个数行话叫「设定项」。 上面那个块大小就是其中一个——你把 1000 还是 2000 填进去, 填的就是这一项。
还有另一个设定项叫「重叠」: 让相邻两块共享结尾和开头的一小段文字, 好处是跨在切口上的那句话不会两边都不完整。
书里的示例给了两个不同的值,却没有一个字解释为什么: 数着字数硬切和顺着结构切那两个示例设的是 0,而认得格式再切的那三个示例设的是 506。 书里从头到尾没有解释这个差别,也没说该怎么定这个数——这是这一章一个明显的缺口。
还有一件事必须在这一步做,书里在第 02 章那边说过、到了切分这一节却没再提: 切下来的每一块都要把元数据带上。 一份 PDF 的第 87 页切出三块, 这三块各自都得贴着「员工手册.pdf / 第 87 页」这张标签走。 这是第 02 章那条规矩在这一步的落点——切块是元数据最容易掉的地方, 一旦在这里掉了,后面答案里就再也给不出「见第 87 页」。
5. 切法一:数着字数硬切
怎么做: 用一个固定大小的窗口,切出一堆等长的块7。
什么时候它反而是对的: 书里给了唯一一个正当理由——两类本来就没有 句子和段落边界的东西:
第一样是原始日志:就是程序自己 一行一行记下来的运行流水账—— 「几点几分、谁做了什么、成没成」,一行一条,写完就不再改。
第二样是传感器每秒报一次的那种源源不断的读数:它像水管里的水一样一直涌进来, 根本没有「结尾」,也没有人替它分段。
对付这两样,定长切能保证块大小一致,处理起来简单,也容易卡在模型的上限之内8。
它们都没有作者,也就没有段落——所以「顺着结构切」在它们身上无处下手。
其余情况一律别用。 理由见第 1 节那段引文。
书里这一节有个自相矛盾的地方要留神: 正文说「用空格作为分隔符(就是拿来断句的那个记号), 这样单词不会被从中间切断」,而示例代码里那一项填的是一对空引号——等于什么分隔符都没给9。 两者不是一回事——照着代码跑,单词真的会被拦腰截断。
书里还给了一个很实用的小工具:一个可视化各种切法效果的网页 chunkviz.up.railway.app,
把切出来的块画出来看,比读十页说明管用10。