主题
11.1 RAG 完整生命周期分层:先把整台机器拆开看
“与其给 RAG 贴满‘第一代、第二代、第三代’的进化标签,不如把它当成一条从原料到成品的流水线工厂 —— 我们逐层参观,看每一道工序在解决什么具体问题。” 本章采用一种与大多数教程不同的讲法:先建立“整机”视野,再逐个攻破业务痛点。而建立整机视野的最好方式,就是把 RAG 按完整生命周期分成四大层次,像参观工厂一样一层层看过去。
为什么不用“版本号”叙事?
很多资料会把 RAG 分成 Naive RAG(朴素版)→ Advanced RAG(进阶版)→ Agentic RAG(智能体版),像手机换代一样讲“第几代”。这种讲法有两个毛病:
- 容易产生“一代更比一代强”的错觉:实际上 Naive 的“简单切块 + 向量检索”在数据量小、问题简单时依然是最优解,你没必要为了“用上高级货”而强行加一堆组件;
- 忽略了“组件之间的协作”:真实生产系统里,HyDE、混合检索、重排、图谱、Agentic 自省是同时并存、各司其职的,而不是“换代淘汰”的关系。
所以我们换一种更贴近工程实践的切法 —— 按数据在系统中的流转阶段分层。这也是你以后向别人讲清任何 RAG 系统时最好用的框架。
RAG 完整生命周期的四大层次
① 数据准备层(离线):决定 RAG 的上限
这是整条链路里最“脏、累、但回报最高”的一层,业界有句俗话:“垃圾进、垃圾出”(Garbage In, Garbage Out)。这一层要回答的问题是:
| 子问题 | 典型做法 | 对应章节 |
|---|---|---|
| 原始文件五花八门,怎么统一成干净文本? | PDF/Word/HTML/Markdown 多格式解析、去噪、OCR、表格还原 | 11.2 |
| 拆成多大多小的块才不会语义断裂? | 递归字符切块、标题切块、语义切块、父子切块 | 11.2 |
| 怎么把文字变成机器能算的坐标? | Embedding 模型(BGE/GTE/OpenAI)、多模态嵌入 | 11.3 |
| 向量存哪里、怎么索引才查得快? | 向量数据库(Chroma/Qdrant/Milvus/Pgvector)与 ANN 索引 | 11.4 |
💡 比喻:这一层像医院的病历室 —— 把纸质病历、化验单、扫描件整理成能读的电子病历。医生(LLM)再会看,递上去的如果是糊成一团的复印件,也开不出靠谱的医嘱。
② 检索层(在线):决定 RAG 的精度
用户问一个问题,系统要在几十毫秒内从海量数据里捞出最相关的几段。这一层要回答:
| 子问题 | 典型做法 | 对应章节 |
|---|---|---|
| 用户口语化、有指代、意图模糊怎么办? | 查询重写(HyDE / Multi-Query / Step-Back)、意图路由 | 11.6 |
| 向量检索“意会”失灵,关键词检索“抠字眼”失灵怎么办? | 混合检索:Dense + BM25 多路召回 | 11.5 |
| 多路结果怎么科学合并排序? | RRF 倒数排名融合 + Cross-Encoder 重排 | 11.5 |
| 宏观/跨章节问题单靠向量搜不到怎么办? | 知识图谱与 GraphRAG 的社区级检索 | 11.7 |
③ 生成层(在线):决定 RAG 的质感
检索回来的“病历页”再好,也要医生(LLM)把它们写成一份说得通的医嘱。这一层要回答:
- 检索回来的 Top-K 段落怎么拼进 Prompt?顺序、去重、压缩噪声;
- 怎么让大模型“只根据资料说话”而不是自由发挥(降低幻觉);
- 怎么让回答自带引用出处(溯源),方便用户和系统核查。
④ 评估与运维层(闭环):决定 RAG 能不能持续变好
这是最容易被人忽略、但生产环境最关键的一层。没有这一层,你永远说不清“我改了切块参数之后,系统到底是变好了还是变差了”。这一层要回答:
- 用什么量化指标衡量“检索准不准、回答忠不忠实”?(RAG 三个主要指标)
- 线上每一次请求的耗时、Token 消耗、节点链路怎么观测?(LangSmith / Phoenix)
- 出现 Badcase 后如何沉淀成回归集,防止下次改动把效果改回退?
四层不是直线,而是带版本号的闭环
真实系统不会“入库一次,从此不动”。更像医院每天收新化验、改用药目录、开病例讨论:文档更新会触发重新解析和索引;线上 Badcase 会进入评测集;评测结果又决定是否调整切块、检索或生成策略。
| 变化 | 必须跟着变的东西 | 不同步会怎样 |
|---|---|---|
| 文档内容或权限变化 | Chunk、向量、稀疏索引、引用锚点、缓存 | 答案引用旧制度,甚至越权泄露 |
| Embedding 模型变化 | 全量向量与 ANN 索引版本 | 新查询向量和旧文档向量不在同一坐标系 |
| Prompt / LLM 变化 | 回归评测基线与缓存命名空间 | 命中旧答案,无法判断效果回退 |
| 检索策略变化 | 候选数、重排与上下文预算 | Recall 提高了,延迟和噪声也可能同时升高 |
因此每次请求至少要能追到四个版本:知识快照、索引版本、检索配置、模型与 Prompt 版本。它们就像药品包装上的批号;出了问题才能知道是哪一批病历、哪条处理流程出了错。
先做失败归因,再选“高级技术”
| 看到的症状 | 先查什么 | 不要急着做什么 |
|---|---|---|
| 正确文档完全没进候选集 | 解析、切块、查询改写、Recall@K | 先换更大的生成模型 |
| 正确文档进了候选集但排太后 | 融合、重排、过滤、nDCG/MRR | 盲目调大 Top-K |
| 资料正确但答案编造 | 上下文组织、接地生成、逐主张验证 | 再建一个向量库 |
| 答案正确但延迟太高 | 每阶段 P95/P99、缓存、并发与模型调用数 | 只看最终总耗时 |
| 只有新制度问题答错 | 来源状态、生效日期、索引与缓存版本 | 把新旧文档都删掉重来 |
这张表是后续各节共同的“故障分诊台”:先确定错误发生在哪一层,再动对应零件。
RAG 与“邻居技术”的边界怎么划?
学习 RAG 时最常见的困惑是:它和微调、长上下文、Agent 到底什么关系?用一张表说清:
| 技术 | 核心思路 | 适合场景 | 不适合场景 |
|---|---|---|---|
| RAG(本章主角) | 提问时检索切块,把资料拼进提示再生成 | 知识会频繁更新、需要溯源、数据量大 | 需要模型掌握某种表达风格或推理方式 |
| 模型微调(Fine-Tuning) | 用数据改变模型权重 | 固定风格、领域行话、特定格式输出 | 知识更新快(微调一次成本高、周期长) |
| 长上下文(Long Context) | 把更多资料直接塞进窗口 | 单篇/少量文档就能覆盖问题 | 资料海量(塞不下)、成本爆炸、容易“迷失在中间” |
| Agent(智能体) | 自主规划、调工具、多步推理 | 需要拆解多步任务、动态决策 | 单轮简单问答(用 Agent 反而更慢更贵) |
| LLM Wiki(知识编译) | 入库时把资料编成互相链接的 Wiki 页,提问时先读这本已经整理过的书 | 长期积累的笔记、人物/项目/概念网络 | 必须逐条引用制度原文;数字对错不能靠模型归纳 |
💡 生产实践:这几者从来不是“二选一”,而是组合拳 —— 用微调定风格,用 RAG 供知识,用长上下文兜底单文档,用 Agent 编排复杂任务。LLM Wiki 若出场,也是解析完成之后的另一条路,不是“更高级的 RAG”。
中文圈有时把 LLM Wiki 顺口叫成「编译式 RAG」,听得懂,但名字容易糊。RAG 三个字母的核心是提问那一刻的 Retrieve + Augment + Generate;Wiki 把「从生肉里现拼关系」提前到了入库。可以把它想成医院的病案室:RAG 是值班医生每次去翻化验原单,Wiki 是先把原单编成电子病历,以后先读病历。方法来自 Karpathy 的 LLM Wiki 模式,常见实现见 nashsu/llm_wiki。本章 testdata 里的差旅上限、年假天数,仍走检索切块、指回原文;11.2 只在解析之后标出这条分叉,不另开一节。
用失败现象定位所在环节
用户说“答案不对”时,先不要立即更换大模型。若正确文档根本没有进入候选集,应检查解析、切块和检索;若文档已命中但排序靠后,应检查融合与重排;若资料正确而回答仍编造,再看生成约束和引用校验。
可以为一次请求保存四份中间结果:规范化后的问题、召回候选、重排结果和最终引用。它们像流水线上的质检记录,能说明问题在哪道工序出现。每次只调整一个主要变量,再用同一组问题复测,才能判断改动是否有效。
本章的“问题驱动”学习地图
现在你已经有了整机视野,接下来 8 个小节就是沿着这条流水线,一站一站去解决真实痛点:
- 数据侧:数据脏乱(11.2)→ 机器不懂语义(11.3)→ 数据多查不快(11.4);
- 检索与理解侧:搜不准搜不全(11.5)→ 提问含糊(11.6)→ 宏观答不了(11.7);
- 智能与治理侧:幻觉与答非所问(11.8)→ 无法度量(11.9)。
每一节都用统一的四段式结构:「痛点 → 思路 → 代码实现 → 拓展」,让你不仅知道“有这个东西”,还能亲手把它写出来。