RAG 入门笔记:从 0 搭起一个最基础的 RAG
这篇主要讲什么
这一份 PDF 对应的是 Part 1 ~ Part 4,重点不是炫技,而是先把 RAG 最基本的工作流搭起来。
如果用一句大白话来讲,RAG 做的事情就是:
先去资料库里找内容,再拿找到的内容去回答问题。
它解决的问题也很直接:大模型本身记忆不稳定、知识会过期、容易一本正经地胡说。RAG 的思路不是让模型“硬背”,而是让模型“边查边答”。
RAG 最基础的四步
1. 先准备资料
文档先加载进来,比如网页、PDF、数据库里的文本。
这里我自己的理解是:资料质量比模型版本更重要。因为后面检索和回答,都是建立在“你喂进去的资料值不值得信”这个前提上。
2. 再把资料切成小块
原文里用了 RecursiveCharacterTextSplitter 这种切分器。它的核心想法不复杂:
不要把整篇长文一股脑塞进去,要切成更容易命中的小段。
为什么要切?
- 太长的文本不容易准确匹配问题
- 太大的块会混入很多无关信息
- 太小的块又会丢失上下文
所以切分不是越细越好,而是要在“信息完整”和“检索精度”之间找平衡。
我个人觉得,很多人一上来就纠结模型选哪个,反而忽视了切分。实际上,切分策略常常比换一个更贵的模型更影响结果。
3. 把文本变成向量,放进向量库
这一步的意思是:
把文字变成一种机器更方便比较相似度的数字表示。
以后用户来提问,也会把问题转成向量,再去找“最像”的文本块。
原文提到了余弦相似度。可以把它简单理解成:
两个句子意思越接近,向量方向越接近。
不需要把这件事想得太数学。对于使用者来说,重点只有一个:向量检索不是看字面一模一样,而是看语义像不像。
4. 检索后再生成答案
这是最典型的 RAG 结构:
- 用户提问
- 检索器找相关片段
- 把片段和问题一起交给模型
- 模型根据上下文生成答案
这一步很关键,因为它决定了模型是在“空想”,还是在“看材料说话”。
这份内容的核心思想
我觉得核心思想只有一句:
不要指望模型自己什么都知道,要给它一个能随时查资料的外脑。
这也是 RAG 的出发点。它不是为了替代模型,而是为了弥补模型知识不稳定、上下文有限、可追溯性弱这些天然缺点。
我自己的理解
我会把基础版 RAG 理解成一个“开卷考试系统”。
- 文档库,就是考试资料
- 检索器,就是翻书动作
- 大模型,就是整理答案的人
如果书没整理好,翻书动作就会很慢、很乱、很容易翻错页。最后答案自然不会稳定。
所以基础版 RAG 真正的重点不是“把链子跑通”,而是下面这三件事:
- 文档是否干净
- 切分是否合理
- 检索到的内容是否真的和问题有关
初学时最容易踩的坑
- 以为能跑通,就等于效果好
- 切分块太大,导致检索结果又长又散
- 只看模型回答,不看它到底检索到了什么
- 资料本身就不准确,却怪模型回答差
学完这篇后应该记住什么
如果只记一件事,我建议记这个:
RAG 不是一个单点技术,而是一条流程。流程里最前面的资料处理做得差,后面的模型再强也救不回来。
一句总结
基础版 RAG 的本质,不是“让模型更聪明”,而是“让模型先找到对的资料,再基于资料回答”。这一步看起来朴素,但后面所有高级技巧,其实都建立在这个地基上。
核心代码实现
方法 1:最基础的 RAG 流程
1 | # 1. 读取文档 |
方法 2:文本切分
1 | def split_documents(docs, chunk_size=1000, chunk_overlap=200): |
方法 3:向量检索
1 | def retrieve(question): |
方法 4:检索后生成
1 | def rag_answer(question): |