向量数据库实战:Milvus 与 Qdrant 选型与落地

向量数据库是支撑 RAG(检索增强生成)与语义检索的核心底座。当大模型需要”记忆”海量文档时,关键不是把文字存进 MySQL,而是把文本转成高维向量,再用近似最近邻(ANN)算法在毫秒级找回最相似的内容。本文对比 Milvus 与 Qdrant 两大主流引擎,手把手讲清索引选型、Docker 部署与生产落地要点,帮你少踩坑。

一、向量数据库到底解决什么问题

传统关系型数据库擅长”精确匹配”:WHERE id = 123、WHERE status = 'paid'。但”找出和这句话意思最接近的三段文案”这种语义搜索,靠 B-Tree 索引根本做不到。向量数据库做的事情,是把文本、图片、音频用 Embedding 模型编码成一串浮点数(如 768 维、1536 维),然后在向量空间里做”近邻搜索”。

它和全文检索引擎(如 Elasticsearch)也不是一回事:倒排索引匹配的是”关键词是否出现”,而向量检索匹配的是”语义是否相近”。两者常常互补——先用关键词粗筛,再用向量精排,效果最好。

维度关系型数据库全文检索引擎向量数据库
查询方式精确等值/范围关键词倒排近似最近邻(ANN)
擅长场景交易、账目日志、站内搜索语义检索、推荐、去重
典型操作SELECT / JOINmatch / termsearch(topK, vector)
RAG 角色元数据存管粗筛语义召回核心

二、核心概念:向量、相似度与索引

2.1 相似度度量

衡量两段向量”多像”,常用三种距离:余弦相似度(只看方向,忽略长度,最常用)、欧氏距离(L2,看绝对距离)、内积(IP,需先归一化)。在 RAG 场景里,余弦相似度几乎成了默认选项,因为它对文本长度不敏感。

2.2 索引类型决定性能与精度

暴力扫描(FLAT)最准但最慢;IVF(倒排文件)把空间聚成若干簇,只搜最近的几个簇,速度快但有损;HNSW(分层可导航小世界图)是当下最主流的近似索引,召回率和延迟都很优秀;DiskANN 则把索引放到磁盘,用少量内存支撑十亿级向量。选错索引,要么慢得不可用,要么召回率掉到无法接受。

import numpy as np

def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
    # 余弦相似度 = 点积 / (模长乘积),范围 [-1, 1],越大越相似
    return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

# 假设已用 Embedding 模型得到三个句向量
q   = np.random.rand(768)
doc1 = np.random.rand(768)
doc2 = np.random.rand(768)

print(cosine_similarity(q, doc1))  # 例如 0.71
print(cosine_similarity(q, doc2))  # 例如 0.43
# 召回时取相似度最高的 topK 个,就是最朴素、也最可靠的语义检索

关于检索质量的量化评估,可参考本站《向量检索测评实战:Recall@K 与 RAG 质量度量》,用 Recall@K 把”召回得准不准”变成可观测的数字。

三、Milvus 实战:面向规模的分布式向量库

Milvus 是开源向量数据库的”老牌选手”,优势在于水平扩展能力强、生态完整(支持多种索引、支持标量过滤、有 Attu 可视化面板)。它提供 standalone(单机)和 distributed(集群)两种形态,生产环境通常用分布式版扛住十亿级数据。

3.1 用 Docker Compose 起一套 standalone

version: '3.5'
services:
  etcd:
    image: quay.io/coreos/etcd:v3.5.14
    command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
  minio:
    image: minio/minio:RELEASE.2024-05-28
    command: minio server /data --console-address ":9001"
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
  milvus:
    image: milvusdb/milvus:v2.4.5
    command: ["milvus", "run", "standalone"]
    ports:
      - "19530:19530"   # gRPC 端口
      - "9091:9091"     # 指标端口
    depends_on:
      - etcd
      - minio

上面的编排把 etcd(元数据)、MinIO(对象存储)和 Milvus 本体一起拉起。在本地验证或 CI 里跑集成测试时,这种组合非常顺手,配合 Docker 编排实战 的套路可以快速复现。

3.2 Python 写入与查询

from pymilvus import MilvusClient

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

# 创建集合并指定向量维度与索引
if client.has_collection("articles"):
    client.drop_collection("articles")

client.create_collection(
    collection_name="articles",
    dimension=768,
    metric_type="COSINE",          # 余弦相似度
    index_type="HNSW",             # 图索引,召回与延迟均衡
    index_params={"M": 8, "efConstruction": 200},
)

# 批量插入(实际中来自 Embedding 模型输出)
data = [
    {"id": 1, "vector": [0.1] * 768, "title": "微服务治理"},
    {"id": 2, "vector": [0.2] * 768, "title": "向量检索入门"},
]
client.insert(collection_name="articles", data=data)

# 语义检索 topK
query_vec = [0.15] * 768
res = client.search(
    collection_name="articles",
    data=[query_vec],
    limit=3,
    output_fields=["title"],
)
print(res[0])   # 返回最相似的三条及相似度分数

四、Qdrant 实战:Rust 打造的高性能引擎

Qdrant 用 Rust 编写,以轻量、高吞吐、API 简洁著称,特别适合想把向量检索嵌进现有服务的团队。它同样支持 HNSW、标量过滤、本地磁盘与云端托管,部署成本通常比 Milvus 低。

4.1 启动并建集合

# 一行 Docker 起服务
docker run -p 6333:6333 -p 6334:6334 \
  -v /Users/mac/WorkBuddy/网站运营/qdrant_storage:/qdrant/storage \
  qdrant/qdrant:latest
from qdrant_client import QdrantClient, models

client = QdrantClient("localhost", port=6333)

client.create_collection(
    collection_name="articles",
    vectors_config=models.VectorParams(
        size=768,
        distance=models.Distance.COSINE,   # 余弦距离
    ),
)

# 写入点(payload 可挂任意业务字段,用于过滤)
client.upsert(
    collection_name="articles",
    points=[
        models.PointStruct(id=1, vector=[0.1] * 768, payload={"title": "微服务治理"}),
        models.PointStruct(id=2, vector=[0.2] * 768, payload={"title": "向量检索入门"}),
    ],
)

# 检索 + 标量过滤(只在某些分类里找)
hits = client.query_points(
    collection_name="articles",
    query=[0.15] * 768,
    limit=3,
    with_payload=True,
).points
for h in hits:
    print(h.id, h.score, h.payload)

五、Milvus vs Qdrant:到底怎么选

对比项MilvusQdrant
实现语言Go / C++Rust
规模上限十亿级、分布式原生千万到亿级、单机够用
运维复杂度中高(依赖 etcd/MinIO)低(单二进制)
生态工具Attu 面板、丰富 SDKDashboard、REST 友好
适合场景大型 RAG 平台、多租户中小团队、嵌入式/轻量服务

一句话建议:数据量冲亿级、要多人多业务共用,选 Milvus;想快速上线、团队小、追求低运维,选 Qdrant。两者 API 都成熟,后期切换成本主要在数据迁移,不算高。

六、专用向量库 vs pgvector:何时不必上重武器

如果数据量在百万级以内、团队本就重度使用 PostgreSQL,其实没必要单独维护一套向量服务。本站《pgvector 实战:用 PostgreSQL 搞定向量检索与 RAG》已经演示了如何用 SQL 直接做相似度查询,开发与运维链路最短。但当向量规模超过千万、或需要复杂的多向量、稀疏-稠密混合检索时,专用向量库在性能和功能上会更从容。

另外,如果偏好”开箱即用”的轻量方案,也可以看看本站《Chroma 向量数据库实战》与《LlamaIndex 实战:用索引与检索器构建生产级 RAG 应用》,它们更偏原型与嵌入式场景,和 Milvus/Qdrant 形成互补。

七、生产落地检查清单

事项要点
维度对齐写入与查询必须用同一个 Embedding 模型,维度不一致会直接报错
索引参数HNSW 的 M / efConstruction 按数据量与精度需求调,别全用默认
标量过滤把租户、时间、分类放进 payload/标量字段,避免全量扫描
一致性确认 insertion 已 flush/可见再查询,CI 里用 GitHub Actions 跑回归
容量规划单条 768 维 float32 约 3KB,亿级即数百 GB,提前算存储
可观测暴露 QPS、检索延迟、召回率指标,配合监控告警

向量数据库不是银弹,但它确实是当下 AI 应用绕不开的一环。从 pgvector 起步、到 Qdrant/Milvus 进阶,按需升级,比一上来就搭集群要务实得多。

上一篇 pnpm 实战:用硬链接与内容寻址重塑 Node 包管理
下一篇 Rspack 实战:用 Rust 构建工具为前端打包提速
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]