主题
第 14 周 · Day 1:RAG 开篇——检索增强生成,给 Agent 装上企业私有知识
对应手册任务:学习「RAG 概念 + Naive RAG 流程」,动手画出「文档 → 切块 → Embedding → 检索 → 生成」的流程图,当日产出一张离线/在线分色的 RAG 全景图。本篇只解决一个问题:LLM 不知道你公司的报销制度写了什么,与其花大钱重新训练模型,不如在它作答之前,先把最相关的那几段资料递到它眼前。
今日目标
- 说得清 RAG 解决什么问题,以及它和长上下文、微调各自的适用边界
- 掌握 Naive RAG 的完整链路:离线侧四步建库,在线侧四步问答,每一环的输入输出都说得出口
- 独立画出一张「文档 → 切块 → Embedding → 检索 → 生成」的流程图,离线、在线两条线分色,并能对着图指出三个最容易翻车的环节
概念讲解:为什么需要 RAG
先看一个场景。你给公司做的客服 Agent 已经跑起来了,工具调用、多 Agent 协作、人工介入都齐了。周一早上,运营同事在群里问它:「出差住宿标准一晚多少钱?」它一本正经地报了一个不存在的数字。
不是模型不行,是它真不知道。LLM 的知识边界就两条:训练数据截止到哪天,公开互联网上有什么。你们公司的差旅制度、产品手册第 38 页、上季度的故障复盘,它一个字都没见过。而这些「企业私有知识」,恰恰是问答场景里八成问题的来源。
怎么让模型知道?摆在面前的三条路,逐个看。
第一条路,把文档塞进上下文。制度全文贴进 prompt,模型确实能答。但每次问答都要传几万字,token 按量计费,账单先扛不住;更要命的是大部分内容和当前问题无关,真正有用的那段被淹没在里面,模型反而容易看漏。文档只有一两页时这招最好用,两百页的手册就别想了。
第二条路,微调。算力和数据准备的成本先不说,致命伤是知识会过期:制度每季度改一次,每改一次都重训一遍?而且微调擅长学的是风格、格式、领域语感,不擅长精确记住事实,硬灌知识进去,模型反而更容易编造。一句话,微调适合「教模型怎么说话」,不适合「给模型喂随时会改的资料」。
第三条路,RAG(Retrieval-Augmented Generation,检索增强生成)。思路一句话:回答之前先检索。把公司文档提前切块、转向量、存进向量库;用户提问时,先拿问题去库里捞出最相关的几段,把它们和问题一起拼进 prompt,再让 LLM 照着资料作答。这就是「检索即外挂记忆」:知识不进模型权重,放在外面,用的时候查出来注入。知识更新不用碰模型,重新入库就行。
做个类比就透了。这是一场考试:长上下文是把整本教材搬进考场,搬得动也翻不过来;微调是考前把书背下来,背完书改版了你也不知道;RAG 是开卷考试,先翻到相关那页摊开在桌上,照着答。大多数企业知识问答,开卷就是最优解。
RAG 还有个隐藏好处:可溯源。回答末尾附一句「依据:差旅制度 3.2 节」,用户信不信得过,是完全不同的两回事。
核心知识
Naive RAG 里的「Naive」不是贬义,它指不加任何优化的最朴素实现,是后面所有进化的底座。先把全景装进脑子,再逐环拆。
1. 全景:一条主线,两条线
主线五个环节:文档 → 切块 → Embedding → 检索 → 生成。落到工程里拆成两条线:
- 离线侧(建知识库):文档 → 切块 → Embedding → 入库。跑一次就完,文档更新时重跑
- 在线侧(每次问答):问题 Embedding → 相似检索 → 拼 Prompt → LLM 生成。每来一个问题跑一遍
像一座图书馆。离线侧是编目上架:进书、拆册、做索引、归架,做完就静静待着。在线侧是读者借阅:问管理员一个问题,管理员查索引,把最相关的那几页复印出来递给你。两条线唯一的交汇点是书架(向量库):离线侧往里写,在线侧从里读。
今天动手任务要画的流程图,画的就是这两条线,所以必须分色。
2. 离线侧四环,逐个看
文档。 一切知识来源:PDF、Word、飞书文档、Confluence、网页。第一步全是把它们变成纯文本。PDF 里的表格和双栏排版是出了名的难缠,这个坑后面专门填。
切块(Chunking)。 为什么必须切?三个理由:Embedding 模型有输入长度上限,整篇进不去;就算进得去,一篇五千字被压成一个向量,语义被稀释成一碗糊糊,分不出「这段讲住宿、那段讲机票」;就算分得出,检索粒度太粗,捞上来一整章塞进 prompt,token 白烧。典型做法是按几百字一块切,块与块之间留一段重叠(overlap),防止一句话被拦腰截断。
Embedding。 把一段文本变成一个向量,也就是一串数字,比如 1536 个浮点数。它的神奇之处在于:语义相近的文本,向量距离也近。「住宿标准」和「差旅住宿报销额度」字面差得远,向量却挨得很近。所以用户不用记住制度文档的原文用词,换个说法照样搜得到。关键词搜索做不到这一点,这是语义检索和字面搜索的分水岭。
入库。 向量数据库(Chroma、Qdrant、pgvector 都行)存的不玄,就三样东西:向量、原文、元数据(哪个文档、哪一节)。入库后它提供一个能力:给一个向量,返回距离最近的 K 条。仅此而已。
3. 在线侧四环,逐个看
问题 Embedding。 用户的问题过一遍 Embedding 模型,变成向量。铁律:必须和离线侧用同一个模型。不同模型的向量空间不互通,拿 A 模型的问题向量去 B 模型的库里找邻居,相似度全是噪声。
相似检索。 拿问题向量去库里找最近的 K 个切块,K 一般取 3 到 5,这一步通常不到 100 毫秒。
拼 Prompt。 把检索到的切块、用户问题、行为指令组装成最终 prompt,长这样:
text
你是公司制度助手。仅根据下面的资料回答问题,资料里没有的就说不知道。
【资料】
{切块 1:差旅制度 3.2 节,住宿标准……}
{切块 2:差旅制度 3.3 节,超标审批……}
【问题】
出差住宿标准一晚多少钱?「仅根据资料回答,没有就说不知道」这一句,是防幻觉的第一道闸。
LLM 生成。 模型照着资料作答。答案的依据就在上下文里,它不需要凭记忆发挥,幻觉概率大幅下降,还能顺手标出处。
4. 每一环怎么翻车:本周期作战地图
Naive RAG 能跑,但每一环都有经典的翻车姿势。提前预告,这就是本周期的地图:
| 翻车点 | 典型现场 | 后果 |
|---|---|---|
| 切块不当 | 一张费率表被从中间切断 | 检索到了也读不懂,答案缺半截 |
| 检索不准 | 答案明明在库里,Top-K 里就是没捞到 | 模型拿着无关资料硬答 |
| 生成幻觉 | 检索结果里没有答案,模型编了个数字 | 一本正经地胡说,比不答更糟 |
注意,用户感知到的「答错了」,病根可能埋在前面任何一环。这正是先画全景图的意义:出了问题,你得知道沿哪条线排查。本周期就把这张地图逐个点打掉:切块策略、检索优化、防幻觉,一天拆一环。
5. 和 Agent 怎么接:两种姿势
你上一周期刚练完 Agent、工具、多 Agent、HITL,自然要问:RAG 和 Agent 什么关系?RAG 不是 Agent 的替代品,是一块能力,接法有两种。
姿势一:RAG 做成工具。把检索封装成一个 search_knowledge_base(query) 工具,挂进 ReAct Agent 的工具列表。用户问「住宿标准」,Agent 自己判断需要查库,发起工具调用,拿到切块再组织回答。检索时机由模型决策,知识库和天气查询、订单系统平起平坐,适合知识库只是众多能力之一的场景。
姿势二:RAG 做前置管道。问题进来先固定过一遍「检索 → 拼 Prompt → 生成」,用户无感。流程写死,可控、好测,适合纯知识问答机器人。
取舍就一条:要不要让模型自己决定「查不查」。姿势一灵活但多一跳决策,姿势二简单但每次都检索。本周期先用裸脚本把 Naive RAG 跑通,再练姿势一,封装工具的活你上周就会了。
动手任务:画一张 RAG 流程图,一步一步
手册任务:画出「文档 → 切块 → Embedding → 检索 → 生成」的流程图,离线/在线分色。拆成 5 步,全程约 20 分钟。
第 1 步:选工具。 推荐 Excalidraw(手绘风、自由排版,导出 PNG 存档),纸笔或任意白板工具也行。下面每一步先把「该画什么」按文字结构列清楚,你在工具里照着摆节点。
第 2 步:画离线侧。 四个节点串成一条线(框成一个区域,标注「离线侧 · 建知识库」):
- 原始文档(PDF / Word / 飞书)→ 切块(几百字一块,带重叠)→ Embedding(文本转向量)→ 向量数据库(向量 + 原文 + 元数据)
第 2 步的要点是那个数据库节点:全图最该用特殊形状标出来的就是它(Excalidraw 里用圆柱体 cylinder),因为它是两条线的交汇点。
第 3 步:画在线侧。 五个节点串成一条线(框成另一个区域,标注「在线侧 · 每次问答」):
- 用户问题 → 问题 Embedding(和离线侧同一个模型)→ 相似检索(取 Top-K 切块)→ 拼 Prompt(资料 + 问题 + 指令)→ LLM 生成(仅根据资料作答)→ 回答用户
第 4 步:连上那条桥,再分色。 两条线之间只连一条边:向量库到相似检索,用虚线箭头表示「跨线读取」,线上标注「Top-K 切块」。最终全图的四要素:
- 离线侧(冷色区域):原始文档 → 切块 → Embedding → 向量数据库
- 在线侧(暖色区域):用户问题 → 问题 Embedding → 相似检索 → 拼 Prompt → LLM 生成 → 回答用户
- 跨线桥:向量数据库 ⇢ 相似检索(虚线,唯一接口)
- 分色:离线统一浅蓝类冷色、在线统一浅橙类暖色,一眼分清两条线
配色随手就行(Excalidraw 选中节点改 fill 色),关键是「两条线两种颜色 + 一条虚线过桥」这个视觉结构。
第 5 步:标翻车点,对着图讲一遍。 在切块、相似检索、LLM 生成三个节点旁各加一行标注:「易翻车:切块不当」「易翻车:检索不准」「易翻车:生成幻觉」,把第 4 小节的作战地图落到图上。画完不算完,合上文章,对着自己把这张图从头讲一遍:离线四步、在线四步、交汇点在哪、三个雷埋在哪。讲不顺的地方,就是接下来要重点补的地方。
用 Excalidraw 的话,画法对应过去:两个 Frame 分别框住离线、在线;数据库用 cylinder 形状;跨线那条边用虚线箭头,线上标注「Top-K 切块」;翻车点用红字便签贴在对应节点旁。要素一致,工具随意。
画完存档
导出 PNG 存进本周笔记,标注「Week14 Day1 产出:RAG 流程图」;.excalidraw 源文件一起留——第 15 周优化 RAG 时要在这张图上改。
常见踩坑
坑 1:把 RAG 等同于向量数据库。 RAG 是一套架构思路,向量库只是其中一个零件。检索这环可以用向量检索,可以用关键词检索(BM25),生产上更常见的是两者混合:专有名词、单号、型号,字面匹配反而更准。先有流程图,再挑零件,别被某个数据库的营销带着跑。
坑 2:离线在线用了不同的 Embedding 模型。 向量空间不互通,问题向量和文档向量根本不在同一个坐标系里,算出来的相似度全是噪声,症状是「答案明明在库里,怎么搜都搜不到」。铁律:进出必须同一个模型;要换模型,全量重新入库,没有捷径。
坑 3:觉得切块大小无所谓。 切太大,语义被稀释成糊糊,检索分不出精度,塞 prompt 还烧 token;切太小,上下文丢失,检索到了也读不懂。经验起点是每块 300 到 500 字、相邻块重叠 10% 到 20%,然后拿你自己的真实文档去调,本周期后面几天就是干这个的。
坑 4:以为检索到了模型就不会胡说。 检索结果里没有答案时,模型照样可能硬编一个。prompt 里写「没有就说不知道」只是第一道闸,不是保险箱,生成端的防幻觉还有后续手段,都在地图上。
坑 5:一上手就想把 RAG 挂进 Agent。 先用裸脚本把 Naive RAG 串起来,看清楚每一环的输入输出,再封装成工具挂进 ReAct。跳过这一步,出了问题你分不清是检索的锅还是 Agent 决策的锅,调试难度直接翻倍。
自测问题
先自己答,再展开对照。答不上来的,回对应小节看一遍。
- 长上下文、微调、RAG 三条路,各自的适用边界是什么?
参考答案
文档量小且稳定(几页、很少改),直接塞长上下文最省事;要改变的是模型的说话方式、输出格式、领域语感,用微调;知识量大、频繁更新、需要溯源,用 RAG。三者不互斥,生产系统经常是 RAG 打底、微调点缀。
- 离线侧和在线侧各跑多少次?两条线的交汇点在哪?
参考答案
离线侧建库时跑一次,文档更新时重跑;在线侧每来一个问题跑一遍。交汇点是向量数据库:离线侧往里写(向量 + 原文 + 元数据),在线侧从里读(Top-K 相似切块)。
- 为什么必须切块?整篇文档直接 Embedding 不行吗?
参考答案
三个原因:Embedding 模型有输入长度上限,长文档进不去;就算进得去,整篇压成一个向量,语义被稀释,检索分不出粒度;就算分得出,捞上来整篇塞 prompt 浪费 token。切块是为了让「检索的最小单位」和「回答问题所需的信息量」大致匹配。
- 语义检索和关键词检索,本质区别在哪?
参考答案
关键词检索匹配字面,查询和文档用词不一致就搜不到;语义检索基于 Embedding,语义相近即可命中,口语提问也能搜到术语写法的文档。但语义检索对专有名词、编号这类精确匹配反而偏弱,所以生产上常用混合检索。
- RAG 接进 Agent 的两种姿势是什么?怎么选?
参考答案
姿势一,RAG 做工具:封装成 search_knowledge_base 挂进 ReAct 工具列表,检索时机由模型决策;姿势二,RAG 做前置管道:每次问答固定先检索再生成。分界线是要不要让模型自己决定「查不查」:知识库只是众多能力之一,选姿势一;纯知识问答,选姿势二。
延伸阅读
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks,RAG 的原始论文(Lewis 等,2020),今天讲的每一步在论文里都有学术原型
- OpenAI:Embeddings 指南,看「文本变向量」到底怎么用,对理解离线侧第 3 环有帮助
- Excalidraw,本篇推荐的画图工具,手绘风,画完导出 PNG 存进笔记
今天的流程图留好,本周期接下来几天就照着它拆零件:先把切块做扎实,再把检索调准,最后把生成的幻觉摁住,一天解决图上一个环节。