RAG
RAG
RAG 总体流程:
- 数据准备与分块
- 向量嵌入
- 索引构建
- 向量检索
- 索引优化
- 系统评估
1、数据准备与分块
文档加载器
主流 RAG 文档加载器
文本分块(Text Chunking)是构建 RAG 流程的关键步骤。它将加载后的长篇文档,切分成更小、更易于处理的单元。这些被切分出的文本块,是后续向量检索和模型处理的 基本单位。
分块策略
固定大小分块
- 先按段落分割(分割符:
\n\n) - 智能合并:将分割后的段落合并,如果超过
chunk_size时形成新快,并通过重叠机制chunk_overlap保持上下文连续性
- 先按段落分割(分割符:
递归字符分块
使用有效分割符分块,从分隔符列表(
["\n\n", "\n", "。", ",", " ", ""])中从前到后遍历,找到第一个在当前文本中 存在 的分隔符。如果都不存在,使用最后一个分隔符(通常是空字符串"")遍历分割好的片段
- 如果片段不超过块大小: 暂存到 合格片段数组 中,准备合并
- 如果片段超过块大小:
- 首先,将暂存的合格片段合并成块
- 然后,检查是否还有剩余分隔符:
- 有剩余分隔符: 递归调用
_split_text继续分割 - 无剩余分隔符: 直接保留为超长块
- 有剩余分隔符: 递归调用
- 最终处理: 将剩余的暂存片段合并成最后的块
按优先级递归尝试多种分隔符,直到块大小满足要求。
典型流程:
- 按
\n\n(段落)分割 - 块太大?→ 按
\n(行)再分 - 还是太大?→ 按
.或空格再分 - 仍然太大?→ 硬切(按字符数截断)
语义分块
- 首先进行句子分割
- 对列表中的每个句子,合并其前后
buffer_size个句子进行嵌入 - 计算嵌入向量之间的余弦距离,并确定动态阈值来区分语义断点
- 根据识别出的所有断点位置,将原始的句子序列进行切分合并
基于文档结构的分块
对于具有明确结构标记的文档格式(如Markdown、HTML、LaTex),可以利用这些标记来实现更智能、更符合逻辑的分割。
2、向量嵌入
将分割的块作为向量嵌入,并存入向量数据库
向量数据库
当前主流的向量数据库产品包括:
Pinecone是一款完全托管的向量数据库服务,采用Serverless架构设计。它提供存储计算分离、自动扩展和负载均衡等企业级特性,并保证99.95%的SLA。Pinecone支持多种语言SDK,提供极高可用性和低延迟搜索(<100ms),特别适合企业级生产环境、高并发场景和大规模部署。
Milvus是一款开源的分布式向量数据库,采用分布式架构设计,支持GPU加速和多种索引算法。它能够处理亿级向量检索,提供高性能GPU加速和完善的生态系统。Milvus特别适合大规模部署、高性能要求的场景,以及需要自定义开发的开源项目。
Qdrant是一款高性能的开源向量数据库,采用Rust开发,支持二进制量化技术。它提供多种索引策略和向量混合搜索功能,能够实现极高的性能(RPS>4000)和低延迟搜索。Qdrant特别适合性能敏感应用、高并发场景以及中小规模部署。
Weaviate是一款支持GraphQL的AI集成向量数据库,提供20+AI模块和多模态支持。它采用GraphQL API设计,支持RAG优化,特别适合AI开发、多模态处理和快速开发场景。Weaviate具有活跃的社区支持和易于集成的特点。
Chroma是一款轻量级的开源向量数据库,采用本地优先设计,无依赖。它提供零配置安装、本地运行和低资源消耗等特性,特别适合原型开发、教育培训和小规模应用。Chroma的部署简单,适合快速原型开发。
向量数据库核心概念
| 概念 | 说明 |
|---|---|
| Collection(集合) | 类似关系数据库中的"表",是一组 Point 的容器 |
| Point(点) | 向量数据库中的基本单元,包含一个向量和可选的 Payload |
| Vector(向量) | 一组浮点数,表示某个对象的语义特征 |
| Payload(载荷) | 附加在 Point 上的元数据(JSON 格式),用于过滤和展示 |
| Distance(距离度量) | 衡量两个向量之间相似度的算法 |
| Index(索引) | 加速搜索的数据结构,Qdrant 自动管理向量索引,也可为 Payload 建立索引 |
常见距离度量
| 度量 | 公式 | 适用场景 |
|---|---|---|
| Cosine(余弦相似度) | 1 - cos(θ) | 文本 Embedding,关注方向而非大小 |
| Euclid(欧氏距离) | √Σ(aᵢ-bᵢ)² | 图像特征,关注绝对差异 |
| Dot(点积) | Σ(aᵢ×bᵢ) | 已归一化的向量,计算最快 |
3、索引构建
索引 是 为了加速查询而设计的复杂数据结构
索引类型
向量索引用 近似最近邻(ANN,Approximate Nearest Neighbor)算法,用少量精度换取巨大的速度提升。Qdrant 默认使用 HNSW 索引
FLAT (精确查找):搜索时就要把查询向量和数据库中 每一个 向量算一遍距离,这就是暴力搜索,精度 100%,但时间复杂度是 O(N×D)(N=数据量,D=维度)
IVF 系列 (倒排文件索引):通过聚类将所有向量分成多个“桶”(
nlist),查询时,先找到最相似的几个“桶”,然后只在这几个桶内进行精确搜索。缺点:召回率不是100%,因为相关向量可能被分到了未被搜索的桶中。
HNSW (基于图的索引):构建一个多层的邻近图。查询时从最上层的稀疏图开始,快速定位到目标区域,然后在下层的密集图中进行精确搜索。检索速度极快,召回率高,尤其擅长处理高维数据和低延迟查询。
缺点:内存占用非常大,构建索引的时间也较长
DiskANN (基于磁盘的索引):一种为在 SSD 等高速磁盘上运行而优化的图索引。
4、向量检索
有了 向量数据库 与 Index 索引,我们要 从海量数据中 高效地检索信息(怎么用索引查好数据)
在 ANN 检索之上,向量数据库通常提供了多种增强检索功能
- 过滤检索:在向量搜索的同时加 Payload 条件过滤。通常有先过滤再检索和先检索再过滤两种策略。几乎所有 RAG 应用都会用到——按时间范围、分类、标签、权限等缩小搜索空间。
- 范围检索:不返回固定的 Top-K,而是返回 所有相似度超过某个阈值 的结果
- 多向量混合检索:允许在一个请求中同时检索多个向量字段,并将结果智能地融合在一起。使用一个重排策略(Reranker)将来自不同检索流的结果合并成一个统一的、更高质量的排序列表。
- 分组检索:搜索结果按某个字段分组,每组只返回最优的 N 条,避免结果被同一类内容淹没。
5、索引优化
稀疏向量与稠密向量
稀疏向量(Sparse Vector)
- 维度极高(等于词汇表大小),绝大多数元素为 0
- 基于词频统计,每个维度对应一个具体的词
- 代表算法:TF-IDF、BM25
- 本质是"词袋模型"——只看词出现与否/频率,不看顺序和语义
稠密向量(Dense Vector)
- 维度较低(通常 384~1536),每个元素都有非零浮点值
- 通过深度学习模型(BERT、Sentence-Transformers 等)生成
- 捕捉的是语义信息,向量距离代表语义相似度
在 RAG 检索中的应用
| 稀疏检索(BM25) | 稠密检索(向量检索) | |
|---|---|---|
| 匹配方式 | 关键词精确匹配 | 语义相似度匹配 |
| 查询"西红柿炒蛋" | 只找包含"西红柿炒蛋"的文档 | 也能找到"番茄炒鸡蛋" |
| 查询"蛋白质丰富的家常菜" | 找不到(无关键词匹配) | 能找到(理解语义) |
实际 RAG 系统中常用 混合检索(Hybrid Search):同时用 BM25 + 稠密向量检索,取两者结果的融合排序,兼顾精确匹配和语义理解。
混合检索
混合检索通常并行执行两种检索算法,然后将两组异构的结果集融合成一个统一的排序列表。以下是两种主流的融合策略:
- 倒数排序融合 (Reciprocal Rank Fusion, RRF):RRF 不关心不同检索系统的原始得分,只关心每个文档在各自结果集中的排名。其思想是:一个文档在不同检索系统中的排名越靠前,它的最终得分就越高。
- 加权线性组合:这种方法需要先将不同检索系统的得分进行归一化(例如,统一到 0-1 区间),然后通过一个权重参数
α来进行线性组合。
重排序
一个文档如果在多个检索结果中都排名靠前,那么它很可能更重要。RRF 通过计算排名的倒数来为文档打分,有效融合了不同检索策略的优势。但是如果只考虑排名信息,会忽略原始的相似度分数,可能丢失部分有用信息。
重排策略:
- RankLLM:直接利用大型语言模型本身来进行重排的方法,精心设计的提示词来实现
- Cross-Encoder(交叉编码器):把 **query 和 document 拼接 **在一起送入预训练的 Transformer 模型(如 BERT)中,模型最终会输出一个单一的分数
- ColBERT 重排:
- 独立编码:ColBERT 分别为查询(Query)和文档(Document)中的每个 Token 生成上下文相关的嵌入向量。这一步是独立完成的,可以预先计算并存储文档的向量,从而加快查询速度。
- 后期交互:在查询时,模型会计算查询中每个 Token 的向量与文档中每个 Token 向量之间的最大相似度(MaxSim)。
- 分数聚合:最后,将查询中所有 Token 得到的最大相似度分数相加,得到最终的相关性总分。