别让 LLM 再胡说了——RAG 检索增强生成完全指南

37 阅读13分钟

RAG 从入门到实践:系统学习与复习指南

本文整理自 RAG 学习笔记,覆盖从 LLM 基础原理到 RAG 完整实战的全链路知识体系,适合作为系统复习参考。

一、前置基础:LLM 是怎么工作的

在理解 RAG 之前,需要先搞清楚大模型到底是怎么"说话"的。

1.1 核心逻辑:看上文,猜下文

LLM 的本质是一个自回归语言模型——它不会一次性输出整段话,而是一个字一个字往外蹦

输入:"我今天很"
  ↓ 模型处理
输出概率:"开" 62%、"难" 18%、"累" 8%、其他...
  ↓ 选最高的
输出:"开" → 拼成 "我今天很开心"
  ↓ 再喂进去,猜下一个字...

每次只多输出一个 token(≈一个字或一个词),你觉得它在流畅对话,其实它把"猜下一个字"这个游戏玩了成千上万次。

1.2 猜字的核心机制:QKV 自注意力

Transformer 架构里,每个 token 怎么知道应该关注前文哪些字?靠的是 QKV 自注意力机制

概念全称通俗含义一句话
QQuery(查询)"我想找谁"当前 token 发出的"寻人启事"
KKey(键)"我是谁"每个 token 给自己的身份标签
VValue(值)"我有什么"每个 token 携带的实际信息

1.3 打比方——图书馆查资料

你写论文要查"Transformer 注意力机制":

  • Q:你脑子里的研究问题——"注意力到底怎么算的?"
  • K:每本书的书名、标签、分类号——帮你定位哪本书
  • V:书里的实际内容——你真正要读的东西

1.4 完整计算过程(举例)

输入 "我爱吃苹",模型要猜下一个字。以最后一个 token "苹" 为例(它负责猜下一个字):

1 步:每个字通过训练好的 W_Q、W_K、W_V 分别生成自己的 Q、K、V
(矩阵乘法,这里直接展示结果)

  token      Q               K               V
  ─────────────────────────────────────────────────
  "我"    [0.2, 0.5, 0.1]  [0.3, 0.1, 0.8]  [1.0, 0.2, 0.5]
  "爱"    [0.4, 0.1, 0.6]  [0.5, 0.7, 0.2]  [0.1, 0.9, 0.3]
  "吃"    [0.7, 0.3, 0.4]  [0.6, 0.2, 0.5]  [0.4, 0.1, 1.0]
  "苹"    [0.6, 0.2, 0.7]  [0.4, 0.5, 0.3]  [0.3, 0.4, 0.8]
2 步:
  Q("苹") · K("吃") = 0.92  ← 最高!动词"吃"是猜食物的最强信号
  Q("苹") · K("我") = 0.76
  Q("苹") · K("苹") = 0.55
  Q("苹") · K("爱") = 0.58

为什么"吃"得分最高? 因为训练数据里"吃苹果"、"吃香蕉"大量出现,梯度下降让 W_K("吃") 和 W_Q(食物相关 token) 的向量方向越来越对齐。Q·K 的分数就是训练出来的统计规律。

3 步:softmax 把分数变成权重(总和为 1)

  原始分数:[0.92,  0.76,  0.58,  0.55]
  softmax  → [0.31,  0.26,  0.22,  0.21]

  "吃" 31% | "我" 26% | "爱" 22% | "苹" 21%
4 步:用权重加权平均所有字的 V,融合整句话的信息

  输出 = 0.31 × V("吃") + 0.26 × V("我") + 0.22 × V("爱") + 0.21 × V("苹")
       = 0.31×[0.4, 0.1, 1.0]
       + 0.26×[1.0, 0.2, 0.5]
       + 0.22×[0.1, 0.9, 0.3]
       + 0.21×[0.3, 0.4, 0.8]
       ─────────────────────────
       = [0.47, 0.37, 0.67]    ← 融合了全文信息的向量
5 步:这个向量过全连接层 + softmax → 词表概率

  "苹果"62%   ← ✅ 最高!
  "果"18%
  "面包"12%
  "香蕉"5%
  其他    →  3%

  模型输出:"果",和前面的"苹"拼成完整的 "苹果"

二、LLM 的死穴:幻觉从哪来

2.1 什么是幻觉(Hallucination)

大模型知道的知识,完全取决于训练时喂给它的数据集。有两个盲区:

  • 知识有截止日期:训练数据之后发生的事,它不知道
  • 没见过私有数据:企业内部文档、产品手册、规范,它也没见过

关键问题是:LLM 不会说"我不知道" 。它是概率生成模型,面对不知道的问题不会拒绝回答,而是基于学到的语言模式"编造"一个听起来合理但实际错误的答案——这就是幻觉

2.2 幻觉的场景危害

场景幻觉表现后果
医疗问答编造不存在的治疗方案危及生命
法律咨询引用虚构的法条和判例法律纠纷
企业客服给出错误的退换货政策客诉、退款损失
金融分析捏造财报数据投资决策失误

三、解决幻觉的两条路:微调 vs RAG

3.1 微调(Fine-tuning)

用新数据继续训练大模型,让模型"学会"新知识。

缺点:

问题说明
成本高需要大量标注数据 + GPU 算力
周期长训练一次几天到几周
不可溯源记住了知识,但说不清从哪学的
更新困难知识过期 → 重新训练

适用场景:大公司、专业垂直领域(医疗影像诊断、法律文书生成)——需要模型"学会一种能力",而不只是"记住一堆事实"。

3.2 RAG(检索增强生成)

不训练模型,而是给它配一个外部知识库。 每次提问先查资料,把资料塞进 Prompt,再让模型对着资料回答。

传统 LLM:
  用户问 → LLM 凭训练记忆回答 → 可能幻觉 ❌

RAG:
  用户问 → 知识库检索 → 找到相关文档 → 拼入 Prompt → LLM 对着资料回答 ✅

3.3 对比总结

维度微调RAG
成本高(GPU + 标注 + 时间)低(只需 Embedding + 存储)
知识更新重新训练增删文档即可
可解释性黑盒可溯源到具体文档
适用方向学"能力"(推理风格、格式)学"知识"(事实、规范、政策)
幻觉控制不一定,可能学到错误信息显著降低(有据可查)

四、RAG 核心机制深度拆解

4.1 三个字母的含义

字母全称含义通俗理解
RRetrieval检索去知识库搜相关文档
AAugmented增强把搜到的文档塞进 Prompt
GGeneration生成LLM 根据增强后的 Prompt 生成答案

4.2 检索阶段:怎么找到相关文档?

方案一:关键词搜索(传统方案,效果差)

直接在文档里做字符串匹配。

用户问:"那种红色脆脆的水果是什么?"
文档里有:"红富士苹果是一种..."

关键词匹配:"红色"✗、"脆脆"✗、"水果"✗ → 搜不到 ❌

根本缺陷:只做字面匹配,不理解语义。换个说法、同义替换就搜不到了。

方案二:向量语义搜索(现代 RAG 标配)

把文本转成向量(一串数字),用向量间的夹角衡量语义相似度。

用两个维度直观理解(真实模型 768~4096 维):

        可食用性          硬度
水果 →  [0.9,             0.3]
苹果 →  [0.9,             0.5]
香蕉 →  [0.8,             0.3]
石头 →  [0.1,             0.9]

水果 vs 苹果:夹角 ≈ 10°  → 强相关 ✅
水果 vs 香蕉:夹角 ≈ 12°  → 强相关 ✅
水果 vs 石头:夹角 ≈ 75°  → 基本无关 ❌

即使用户问"红色脆脆的水果",它的向量也和"红富士苹果"的向量夹角很小——搜的是意思,不是字面


五、嵌入模型与向量化

5.1 什么是嵌入模型(Embedding Model)

专门把文本(图片/语音/PDF)转成向量的模型。 和生成式 LLM 是两回事:

对比维度嵌入模型生成式大模型
任务文本 → 向量文本 → 文本
模型大小小(几百 MB)大(几百 GB)
推理成本低(便宜)高(贵)
推理速度
代表模型text-embedding-3-smallGPT-4o、Claude

5.2 向量化的意义

把非结构化文本变成计算机能计算的数字:

"你好啊" → [0.21, -0.53, 0.78, ..., 0.09]  (768 维)
"今日は" → [0.02, -0.61, 0.81, ..., 0.12]  (日语"你好",意思相近,向量也接近)

两个向量的语义相似度用余弦相似度(Cosine Similarity)计算,范围 -1 到 1,越接近 1 越相似。

5.3 支持的数据类型

不只是文本——只要嵌入模型支持,都可以向量化做语义搜索:文本、PDF、图片(多模态嵌入模型)、语音(转文字后向量化)、代码文件。


六、向量数据库

6.1 为什么需要专门的向量数据库

传统数据库(MySQL、PostgreSQL)存的是结构化数据(数字、字符串),索引基于 B-Tree / Hash,擅长精确匹配。但高维向量的相似度计算需要 ANN(近似最近邻)索引,传统数据库做不到。

向量数据库专门为此设计,核心三板斧:

能力说明
海量高维向量持久化存储
毫秒级 ANN(近似最近邻)检索
结合 metadata 做标量过滤("只查第 3 章的文档")

6.2 常见向量数据库

产品定位特点
Chroma轻量开源适合学习和小项目,Python/JS 双 SDK
Milvus企业级开源分布式、高性能、多索引类型
Pinecone云服务全托管、开箱即用
Weaviate开源内置向量化模块,支持混合搜索
Qdrant开源Rust 编写,性能优秀
PGVectorPostgreSQL 插件在 PG 里直接存向量,降低架构复杂度

6.3 相似度检索流程

1. 用户问:"光光和东东是怎么成为朋友的?"
       ↓
2. 嵌入模型把问题向量化 → [0.34, -0.12, 0.78, ...]
       ↓
3. 向量库用 ANN 算法找最相似的 Top-K 个文档向量
       ↓
4. 返回相似度最高的 K 篇文档(如 K=3

七、文档切分策略

7.1 为什么必须切分

两个原因:

  1. 上下文窗口有限:一整本书塞不进 Prompt
  2. 检索精度:一段 5000 字的文档,用户问其中一个小细节,无关内容会稀释向量相似度

7.2 切分策略对比

策略适用场景优点缺点
按章节结构化强的长文语义完整粒度可能太粗
按段落一般文章自然语义边界段落长度不均
按固定字数通用简单可控可能切断语义
递归字符分割LangChain 默认按分隔符优先级逐级切需调 chunk_size
语义分块高质量要求用模型判断自然断点成本高

7.3 核心原则

每个切片保持完整的自然语义,不要拦腰砍断一句话。

7.4 hello-rag 中的实际切分

故事按章节切成了 7 个 Document,每段是一个完整情节:

第 1 章:角色介绍(光光)
第 2 章:角色介绍(东东)
第 3 章:友情情节(光光邀请东东踢球)
第 4 章:友情情节(互相帮助练习)
第 5 章:高潮转折(赢得比赛)
第 6 章:结局(友谊升华)
第 7 章:尾声(多年以后)

8.1 环境配置

import 'dotenv/config'

自动读取 .env,把敏感信息加载到 process.env

OPENAI_API_KEY=sk-xxxxxxxx
OPENAI_API_BASE_URL=https://your-proxy.com/v1
MODEL_NAME=gpt-4o
EMBEDDING_MODEL_NAME=text-embedding-3-small

8.2 初始化 LLM(生成式模型)

import { ChatOpenAI } from 'langchain/openai'

const model = new ChatOpenAI({
  temperature: 0,                          // RAG 场景必须为 0
  model: process.env.MODEL_NAME,           // 如 gpt-4o
  apiKey: process.env.OPENAI_API_KEY,
  configuration: {
    baseURL: process.env.OPENAI_API_BASE_URL,  // 代理/中转地址
  }
})

temperature 参数(OpenAI 范围 0~2):

效果RAG 适用性
0每次回答几乎一致,严格按输入✅ RAG 必选
0.7~1有一定创造性❌ 可能偏离文档
>1.5创造性极强❌ 容易编造

8.3 初始化嵌入模型

import { OpenAIEmbeddings } from 'langchain/openai'

const embeddings = new OpenAIEmbeddings({
  apiKey: process.env.OPENAI_API_KEY,
  model: process.env.EMBEDDING_MODEL_NAME,      // 如 text-embedding-3-small
  configuration: {
    baseURL: process.env.OPENAI_API_BASE_URL,
  }
})

关键区分ChatOpenAI(LLM,负责生成回答)和 OpenAIEmbeddings(嵌入模型,负责文本→向量)是两个独立实例,各司其职。

8.4 构建文档数组

import { Document } from 'langchain/core/documents'

const document = [
  new Document({
    pageContent: `光光是一个活泼开朗的小男孩...`,  // 正文,参与向量化
    metadata: {                                     // 标签,不参与向量化
      chapter: 1,
      character: "光光",
      type: "角色介绍",
      mood: "活泼"
    },
  }),
  // ... 共 7 个 Document
]

Document 的两个字段:

字段作用参与向量化?用途
pageContent文档正文✅ 是检索匹配的主体
metadata附加标签❌ 否过滤、溯源、权限控制

metadata 的三种实际用途:

  • 过滤:搜完后只留 type === "角色介绍" 的结果
  • 溯源:回答附上"参考自第 3 章"
  • 权限:按文档密级过滤

8.5 定义查询

const question = [
  "光光和东东的友谊是怎样的?"
]

后续流程:向量化问题 → 相似度检索 → 返回最相关 Document → pageContent 拼 Prompt → LLM 生成答案。

当前代码到这里为止还是"准备阶段",真正的检索 + 增强 + 生成逻辑需要后续补全。


九、RAG 完整流程总结

═══════════════════════════════════════════════════════════════
                        RAG 完整数据流
═══════════════════════════════════════════════════════════════

【离线阶段:知识入库  —  只在文档更新时做一次】
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ 1.加载文档 │ → │ 2.切分    │ → │ 3.向量化   │ → │ 4.存入向量库│
│ Document  │    │ Chunking │    │ Embedding│    │ VectorDB  │
└──────────┘    └──────────┘    └──────────┘    └──────────┘

【在线阶段:问答  —  每次用户提问都执行】
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ 5.用户提问 │ → │ 6.向量化   │ → │ 7.相似度   │ → │ 8.拼入    │
│ Question  │    │ Embedding│    │ 检索Top-K │    │ Prompt   │
└──────────┘    └──────────┘    └──────────┘    └─────┬────┘
                                                       ↓
                                                ┌──────────┐
                                                │9.LLM生成  │
                                                │  最终答案  │
                                                └──────────┘
═══════════════════════════════════════════════════════════════

关键三步总结:

步骤做什么核心工具
R 检索问题向量化 → 向量库相似度计算 → 返回 Top-K 文档Embedding Model + VectorDB
A 增强将检索到的文档拼接进 Prompt 作为背景知识Prompt 模板
G 生成LLM 阅读参考资料,生成有据可查的回答ChatOpenAI / LLM

十、如何系统学习和复习 RAG

10.1 七层递进学习路线

1 层:LLM 基础
  ├── 自回归生成(token 级别,一个字一个字蹦)
  ├── Transformer 注意力(QKV 计算过程,手推一遍)
  └── LLM 局限性(幻觉、知识截止、上下文窗口有限)

第 2 层:为什么要 RAG
  ├── 幻觉产生的根本原因(概率生成 + 知识盲区)
  ├── 微调 vs RAG 对比(成本、可解释性、更新方式)
  └── RAG 的核心思想:检索 → 增强 → 生成

第 3 层:嵌入与向量
  ├── 嵌入模型 vs 生成式 LLM(任务不同、成本不同)
  ├── 向量的语义含义(多维数字 = 语义坐标)
  ├── 余弦相似度计算原理
  └── 多模态向量化(文本、图片、语音)

第 4 层:向量数据库
  ├── 为什么 MySQL 干不了(B-Tree 无法索引高维向量)
  ├── ANN 近似最近邻(牺牲微小精度换百倍速度)
  ├── 主流选型(Chroma 入门 → Milvus/Pinecone 生产)
  └── 混合搜索(向量相似度 + metadata 标量过滤)

第 5 层:文档处理
  ├── 切分策略(按章节/段落/固定字数/语义/递归)
  ├── Chunk Size 与 Overlap 调参
  ├── metadata 设计(为过滤和溯源服务)
  └── 多格式加载(PDF、网页、数据库、API)


10.2 核心概念速查表

概念一句话解释关键词
LLM 幻觉模型不知道但不会拒绝,基于概率编造答案知识截止、概率生成
RAG先查资料再回答,给 LLM 加上"外脑"Retrieval + Augmented + Generation
微调继续训练模型来学新知识成本高、GPU、标注数据
嵌入模型文本→向量的专用模型便宜、快、小、和 LLM 不同
向量一段文本的"语义坐标"多维数组、余弦相似度
余弦相似度两个向量夹角的余弦,衡量语义相关度-1~1,越近 1 越相似
向量数据库存向量 + 快速 ANN 检索Chroma、Milvus、Pinecone
Chunk切分后的文本片段保持完整语义
DocumentpageContent(正文)+ metadata(标签)正文向量化,标签不向量化
metadata文档的标签属性过滤、溯源、权限
temperatureLLM 输出的随机度RAG 设为 0
Top-K检索返回最相似的 K 篇通常 3~10
QKVTransformer 注意力核心机制Q 找、K 标、V 给
LangChainAI 应用开发框架封装 LLM、向量库、文档操作

10.4 自检清单

  •  LLM 的幻觉是什么?为什么会幻觉?
  •  微调和 RAG 的优缺点?各自适用什么场景?
  •  RAG 三个字母代表什么?每一步具体做了什么?
  •  关键词搜索比向量语义搜索差在哪?
  •  嵌入模型和 LLM 有什么区别?
  •  向量数据库解决了什么问题是 MySQL 解决不了的?
  •  Document 的 pageContent 和 metadata 分别干嘛用?
  •  文档切分的核心原则是什么?
  •  从用户提问到 LLM 回答,RAG 完整链路是怎样的?
  •  Q、K、V 分别代表什么?在 Attention 中如何配合?
  •  余弦相似度怎么算?为什么用余弦而不是欧氏距离?
  •  temperature 在 RAG 场景应该设多少?为什么?

本文基于 LangChain + OpenAI Embeddings 实战代码编写,从 LLM 底层 QKV 机制讲到 RAG 完整工程链路,建议收藏作为系统复习手册。