RAG 基础
Written: 2026.06 上一讲:项目概述与环境搭建下一讲:LangChain 生态系统
1. 本讲目标
- 深入理解向量检索的数学原理
- 掌握 Embedding 模型的工作机制
- 理解 Dense 检索和 Sparse 检索的区别与互补
- 了解 Reranker(重排)在 RAG 链路中的作用
2. 前置知识 — Embedding 模型
2.1 什么是 Embedding
Embedding(嵌入) 是将非结构化数据(文本、图片、音频)转换为固定长度的浮点数向量的技术。 在文本领域,Embedding 模型接收一段文字,输出一串数字(通常是 512 到 4096 维的向量),这个向量在数学空间中代表了这段文字的”语义位置”。2.2 为什么要 Embedding
计算机本质上只能做数值计算。要让计算机”理解”两段文字是否相似,必须先把文字变成它可以计算的数字。 早期方法(如 TF-IDF、Bag-of-Words)只统计词频和共现关系,无法理解语义:- “我很开心” 和 “我非常高兴” 的词完全不同,但语义相同
- “银行利率很高” 和 “河边的银行很美” 词相同,但语义完全不同
2.3 向量相似度计算
Embedding 把文本变成向量以后,检索系统要回答一个问题:用户问题向量和知识库中哪个 chunk 向量更接近? 这里要先区分两个概念:- 相似度(similarity):分数越大越相似,例如 Cosine、Inner Product
- 距离(distance):数值越小越接近,例如 Euclidean Distance
score,不一定都严格等于数学公式原始值,而是 Milvus / LangChain 返回的检索排序分数。
2.3.1 余弦相似度:看方向
余弦相似度 (Cosine Similarity) — 最常用A \cdot B是两个向量的点积||A||和||B||是两个向量的长度- 分母的作用是把长度影响消掉,只比较两个向量的方向
- 取值范围 [-1, 1]
- 1 表示方向完全一致,0 表示正交(不相关),-1 表示方向相反
- 只看方向不看长度,适合文本语义比较
2.3.2 欧几里得距离:看直线距离
欧几里得距离 (Euclidean Distance) — 适合 L2 归一化后的向量- 数值越小,表示越相似
- 数值越大,表示越不相似
2.3.3 内积:看方向和长度的乘积
内积 (Inner Product / Dot Product):- COSINE:语义检索中最容易解释
- IP:归一化后效果等价,计算更直接
- L2:适合一些几何距离场景
2.3.4 本项目在哪里用相似度计算
本项目不是只在一个地方做“相似度计算”,而是在检索链路中分层使用:| 使用位置 | 代码位置 | 计算方式 | 作用 |
|---|---|---|---|
| Dense 向量检索 | qa_core/retrieval/store.py → similarity_search_with_score() | BGE-M3 生成 1024 维 dense 向量,Milvus 按 dense 向量字段检索 | 找到语义相近的 FAQ / 文档 chunk |
| Dense 索引示例 | 第 4 讲 pymilvus 示例 | metric_type="COSINE" | 教学展示 Milvus 如何按向量相似度搜索 |
| Sparse BM25 检索 | qa_core/retrieval/milvus_compat.py → BM25BuiltInFunction | 中文分词 + BM25 词频/逆文档频率评分 | 找到精确包含关键词、术语、编号的内容 |
| Hybrid 融合 | qa_core/retrieval/store.py | ranker_type="weighted",权重 [0.55, 0.45] | 将 dense 语义分数和 sparse BM25 分数融合排序 |
| CrossEncoder 重排 | qa_core/retrieval/ranking.py | query + passage 成对输入 reranker 模型 | 对 Milvus 召回候选做二阶段精排 |
2.3.5 Sparse 检索也是用余弦相似度吗?
不是。至少在本项目中不是。 Dense 检索比较的是 BGE-M3 生成的连续浮点向量,例如 1024 维:- TF:词在当前文档里出现多少次
- IDF:词在整个语料中稀不稀有,越稀有越重要
- 长度归一化:长文档不能因为词多就天然分数高
2.4 BGE-M3 模型介绍
本项目使用的是 BGE-M3(BAAI General Embedding M3),由北京智源研究院(BAAI)开发。📖 深入学习:如果你想了解 Embedding 模型的完整工作原理(Tokenization → Transformer → Pooling → 向量输出)、维度选择、模型对比和 L2 归一化,请阅读 附录F:Embedding 模型深入。BGE-M3 的核心特点:
| 特性 | 说明 |
|---|---|
| 多语言 | 支持中英双语及 100+ 语言 |
| 多粒度 | 支持短句到长文档(最多 8192 token)的向量化 |
| 多功能 | 同时支持 Dense 检索、Sparse 检索和 Multi-Vector 检索 |
| 维度 | 默认输出 1024 维 Dense 向量 |
| 部署 | 可在本地 GPU/CPU 上运行,不需要调用外部 API |
models/bge-m3/ 目录下,通过 LangChain 的 Embedding 接口调用:
3. 前置知识 — 向量数据库
3.1 为什么需要专门的向量数据库
初看可能会问:PostgreSQL 不是也有 pgvector 插件吗?为什么还要用 Milvus? 答案是性能和规模:| 对比维度 | pgvector | Milvus |
|---|---|---|
| 百万级向量检索 | 较慢(秒级) | 毫秒级 |
| 索引类型 | IVFFlat, HNSW | HNSW, IVF, DiskANN 等 11 种 |
| 混合检索 | 不支持 | Dense + Sparse 原生混合 |
| 分布式 | 需额外配置 | 原生支持分布式 |
| 过滤表达式 | 基础 | 丰富的标量过滤 |
3.2 Milvus 核心概念
前置知识:如果你不熟悉 HNSW 图索引原理,请先阅读 附录C:HNSW 图索引原理。如果你想了解 Milvus 各种索引类型的图解和 pymilvus 基本操作代码,请阅读 第4讲:Milvus 索引机制与基本操作。Collection(集合):类似关系数据库中的”表”。一个 Collection 存储一组相同结构的数据。 Field(字段):Collection 中的列。包括:
- 主键字段 (Primary Key)
- 向量字段 (Vector Field) — 用于相似度搜索
- 标量字段 (Scalar Field) — 用于过滤(如 source, kb_version)
- HNSW:基于图的索引,适合高召回率场景
- IVF_FLAT:基于聚类的索引,内存占用小
- 本项目使用默认的 HNSW 索引
3.3 Milvus 的部署架构
- etcd:分布式键值存储,Milvus 用它存储元数据(Collection 定义、索引状态、节点信息)
- MinIO:S3 兼容的对象存储,Milvus 用它存储向量索引文件、日志和 binlog
- Milvus Standalone:核心引擎,处理向量写入、索引构建和相似度搜索
4. Dense 检索 vs Sparse 检索
这是本项目最核心的检索概念。让我们用一个具体的例子来理解。4.1 场景设定
假设知识库中有以下文档片段:| ID | 内容 |
|---|---|
| D1 | ”忘记密码时,可以通过绑定的邮箱或手机号自助重置” |
| D2 | ”管理员可以在后台重置任何用户的密码” |
| D3 | ”Webhook 回调地址配置在系统设置-集成管理页面” |
| D4 | ”API 密钥在个人设置-安全页面中生成和管理” |
4.2 Dense 检索(语义相似度)
用户提问:“我怎么修改自己的登录密码” Dense 检索使用 Embedding 模型将问题和文档都转成向量,计算余弦相似度:- 理解语义,同义词和改写都能识别
- “重置密码”、“修改密码”、“改密码”、“忘记密码怎么办”等表达都能召回
- 对专业术语、编号、代码等精确匹配较弱
- 例如搜索”API v3.2 变更”,Dense 检索可能召回所有和 API 相关的文档,难以精确定位到特定版本
4.3 Sparse 检索(关键词匹配)
Sparse 检索(本项目使用 BM25 算法)基于词频和逆文档频率,对关键词做精确匹配:- 精确匹配专业术语、编号(如 “API v3.2”、“HS 编码 8471.30”)
- 对生僻词和专有名词效果极好
- 计算效率高,不需要 GPU
- 无法理解语义:搜”修改密码”不会召回”忘记密码怎么办”
- 同义词需要手动维护
4.4 Hybrid Search(混合检索)
混合检索 = Dense + Sparse,取长补短:5. Reranker(重排器)
5.1 为什么需要重排
Embedding 模型的检索是双塔架构(Bi-Encoder):问题和文档分别编码为向量,然后计算相似度。5.2 Reranker 的工作流程
5.3 BGE Reranker Large
本项目使用 BGE Reranker Large(同样是 BAAI 开发),与 BGE-M3 Embedding 模型配合使用:- 架构:CrossEncoder(XLM-RoBERTa 基座)
- 输入:
[CLS] query [SEP] document [SEP] - 输出:0-1 之间的相关性分数
- 部署:本地运行,位于
models/bge-reranker-large/
6. 在本项目中的体现
回顾第 1 讲中的核心架构图,现在你应该能理解每个组件的角色:7. 本讲实践闭环
| 项目 | 内容 |
|---|---|
| 本讲类型 | 原理实验 |
| 实践产物 | Embedding 相似度、BM25、Reranker 的单点实验 |
| 是否进入最终项目 | 否,作为理解检索原理的 demo;模型加载逻辑会进入项目 |
| 验收方式 | 运行 demo 后,相似问题分数更高,Reranker 能把更相关文本排到前面 |
| 后续落点 | 第 8 讲落到 Hybrid Search,第 17 讲落到检索评测 |
8. 重点掌握
| 优先级 | 内容 | 原因 |
|---|---|---|
| ★★★ 必会 | Embedding 的概念:文本→固定长度浮点数向量,语义相近的文本向量距离近 | 向量检索的基石,面试必问 |
| ★★★ 必会 | Dense 检索(语义相似度)vs Sparse 检索(关键词 BM25)的区别和互补 | 混合检索策略的核心,决定召回质量 |
| ★★★ 必会 | Hybrid Search = Dense + Sparse 取长补短 | 本项目 Milvus 的核心检索方式 |
| ★★★ 必会 | Reranker(CrossEncoder)解决 Bi-Encoder 精度不足的问题:先粗排后精排 | 提升检索精度的关键环节,面试高频 |
| ★★ 理解 | 余弦相似度的取值范围和含义 | 理解向量比较的基础 |
| ★★ 理解 | BGE-M3 的多语言、多粒度、多功能特性 | 了解本项目 Embedding 模型的选择理由 |
| ★★ 理解 | Milvus 核心概念:Collection、Field、Index、Partition | 为第 4 讲 Milvus 索引机制与第 8 讲混合检索做铺垫 |
| ★ 了解 | 向量相似度的三种计算方式(余弦/欧氏/内积)的公式 | 面试可能问到,但项目中使用默认内积 |
| ★ 了解 | pgvector vs Milvus 的对比 | 了解选型理由即可 |
9. 本讲小结
- Embedding 模型将文本转换为语义向量,语义相近的文本在向量空间中距离也近
- BGE-M3 是本项目使用的多语言 Embedding 模型,支持 Dense + Sparse 双向量输出
- Milvus 向量数据库不同于传统数据库,专为十亿级向量的高效相似度搜索设计
- Dense 检索(语义)和 Sparse 检索(关键词)各有所长,混合检索取长补短
- Reranker(CrossEncoder)对检索结果做精排,将问题和文档联合编码获得更精确的相关性
- 完整的检索链路是:Embedding → 混合检索 → 去重 → Reranker → 上下文筛选

