36-检索优化与向量库
向量检索算法
HNSW(Hierarchical Navigable Small World)
HNSW 是目前最流行的近似最近邻搜索(ANN)算法之一,广泛用于向量数据库中。
核心思想:
- 构建多层图结构,上层是稀疏的连接,下层是稠密的连接;
- 搜索从顶层开始,逐层向下精炼,找到最近邻;
- 基于贪心搜索找到近似最近邻。
优点:
- 查询速度快,适合大规模向量检索;
- 在百万级向量上仍能保持低延迟;
- 精度较高。
缺点:
IVF(Inverted File)
IVF 是另一种经典的向量检索算法:
核心思想:
- 先对向量进行聚类,得到 n 个聚类中心;
- 每个向量分配到最近的聚类中心;
- 查询时先找最近的 k 个聚类中心,然后只在这些簇中搜索。
优点:
- 构建索引快;
- 内存占用比 HNSW 低;
- 适合超大规模向量。
缺点:
- 聚类质量影响检索精度;
- 在向量维度不高时速度优势不明显。
向量数据库对比
| 向量数据库 | 特点 | 适用场景 |
|---|
| FAISS | Facebook 开源,纯 Python/C++ 实现,轻量易用 | 中小规模数据集,原型验证,本地部署 |
| Chroma | 开源,轻量,原生 Python,集成 LangChain | 开发测试,中小规模,快速原型 |
| Milvus | 开源云原生向量数据库,支持分布式,功能丰富 | 生产环境,大规模向量,分布式部署 |
| Pinecone | 全托管云服务,无需运维,易用性好 | 云原生应用,快速上线,不想自己运维 |
| Weaviate | 开源,支持多模态,GraphQL API | 云原生,多模态场景 |
| Pgvector | PostgreSQL 扩展,关系数据库 + 向量检索 | 已有 PostgreSQL 栈,事务需求,混合查询 |
选择建议
- 原型开发:Chroma / FAISS 足够;
- 生产部署:Milvus / Pinecone(云);
- 需要事务和混合查询:Pgvector 结合 PostgreSQL;
- 中小规模:FAISS 足够用,无需额外数据库。
重排序(Rerank)策略
当查询向量存储时,Top-k 结果不一定按最相关的方式排序,重排序可以提升检索效果。
为什么需要重排序?
向量检索返回的前 k 个结果中,最相关的可能排在第 5 或第 7 位,而不是第 1 或第 2 位。重排序将最相关的信息重新定位到前面,提高大模型获取关键信息的概率。
常见重排序方法
- Cohere Rerank:使用专门的重排序模型,效果好但需要 API;
- Diversity Ranker:根据文档多样性进行重新排序,提高结果多样性;
- LostInTheMiddleRanker:在上下文窗口的开始和结束之间交替放置最佳文档,缓解大模型对中间信息关注不足的问题;
- LLM 重排序:让大模型根据相关性对文档排序,效果好但成本高。
混合检索(BM25 + 向量)
为什么需要混合检索?
向量搜索擅长捕捉语义相似度,但在匹配精确关键词方面有时不够精准。例如,查询"阿迪达斯 XYZ 白色运动鞋",向量检索可能返回很多相关但不包含精确 XYZ 型号的结果,漏掉精确匹配。
混合检索结合了向量搜索和关键词搜索的优势,智能地将两种结果融合,在保持语义理解的同时,保证精确关键词匹配。
实现方式
- 并行检索:同时用 BM25(关键词)和向量进行检索;
- 结果融合:使用 RRF(逆向排名融合)将两个排名列表融合;
- 返回融合后的 Top-k 结果。
RRF(逆向排名融合)
RRF 是一种简单有效的结果融合方法:
1def reciprocal_rank_fusion(search_results_dict, k=60):
2 """
3 search_results_dict: {query: [doc_id ranked by similarity]}
4 """
5 fused_scores = {}
6 for query, doc_ids in search_results_dict.items():
7 for rank, doc_id in enumerate(doc_ids):
8 if doc_id not in fused_scores:
9 fused_scores[doc_id] = 0
10 fused_scores[doc_id] += 1 / (rank + k)
11 # 按分数降序排序
12 sorted_docs = sorted(fused_scores.items(),
13 key=lambda x: x[1], reverse=True)
14 return [doc_id for doc_id, _ in sorted_docs]
原理:不依赖绝对分数,只利用相对排名,非常适合融合不同检索方法的结果。
检索优化策略汇总
1. 查询转换优化
- HYDE:让大模型生成假设性答案,用生成的答案辅助检索;
- 查询重写:用户提问表述不清时,让大模型重写为更适合检索的查询;
- 多查询生成(RAG-Fusion):生成多个不同角度的查询,每个查询检索后融合结果;
- StepBack 提示:让大模型从具体问题抽象出更一般性的问题,辅助召回。
2. 索引优化
- 数据质量:预处理删除重复、噪声、无关文档;
- 元数据增强:添加元数据(日期、章节、作者等),支持按元数据过滤;
- 提示压缩:使用 LLMLingua 等方法压缩检索到的上下文,突出重点,减少噪声;
- 多级索引:先粗筛再精排,提高效率。
3. 结果后处理
- 重排序:对初筛结果重新排序,把最相关的放前面;
- 上下文重排序:使用 LongContextReorder 解决"丢失在中间"问题;
- 提示压缩:压缩长上下文,保留关键信息。
4. 如果 RAG 召回率低,排查思路
- 检查知识库本身是否包含答案,如果不包含那是覆盖不全问题;
- 如果知识库有答案但没召回:
- 检查分块方式是否不合理,知识点被错误分割 → 修改分割方式;
- 先用 BM25 召回,再用模型精排;
- 调整 chunk_size 和 top_k 参数,在验证集上调参;
- 微调 embedding 模型适配你的领域;
- 尝试混合检索结合关键词和向量。
大模型辅助召回的高级方法
FLARE(Active Retrieval Augmented Generation)
传统 RAG 只根据用户 query 做一次文档召回,在长文本生成场景效果不好。FLARE 提出了主动多次召回:
两种主动召回策略:
-
策略一:让模型在生成过程中,当遇到需要查询知识时,主动输出检索标识,执行召回,然后继续生成。
- 缺点:LLM 不愿意生成主动召回标识,需要调优生成概率;不微调可靠性不高。
-
策略二:基于生成 token 概率判断,每生成 N 个 token,如果有 token 概率低于阈值,就用当前生成的部分做一次检索,补充信息后继续生成。
- 原理:低概率 token 往往意味着模型对这部分知识不确定,需要检索补充。
负样本挖掘优化检索
为了训练好一个高质量的检索模型,需要高质量负样本:
| 方法 | 思路 | 优缺点 |
|---|
| 随机采样 | 随机抽候选文档作为负例 | 简单,但负例太简单,对模型提升小,训练不稳定 |
| Top-K 难负例采样 | 选分数最高但不相关的作为负例 | 难例对模型帮助大,但可能采样到假负例 |
| SimANS | 对接近正例的困惑负例按概率采样 | 平衡了难度和假负例问题,效果较好 |
| 批内负采样 | 同一个 batch 内其他样本作为负例 | 计算高效,不需要额外采样 |
| 同文章难负例 | 正例所在文章的其他块作为负例 | 难例质量高,因为主题相似,更有区分度 |
| LLM 辅助蒸馏 | 让大模型给候选文档打分,作为软标签 | 利用大模型判断文档重要性,指导训练,但计算量大 |
面试常见问题
1. HNSW 和 IVF 的区别是什么?
回答要点:
- HNSW 基于多层图结构,查询快,构建慢,内存大;
- IVF 基于聚类,构建快,查询相对慢一点,适合更大规模;
- 百万级以内 HNSW 延迟更低。
2. 什么是混合检索?为什么需要它?
回答要点:
- 结合向量检索(语义)和关键词检索(精确匹配);
- 向量检索擅长语义,但精确匹配不如关键词;
- 融合后能兼顾两者优点,提升召回质量。
3. 为什么需要重排序?
回答要点:
- 向量检索返回的 Top-k 不一定按相关性完美排序;
- 重排序能把最相关的结果排在更前面,提高大模型获取关键信息的概率;
- 可以先大范围检索,再用重排序模型精排,兼顾效率和效果。
4. RAG 召回率低可能有哪些原因?怎么优化?
回答要点:
- 原因 1:知识库本身不包含答案 → 需要补充知识库;
- 原因 2:分块不合理,知识点被切开 → 调整分块大小和策略;
- 原因 3:embedding 模型不匹配领域 → 微调 embedding;
- 原因 4:只使用向量检索 → 加入 BM25 混合检索;
- 原因 5:检索结果排序不好 → 加入重排序步骤。
5. 介绍一下 RRF(逆向排名融合)
回答要点:
- RRF 用于融合多个不同检索结果的排名列表;
- 每个文档的分数是 1/(rank + k),然后按分数排序;
- 优点:不依赖检索算法输出的绝对分数,只需要相对排名,实现简单,效果稳定;
- 常用于融合 BM25 和向量检索结果,或者融合多个查询的检索结果(如 RAG-Fusion)。