17.Milvus如何完成一次向量相似度检索

Milvus 如何完成一次向量相似度检索?

码海寻道 · 大模型、智能体与 RAG 工程组件系列第 17 篇

在 RAG 项目里,"向量检索"经常被一句 search() 代码带过。但要真正排查召回为空、结果不准和延迟升高,必须理解一次检索内部发生了什么。

可以把它概括为:查询向量进入 Milvus,经过集合和索引定位候选,再计算距离、执行过滤,最后返回 Top K 结果。

如果把一次查询放回部署架构中,关键路径可以这样看:

text 复制代码
PyMilvus / REST 客户端
          ↓
Milvus Proxy:接收请求、校验参数、路由请求
          ↓
Query Coordinator / Query Node:确定数据范围并执行检索
          ├── 从 etcd 获取集合、分区、索引和节点状态等元数据
          └── 从 MinIO / 本地缓存加载数据文件和索引文件
          ↓
返回 Top K 结果

这里的 etcd 和 MinIO 不在应用的 search() 调用里直接出现,但它们会影响 Milvus 是否知道"该查什么"和"到哪里读取索引"。因此,检索报错时不能只盯着 Python 参数,也要检查依赖服务和数据卷。

一、一次检索的完整链路

text 复制代码
用户问题
   ↓
Embedding 模型生成 query_vector
   ↓
Proxy 接收请求并校验参数
   ↓
Query Coordinator 确定目标数据范围
   ↓
Query Node 加载索引并搜索候选向量
   ↓
执行标量过滤与 Top K 合并
   ↓
返回 id、distance 和 output_fields

不同部署模式下组件名称和内部实现会有所差异,但从应用开发者视角,最重要的是确认四件事:集合是否存在、数据是否已加载、向量维度是否正确、索引与距离指标是否匹配。

二、相似度到底如何计算?

1. L2 距离

L2 是欧氏距离,距离越小通常表示越相近:

text 复制代码
d(x, y) = sqrt(sum((x_i - y_i)^2))

2. 内积 IP

内积常用于已经做过归一化或对方向相似度有要求的向量。不同模型对向量长度的含义不同,不能只凭经验选择。

3. 余弦相似度 COSINE

余弦相似度关注向量方向,常用于文本语义检索。使用时要保证写入和查询采用一致的向量预处理方式。

最重要的原则是:

写入向量、查询向量、索引 metric_type 必须属于同一套约定。

三、一个可复现的搜索示例

python 复制代码
from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

query_vector = [0.01, 0.12, 0.34]  # 仅示例,维度必须匹配集合

results = client.search(
    collection_name="knowledge_chunks",
    data=[query_vector],
    anns_field="embedding",
    limit=5,
    filter='tenant_id == "tenant-a" and status == "published"',
    output_fields=["document_id", "chunk_id", "text"],
    search_params={"params": {"ef": 64}},
)

for hits in results:
    for hit in hits:
        print({
            "id": hit["id"],
            "distance": hit["distance"],
            "entity": hit.get("entity", {}),
        })

不同索引的 search_params 不同,ef 是 HNSW 的搜索参数,不能照搬到 IVF 或其他索引。代码示例用于说明调用结构,实际参数要与创建的索引一致。

四、Milvus 会先做过滤还是先做向量搜索?

应用通常会同时提供向量和标量过滤条件,例如:

text 复制代码
相似于"差旅报销"的内容
并且 tenant_id = tenant-a
并且 status = published

过滤和向量搜索的执行方式受索引、数据规模和查询计划影响。工程上不要假定"过滤一定先执行"或"向量一定先执行",而应通过真实数据压测观察:

  • 过滤字段的选择性;
  • 过滤后候选数量;
  • Top K 大小;
  • 查询延迟和资源使用;
  • 跨分区搜索数量。

如果过滤字段决定权限范围,必须确保过滤表达式由可信服务生成,不能直接拼接用户输入。

五、Top K 不是越大越好

RAG 经常把 Top K 设置成 5、10 或 20,但 K 越大并不一定提高答案质量:

  • 召回内容太少,可能遗漏关键事实;
  • 召回内容太多,会挤压大模型上下文;
  • 相似但重复的 Chunk 会降低信息密度;
  • 低相关片段会增加模型误判机会。

通常应把 Milvus 的 Top K、去重、Reranker 和最终送入大模型的上下文数量分开设计:

text 复制代码
Milvus 召回 Top 20
   ↓
按文档或章节去重
   ↓
Reranker 重排
   ↓
选 Top 5 进入 Prompt

六、为什么返回 distance 不能直接当答案可信度?

距离是向量空间中的数值,不等于事实正确率。它会受以下因素影响:

  • Embedding 模型;
  • 文本切分方式;
  • 距离指标;
  • 文档领域;
  • 查询表达方式;
  • 向量是否归一化。

因此,阈值需要用标注数据校准。不要直接认为"距离小于某个固定值就一定相关"。

七、检索不到数据时的排查顺序

第一步:确认集合和字段

检查 Collection 名称、向量字段名、主键字段和输出字段是否与代码一致。

第二步:确认向量维度

把 Embedding 模型输出的 len(vector) 与 Schema 中的 dim 比较。维度不一致时,插入和搜索都会失败或无法得到预期结果。

第三步:确认数据已经加载

Milvus 搜索前需要让目标 Collection 或 Partition 处于可搜索状态。未加载时,客户端通常会返回相应错误。

第四步:去掉过滤条件做对照

先搜索全量范围,再逐个加上租户、版本和状态条件。如果去掉过滤后有结果,问题往往出在表达式、字段值或数据类型上。

第五步:检查距离指标和模型

确认写入向量和查询向量来自同一 Embedding 模型,且索引使用的 metric 与查询预期一致。

第六步:检查 Milvus 依赖服务

在 Standalone Docker Compose 部署中,可先查看:

bash 复制代码
docker compose ps
docker compose logs --tail 100 standalone
docker compose logs --tail 100 etcd
docker compose logs --tail 100 minio

常见判断方式如下:

  • etcd 不健康:Milvus 可能无法读取集合、索引或节点状态等元数据;
  • MinIO 不健康或数据卷不可用:Milvus 可能无法读取索引文件或持久化数据;
  • Milvus Standalone 不健康:客户端无法正常建立连接或执行查询;
  • 三者都正常但仍然空结果:继续检查集合加载、过滤条件、向量模型和一致性设置。

不要直接修改 etcd 数据,也不要只删除 MinIO 中看起来"没用"的文件。它们由 Milvus 的元数据和文件布局共同管理,手工删除可能造成元数据与对象不一致。

八、如何看待一致性?

刚写入的数据不一定在所有查询节点上立即可见。Milvus 支持 Strong、Bounded、Session 和 Eventually 等一致性级别。默认级别和具体版本有关,生产项目应明确配置并测试。

例如,知识库上传后立即要求用户搜索到新文档,可以在这个确认链路使用更高的一致性级别;推荐系统等可接受短暂延迟的场景,则可以使用更低延迟的策略。

不要把"搜索不到刚写入的记录"直接判断为写入失败,先检查写入结果、刷新状态和一致性设置。

九、检索质量如何验证?

建立一组有标准答案的问题,记录:

  • Recall@K:相关片段是否被召回;
  • MRR 或 NDCG:相关结果排名是否靠前;
  • P50、P95、P99 延迟;
  • 过滤条件下的有效召回数量;
  • 最终回答的引用正确率。

把"检索正确"和"回答正确"分开评估,才能知道问题出在 Embedding、Milvus、Reranker 还是大模型生成环节。

结语

一次向量检索不是简单的"传入向量、返回结果",而是模型、Schema、索引、过滤、一致性和资源状态共同作用的结果。掌握这条链路,才能在出现空结果、错结果和慢查询时快速定位。

下一篇将重点比较 FLAT、IVF 和 HNSW,回答"Milvus 索引到底应该怎么选"。

参考资料

  1. Milvus 官方文档:Single-Vector Search
  2. Milvus 官方文档:Consistency
  3. Milvus 官方文档:Run Milvus with Docker Compose
  4. Milvus 官方文档:Product FAQ

本文为"码海寻道"原创技术文章。检索参数、返回结构和一致性默认值请结合目标 Milvus 与 PyMilvus 版本确认。

相关推荐
芒果作者19 分钟前
视频审核助手
人工智能·音视频
CODER030420 分钟前
ubuntu24.04:降内核+显卡驱动+cuda+cudnn+pytorch+anaconda+pycharm
人工智能·pytorch·深度学习·自然语言处理·cuda·ubuntu24.04·降内核
Likeadust21 分钟前
多视角直播破局!企业融媒体系统在线高清直播EasyDSS多路同屏技术,重构实时可视化传播体验
人工智能·重构·媒体
万邦科技Lafite21 分钟前
1688一键创建订单付款API操作指南讲解
人工智能·微信·api·电商开放平台·淘宝开放平台·api开放接口
Forerror202622 分钟前
API网关能做什么?MAI Gateway如何赋能企业AI能力
人工智能·maigateway·finapi·企业级ai网关·大模型财务管控
多多鼠31 分钟前
Tool Calling的信任边界:从协议校验到执行沙箱的完整链路设计
运维·开发语言·网络·人工智能·python·langchain
一水鉴天34 分钟前
问题分类的三元组映射体系与求解方法论 20260901(千问)
人工智能·算法·机器学习
ar012339 分钟前
AR工业眼镜应用:从现场辅助工具升级为工业作业智能入口
人工智能·ar
YoanAILab39 分钟前
大语言模型基础:Token、Embedding、Transformer、KV Cache 与 RAG
语言模型·transformer·embedding·token·rag