RAG with Python Cookbook — 全书拆解
30 秒导读: 这本书回答一个很窄、也很实在的问题: 「让机器先查资料再回答」这件事,每一步的代码到底怎么写?
先把这里的「机器」交代掉:它行话叫大语言模型 —— 读过海量人类写下的文字,学会的本事只有一件:照着眼前这段文字往下接,一次接一个词; 它的英文缩写叫 LLM,平时说的「大模型」就是它。标题里那三个字母是什么,第 2 节第 ③ 步讲。
它不讲原理,讲配方 —— 11 章、121 段可以直接跑的 Python 程序。 但它真正值钱的地方在别处:书里大量程序输出其实是失败的,作者原样印了出来、一个字没评。 同义词扩展把「跟我讲讲健康」改成了「跟缅因州讲讲健康」;摘要长度写死之后, 机器当场编出一本不存在的书;而唯一真正回答了问题的那句话, 因为开头是个「它」、而「它」指谁已经被切没了,被打了个负分排到最后一名。 这些都是现场证据,别处买不到。
本组文档是我们重写的完整拆解,十二章。读完不必看原书。
别串书: 我们库里另有一本书名几乎一样的
rag-python-cookbook(Dominik Polzer,O'Reilly)。 两本书除了书名毫无关系。
1. 先交代清楚:这是谁在什么时候写的
| 作者 | Deepak Dhyani —— 自述有 25 年以上的企业软件从业经历,带过工程团队,不是研究者1 |
| 出版 | BPB Online,2026 年 |
| 面向谁 | 自述面向工程师、架构师、数据科学家,目标是「做得出能上生产的系统」2 |
| 体量 | 全书约 50.5 万字符、121 个配方 —— 平均每个配方只摊到四千多字符,其中约七成还是代码和程序输出 |
| 环境 | Windows · Python 3.13.3 · LangChain 1.0.5(LangChain 是一套把这些步骤包好的 Python 库,这本书从头到尾用它)3 |
三件事必须先说,否则会误读这本书。
第一,它的时效性是最硬的价值。 2026 年出版,贴着 LangChain 1.0 之后改过的包名写。 同类书大多还停在旧写法上,而这本书里出现的一批新名字,你今天照着装就能跑。 但同一本书里也混着已经废弃两年的旧写法 —— 两种写法在相邻的两个配方里打架,书自己没有察觉。
第二,全程本地、零云端。 它一次都没有调用过任 何一家公司的在线服务。
那种在线服务有个统称叫接口:你把请求发过去,它把结果发回来,你不必知道它内部是怎么做的; 它的英文缩写你天天见,叫 API。
这本书用的全是能下载到自己机器上跑的小模型。 这是它的口径,不是它的立场 —— 作者没有声明任何利益相关,书里也没有推销任何产品。 但代价是真的:它所有的输出质量,都被这个选择压着。
第三,书里的代码有相当一部分跑不起来。 全角引号、两行粘在一起的 import、缩进跑到循环外面、赋值语句被注释吃掉。 照抄下来会直接报错。 这不影响读它的思路,但影响你对它的期待。
2. 全书一条主线
这本书的十一章,是一条被上一步逼出来的链条。下面把这条链完整走一遍 —— 不看后面任何一章,只读这一节,你也能把这本书讲给别人听。
细节全部留给对应的章节,这里只说「发生了什么、为什么只能这样」。
① 机器只会照自己肚子里的东西答
上面说过,这台机器的本事只有一件:照着眼前这段文字往下接,一次接一个词。 那它接得像不像人写的,靠什么?
靠一个叫训练的过程:拿海量文字反复调整机器内部那几十 亿个数,调到它接得像为止。 关键在于,这个过程做完就停了 —— 那几十亿个数从此固定下来,不会再自己更新。
所以有两件事它天生做不到:
- 昨天发生的事它不知道 —— 它读的那批文字停在某个时间点上;
- 你们公司的文档它一个字没见过 —— 那些东西压根不在公开的网上。
再让它读一遍新材料行不行? 那要花掉一次极其昂贵的重来,而且明天又有新的。这条路走不通。
② 但它会理睬你贴给它的东西
这一步是整件事的地基,也是最容易被跳过的一步。
因为它做的事就是「照着眼前这段文字往下接」,所以你写进去的内容, 和它肚子里的知识是同等待遇的 —— 都只是「眼前的文字」的一部分。
书里有一处现场证据:某个配方把两句资料贴在问题前面交给机器, 它给出的答案是把那两句一字不差地抄了回来。 抄得太老实了,老实到暴露了机制。
于是出路就出来了:别动这台机器,动它眼前看到的东西。
③ 那就先查资料,再把原文塞进去
具体是两个动作,一个都不能少:
用户问一句话
│
├─ 动作一:去你自己的资料里搜一遍,把最相关的几段找出来
│
├─ 动作二:把找到的**原文**连同问题一起写成一段话,交给机器
▼
机器照着这段话作答
图说:机器一个数都没改,变的只是它眼前看到的东西。
上面这两个动作合起来的这套做法,行话叫检索增强生成(英文 retrieval-augmented generation), 缩写就是标题里那三个字母 RAG —— 你在任何一家的文档、界面、报错里都会撞见它。
注意它不是一种模型,也不是一个产品。它是两个动作。
动作二里那段拼好的、交给机器的文字,行话叫提示(英文 prompt)—— 你在任何一家的界面和文档里也都会撞见这个词,说的就是它。
④ 可「资料」有十几种格式
真实的资料是 PDF、Word、网页、表格、一堆键值对堆成的数据文件…… 每种的内部结构都不一样。要是后面每一步都得为每种格式各写一遍,这事没法做。
所以第一站是统一形状:不管进来的是什么格式,一律变成同一种东西 —— 一段正文 + 一小袋标签。
标签里记的是「这段话哪来的、谁写的、什么时候的」,行话叫元数据。
这一步是唯一能挂上标签的时机。 漏挂了,后面再也补不回来 —— 而「这句话是从哪份文件里来的」全靠它。(第 02 章)
⑤ 整篇塞不进去,必须切块
两个硬约束把「整篇文档直接用」这条路堵死了:
- 机器一次能看的文字有上限,整篇塞进去会溢出;
- 而且整篇算成一个东西,就等于把里面所有主题平均掉了,搜什么都不像。
所以要切块:把长文档切成一段一段。而切多大、在哪儿下刀,是全书埋得最深的一颗雷 —— 它决定了后面几章会不会疼。(第 03 章)
⑥ 切完的块,凭什么能「按意思」被找到
因为机器只会算数,所以要先把每块文字变成一串数。
这串数的性质是被专门训出来的:意思相近的两段话,这两串数也相近。 于是「像不像」这个说不清的判断,变成了「远不远」这个算得出来的量。
这串数就叫这段文字的嵌入(embedding) —— 这个词你出门一定会撞见。
这串数还有一个更常见的名字,就叫向量:数学里管「一串有顺序的数」叫这个。 以后看到「把文档转成向量」,说的就是这一步。
干这件事的那个模型有个专门的名字叫编码器(encoder):它只负责把文字编成数,不负责说话。 记住这个词,第 ⑧ 步还要用它。
(这串数具体怎么算出来、凭什么意思近的就数也近、一共有多少个数,第 04 章讲。)
⑦ 几十万串数放哪儿,以及一个从头坑到尾的默认行为
存这些数、给它们建一套查得快的结构、按「谁离得最近」取前几条 —— 干这三件事的东西叫向量库。
中间那件事的产物有个名字叫索引:事先排好的一份查找结构,像书末尾那几页「某某见第几页」—— 有了它就不必每次从头翻。
取几条这个数一般叫 k。而这里有一个贯穿全书的坑:它永远凑够 k 条。
你要三条,它就给三条 —— 哪怕库里根本没有一条和你的问题有关。 书里的证据一地都是:问「怎么减少胡编」,第二名返回的是「出国旅行长见识」。
解药很简单:划一条相关性下限,低于线的一律丢掉。 书里有这味药,却从没和这个病放在一起说过 —— 这个连接是我们替它做的。(第 05 章)
⑧ 找回来的经常不对,怎么让它更准
两条路各有死角,所以要一起用:
| 走哪条路 | 强在哪 | 死角 |
|---|---|---|
| 按意思找 | 换个说法也能命中 | 型号名、人名、罕见词这类只认字面的东西反而找不准 |
| 按词面找 | 罕见词一抓一个准 | 换个说法就完全命中不了 |
按词面找那一路有个几十年的老办法,名字叫 BM25 —— 它比单纯数词频多做三件事。 这是全书唯一一次把一套算法(一串固定的计算步骤,同样的输入一定给出同样的输出)的内部讲清楚。
两路各出一份名单,合成一份;然后拿一个更贵、更准的模型,把前几条重新打一遍分。 这一步就叫重排。
干这活的模型叫交叉编码器(它不像上面那种编码器各编各的,而是把问题和候选那段话拼在一起 读一遍,直接吐一个「有多相关」的分)。
这是全书最扎实的一段,而且数字极其干 净: 重排之后,相关的那条得 +8.4985 分,四条无关的挤在 −11.34 到 −11.42 之间 —— 差了将近 20 分,界限清楚得不像话。(第 06 章)
⑨ 准是准了,库一大就慢
默认的做法是逐条算、一条不漏:库里一千条就算一千次,一百万条就算一百万次。
于是有了一堆加速手段:只搜其中几堆、按主题分区只搜一个区、把每串数压短一点, 还有一样是把问过的答案存下来、下次直接给 —— 这一样叫缓存。 它们的共同点是同一笔买卖:拿「可能找不到」换「快」。
「本该找到的,实际找到了几成」这件事有个名字叫召回。 每加一样加速手段,就要记一笔召回的账。 而书从头到尾没记过。(第 07 章)
⑩ 「找对了」和「答对了」是两件事
资料找回来之后,最朴素的做法是原样塞进提示 —— 这种做法有个名字叫 stuff。 短的时候够用,长了直接溢出。
然后你会发现一件让人不舒服的事:提示是请求,不是约束。 你写「不要只是复述,要给出解释」,它照样逐字复述; 你写「请标上 [1]、[2] 这样的出处」,它输出里一个方括号都没有; 你在提示里画一个数据格式的模板要它照填, 它给你一段看着像、程序却读不出来的东西。
书自己给了全书最有价值的一条忠告:提示只能鼓励,保证不了。 要真的保证,得用专门的接口去约束输出,不能只靠嘴说。(第 08 章)
⑪ 它给了一句答案,凭什么信它
机器一本正经地说出不存在的事,行话叫幻觉。
书里三处给答案配了「置信度」这个数,只有一处是真的: 一处量的是答案有多少个字符,一处量法有算术错误,只有第三处量的是「找回来的资料到底有多像」。
而它还自带一组对照:同一个摘要工具,把长度写死,机器为了凑字数当场编出一本不存在的书; 改成按输入长度动态算,摘要就老老实实。 这是「被格式要求逼出来的幻觉」最好的现场。(第 09 章)
⑫ 这些步骤要能拼装
每次都手写一遍这六站太蠢,所以把它们做成可以拼接、可以替换的段 —— 这叫链。
多轮对话(用户一句接一句地追问,而不是问一句就结束)的难点在一个你想不到的地方。
用户追问「那它用的是哪种检索方法?」, 这句话里的「它」不在句子里。 直接拿这句去搜,必然落空 —— 先崩的是检索这一步,和机器强不强没关系。
真正的做法是:先把「追问 + 之前说过的话」合成一个能独立成立的问题,再拿它去搜。 书靠现成的组件答对了,却没讲这一步 —— 而那正是多轮对话的全部难点。(第 10 章)
⑬ 链是写死的顺序,而书自称的落点是让它会变通
链有个根本毛病:第一次没搜到,它照样往下走,照样给你编一个答案出来。
出路是让机器自己控制检索,循环起来: 先给个初步答案 → 评估手上的证据够不够 → 不够就改写问题再搜一遍 → 直到满足停止条件(比如够有把握了、或者搜够几轮了、或者花的钱到顶了)。 这套做法叫代理式 RAG,是这本书自称的落点。
而书没落住。 最后一章十个「代理」,没有一个有循环、没有一次自我评估、没有一个停止条件。 更讽刺的是:全书对这件事最完整的定义,藏在第 7 章的结语里,而不在专讲它的第 11 章。(第 11 章)
⑭ 从头到尾,凭什么说这套东西是好的
这是全书最大的洞。
全书只用数字衡量过一次检索质量,结果是两条题对 了一条。书对这个数字不置一词。
而它的判分方法是:看标准答案里那几个字母,有没有出现在搜回来的文字里。 它量的不是「答对没有」,是「有没有出现这几个字母」。
另一处调设置更松,只比对标准答案的第一个词,而那几个词是「AI」「Deep」—— 「AI」这两个字母在几乎任何一段英文里都能命中。 于是 27 组不同的设置全部拿到满分 1.00,那张表整个不作数。(第 12 章)
⑮ 一句话收尾
这本书把「怎么做」写全了,把「做得对不对」整个漏掉了。
它的十一章是一条完整的施工图,而验收环节是空的。 读它的正确姿势是:拿它当施工图,别拿它当结论; 凡是它说「这样就好了」的地方,回头看第 12 章那两个坏掉的判据。
3. 十二章地图
这张表不用记任何术语 —— 每一章的名字后面,写的是「读完你能回答什么问题」。
| 章 | 读完你就能回答 |
|---|---|
| 01 一句话进去,一句话出来 | 机器为什么需要外挂资料?把资料贴给它,它凭什么会理睬? |
| 02 把十几种格式收成一种东西 | 同一批数据换个读法,为什么「Rajeev 多少岁」就答不上来了? |
| 03 切成多大、在哪儿切 | 切块的刀口下在哪儿,后面几章就在哪儿疼。这一章埋雷,别跳 |
| 04 一句话怎么变成一串数 | 机器只会算数,凭什么两句话能比出「谁更像」? |
| 05 向量放哪儿、怎么比 | 为什么你要三条它就给三条,哪怕一条都不相关?怎么治? |
| 06 找得准 | 怎么让搜回来的东西真的对。全书最扎实的一段,数字最漂亮 |
| 07 找得快 | 库一大就慢,加速手段各自偷偷牺牲了什么? |
| 08 找回来之后怎么答 | 提示里写清楚了,为什么它还是不照做? |
| 09 怎么知道它在编 | 系统报的「置信度」能信吗?什么样的设置会逼出胡编? |
| 10 把步骤拼成链 | 多轮对话里那个「它」,为什么会把检索整个搞崩? |
| 11 从写死的链到会变通的代理 | 什么才算「 会自己决定要不要再查一次」?书为什么没做到? |
| 12 怎么知道好是坏 | 你怎么证明自己搭的这套东西真的有用? |
推荐顺序: 01 → 02 → …… → 12,这就是流水线顺序,也是原书的顺序(除了 06、07 我们调了位置)。
只想拿结论的话: 读本页第 2 节,加第 03、06、12 三章。 只想找代码怎么写的: 直接查你要的那一站,每章末尾都有回原文的跳转表。
4. 这本书覆盖什么、不覆盖什么
这两张表和上面那张地图一个口径:不用记任何术语。
覆盖(而且给了可以直接跑的代码)—— 读完你能做:
- 把 PDF、Word、网页、表格、一堆键值对堆成的数据文件读进同一套流程;
- 把长文档切成块,并且知道十几种下刀的位置各适合什么材料;
- 把文字变成一串数、存进去、按「谁最像」取回来;
- 两条搜法一起用、把结果合成一份、再拿更贵的模型把前几条重新打分;
- 库大了之后的一整套加速手段,以及它们各自的代价;
- 把搜到的东西交给机器作答,并按你要的形式输出;
- 把这些步骤拼成可复用的段。
不覆盖(别指望在这本里找):
| 缺什么 | 说明 |
|---|---|
| 任何算法的推导 | 全书零公式。它告诉你把哪个数字调成多少,不告诉你为什么是这个数字 |
| 怎么验证自己做得对 | 只用数字衡量过一次,而那次的判分方法本身是坏的 —— 这是最大的洞 |
| 加速手段真正的内部机制 | 有一章挂着「近似搜索」的标题,演示的却是精确的暴力搜索,一点都不近似 |
| 多路结果的标准合并法 | 业界有个只看名次不看分数的通用做法,书从未提及(我们在第 06 章补上) |
| 上生产要操的心 | 花多少钱、等多久、谁能看哪些资料、敏感信息怎么脱、怎么防有人往提示里下毒 —— 第 7 章提了一句「安全需要独立的一层」,此后再无下文 |
| 云端模型与商用服务 | 全程本地小模型。你要评估「上了大模型会怎样」,这本书帮不了你 |
| 中文与多语种、图片,以及知识图谱(把资料先整理成「谁—和谁—什么关系」的一张网,再顺着网找)那条路 | 一个字没有 |
5. 今天读,要补的六处
这六处不是它写错了,是它没写。六处我们都已经从自己的书架上补齐,写进了对应的章节。
| 缺口 | 我们补在哪 | 依据 |
|---|---|---|
| 「意思近的东西,那串数为什么会近」 | 第 04 章第 3 节 —— 那是训出来的,不是天然的 | 我们的 ai-frontier-reference 书架4 |
| 多路结果的标准合并法 | 第 06 章第 5 节 —— 只看名次不看分数的 RRF | 我们的 ai-agent-reference 书架5 |
| 加速用的那套查找结构到底近似在哪 | 第 07 章第 3、4 节 —— 分堆、跳图、压短码 | 我们的 ai-agent-reference 书架 |
| 要格式该怎么真的管住(不能只写在提示里) | 第 08 章第 6 节 | 我们的 ai-frontier-reference 书架 |
| 多轮追问怎么改写、「退一步提问」的来历 | 第 10 章第 5、6 节 | 同库的 learning-langchain 与 essential-graphrag |
| 「怎么衡量一套 RAG 好不好」 | 第 12 章 —— 分检索层和生成层两层量 | 我们的 ai-frontier-reference 书架与同库的 hands-on-rag-for-production-design |
6. 我们的判断
判断(我们的,不是书里的): 这本书今天的价值排序是 —— ① 它自己的失败输出(独一份) > ② 贴着最新库版本的配方索引(会过期,但现在最新) > ③ 它的概念讲解(极薄,而且有几处是错的)。 引用它的时候引①和②,别引它的概念表述;概念层去读同库的
hands-on-rag-for-production-design(讲工程取舍)。 如果错,会错在: 如果那些「失败输出」其实是排版事故而不是程序真实输出 (这本书确实有排版事故,比如某个配方的输出串到了另一个配方里), 那么我们据以立论的证据就要逐条重核。判据是:代码本身是否必然产生那个输出 —— 我们引用的每一处都当场核过代码。
判断(我们的,不是书里的): 这本书最该被带走的一条,不是任何一段代码, 而是**「一个数看着像那么回事,不等于它在量你以为它在量的东西」**。 全书三个「置信度」两个是假的,唯一一次评测的判分方法是坏的,调参表全是满分 —— 每一处都长得很专业。这类错误不会报错,只会让你放心。 如果错,会错在: 如果作者本意只是「演示 API 怎么调」、从未打算让这些数字被当真, 那这就不是错误,而是我们对一本配方书要求过高了。 但书里把它们写成了结论(「最优的那组设置是……」),所以我们按结论追究。
判断(我们的,不是书里的): 这本书里那条最好的暗线,书自己从没连起来: 第 3 章怎么切,第 10 章就怎么疼。 一块文字里如果留下了失去指代对象的代词(「它」「这」),这一块就永远检索不准 —— 因为再聪明的打分模型也看不出「它」指谁。 书在四个不同的章节印出了这个病的四次发作,一次都没有指认出病因。 如果错,会错在: 如果那句被打成负分的话之所以垫底,主要原因是别的 (比如它讲的是「减重」而问题问的是「好处」,主题本来就偏), 那这条暗线就只是巧合。判据是:把开头的「It」换成明确的主语再打一次分 —— 这个实验书里没做,我们也没有跑,所以它仍然是判断,不是结论。