【LLM技术全景】RAG 从原理到实战——检索增强生成完整指南

本篇是「应用实战篇」第 3 篇。前两篇我们分别解决了"如何让模型听指令"(第21篇 Prompt Engineering)和"如何让模型调工具"(第22篇 Function Calling)。但还有一个更普遍的需求:让模型回答它没学过、或知识已过时的问题。这正是 RAG(Retrieval-Augmented Generation,检索增强生成)的主场------先检索、再生成。

摘要

  • 核心问题:LLM 知识冻结、易产生幻觉(《第17篇:模型幻觉与评估》),无法回答私有或实时问题。
  • 主要贡献:系统讲解 RAG 的两条主链路(离线建库、在线检索---生成),以及切分、向量化、混合检索、重排等关键技术。
  • 阅读收获
    1. 掌握文档切分(chunking)与向量化的工程权衡。
    2. 理解"混合检索 + 重排"为何优于纯向量检索。
    3. 能跑通一段可运行的迷你 RAG 代码,并知道何时用 RAG 而非微调或长上下文。

一、背景与动机

1.1 为什么单靠模型不够

《第03篇:Transformer 架构》奠定了 LLM 是"基于上下文预测下一个 token"的范式。它的知识全部来自预训练语料(《第04篇:预训练与微调》),带来两个根本限制:

  1. 知识截止(Knowledge Cutoff):训练之后的事件,模型无从知晓。
  2. 私有数据不可见:企业文档、个人笔记、内部 Wiki 不在公开语料中。
  3. 幻觉风险:不知道时,模型倾向于"自信地编造"(《第17篇》详述了成因与缓解)。

微调(《第24篇》将讲)能把知识"烧"进权重,但成本高、更新慢、且对小语料易过拟合。RAG 提供了一条更轻、更可控的路:把知识放在外部,用时再取------这和第22篇 Tool Use 的思路一脉相承,都是"把确定性能力交给外部系统,模型只负责推理"。

1.2 RAG 的定义

RAG = 检索(Retrieval) + 生成(Generation)。在生成回答前,系统先从知识库检索出与问题最相关的若干片段,把它们作为上下文拼进 prompt(呼应《第21篇》的"上下文段"),再由模型据此作答。模型从"凭记忆答"变成"带着资料答"。


二、技术原理

RAG 有两条主链路:离线建库链路在线检索---生成链路 (见配图 diagram_53)。

2.1 离线建库:文档 → 切分 → 向量化 → 入库

步骤 1:文档加载与清洗

把 PDF、网页、Markdown、数据库记录等统一为纯文本,去除页眉页脚、乱码、冗余空白。

步骤 2:切分(Chunking)

大模型上下文有限(《第12篇:长上下文技术全景》),不能把整本书塞进去,必须切成片段(chunk)。常见策略(见配图 diagram_54 左):

策略 做法 优点 缺点
固定大小 按 token/字符数切,带重叠(overlap) 简单、均匀 可能切断语义
按句子/段落 以标点或空行为界 保留句子完整 长短不一
递归切分 先按标题,再按段、句逐级切 兼顾结构语义 实现稍复杂
语义切分 按 embedding 相似度断点 语义边界最优 需额外计算

经验法则:chunk 大小常取 256--512 token,重叠 10--20%,既能保留上下文又避免碎片化。

步骤 3:向量化(Embedding)

每个 chunk 用一个嵌入模型(如 BGE、E5、OpenAI text-embedding)编码成高维向量。语义相近的文本,向量在空间中距离更近------这是检索的数学基础。

步骤 4:入库

chunk 文本 + 向量 + 元数据(来源、页码) 写入向量数据库(FAISS、Milvus、Qdrant、pgvector 等)。

2.2 在线检索---生成:查询 → 召回 → 重排 → 拼接 → 生成

步骤 1:查询向量化:用户问题同样编码成向量。

步骤 2:召回(Retrieve)

  • 向量检索(Dense):用近似最近邻(ANN,如 HNSW、IVF)找最相似的 top-k chunk。
  • 关键词检索(Sparse):如 BM25,基于词频匹配,擅长专有名词、编号、精确术语。
  • 混合检索(Hybrid) :二者加权融合,兼顾"语义相关"与"字面命中"(见配图 diagram_54 右)。实践中混合检索的召回质量通常优于单一方式。

步骤 3:重排(Rerank)

召回的 top-k(如 20)再经一个 Cross-Encoder 重排模型精排,取最相关 top-n(如 4--6)送入上下文。重排模型对"查询---文档"对联合编码,排序精度高于向量余弦,但慢------故只在少量候选上用,是"先粗召、后精排"的两段式。

步骤 4:拼接与生成

将重排后的片段拼成上下文,与问题、指令组成最终 prompt(呼应《第21篇》六段式),交给生成模型产出答案,并尽量附上引用来源以增强可溯性。

2.3 RAG 与 Function Calling 的配合

二者不是替代,而是互补:RAG 解决"取知识",Tool Use(第22篇)解决"做动作"。一个常见组合是------把检索本身做成一个工具 。例如定义一个 search_knowledge_base(query) 的 Function Calling 工具,让 Agent 在需要私有知识时主动调用,再基于结果作答。这样 RAG 能力被自然地嵌入第22篇的 ReAct/工具循环,模型自行决定"何时该检索"。

2.4 评估指标

RAG 质量要看两端:

  • 检索端Recall@k(正确答案是否在前 k 个被召回)、MRRNDCG
  • 生成端:答案相关性、忠实度(是否忠于检索内容、不臆造)、引用准确率。

三、实战代码

下面是一段可运行 的迷你 RAG。为免依赖重型库,我们用 numpy 做向量检索,并用一个"假嵌入"函数演示流程------把嵌入替换成真实模型(如 sentence-transformers)即可上线。

python 复制代码
import numpy as np

# ---------- 1. 离线建库 ----------
def fake_embed(texts):
    """演示用假嵌入:统计词频向量。真实场景换成 BGE/E5 等。"""
    vocab = sorted({w for t in texts for w in t.split()})
    v = np.zeros((len(texts), len(vocab)))
    for i, t in enumerate(texts):
        for w in t.split():
            v[i, vocab.index(w)] += 1
    # L2 归一化,使余弦=点积
    return v / (np.linalg.norm(v, axis=1, keepdims=True) + 1e-9)

docs = [
    "RAG 通过检索外部知识增强大模型的回答。",
    "Function Calling 让模型以结构化方式调用外部工具。",
    "向量数据库用于存储和检索文本嵌入。",
    "重排模型能对召回结果做更精准的排序。",
]
chunks = [d for d in docs]          # 真实场景需先做 chunking
doc_vecs = fake_embed(chunks)       # 建库:每个 chunk 的向量

# ---------- 2. 在线检索 ----------
def retrieve(query, top_k=2):
    q = fake_embed([query])[0]
    sims = doc_vecs @ q             # 余弦相似度(已归一化)
    idx = np.argsort(-sims)[:top_k]
    return [(chunks[i], float(sims[i])) for i in idx]

# ---------- 3. 拼接 + 生成(生成由 LLM 完成,此处模拟) ----------
def rag_answer(query):
    hits = retrieve(query, top_k=2)
    context = "\n".join(f"[{i+1}] {t}" for i, (t, _) in enumerate(hits))
    prompt = (
        "根据以下资料回答问题,并标注引用编号:\n"
        f"{context}\n\n问题:{query}\n回答:"
    )
    # 真实场景:把 prompt 发给 LLM
    return prompt, hits

q = "RAG 是怎么增强回答的?"
prompt, hits = rag_answer(q)
print("召回片段:")
for t, s in hits:
    print(f"  ({s:.2f}) {t}")
print("\n构造的 Prompt:\n", prompt)

运行后,retrieve 会基于词频相似度召回与问题最相关的片段(此处命中第 1 条关于 RAG 的描述),rag_answer 把它们拼进带引用标记的 prompt------这一步的 prompt 正是喂给生成模型的输入。将 fake_embed 换成真实 embedding、print 换成 LLM 调用,就是一个生产级 RAG 的最小骨架。


四、优缺点分析

维度 RAG 微调(Fine-tuning) 长上下文(直接喂全文)
知识更新 改库即可,实时 需重训,慢 随输入走,但贵
私有知识 天然适配 可注入但成本高 可,但占窗口、易丢失
可溯性 高(有引用) 低(藏在权重)
成本 检索便宜,生成常规 训练贵,推理省 推理极贵(长输入)
适用规模 海量知识库 稳定模式/风格 中短文档

选型建议(决策树式)

  • 知识频繁更新 / 体量巨大 / 需引用出处 → RAG
  • 需改变模型"风格、格式、稳定行为模式" → 微调(《第24篇》)。
  • 文档短、需整体精读、且不超过窗口 → 长上下文直喂(《第12篇》)。
  • 现实多数系统:RAG + 长上下文 组合,用检索把长文档压成相关片段再生成。

五、总结与展望

关键点回顾

  1. RAG 把"凭记忆答"变为"带着资料答",直接缓解知识截止与幻觉。
  2. 两条链路:离线建库 (切分→向量化→入库),在线检索---生成(召回→重排→拼接→生成)。
  3. 切分粒度、混合检索(BM25+向量)、重排是质量三支柱。
  4. RAG 与 Function Calling 互补:可把检索本身封装为工具,由 Agent 按需调用。
  5. 选型上 RAG 擅长"海量、易变、需溯源"的知识,微调擅长"稳定行为模式"。

未来方向

RAG 正从"向量检索"走向多模态 RAG (检索图文/表格/音视频)、GraphRAG (把知识建图、做多跳推理),以及Self-RAG(模型自决"是否检索、检索什么、答案是否够好")。它与第22篇的工具生态、下一篇的微调,共同构成应用落地的三块基石。

下期预告:《第24篇:Fine-tuning 实战------全参数微调 vs 参数高效微调》。我们将讲解何时该把知识"烧"进权重,LoRA/QLoRA 如何以极小代价微调,以及数据集构建与训练技巧。


参考资料

  • Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, 2020(RAG 原论文)
  • Gao et al., Retrieval-Augmented Generation for Large Language Models: A Survey, 2023
  • 本博客:《第03篇 Transformer 架构》《第04篇 预训练与微调》《第12篇 长上下文技术全景》《第17篇 模型幻觉与评估》《第21篇 Prompt Engineering》《第22篇 Function Calling》

延伸讨论

  • 思考题:你正在做的系统里,哪些回答其实"本应来自最新文档"却依赖模型记忆?这些是不是 RAG 的高价值落点?
  • 实践作业 :把本文的 fake_embed 换成 sentence-transformers 的真实模型,用一个自己的 txt 文档跑通端到端 RAG。
  • 读者问答:你在 RAG 落地中踩过最深的坑是什么?(切分碎了?召回错了?上下文太长?)欢迎评论区分享,我会在下一篇结合微调一并回应。
相关推荐
LuminousCPP2 小时前
单链表专题(三)-刷题复盘篇:从快慢指针到环形链表 II 数学推导
数据结构·经验分享·笔记·学习·算法·链表
-dzk-2 小时前
【贪心算法】LC 121.买卖股票的最佳时机
算法·贪心算法
hanlin032 小时前
动态规划专练:力扣第718、1143题
算法·leetcode·动态规划
ChaoZiLL2 小时前
二叉树经典例题
数据结构·算法
爆写加倍2 小时前
2026年3款视频转文字软件测评技术升级让转写整理更准更省心
人工智能·ai
樊小肆2 小时前
DeepSeeker-Code源码导读02-runAgent主循环
人工智能·agent
ACP广源盛139246256733 小时前
WAIC2026 国产算力浪潮@ACP#YLB3118 在算力矩阵中的存储定位与落地场景
大数据·人工智能·分布式·单片机·嵌入式硬件
ACP广源盛139246256733 小时前
WAIC2026 国产算力浪潮下@ACP#IX8024 在算力矩阵中的定位与落地场景
大数据·数据库·人工智能·嵌入式硬件·线性代数·矩阵
不正经学生3 小时前
C语言字符串函数进阶:安全版函数 + 错误处理 + 子串查找
c语言·开发语言·c++·算法·面试