全书导航
大模型之路:从图灵、感知机到 ChatGPT · 卷 4

第 34 章:RAG:让模型去查资料

本章问题:模型的知识"冻结"在训练截止日——如何让它回答训练数据中没有的新信息?


34.1 记忆的代价

一个语言模型的所有知识都存储在它的权重中——这是它的根本局限。

一个训练数据截止在 2023 年的模型,不会天然知道 2024 年的奥运会结果、不知道昨天发布的那个重要的开源框架版本、也不知道你公司内部 wiki 上的产品变更。当它被问到这些它没有见过的问题时,它有两个选择——承认自己不知道,或者编造(幻觉)。在压力下——在很多用户追问下——它往往选择后者。

让模型记住更新的知识需要重新训练或微调——两者都极其昂贵且耗时。一个新信息从发布到被模型"学会"——可能需要几个月的时间和上百万美元的成本。

有没有另一种设计?不让模型记住所有知识——而是让模型在回答前先去查资料?

这就是 RAG——检索增强生成(Retrieval-Augmented Generation) 的核心。


34.2 RAG 的架构:先检索,再阅读,再回答

RAG 把回答一个问题的流程拆成两个阶段:

阶段一:检索。 用户的问题作为查询。用这个查询去搜索一个外部知识库(你的文档、百科、代码库等)——找出最相关的几段文本。

阶段二:生成。 把检索到的文本和用户的问题一起作为上下文输入语言模型——让模型"阅读"这些检索材料,然后生成答案。

这个过程可以用一句话概括:模型不再需要记住所有的知识——它只需要在被问到的时候去查找相关的资料,然后基于资料回答。

完整的 RAG 流水线:

用户提问[查询编码 → 向量搜索 → 取 top-K 文档]构建提示词: "参考以下资料回答问题:\n---\n{检索结果}\n---\n用户问题:{问题}"LLM 生成答案(基于检索资料 + 其自身的通用能力)

关键洞察是:语言模型非常擅长"阅读并综合信息"——RAG 把这部分能力和外部的、可随时更新的知识库解耦了。模型负责理解、整合、表达;知识库负责保存和更新事实。


34.3 向量检索——如何找到"相关"文档

RAG 的检索不是传统的关键词搜索(grep)——那种方式下"番茄"搜不出"西红柿","机器学习"搜不出"统计学习"。RAG 用的是语义搜索——通过向量嵌入找"意思相近"的文本。

第 21 章 Word2Vec 的核心洞见在这里被推到了工程级别:

  1. 用一个嵌入模型(如 OpenAI 的 text-embedding-3-small 或开源的 BGE)把每段文档编码成一个稠密向量(通常 768 维或 1536 维)。
  2. 把所有文档向量存储在一个向量数据库中。
  3. 当用户提问时——用同一个嵌入模型把问题也编码成向量。
  4. 在向量数据库中找与问题向量最接近的 top-K 个文档向量——用余弦相似度或欧氏距离。
  5. 把对应的文档原文拿出来,附在提示词中。

向量检索能发现"语义上相关"的内容——即使关键词完全不重叠。"血压高吃什么好"能检索到"高血压饮食建议"——尽管关键词几乎没有重合。


34.4 文档切块——RAG 最被低估的工程决策

长文档不能整个塞进模型——一个 200 页的 PDF 可能有几十万字符,远超模型的上下文窗口(即使是 128K 上下文的模型,输入上下文越长,生成质量和检索精度之间的平衡也越敏感)。

你需要把文档切成小块(chunks)——然后对每个 chunk 做嵌入和检索。

切块的策略直接影响 RAG 的质量:

  • 切太细(每 chunk 50 tokens):一个完整的概念可能被切成两块——检索返回的结果不完整,模型没有足够上下文去正确回答。
  • 切太粗(每 chunk 2000 tokens):一个 chunk 里包含了太多不相关的内容,检索精度下降——模型被噪声淹没,找不到正确答案。
  • 正确的做法:合理的块大小(通常 256-512 tokens),加上相邻块之间的重叠(overlap,通常 10-20%)——确保关键句子不会恰好卡在块边界上。

实际应用中,很多团队的 chunk 设计还包括元数据继承:每个 chunk 保留它来自哪个文档、哪个小节的标题——这些元数据在检索时一同返回,帮助模型定位和引用。


34.5 最小代码:30 行 RAG 流水线

以下代码演示完整的 RAG 流水线——从文档嵌入到检索增强回答:

python
import numpy as npfrom sentence_transformers import SentenceTransformer# 1. 准备知识库documents = [    "VX-9000 显影液需存放在 15-25°C 环境中,保质期 12 个月。",    "产品 A 的保修期为购买日起两年,需保留原始发票。",    "公司将于 2025 年 1 月起调整所有产品价格,幅度 5-15%。",    "客户投诉需在 24 小时内首次回应,72 小时内给出解决方案。",]# 2. 嵌入文档embedder = SentenceTransformer("BAAI/bge-small-zh-v1.5")doc_embeddings = embedder.encode(documents, normalize_embeddings=True)# 3. 查询query = "客户投诉要在多久内回复?"query_embedding = embedder.encode(query, normalize_embeddings=True)# 4. 检索 top-2scores = doc_embeddings @ query_embedding  # 余弦相似度(向量已归一化)top_k = np.argsort(scores)[-2:][::-1]      # 取 top-2retrieved = [documents[i] for i in top_k]# 5. 构建上下文 + 生成context = "\n".join(retrieved)prompt = (    f"参考以下资料回答问题。如果资料中没有相关信息,请说'资料中未提及'。"    f"\n---\n{context}\n---\n问题:{query}")print("发送给模型的提示词:")print(prompt)

输出:

发送给模型的提示词:参考以下资料回答问题。如果资料中没有相关信息,请说'资料中未提及'。---客户投诉需在 24 小时内首次回应,72 小时内给出解决方案。产品 A 的保修期为购买日起两年,需保留原始发票。---问题:客户投诉要在多久内回复?

检索到的文档精确包含答案。模型现在不是在"回忆"——它在"阅读"。答案在上下文中——模型只需提取并整理。

完整的 RAG 系统还需要:一个嵌入模型(embedder)、一个向量数据库(Chroma、Milvus 或 Faiss)、和一个生成模型(任何 LLM)。但核心逻辑就是上述 30 行。


34.6 大规模 RAG 的额外组件

当文档量从 4 段变成 4 万篇 PDF 时,同样的基础架构需要加几个额外组件:

重排序(Reranker):先用向量检索拿回 top-50 个候选文档(快速但粗),再用一个更精确但更慢的交叉编码器模型对候选做重排序——筛选出最终给 LLM 读的 top-3。两阶段设计在现代 RAG 系统中已经是标准配置。

引用追溯(Source attribution):RAG 让你天然具备被溯源性——每个回答的支撑材料(检索到的 chunk)是已知的。你可以在回答中自动附带引用链接或参考列表——在需要人类核查的场景(医疗、法律、金融)至关重要。

查询重写(Query rewriting):用户的自然语言问题经常不完全匹配文档的写作方式。在被嵌入前,用一个小型模型重写查询以提高检索命中率——例如把"怎么处理难缠的客户"改写为"客户投诉处理流程"。

混合检索(Hybrid search):结合向量检索(语义匹配)和关键词检索(BM25 等精确词匹配)——在需要精确匹配产品编号、法律条款编号或人名的场景中,混合检索的召回率显著高于纯向量检索。


34.7 本章小实验:对比有 RAG 和没有 RAG 的模型回答

找一个有时效性的问题——任何你的语言模型无法从训练数据中知道的问题:

"下一届诺贝尔文学奖得主是谁?"

  1. 先直接问模型——观察它如何回应。它可能拒绝回答,也可能编造一个名字。
  2. 然后你先在网上查到正确答案,把相关文本粘贴到提示词前面(充当"RAG 检索结果"的角色)——再问一次。观察回答的准确性和引用方式。

如果模型确实会基于你给的上下文纠正自己的回答——你就在刚才完成了一次人工 RAG。把这个流程自动化——也就是本章的内容——就是 RAG 系统。


34.8 本章地图

text
问题:模型的知识"冻结"在训练截止日——如何让它回答训练数据中没有的新信息?架构:知识库(外部、可更新)← 检索 → 语言模型(阅读理解 + 生成答案)技术栈:嵌入模型(编码查询和文档为向量)→ 向量数据库(存储和搜索)→ 文档切块(chunking + overlap)→ LLM(基于检索结果生成答案)。优势:知识可随时更新不需重训、减少幻觉(答案基于检索材料)、天然可追溯(每个回答有引用源)。高级组件:重排序(reranker)、查询重写(query rewriting)、混合检索(向量 + 关键词)、引用追溯(source attribution)。今天:RAG 是让 LLM 接入私有数据和最新信息的主流工程方案——很多企业 LLM 应用都会在底层接入检索、引用或知识库组件。

34.9 本章结语:不要试图让模型背诵世界

RAG 的核心哲学是:世界在不断变化——不要试图把世界装进模型的权重里。让模型学会"读"世界,而不是"记住"世界。

这标志着一个重要的范式转变。在 RAG 之前——AI 的知识更新意味着重新训练或周期性微调。在 RAG 之后——知识更新只需要更新向量数据库。新政策、新产品说明、新的科研论文——文档更新后几秒钟就能被检索到并被 LLM 使用。

RAG 把语言模型的角色从一个"固态的知识存储器"变成了一个"可以查询动态知识的阅读理解引擎"。前者快但过时;后者慢(多了一步检索)但总是最新的。

但 RAG 解决的是"模型不知道"的问题——不是"模型不会行动"的问题。当模型需要不只是回答,而是采取行动——查询日历、发送邮件、调用 API——RAG 的信息检索就不够了。模型需要能够调用工具。

下一章:Agent——当模型开始使用工具。

SECTION §02 · ENGAGE

Discussion

留言区 · GitHub-powered comments via Giscus