跳到主要内容

切成多大、在哪儿切 — 全书埋得最深的一颗雷

这一章讲三件事: 为什么整篇文档不能直接用;切块的两个旋钮(多大、在哪儿下刀)各自在动什么; 以及切坏了会在哪里、以什么形式爆发。 它在全书链条里的位置: 这是六站里的第二站,也是全书唯一一颗跨章的雷 —— 第 06、10 两章里那些「明明是对的答案却排在最后」的怪事,病根都在这一站。

1. 顶层全景

一篇长文档

├─ 旋钮 A:每块最多多大? (chunk_size)
├─ 旋钮 B:在哪儿下刀? (separators / 结构 / 意思)
├─ 旋钮 C:相邻两块重叠多少? (chunk_overlap)

一串块 ──► 每块单独变成一串数 ──► 每块单独被检索

图说:最后那两个「单独」是全章的要害。
块和块之间从此互不相识——一块里说不清的事,别的块救不了它。

一句话链条: 整篇塞不下也搜不准 → 必须切 → 切的时候有三个旋钮 → 每个旋钮拧错都有具体后果 → 而其中一种后果要到七章之后才会显形。

2. 为什么必须切:三条硬约束

书列了四条理由,其中三条是硬约束、一条是结果1:

约束具体是什么
模型一次能看的文字有上限超了直接放不下
多用一分就多花一分钱书的原话是「不必要地多用标记会直接增加使用成本」
整篇算成一个东西,搜什么都不像一篇讲十件事的文档,压出来的那个点哪件事都不靠近

第三条书没有明说,但它是全书最实在的一条,所以我们把它讲透。

为什么整篇算一个点会「哪件事都不靠近」? 第 02 章那张 Excel 表已经演示过一次:三个人的记录压成一个点,谁都不像。 一篇二十页的文档同理 —— 你问其中第 17 页那件事,而整篇的「平均意思」离它很远。

书还列了三个坑,这三个坑正好对应下面三节2:

  • 块太小 → 丢上下文(第 6 节讲重叠怎么救、什么时候救不了);
  • 块太大 → 超模型上限(第 4 节讲块大小);
  • 重叠和句子边界处理错 → 丢语义(第 5 到 9 节,一节一种切法)。

3. 「长度」的单位:字符不是标记

这一节只解释一个词,但这个词是这一章所有数字的单位。

先看现象:同一段文字,两个配方给的「长度」对不上

书里同一句 RAG 定义句,被两个配方各切了一遍。 一个把上限写成 300,注释说单位是「字符」;另一个把上限写成 30,注释说单位是另一样东西。

同一句话,一个说 300、一个说 30,差了十倍,而两个数说的都是「一块最多多大」。

那个单位叫「标记」

模型不是按字符数东西的,它数的是另一种单位,那个单位就叫标记**。**

标记是模型切分文字的最小单位 —— 它可能是一个完整的词,也可能只是词的一小截: 英文里像 preingized 这样的词头词尾,各自算一个标记。

它的英文就叫 token。你在任何一家的计费页面、上限说明、报错信息里看到这个词,说的都是它。

于是上面那两个配方的差别就清楚了:

配方上限怎么写切出几块
配方 2chunk_size = 300,注释写「max characters」(字符)4 块,第一块 276 个字符
配方 3chunk_size=30,注释写「max tokens per chunk」(标记)3 块

一个标记大概多大?书里的两个输出就够算出来

这个比例不必去查,书自己给的两个数就能推出来:

那句定义句 276 个字符(配方 2 的输出印着 "Chunk 1 (276 chars)")
按标记切,每块 30 个标记、重叠 10 个 → 切出 3 块(配方 3 的输出印着 "Total Chunks: 3")

重叠 10 意味着每次往前挪 30 − 10 = 20 个标记。
挪两次(0、20、40)刚好切满 3 块 ⇒ 这句话一共 51 到 70 个标记之间。

276 ÷ 60 ≈ 4.6

图说:一个标记大约合四到五个英文字符。这个数是从书里两处输出算出来的,不是查来的。

这个比例一算出来,书里就露出一个矛盾

书在第 6 章给了一条经验值:块大小常在 300 到 800 个标记之间3

换算成字符,是 1200 到 3600 个字符左右。

而书里所有配方用的 chunk_size 是: 300、500、200、1000、100、80、60、50 —— 单位是字符。

书自己推荐的下限 300 标记 ≈ 1200 字符
书自己配方里最大的 1000 字符 ≈ 220 标记

图说:书里最大的那个块,还不到它自己推荐下限的四分之三;
最小的那个(50 字符 ≈ 11 个标记)差了近三十倍。

判断(我们的,不是书里的): 这不是书写错了数,是书在两个单位之间来回跳而从不声明。 那条 300–800 的经验值是对的(它和业界常见口径一致),而所有演示用的都是几百个字符的小块 —— 因为演示用的那三段话太短了,块开大了就只剩一块(下一节的走查里你会看到 1000 字符那次只剩 1 块)。 如果错,会错在: 如果作者那条经验值本来说的也是字符 (原文写的是 tokens,所以不太可能),那么书里的配方就没有矛盾,矛盾只存在于我们的换算。 判据是原文那个词:它写的是 300–800 tokens

4. 主走查:同一段文字,块大小取三个值

这一节是本章的主走查。下面每一节的机制,都回到这条线上。

书里有一个配方专门做这件事:拿同一份 RAG.txt(就是第 01 章那段 RAG 正文,三个自然段), 把块大小依次取 200 / 500 / 1000 字符,重叠固定 50,每次都问同一个问题「What is RAG?」, 取前 3 条4

这是全书数字前后对得上的一段走查:喂进去的那堆文本不换、问题不换、只动一个数。

(喂给程序的那一堆文本,行话就叫语料。这一章后面还会反复用到这个词。)

三次结果并排

块大小切出几块第 1 名是什么第 2 名是什么
2006 块Retrieval Augmented Generation (RAG) is an architecture that combines the ability of large language models (LLMs) with a retrieval system to enhance t…the factual accuracy, contextual relevance, and quality of generated response against the query raised by user to a RAG system.
5003 块同上(完整的定义句)Traditional generative models rely solely on internal parameters…(第二段)
10001 块整篇三段合成的那一块没有第 2 名 —— 库里只有一块

(每行末尾的 是程序只印前 150 个字符造成的,不是块的边界。)

逐行读这张表

第一行:200 字符把定义句拦腰切断了。

那句定义句是 276 个字符,而块上限是 200 —— 装不下,只能切。 于是第 1 块停在「…with a retrieval system to enhance」, 第 2 块从「the factual accuracy, contextual relevance…」开始。

看第 2 块单独长什么样:

the factual accuracy, contextual relevance, and quality of generated response against the query raised by user to a RAG system.

这一块没有主语。 它在说「谁」提高了事实准确性?不知道 —— 那个「谁」留在上一块里了。 这就是块被切坏最典型的样子,而它已经被排到了第 2 名交给模型。

第二行:500 字符是这份语料上唯一「刚刚好」的一档。 三个自然段各自成块,每块讲一件完整的事,前三名正好是三段。

第三行:1000 字符整篇只剩一块。 问什么都只回得出这一块 —— 检索这一站等于没做,模型每次都要读全文。

这条线上,三个旋钮各在哪一步

旋钮在走查里是哪一步拧错的后果
A:块多大200 / 500 / 1000 这三次太小切断句子(第一行),太大等于不切(第三行)
B:在哪儿下刀三次用的都是同一种刀(下一节讲它)见第 6、7 节
C:重叠多少三次都固定 50 字符见第 5 节

5. 「递归」到底递归什么

这一节回答一个书用了四次、一次没解释的东西。

上面三次切分用的都是同一个切分器,名字叫 RecursiveCharacterTextSplitter。 配方 2 把它的参数原样印了出来5:

separators = ["\n\n", "\n", ".", " ", ""]

「递归」指的是刀口的一层层退让顺序,不是「切完再切」。

拿到一段文字,先试第一种刀口:空行(\n\n),按它切

├─ 切出来的块都不超过 chunk_size 了? → 收工

└─ 还有块太大? → 只对那些太大的块,退到第二种刀口:换行(\n)

└─ 还太大? → 退到句号(.)

└─ 还太大? → 退到空格

└─ 还太大? → 逐字符硬切

图说:列表里越靠前的刀口越「体面」——空行处下刀不破坏任何句子;
越往后越粗暴,最后那个空字符串就是「不管三七二十一,数到 300 个字符就砍」。

为什么这个设计有效: 它把「保住结构」和「保证不超上限」这两个互相打架的要求排了个优先级 —— 能体面就体面,不能体面也绝不超限。

边界在哪: 退让到最后一档时,它和「数字符硬砍」没有任何区别。 第 4 节那次 200 字符的切分,砍在「to enhance | the factual accuracy」中间, 就是退到了倒数第二档(空格)的结果。递归不保证句子完整,它只保证「尽量」。

6. 重叠防的是什么,以及它兜不住的时候

它解决什么问题

一句话被切进两块,两块都答不了这个问题:

块 1: ……retrieval system to enhance
块 2: the factual accuracy, contextual relevance……

问:RAG 提高的是什么?
块 1 有主语没答案,块 2 有答案没主语。谁都答不了。

它怎么做

让相邻两块共享一段文字。 第 4 节那三次切分都设了 chunk_overlap = 50, 意思是第 2 块的开头,要把第 1 块结尾的 50 个字符再抄一遍。

于是骑在刀口上的那句话,至少在一块里是完整的。

为什么这么做有效

因为检索是逐块进行的:一块能不能被找到,只取决于它自己写了什么。 重叠等于给刀口附近的内容买了一份保险 —— 它在两个块里各出现一次,两次机会。

边界:重叠不是万能保险

书自己在第 9 章给出了反例。那个配方按切,每块 30 个词、重叠 5 个词, 输出里两块长这样6:

某一块的结尾: ……Dense retrieval uses vector embeddings for semantic similarity. BM25 is
另一块的开头: for semantic similarity. BM25 is a sparse retrieval method based on……

图说:第一块结尾停在半句「BM25 is」——BM25 是什么,没了。
第二块开头是「for semantic similarity.」——什么东西 for semantic similarity,没了。
重叠 5 个词只够抄回来「for semantic similarity. BM25 is」这几个词,兜不住整句。

判据一句话:重叠要大到能装下你最长的那类句子。 5 个词装不下一句英文,50 个字符也装不下。 而书里所有配方的重叠都是 50 字符或更少 —— 大约 11 个标记,不到一句话。

7. 两大类刀口:靠看得见的标记切,还是靠意思切

书在这一章开头给了全书为数不多的一段真解释,把切法分成两大类7:

类别靠什么下刀例子适合什么
结构式文档里看得见的记号:标题、章节、页边界、标签、说话人按标题切、按固定格式切、按页切排版规整的文档
语义式意思:概念相似度、话题连贯性、语义转折按主题分组切、按意思的转折切无结构、概念密集的文本

这个二分是对的,也很有用。问题是书自己的配方严重偏向一边。

这一章十四个配方:
结构式 ████████████████████████████ 13 个
语义式 ██ 1 个

图说:开篇承诺了两条路,而实际只走了一条。那唯一的一条语义式配方,
还恰好是本章两个「静默丢数据」现场之一(第 9 节)。

十三个结构式配方其实是同一条原理的十三次重复:找一个看得见的记号,照它切。 所以我们不逐个讲,只列一张表,读者需要哪种就照着找。

表里有一行讲会议转写稿,那里会出现一个词叫时间戳:就是每句话旁边记着的 「这是第几分几秒说的」那个数。

你的资料长什么样拿什么当刀口顺带能挂上什么标签
Markdown(一种用 #- 这类符号标出标题和列表的纯文本写法)文档二级、三级标题(写正则时用一个「只看不吃」的技巧,让标题本身留在块里)——
有固定小标题格式的报告正则匹配那个格式,再把「标题 + 内容」两两配对——
HTML 网页标签(h1p 各成一块),再过一遍字符切分——
PDF按页(PDF 加载器本来就是一页一个,所以「按页切」等于什么都不做)页码
表格按行,每行拼成「列名: 值」行号
会议纪要 / 访谈按说话人(行首冒号前的那一段)说话人
带时间戳的转写稿按固定时长的窗口起始时间
幻灯片--- 这样单独一行的符号第几页
一行一条记录的数据文件一行一块记录的 id

这张表就是这一章十三个配方的全部内容。 挑一个刀口、挂上对应的标签,没有别的了。

8. 另起一处:n-gram 那个配方把句尾整个扔了

这是本章第一个失效现场。书原样印了出来,一个字没评。

走一遍

输入是那句 RAG 定义句,一共 42 个词。配方的设置是「每块 8 个词、重叠 3 个词」, 所以每次往前挪 8 − 3 = 5 个词8

起点 0 → 词 1–8 Retrieval Augmented Generation (RAG) is an architecture that
起点 5 → 词 6–13 an architecture that combines the ability of large
起点 10 → 词 11–18 ability of large language models (LLMs) with a
起点 15 → 词 16–23 (LLMs) with a retrieval system to enhance the
起点 20 → 词 21–28 to enhance the factual accuracy, contextual relevance, and
起点 25 → 词 26–33 contextual relevance, and quality of generated response against
起点 30 → 词 31–38 generated response against the query raised by user
起点 35 → ? 词 36–43 —— 可是只有 42 个词,凑不满 8 个

图说:循环的条件是「起点 + 8 不能超过总词数」,所以起点 35 这一轮根本不会发生。
第 39 到 42 个词——「to a RAG system.」——**一个块都没进,直接消失。**

书印出来的输出正好七块,最后一块结尾是「…by user」9「to a RAG system.」不在任何一块里。

为什么这件事要紧

它不报错。 程序正常结束、输出正常打印、块数看起来很合理。 你唯一能发现它的办法,是自己把原文和所有块拼回去对一遍 —— 而没人会这么做。

丢的还偏偏是句尾。 英文句子的宾语、结论、限定条件常常在后半句; 这次丢掉的「to a RAG system」正是「提高的是谁的回答质量」这个限定。

顺带纠正一个名字

书管这个切法叫 n-gram这是作者自己的用法,和这一行里 n-gram 的标准含义不是一回事。

书里的用法标准含义
指什么「每块 n 个词、滑动 step 个词」的一种切块方式文本里任意 n 个连续词构成的片段,用来做词频统计
用在哪切文档统计语言模型、拼写纠错、检索里的短语匹配

而且书举的例子本身是错的: 它说「n=3 时,这句话会变成:RAG with Python」—— 那是三个词一整块,不是 3-gram 的写法;紧接着它又说「切成大小为 2 的 gram,就变成:RAG with, with Python」—— 这一句才是对的,而前一句和它自相矛盾10

9. 另起一处:朴素语义切分把九句里的五句丢没了

这是本章第二个失效现场,比上一个更严重。

走一遍

输入是九句话,分三组主题各三句:一组讲 LangChain,一组讲一类专门用来理解语言的模型,一组讲 Python。 配方的做法是11:

① 把 9 句各变成一串数
② 两两算相似度,得到一张 9×9 的表
③ 硬编码三个「中心句」:第 0、3、6 句
④ 对每个中心,把「和它相似度 > 0.5 且还没被分走」的句子收进同一簇
⑤ 每簇拼成一块

图说:第 ③ 步的三个中心是作者写死的,书自己承认这是「为了简单清楚」。
真正的问题在第 ④ 步——**没有第 ⑤ 步之外的兜底。**

第 ④ 步的条件是「> 0.5」。相似度没过 0.5 的句子,不属于任何簇。 而代码里没有任何一行处理这些句子。它们就这么没了。

结果:9 句进,4 句出

书印出来的三块是12:

Topic Chunk 1: LangChain is a powerful framework for working with large language models.
Topic Chunk 2: Transformers are deep learning models that understand language context.
Topic Chunk 3: Python is a popular programming language.
Python supports libraries like Pandas, NumPy, and Scikit-learn.

图说:一共 4 句。输入是 9 句。**五句消失了**,其中包括
「It provides tools for loading documents, creating embeddings, and building retrieval pipelines.」
——这句话讲的正是 LangChain 能干什么,信息量比留下来的那句还大。

注意第 3 块: 它收了两句 Python 的,却漏掉了中间那句 「It is used in machine learning, web development, and automation.」—— 因为那句以「It」开头,而「It」指谁不在句子里,它和中心句「Python is a popular programming language.」 的相似度过不了 0.5。

这是本章那颗雷的第一次现形,而且是在切分器内部就现形了。

为什么会这样:阈值法的通病

九句话在「意思空间」里的位置
●中心0 ●中心3 ●中心6
○ ○ ○ ○ ○ ○
└─ 落在 0.5 圈外的这些,代码里没人管

图说:凡是「符合条件的收进来」而没有「剩下的怎么办」的写法,都会静默丢东西。
书自己承认中心和阈值是「for simplicity」硬编码的,但**没有说未分配的句子会消失。**

10. 这颗雷会在哪里爆:块内指代断裂

这一节是全章的落点,也是全书最好的一条暗线。

病根一句话

一块文字里如果留下了失去指代对象的代词(It / They / 这 / 它),这一块就永远检索不准。

我们给这个病起个名字叫块内指代断裂,以便后面几章回指。 (第 10 章还有一种长得很像、但完全不同的病,叫查询侧指代 —— 那是用户的问题里有代词。 两者要严格分开:一个坏在库里,一个坏在查询里,修法完全不同。)

为什么它必然导致检索不准

回到第 1 节那张图的最后一句:每块单独变成一串数,每块单独被检索。

原文: Intermittent fasting has several benefits.
It may help with weight loss by reducing calorie intake.

切开后的那一块只有: It may help with weight loss by reducing calorie intake.

打分模型看到这一块时,它能确定的只有「某个东西有助于减重」。
「某个东西」是什么?——**不在这一块里,而模型只能看到这一块。**

图说:不是模型笨,是这一块里的信息真的不够。

账单:第 10 章配方 110

书在第 10 章有一个重排配方:问「间歇性禁食有什么好处?」,五条候选被逐条打分13:

分数那一块的内容
8.5342Intermittent fasting improves insulin sensitivity.
6.0997Exercise combined with intermittent fasting can boost fat loss.
3.8877Fasting can reduce inflammation and support cellular repair.
1.2349Drinking water during fasting helps with hydration.
−6.5435It may help with weight loss by reducing calorie intake.

减重是间歇性禁食最有名的好处,而这一条排最后,还是负分。 它和第一名差了 15 分,和倒数第二名差了将近 8 分 —— 不是名次差一点,是被扔出局了。

唯一的区别是它以「It」开头。 其余四条每一条都自带主语(fasting / exercise / water)。

判断(我们的,不是书里的): 我们认为这条负分的主因就是那个 It。 依据是同一份候选里的对照:另外四条主题都比它更偏(补水、消炎、运动),分数却全是正的; 而唯一含有问题所问关键词(好处 / 减重)的这一条反而垫底 —— 区别只剩「有没有主语」这一条。 如果错,会错在: 如果打分模型只是单纯不认为「减重」是「好处」的强相关词, 那么这条负分与代词无关。判据是把开头的「It」换成「Intermittent fasting」再打一次分 —— 这个实验书里没做,我们也没有跑。

怎么防

三条,按代价从低到高:

做法代价
在句子边界下刀,别在句中几乎免费 —— 用第 5 节那个退让顺序,把句号排在靠前的位置
重叠开得够大,至少装得下一个完整句子存储和检索量按重叠比例上升
给每块拼上一句它所属的上下文(比如章节标题、上一句)要额外一遍处理,而且拼上去的内容会稀释这一块的主题

书这三条一条都没提。 但它把病症印了四次。

11. 作者的判断与证据

书里给了证据的:

说法证据
块大小直接改变切出几块配方 63 的输出:200 / 500 / 1000 → 6 / 3 / 1 块
切法分结构式与语义式两类这一章开头那段定义,是全书少有的真解释
结构式适合排版规整的文档十三个配方,每个各挑一种看得见的标记
块太小会丢上下文配方 63 那次 200 字符切出的第 2 块,自己就是证据

作者只是断言、没有给证据的:

说法缺什么
「块大小常在 300–800 标记」书里没有一个配方用过这个量级,也没有做过任何对比
n-gram 切法「有助于跨块保住语义」它自己的输出丢掉了句尾,而书没有比较过丢与不丢的检索效果
按主题切分「保证每块的上下文不丢」它自己的输出丢了 9 句里的 5 句
「按元数据分组再切」这个配方分组之后仍是逐个文档单独切,分组那一步对结果没有任何影响,输出和不分组时一样
「自适应切分」保证代码块整块保留输出就是反例:一个 class Student 被空行劈成了两块,一块只剩构造函数、一块只剩方法14

12. 边界与局限

  • 这一章不讲怎么选块大小。 十四个配方用过 300、200、100、60、50 字符,一次都没说为什么。 选块大小的讨论被推到了第 6 章和第 9 章。
  • 不讲「递归」是什么,尽管这个切分器全书用了四次。
  • 不提现成的语义切分器,那个唯一的语义式配方是手写的替代品:中心句和阈值都直接写死在代码里。
  • 两个静默丢数据的配方,书一个字没提。
  • 按时间窗切分那个配方有个边界缺陷: 它每次只把起始时间往后推一个窗口, 所以两条记录间隔超过一个窗口时,后面所有块的时间标签都会偏小。书里的样例数据恰好避开了这个坑。
  • 没有一处讨论「切完之后怎么验」 —— 比如把所有块拼回去和原文比一遍, 这一步能当场抓出上面两个丢数据的配方。

13. 可带走的

全章那条走查,一行写完: 同一份 RAG.txt → 块大小 200 → 6 块,定义句被拦腰切断, 第 2 名是一块没有主语的「the factual accuracy…」→ 块大小 500 → 3 块,三段各自成块,刚刚好 → 块大小 1000 → 1 块,检索这一站等于没做。

  1. 模型数长度的单位是标记,不是字符 —— 一个标记大约合四到五个英文字符 (这个比例是从书里两处输出算出来的);
  2. 书里的 chunk_size 全是字符,而它自己给的经验值是标记 —— 差着四五倍,书从不声明;
  3. 「递归」指的是刀口的退让顺序:空行 → 换行 → 句号 → 空格 → 逐字符; 它只保证不超上限,不保证句子完整;
  4. 块太小切断句子,块太大等于不切 —— 1000 字符那次整篇只剩一块;
  5. 重叠防的是「一句话被切进两块,两块都答不了」;但重叠要大到装得下一个完整句子, 5 个词、50 个字符都不够;
  6. 切法只有两大类:靠看得见的标记切,靠意思切。 前者十三种写法是同一条原理的十三次重复;
  7. 凡是「符合条件的收进来」而没写「剩下的怎么办」的切分代码,都会静默丢数据 —— 书里两个配方各丢了一次,一次丢句尾、一次丢了 9 句里的 5 句;
  8. 静默丢数据不报错,唯一能发现它的办法是把所有块拼回去和原文对一遍;
  9. 块内指代断裂:块里留下失去指代对象的代词,这块就永远检索不准 —— 账单在第 10 章,一句「It may help with weight loss」被打了 −6.5435 分、五条垫底;
  10. 防它的第一条最便宜:在句子边界下刀,别在句中。

14. 原文地图

主题原书章原文位置
为什么必须切、三个坑CHAPTER 3 Document Splitting Techniquestext/10-fm-introduction.txt:103(搜「LLMs have token limits」) · text/10-fm-introduction.txt:111(搜「If the chunk is too small, it will lose the context」)
结构式 vs 语义式的二分同上text/10-fm-introduction.txt:41(搜「preserve the document’s original organization」) · text/10-fm-introduction.txt:43(搜「focus on meaning rather than structure」)
递归切分器的刀口列表CHAPTER 1 Foundation of Retrieval-augmented Generationtext/08-fm-introduction.txt:295(搜「separators = [」)
按标记切,同一句话 3 块同上text/08-fm-introduction.txt:369(搜「chunk_size=30, # max tokens per chunk」) · text/08-fm-introduction.txt:399(搜「Total Chunks: 3」)
n-gram 切法丢句尾CHAPTER 3 Document Splitting Techniquestext/10-fm-introduction.txt:221(搜「for i in range(0, len(words) - self.n + 1, step)」) · text/10-fm-introduction.txt:276(搜「generated response against the query raised by user」)
n-gram 的例子自相矛盾同上text/10-fm-introduction.txt:75(搜「for example, for n=3, the sentence will look like」) · text/10-fm-introduction.txt:81(搜「RAG with, with Python」)
语义切分丢 5 句同上text/10-fm-introduction.txt:438(搜「similarity_matrix[center][j] > 0.5」) · text/10-fm-introduction.txt:460(搜「--- Topic Chunk 1 ---」)
块大小 200/500/1000 → 6/3/1CHAPTER 6 Efficient Retrieval from Vector Storetext/13-fm-introduction.txt:308(搜「Testing with chunk size = 200」) · text/13-fm-introduction.txt:310(搜「Total Chunks Created: 6」) · text/13-fm-introduction.txt:334(搜「Total Chunks Created: 1」)
块大小经验值 300–800 标记同上text/13-fm-introduction.txt:187(搜「300–800 tokens depending on the use case」)
自适应切分把类劈成两块同上text/13-fm-introduction.txt:1612(搜「block.startswith("def ") or block.startswith("class ")」) · text/13-fm-introduction.txt:1750(搜「class Student:」)
重叠 5 个词兜不住CHAPTER 9 Effective Search for RAG Systemstext/16-fm-introduction.txt:1270(搜「Dense retrieval uses vector embeddings for semantic similarity. BM25 is」) · text/16-fm-introduction.txt:1274(搜「for semantic similarity. BM25 is a sparse retrieval method」)
「It」被打成 −6.5435CHAPTER 10 Implementing RAG with Chainstext/17-fm-introduction.txt:1716(搜「It may help with weight loss by reducing calorie intake」) · text/17-fm-introduction.txt:1708(搜「Intermittent fasting improves insulin sensitivity」)

Footnotes

  1. 出处:「CHAPTER 3 Document Splitting Techniques」第 103 段(text/10-fm-introduction.txt:103,搜「LLMs have token limits」)。原文:「大模型有标记上限,不必要地多用标记会增加使用成本。」第三条约束(整篇算一个向量搜什么都不像)书没有明说,是我们从第 02 章那个 Excel 例子推的。

  2. 出处:同章第 111 段(text/10-fm-introduction.txt:111,搜「If the chunk is too small, it will lose the context」)与第 115 段(text/10-fm-introduction.txt:115,搜「Wrong overlapping, sentence boundaries」)。

  3. 出处:「CHAPTER 6 Efficient Retrieval from Vector Store」第 187 段(text/13-fm-introduction.txt:187,搜「300–800 tokens depending on the use case」)。原文写的是 often ranging between 300–800 tokens depending on the use case and the model's context window补充(不在书里,来自通用知识): 英文里一个标记大约合四个字符,所以 300–800 标记大致是 1200–3200 个字符;这个换算我们在正文里用书自己的两处输出复算过一遍。

  4. 出处:「CHAPTER 6 Efficient Retrieval from Vector Store」第 308 段(text/13-fm-introduction.txt:308,搜「Testing with chunk size = 200」)、第 310 段(text/13-fm-introduction.txt:310,搜「Total Chunks Created: 6」)、第 322 段(text/13-fm-introduction.txt:322,搜「Total Chunks Created: 3」)、第 334 段(text/13-fm-introduction.txt:334,搜「Total Chunks Created: 1」)。输入文件与第 01 章那段正文相同(text/13-fm-introduction.txt:298,搜「RAG.txt is the input file」)。

  5. 出处:「CHAPTER 1 Foundation of Retrieval-augmented Generation」第 295 段(text/08-fm-introduction.txt:295,搜「separators = [」)。这一行的注释只写了 split on these char,没有解释顺序的含义。这个切分器在书里出现四次(配方 2、14、63、70),四次都只给参数、不给解释。

  6. 出处:「CHAPTER 9 Effective Search for RAG Systems」第 1270 段(text/16-fm-introduction.txt:1270,搜「Dense retrieval uses vector embeddings for semantic similarity. BM25 is」)与第 1274 段(text/16-fm-introduction.txt:1274,搜「for semantic similarity. BM25 is a sparse retrieval method」)。切分参数写在第 1165 段(text/16-fm-introduction.txt:1165,搜「def chunk_document(doc, chunk_size=30, overlap=5)」)。

  7. 出处:「CHAPTER 3 Document Splitting Techniques」第 41 段(text/10-fm-introduction.txt:41,搜「preserve the document’s original organization」)与第 43 段(text/10-fm-introduction.txt:43,搜「focus on meaning rather than structure」)。选法的建议在同一段末尾:排版规整的文档用结构式,无结构、概念密集的文本用语义式。

  8. 出处:同章第 221 段(text/10-fm-introduction.txt:221,搜「for i in range(0, len(words) - self.n + 1, step)」)。step 的定义在第 219 段(text/10-fm-introduction.txt:219,搜「step = self.n - self.overlap」);n=8、overlap=3 的设置写在第 123 段(text/10-fm-introduction.txt:123,搜「n=8 means each chunk will have 8 words」)。

  9. 出处:同章第 276 段(text/10-fm-introduction.txt:276,搜「generated response against the query raised by user」)—— 这是第 7 块,也是最后一块。输入那句话印在第 148 段起(text/10-fm-introduction.txt:157,搜「against the query raised by user to a RAG system」),句尾确实是「to a RAG system.」。

  10. 出处:同章第 75 段(text/10-fm-introduction.txt:75,搜「for example, for n=3, the sentence will look like」)与第 81 段(text/10-fm-introduction.txt:81,搜「RAG with, with Python」)。补充(不在书里,来自通用知识): n-gram 在自然语言处理里的标准含义是「文本中任意 n 个连续的词(或字符)构成的片段」,主要用于词频统计与语言建模,不是一种文档切块策略。

  11. 出处:同章第 428 段(text/10-fm-introduction.txt:428,搜「centers = [0, 3, 6]」)与第 438 段(text/10-fm-introduction.txt:438,搜「similarity_matrix[center][j] > 0.5」)。书自己承认中心与阈值是硬编码的:第 308 段(text/10-fm-introduction.txt:308,搜「hard coded list of cluster centers and a fixed similarity threshold」),并建议真实场景换成 K-means 或层次聚类 —— 但没有提未分配的句子会消失。

  12. 出处:同章第 460 段(text/10-fm-introduction.txt:460,搜「--- Topic Chunk 1 ---」)、第 466 段(text/10-fm-introduction.txt:466,搜「Transformers are deep learning models that understand language context」)、第 470 段(text/10-fm-introduction.txt:470,搜「Python supports libraries like Pandas, NumPy, and Scikit-learn」)。九句输入印在第 370 段起(text/10-fm-introduction.txt:375,搜「It provides tools for loading documents, creating embeddings」;text/10-fm-introduction.txt:388,搜「It is used in machine learning, web development, and automation」)。

  13. 出处:「CHAPTER 10 Implementing RAG with Chains」第 1716 段(text/17-fm-introduction.txt:1716,搜「It may help with weight loss by reducing calorie intake」)。其余四条印在第 1708–1714 段(text/17-fm-introduction.txt:1708,搜「Intermittent fasting improves insulin sensitivity」)。查询写在第 1702 段(text/17-fm-introduction.txt:1702,搜「What are the benefits of intermittent fasting?」)。同一个病在第 9 章配方 97 也现过一次(见脚注 6)。

  14. 出处:「CHAPTER 6 Efficient Retrieval from Vector Store」第 1612 段(text/13-fm-introduction.txt:1612,搜「block.startswith("def ") or block.startswith("class ")」)—— 规则写的是「代码整块保留」;而输出里第 1750 段(text/13-fm-introduction.txt:1750,搜「class Student:」)和第 1762 段(text/13-fm-introduction.txt:1762,搜「def promote(self):」)分别是第 4 块和第 5 块。原因是它先按空行分块,而这个类的两个方法之间正好有一个空行。同一个配方判断「这是不是列表」的条件是「这一块里有没有连字符」(text/13-fm-introduction.txt:1618,搜「elif "-" in block」),任何含连字符的句子都会被误判。