创见博客
Milvus 向量数据库实战:概念、选型与 LangChain 接入
七崽爱吃小饼干2026/10/18阅读 0

前几篇把 RAG 的各个环节拆开讲了:Loader、切分、Embedding。现在到了存储环节:向量数据库。

demo-23 用的是 MemoryVectorStore,适合理解原理,但进程一退出数据就没了,也撑不起真实业务。这一篇讲清向量数据库是什么、为什么需要、常见产品有哪些,并用 Milvus 跑一遍完整的写入、建索引、检索和过滤流程。

代码基于 JavaScript 版 langchain v1,向量库使用 Milvus,Embedding 复用 demo-23 的 Qwen 文本向量模型。

一、什么是向量数据库

向量数据库(Vector Database)是专门用来存储和检索向量的数据库。

它不只是「把数组存起来」,还需要提供:

  1. 向量存储:保存高维向量、原文和 metadata;
  2. 相似度索引:用 HNSW、IVF、DiskANN 等索引加速最近邻搜索;
  3. 相似度检索:Top-K 查询,支持 COSINE / IP / L2 等度量;
  4. 标量过滤:按 category、tenant_id、时间等字段先过滤再检索;
  5. CRUD:插入、更新、删除、按条件删除;
  6. 持久化与运维:落盘、备份、扩容、监控、多租户。

它和传统数据库的区别:

关系型数据库向量数据库
主要查询精确匹配、范围查询、事务按语义相似度排序
核心索引B+Tree、HashHNSW、IVF、DiskANN
典型问题「id 等于 1 的记录」「和这句话最像的 5 条」
结果精确结果集Top-K 近似结果

它和向量索引库(如 FAISS)的区别:

  • FAISS 更像一个索引库,擅长向量计算;
  • 向量数据库在索引之外,还负责存储、过滤、并发、持久化和集群。

二、为什么需要向量数据库

demo-23 的 MemoryVectorStore 适合开发和演示。一旦进入真实业务,会很快遇到它的边界:

需求MemoryVectorStore向量数据库(如 Milvus)
数据持久化进程退出即丢失落盘、备份、恢复
数据规模受内存限制支持千万 / 亿级向量
检索性能线性扫描ANN 索引,毫秒级
标量过滤手写函数表达式过滤 + 标量索引
并发与多实例单进程多客户端、集群
多租户自己隔离collection / partition
运维无监控、扩缩容、权限

什么时候该上向量数据库:

  • 文档量持续增长,内存放不下;
  • 查询延迟有要求,线性扫描太慢;
  • 需要按用户、租户、类型过滤;
  • 需要持久化、备份和多实例共享;
  • 需要把向量检索接入正式服务。

三、常见向量数据库

产品类型特点
Milvus开源 / 云服务分布式、亿级规模、索引类型丰富
Zilliz Cloud托管 Milvus免运维,兼容 Milvus API
Qdrant开源 / 云服务Rust 实现,过滤能力强,部署轻量
Weaviate开源 / 云服务模块化,支持混合检索
Chroma开源轻量,适合本地开发和原型
pgvectorPostgreSQL 扩展已有 Postgres 时最省事,支持 SQL 过滤
Pinecone全托管免运维,适合快速上线
Redis内存数据库扩展低延迟,适合缓存与实时场景
FAISS向量检索库不是数据库,适合离线实验和自建服务

怎么选:

  • 已经在用 Postgres,数据量中小:先看 pgvector;
  • 想快速做原型:Chroma、MemoryVectorStore;
  • 需要大规模、分布式、丰富索引:Milvus;
  • 想要托管、不想运维:Zilliz Cloud、Pinecone;
  • 需要强过滤和轻量部署:Qdrant。

四、Milvus 核心概念与架构

Milvus 是开源的分布式向量数据库,核心概念如下:

概念说明
Collection类似关系库里的「表」,一组同构向量和字段
PartitionCollection 内的逻辑分区,常按租户 / 时间划分
Schema字段定义:主键、向量字段、标量字段
Primary Key每行的唯一 ID,可以 autoId 或手动指定
Vector Field向量字段,必须指定维度和数据类型
Scalar Field普通字段,用于过滤、展示和排序
Index向量索引,如 HNSW、IVF_FLAT、IVF_SQ8、DiskANN
Metric相似度度量:COSINE、IP、L2
Search Params检索参数,如 HNSW 的 ef
Load / Release检索前需要把 collection 加载到内存

4.1 两种部署形态

Standalone

单机进程,依赖 etcd 和 MinIO,适合开发、测试、中小规模。

Milvus Standalone
  ├── etcd      元数据
  └── MinIO     对象存储

Distributed

Proxy、Coordinator、Query Node、Data Node、Index Node 等组件,适合大规模、高并发、生产环境。

Proxy -> Coordinator -> Query / Data / Index Nodes
                         ├── etcd
                         └── 对象存储

本 demo 用 Standalone,通过 Docker Compose 启动。

4.2 一次检索发生了什么

查询文本
   ↓ Embedding
查询向量
   ↓
Milvus 在 Collection 的向量索引中做 ANN 搜索
   ↓
可选:标量过滤(category == "milvus")
   ↓
返回 Top-K 向量 + 原文 + metadata

五、环境准备

5.1 启动 Milvus

demo-24 提供了一份 docker-compose.yml,包含 etcd、MinIO 和 Milvus Standalone:

bash
cd demo-24
docker compose up -d
docker compose ps

端口说明:

端口用途
19530Milvus gRPC
9091Milvus 健康检查
9000MinIO
9001MinIO 控制台

检查是否启动:

bash
nc -z localhost 19530

看到 succeeded 或端口可连接后,再运行 demo。

如果使用 Zilliz Cloud,把 MILVUS_ADDRESS 设为云端地址(通常带 :443),并配置 MILVUS_TOKEN。云端 collection 和索引的创建方式一致。

5.2 安装依赖

bash
npm install @langchain/community @zilliz/milvus2-sdk-node
  • @langchain/community/vectorstores/milvus:LangChain 的 Milvus 适配;
  • @zilliz/milvus2-sdk-node:Milvus 官方 Node.js SDK。

5.3 环境变量

bash
MILVUS_ADDRESS=localhost:19530
MILVUS_TOKEN=                 # 本地 Milvus 留空
MILVUS_COLLECTION=demo24_documents

Embedding 配置复用 demo-23:

  • API_KEY;
  • EMBEDDING_BASE_URL;
  • EMBEDDING_MODEL=qwen3.7-text-embedding。

demo 会优先读取 demo-24/.env,没有则读取 demo-23/.env。

六、用 LangChain 连接 Milvus

6.1 先做健康检查

Milvus 类内部会自己创建客户端。为了尽早发现连接问题,demo 先用官方 SDK 探活:

js
import { MilvusClient } from "@zilliz/milvus2-sdk-node";

const clientConfig = {
  address: "localhost:19530",
  timeout: 5000,
  maxRetries: 1,
  retryDelay: 500,
};

const probe = new MilvusClient(clientConfig);
await probe.connectPromise;

const health = await probe.checkHealth();
if (!health.isHealthy) {
  throw new Error("Milvus 健康检查未通过");
}

const exists = await probe.hasCollection({
  collection_name: "demo24_documents",
});
if (exists.value) {
  await probe.dropCollection({ collection_name: "demo24_documents" });
}

await probe.closeConnection();

删除旧 collection 是为了让 demo 可重复运行,避免 schema 或数据残留导致冲突。

6.2 创建 VectorStore

js
import { Milvus } from "@langchain/community/vectorstores/milvus";

const vectorStore = await Milvus.fromDocuments(documents, embeddings, {
  collectionName: "demo24_documents",
  clientConfig,
  autoId: true,
  indexCreateOptions: {
    index_type: "HNSW",
    metric_type: "COSINE",
    params: {
      M: 16,
      efConstruction: 200,
    },
    search_params: {
      ef: 64,
    },
  },
});

fromDocuments 会自动完成:

  1. 创建 collection;
  2. 根据 metadata 创建标量字段;
  3. 创建向量字段;
  4. 创建 HNSW 索引;
  5. 写入文档和向量。

注意配置项名字是 indexCreateOptions,不是 indexConfig。

6.3 文档和 metadata

js
import { Document } from "@langchain/core/documents";

const documents = [
  new Document({
    pageContent: "Milvus 是一个开源的分布式向量数据库……",
    metadata: {
      source: "vector-db.md",
      category: "milvus",
      lang: "zh",
    },
  }),
  // ...
];

Milvus 适配器会把 metadata 的每个 key 变成标量字段,所以:

  • 所有文档的 metadata key 和类型必须一致;
  • 过滤字段要有明确的类型;
  • 不要把大对象塞进 metadata;
  • 向量字段由适配器管理,不需要手动写进 metadata。

七、写入、建索引与检索

7.1 写入结果

demo 写入 6 条文档,每条 1024 维向量。写入后可以查看 collection 的字段和统计:

js
const description = await vectorStore.client.describeCollection({
  collection_name: "demo24_documents",
});

console.log(description.schema.fields.map((field) => field.name));

const stats = await vectorStore.client.getCollectionStatistics({
  collection_name: "demo24_documents",
});

console.log(stats.data);

预期字段包括:

pk, text, vector, source, category, lang
  • pk:主键,autoId;
  • text:原文;
  • vector:1024 维向量;
  • source、category、lang:标量字段。

7.2 相似度检索

js
const query = "Milvus 支持哪些索引类型?";

const results = await vectorStore.similaritySearchWithScore(query, 3);

for (const [doc, score] of results) {
  console.log(score, doc.metadata.category, doc.pageContent);
}

结果按相似度排序,score 来自 Milvus。使用 COSINE 时,分数越高越相似。

7.3 带标量过滤的检索

js
const results = await vectorStore.similaritySearchWithScore(
  "向量数据库有哪些索引?",
  5,
  'category == "milvus"'
);

过滤表达式使用 Milvus 的标量过滤语法:

  • category == "milvus";
  • lang == "zh";
  • rating >= 4;
  • category in ["milvus", "qdrant"];
  • 组合:category == "milvus" && lang == "zh"。

先过滤再检索,可以显著减少候选集,也能满足多租户隔离。

7.4 按条件删除

js
await vectorStore.delete({
  filter: 'category == "qdrant"',
});

删除后再查一次,qdrant 分类的文档就不会出现在结果里。

7.5 Collection 管理

js
// 统计
await vectorStore.client.getCollectionStatistics({
  collection_name: "demo24_documents",
});

// 删除整个 collection
await vectorStore.client.dropCollection({
  collection_name: "demo24_documents",
});

// 关闭连接
await vectorStore.client.closeConnection();

八、Milvus 索引与参数怎么选

8.1 常见索引

索引特点适用场景
FLAT暴力扫描,100% 召回小数据、评估基线
IVF_FLAT倒排聚类,速度与精度平衡中大规摸
IVF_SQ8量化压缩,省内存内存受限
HNSW图索引,查询快、召回好在线检索默认选择
DiskANN基于磁盘,超大规摸内存放不下时

本 demo 使用 HNSW,参数:

js
{
  M: 16,              // 每个节点的邻居数
  efConstruction: 200 // 建索引时的候选队列大小
}

检索参数:

js
{ ef: 64 } // 查询时的候选队列大小,越大越准但越慢

8.2 Metric 怎么选

Metric含义适用场景
COSINE余弦相似度文本 embedding,最常用
IP内积向量已归一化时与 COSINE 等价
L2欧氏距离图像、未归一化向量

文本向量一般用 COSINE。如果 embedding 模型输出已经归一化,IP 和 COSINE 的排序结果基本一致。

8.3 参数调优顺序

  1. 先用 HNSW + COSINE 做 baseline;
  2. 用真实问题集测 Recall@K 和延迟;
  3. 再调整 M、efConstruction、ef;
  4. 数据量继续增长时,再考虑 IVF、DiskANN 或分区。

不要一开始就追求复杂索引,baseline 往往已经够用。

九、生产实践

9.1 Schema 设计

  • 主键、向量维度、标量字段要提前规划;
  • 过滤字段建标量索引;
  • 多租户可以用 partition 或 tenant_id 字段隔离;
  • 文本字段长度要留足,但不要盲目设成超大值。

9.2 写入与更新

  • 批量写入,控制单批大小;
  • 更新通常用 upsert 或先删后插;
  • 删除要同步清理原始文档和缓存;
  • 记录写入失败和重试,避免数据不一致。

9.3 运维

  • 监控 QPS、延迟、内存、磁盘和索引构建时间;
  • 定期备份 etcd、MinIO 和 collection;
  • 生产环境用分布式部署或 Zilliz Cloud;
  • 升级 Milvus 前先在测试环境验证兼容性。

9.4 和 RAG 的配合

  • Embedding 模型和向量维度必须与索引一致;
  • 换模型后要重建索引;
  • 检索结果还要经过 rerank、上下文压缩和提示词约束;
  • 过滤条件要和权限系统保持一致。

十、Python 对应写法

Python 侧可以使用 langchain-milvus:

bash
pip install langchain-milvus pymilvus
python
from langchain_milvus import Milvus

vector_store = Milvus.from_documents(
    documents,
    embedding=embedding,
    collection_name="demo24_documents",
    connection_args={"uri": "http://localhost:19530"},
    index_params={
        "index_type": "HNSW",
        "metric_type": "COSINE",
        "params": {"M": 16, "efConstruction": 200},
    },
    search_params={"ef": 64},
    drop_old=True,
)

results = vector_store.similarity_search_with_score(
    "Milvus 支持哪些索引类型?",
    k=3,
    expr='category == "milvus"',
)

for doc, score in results:
    print(score, doc.metadata["category"], doc.page_content)

也可以直接用 pymilvus:

python
from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")
print(client.list_collections())
print(client.get_collection_stats("demo24_documents"))

十一、小结

  • 向量数据库:存储向量,并提供 ANN 索引、相似度检索、标量过滤和 CRUD。
  • 为什么需要:持久化、规模、性能、过滤、并发、多租户和运维。
  • 常见选择:Milvus、Qdrant、Weaviate、Chroma、pgvector、Pinecone、FAISS。
  • Milvus 核心:Collection、Partition、Schema、Vector Field、Index、Metric。
  • 使用流程:连接 → 创建 collection / 索引 → 写入向量 → 相似度检索 → 过滤 / 删除。
  • LangChain 接入:
    • Milvus.fromDocuments(documents, embeddings, config);
    • similaritySearchWithScore(query, k, filter)。
  • 生产注意:索引选型、metric、schema、批量写入、监控、备份和模型版本。

一句话:MemoryVectorStore 适合理解原理,Milvus 负责把向量检索做成可持久化、可扩展的服务。

评论
0/100