RAG 范式总览:从提示工程到检索增强
大模型的"天花板":为什么仅靠提示工程远远不够
2022 年底 ChatGPT 发布以来,"提示工程(Prompt Engineering)"一度被视作释放大模型潜力的银弹。只要写出精妙的提示词,似乎就能让模型完成任何任务。但仅仅一年之后,大量生产团队就撞上了同一堵墙:精心调校的提示词,无法让模型回答它根本不知道的事情。这一节我们从四个根本性的局限出发,剖析为什么仅靠提示工程不足以支撑严肃的生产系统。
1.1 幻觉:模型在"自信地说谎"
幻觉(Hallucination)是大模型最广为人知、也最危险的缺陷。它指的是模型生成了语法流畅、措辞自信、但与事实不符的内容。更麻烦的是,模型不会像人一样犹豫或回避——它会用"是的"、"根据我的研究"这类口吻,把虚构的内容包装成确凿的事实。
2023 年纽约联邦法院的 Mata v. Avianca 案是一个教科书级别的反面教材:一位律师使用 ChatGPT 准备法律文书,模型"创造"了六起完全不存在的判例,律师未加核实便提交给法庭,最终受到制裁。这个案例之所以典型,不是因为它罕见,而是因为它每天都发生在无数场景中:客服机器人虚构退换货政策、研发助手编造 API 签名、教育应用"引用"不存在的论文。
从技术角度看,幻觉的根源在于大模型本质上是一个"下一个 token 预测器",它的训练目标是让输出在统计上合理,而不是让输出在事实上正确。提示工程可以缓解幻觉——比如要求"如果你不知道,请回答不知道"——但无法根除,因为模型并没有真正访问外部知识的能力,它只是在"扮演"一个知道答案的人。
1.2 知识截断:模型是一张凝固的快照
所有大模型都有训练数据截止日期(Knowledge Cutoff)。GPT-4 训练数据截至 2023 年 10 月,Claude 截至 2024 年初,国内主流模型通常落后 1-3 个月。这意味着:
- **时间敏感型问题失效**:股价、天气、新闻、政策法规——任何训练之后发生的事,模型都"不知道"。
- **增量更新成本极高**:要让模型"学会"一份新发布的法规或一份新上线的产品手册,标准的做法是重新预训练或微调,单次成本从几万到几百万美元不等,且周期以周或月计。
- **版本漂移不可避免**:你今天回答正确的知识,明天就可能过时。依赖提示工程无法解决这个时间维度的问题。
提示工程本质上是在问"如何更好地问",但如果模型的知识库里就没有答案,问得再巧妙也得不到正确回答。
1.3 领域知识缺失:通用大模型的"水土不服"
通用大模型在广泛任务上表现出色,但在垂直领域——医疗、法律、金融、制造业、特定企业内部知识——往往捉襟见肘。原因有三重:
第一,训练数据偏差。大模型的训练语料以互联网公开数据为主,专业领域的核心知识(如医院内部的诊疗规范、银行的合规手册、工厂的工艺参数)几乎从未出现在训练集中。
第二,术语与口径差异。同一术语在不同行业、不同企业有完全不同的含义。通用模型只能按"大众理解"来回答,输出的内容在专业场景中可能是错的。
第三,合规与责任要求。医疗、金融、法律等场景对准确性、可追溯性有刚性要求。仅靠模型"看起来对"的回答无法满足审计、举证需求。
提示工程可以通过 few-shot 给出示例,但示例能传递的是"风格",不是"知识"。把一份 500 页的合规手册塞进上下文,模型既记不住、也算不准。
1.4 推理不可控:黑盒决策与可解释性困境
大模型的推理过程是一个黑盒:给定输入,模型经过数千亿参数的复杂运算后输出结果,但中间步骤无法被人类完整理解。这带来几个生产上的痛点:
- **结果不可复现**:同一问题在略微不同的 prompt 下可能得到不同答案,对于需要稳定输出的业务(如合同条款解读)几乎不可接受。
- **错误难以定位**:当模型给出错误回答时,无法像传统程序那样通过单步调试定位问题。
- **逻辑链无法审计**:在金融尽调、法律咨询、医疗辅助等场景,决策依据必须可追溯,而模型给出的"理由"往往是事后合理化的产物。
Chain-of-Thought、ReAct、Tree of Thoughts 等提示技术确实能提升推理质量,但它们仍然是在模型的"内部"运行,仍然受制于模型参数固有的能力上限。
1.5 四大局限的共同指向
把上述四个问题放在一起看,会发现它们有一个共同的症结:大模型把"知识"和"推理"两件事死死地焊在了同一组参数里。模型既负责"知道什么"(知识),又负责"怎么想"(推理)。这种耦合导致了所有上述问题——知识陈旧是因为参数无法实时更新,幻觉是因为模型在用推理去"补"知识,领域知识缺失是因为参数空间无法装下所有垂直知识。
要解决这个问题,思路就变得清晰了:把知识从模型参数中剥离出来,放到一个可独立更新、可独立检索、可独立审计的外部存储中。这正是 RAG(Retrieval-Augmented Generation,检索增强生成)的核心动机。
---
RAG 的核心思想:把知识交给知识库,把推理留给大模型
RAG 这个词最早来自 2020 年 Facebook AI Research 的 Patrick Lewis 等人发表的论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》。论文的核心观点用一句话概括:让大模型在回答问题之前,先从一个外部知识库中"查资料",再基于查到的资料生成回答。
2.1 一个直觉类比:开卷考试 vs 闭卷考试
如果把大模型比作一个考生,传统的 prompt-only 方式就是"闭卷考试"——考生只允许凭借自己大脑里记住的东西答题。考生再聪明,也答不出自己没学过的东西,记忆再牢,也记不住最新发生的事。
RAG 则把考试变成了"开卷"——考生可以翻阅参考资料,根据问题找到相关章节,再结合自己的理解写出答案。在这个设定下:
- **知识库**就是那本"参考资料"。它可以被随时更新,而不需要重新培训考生。
- **检索(Retrieval)**就是"翻书找章节"的过程,根据问题快速定位最相关的资料。
- **大模型**就是那个"会答题的考生",它的核心能力是阅读理解、归纳总结、逻辑推理。
这个类比揭示了 RAG 的本质:它不是要替代大模型,而是要补足大模型"开卷能力"的缺失。在闭卷场景下,大模型独自承担一切;在开卷场景下,大模型只需要专注于它最擅长的事——理解和生成。
2.2 形式化定义:什么是 RAG
从工程视角,我们可以把 RAG 抽象为以下三步循环:
1. 索引(Indexing):将外部知识(文档、网页、数据库记录等)切分为适当大小的片段(chunk),通过 Embedding 模型转化为向量,存入向量数据库。这一步通常离线完成。
2. 检索(Retrieval):当用户提出问题时,先将问题也用同一个 Embedding 模型转化为向量,然后在向量数据库中找出与问题向量最相似的 Top-K 个片段。
3. 生成(Generation):将检索到的 Top-K 片段连同原始问题一起拼装成 Prompt,送入大模型,由大模型基于这些上下文生成最终回答。
用伪代码表示就是:
```python def rag_answer(question, knowledge_base): chunks = retrieve(question, knowledge_base, top_k=5) # 检索 context = "\n".join(chunks) # 拼接 prompt = build_prompt(question, context) # 构造提示 answer = llm(prompt) # 生成 return answer ```
这个三段式结构看似简单,但它打开了一扇大门:知识从此可以独立于模型存在、独立于模型更新、独立于模型审计。新法规发布了?把文档加进知识库就行,不需要重新训练模型。某个回答出错了?直接检查知识库中对应的内容即可,不需要去调试模型权重。
2.3 RAG 与提示工程的本质区别
很多初学者会把 RAG 当作"提示工程的一种高级形式",这种理解低估了 RAG 的工程意义。它们的差异至少体现在三个层面:
- **作用对象不同**:提示工程作用于"输入"——通过优化提问方式让模型更好地回答;RAG 作用于"知识"——通过引入外部信息让模型能够回答。提示工程改的是问题,RAG 改的是模型能看到的"事实"。
- **能力边界不同**:提示工程的上限是模型本身的知识容量;RAG 的上限是外部知识库的容量。两者结合后,系统的能力上限被显著抬高。
- **可维护性不同**:提示词调优难以版本化、难以协作、难以回滚;RAG 的知识库可以像代码一样管理:版本控制、增量更新、灰度发布、A/B 测试。
在生产实践中,提示工程与 RAG 不是替代关系,而是叠加关系。一个成熟的 RAG 系统内部,Prompt 设计本身仍然至关重要——但 Prompt 是用来"引导模型如何利用检索到的资料",而不是"试图让模型记住所有知识"。
2.4 RAG 的边界:它不是银弹
尽管 RAG 解决了"知识更新"和"领域知识"两大痛点,但它有自己的边界:
- **不适合强逻辑推理**:RAG 提供的是"事实",不是"推理链"。如果任务需要复杂的多步推理(例如数学证明、代码调试),单靠检索可能不够。
- **检索质量是天花板**:如果检索环节找不到相关资料,再强大的生成模型也救不回来。这就是为什么后续章节会花大量篇幅讲检索优化。
- **延迟和成本更高**:相比纯生成,RAG 多了检索 + 拼接 + 更长上下文的开销,对实时性敏感的场景需要权衡。
- **不适合高频小数据**:如果整个知识库就几句话,直接放进 Prompt 反而更简单。
理解这些边界很重要——它能帮助我们在第 5 节做出正确的技术选型。
---
范式演化:从 Naive RAG 到 Modular RAG
RAG 自 2020 年提出以来,经历了快速的工程化演进。按照业界广泛采用的分类法,RAG 范式大致经历了三代:Naive RAG → Advanced RAG → Modular RAG。理解这三代的差异,是建立 RAG 工程认知地图的关键。
3.1 Naive RAG:最朴素的"检索-拼接-生成"
Naive RAG 就是上一节描述的三段式:Query → Retrieve → Concat → Generate。它的实现非常直接:
1. 用户提问:`"公司的年假政策是什么?"` 2. 检索:从知识库中找出与"年假"相关的 3-5 个文档片段 3. 拼接:把这些片段与原问题拼成一段长 Prompt 4. 生成:把 Prompt 喂给 LLM,得到最终回答
Naive RAG 的优点是简单直接、易于上手,一个下午就能跑通。缺点同样明显:
- **检索精度差**:用户问"年假",但"年假"这个词在文档里可能写成了"带薪年休假"或"annual leave",简单的向量相似度会漏掉。
- **上下文噪声大**:把 Top-K 个片段一股脑塞给模型,模型可能被不相关的片段干扰。
- **生成结果缺乏引用**:模型给出的回答,用户不知道依据是什么,无法验证。
- **无法处理多跳问题**:例如"去年使用年假最多的人是谁"需要先找到年假记录再聚合统计,单次检索拿不到。
在实际生产中,纯粹的 Naive RAG 几乎不能满足严肃场景的需求。但它作为起点,为后续优化提供了清晰的改进点。
3.2 Advanced RAG:在检索前后做工程化增强
Advanced RAG 的核心思想是:在检索之前优化"问",在检索之后优化"答"。它在 Naive RAG 的三段式前后各加了一系列工程模块。
检索前(Pre-Retrieval)优化:
- **Query 改写/扩展(Query Rewriting / Expansion)**:用 LLM 把用户的原始问题改写成更利于检索的形式。例如把"年假政策"改写成"带薪年休假 天数 计算方式 适用条件"。
- **HyDE( Hypothetical Document Embeddings)**:让 LLM 先"想象"一个理想答案,再把这个答案作为检索 query,往往比原问题检索效果更好。
- **Query 分解(Query Decomposition)**:把复杂问题拆成多个子问题,分别检索再合并。
检索后(Post-Retrieval)优化:
- **重排序(Reranking)**:用更精细的 Cross-Encoder 模型对初检结果重新排序,把真正相关的片段排到前面。
- **上下文压缩(Context Compression)**:去掉检索结果中冗余、与问题无关的句子,只保留关键信息。
- **元数据过滤**:结合时间、来源、作者等元数据对检索结果做硬过滤。
Advanced RAG 是目前业界落地最广泛的形态,它在工程复杂度和效果之间取得了较好的平衡。后续章节我们会逐一深入这些模块的实现细节。
3.3 Modular RAG / Agentic RAG:算子化与编排化
随着应用场景越来越复杂,研究者和工程师开始意识到:RAG 不应该是一条固定流水线,而应该是一组可插拔的算子(Operator),由一个智能体(Agent)根据具体问题动态编排。这就是 Modular RAG(模块化 RAG),也常被称为 Agentic RAG。
Modular RAG 的核心抽象是:
- **算子(Module)**:把"检索"、"重排"、"生成"、"查询 SQL"、"调用 API"、"反思"等动作都抽象为独立的算子,每个算子有清晰的输入输出。
- **编排器(Orchestrator)**:通常是一个具备规划能力的 LLM Agent,它根据当前问题决定调用哪些算子、以什么顺序调用、是否需要循环。
- **记忆与状态(Memory)**:Agent 在多轮交互中维护状态,使系统能处理需要多步推理、跨数据源的复杂任务。
举几个典型场景:
- **多源检索**:Agent 决定先用向量检索找相关文档,再用 SQL 工具查询结构化数据库,最后综合两者生成回答。
- **多跳推理**:Agent 发现单次检索不够,会把检索结果作为新 query 继续检索,直到凑齐所有证据。
- **自我反思(Self-RAG / Corrective RAG)**:生成回答后,Agent 再用一次"质检检索"判断回答是否基于了真实资料,是否有遗漏。
Modular RAG 灵活性最强,但工程复杂度也最高,对 Agent 的规划能力有较强依赖。它代表的是 RAG 的前沿形态,也是未来 1-2 年工程化探索的重点。
3.4 三种范式的对比与选型
下表从多个维度对比三种范式:
| 维度 | Naive RAG | Advanced RAG | Modular RAG / Agentic RAG | |---|---|---|---| | 架构形态 | 固定三段式 | 检索前后增强 | 算子 + 编排器 | | 实现复杂度 | 低(小时级) | 中(天-周级) | 高(周-月级) | | 适用场景 | 演示、简单 FAQ | 多数企业级知识问答 | 复杂多源、多跳任务 | | 效果上限 | 较低 | 中等 | 较高 | | 维护成本 | 低 | 中 | 高 | | 调试难度 | 易 | 中 | 难(涉及 Agent 行为) | | 代表方法 | 原始 RAG 论文 | Rerank、HyDE、CRAG | Self-RAG、FLARE、Agentic RAG |
选型建议:
- 如果你做的是内部知识库的轻量问答、且数据量在千级以下,从 Naive RAG 起步;
- 如果数据量在万级以上、对准确率有要求、希望快速上线,Advanced RAG 是工业界的事实标准;
- 如果场景涉及多个异构数据源、需要复杂推理或个性化决策,再考虑 Modular RAG。
下图直观展示了三种范式的架构差异:
```mermaid flowchart LR subgraph NaiveRAG["Naive RAG"] N1[Query] --> N2[Retrieve] --> N3[Concat] --> N4[Generate] end subgraph AdvancedRAG["Advanced RAG"] A1[Query] --> A2[Query Rewrite] --> A3[Retrieve] --> A4[Rerank] --> A5[Compress] --> A6[Generate] end subgraph ModularRAG["Modular RAG / Agentic RAG"] M1[Agent Planner] --> M2{Route} M2 --> M3[Retrieve Module] M2 --> M4[Reason Module] M2 --> M5[Tool Module] M3 --> M6[Generate] M4 --> M6 M5 --> M6 end ```
可以看到,演化路径是非常清晰的:从"硬编码的三步流程"到"加入多个优化模块的流水线",再到"由 Agent 动态编排的算子集合"。每一步演化都让系统更灵活、更强大,但同时也带来了更高的工程复杂度。后续章节我们会从 Advanced RAG 入手,逐层拆解每一个模块,最终在第 13-14 章触及 Modular RAG 的工程实现。
---
端到端最小 RAG Demo:跑通你的第一个 RAG 系统
理论讲了这么多,是时候让代码跑起来了。本节我们用最主流的技术栈——LangChain + Chroma + OpenAI GPT-4——构建一个最小但完整的 RAG 系统。整个 Demo 不到 60 行代码,跑通后你就能直观看到 RAG 的工作流程。
4.1 技术栈选型理由
- **LangChain**:目前最流行的 LLM 应用开发框架,提供了从文档加载、文本切块、向量检索到 Prompt 模板的全套组件。它的抽象层次合适,既不会让你陷入底层细节,又