上一篇把文档加载、切分、向量化并存进了 Milvus,知识库已经就位。这一篇讲 RAG 的后半场——检索与生成:用户的问题进来之后,如何从库里又快又准地捞出相关内容,如何把稠密和稀疏两路检索的结果融合排序,最后如何把检索结果喂给模型生成答案。走完这一篇,一个完整的 RAG 应用就闭环了。
一、检索流程总览#
先回忆上篇结尾的分工:索引流程是离线的,把文档变成向量入库;检索流程是在线的,每次用户提问都要跑一遍:
- 把用户的问题用同一个嵌入模型转成向量(和入库时保持一致,否则不在同一个向量空间里,比对没有意义);
- 拿问题向量和库里的 chunk 向量做相似度比对,选出 Top-K;
- 把命中的原文拼进提示词,交给模型生成答案。
第一步的代码和上篇入库时如出一辙——BGE-M3 一次编码,同时拿到稠密和稀疏两种向量:
from FlagEmbedding import BGEM3FlagModel
from pymilvus import MilvusClient
client = MilvusClient(uri="http://localhost:19530")
def query_to_vector(query: str):
model = BGEM3FlagModel(model_name_or_path="BAAI/bge-m3")
result = model.encode(
sentences=query,
return_dense=True, # 稠密向量:管语义
return_sparse=True, # 稀疏向量:管关键词
)
return result["dense_vecs"], result["lexical_weights"]
接下来的问题是:"比对"这一步具体怎么做。
二、KNN 与 ANN:精确检索和近似检索#
比对相似度,最朴素的做法是 KNN(K 近邻搜索):把问题向量和库里每一个向量逐一算距离,返回最近的 K 个。它对应 Milvus 的 FLAT 索引(暴力检索),结果 100% 精确、零召回损失——代价是数据量一大,每次查询都要全库遍历,性能顶不住。
工程上的主流选择是 ANN(近似最近邻搜索):借助索引结构跳过大部分向量,不做全库遍历,用少量召回精度换来数量级的速度提升。上篇建索引时选的两种就是 ANN 家族的成员:
- HNSW:稠密向量的多层图索引,从顶层粗略导航、逐层精确逼近;
- SPARSE_INVERTED_INDEX:稀疏向量的倒排索引,先快速筛出包含查询词的候选文档再算分;
- 另外常见的 IVF_FLAT 可以理解为"先聚类分桶,再在最近的几个桶里暴力搜索"——书架式管理,先找对书架,再在架内仔细翻。
一句话选型:小数据集或对召回有严格要求用 FLAT,常规场景用 HNSW 这类 ANN 索引。


还没有公开留言,成为第一个写下回声的人。