作者:唐璜Taro | AI 教程系列 | 适合读者:零基础开发者
阅读时间:约 25 分钟
系列:本文为上篇,下篇见 →[ [《向量数据库从入门到生产(下):生产实践与 Agent 集成》](https://blog.csdn.net/weixin_44067347/article/details/161272114))


目录


第一章:什么是向量数据库

1.1 从一个生活场景说起

假设你去图书馆找一本关于"如何做红烧肉"的书:

  • 关系数据库的做法:你去查书名目录,精确匹配"红烧肉"三个字。如果书名是《家常菜烹饪技巧》,哪怕内容 90% 讲红烧肉,你也找不到。
  • 向量数据库的做法:你告诉图书管理员"我想学做红烧肉",管理员理解你的语义,把《家常菜烹饪技巧》《中华料理大全》甚至《酱油的妙用》都推荐给你——因为它们在内容含义上和你的需求接近。

这就是向量数据库的核心能力:基于语义相似度的模糊搜索
在这里插入图片描述

1.2 什么是向量(Embedding)

在计算机的世界里,文字、图片、音频本身不能直接计算"相似度"。我们需要先把它们转换成一组数字,这组数字就叫向量(Vector),转换的过程叫Embedding(嵌入)

举个例子:

"红烧肉" → [0.23, -0.45, 0.87, 0.12, ..., 0.56]   (1536 个数字)
"家常菜" → [0.21, -0.42, 0.85, 0.15, ..., 0.53]   (很接近!)
"量子力学" → [-0.78, 0.33, -0.12, 0.91, ..., -0.44] (差很远)

向量之间的距离(余弦相似度、欧氏距离等)就代表了原始内容的语义相似程度

1.3 向量数据库 vs 关系数据库

维度关系数据库(MySQL/PostgreSQL)向量数据库(Milvus/Chroma)
数据模型二维表(行和列)高维向量 + 标量字段
查询方式SQL 精确匹配(WHERE name = '张三'相似度搜索(“找最像张三的人”)
索引原理B+Tree / HashANN(近似最近邻)算法
典型场景事务处理、CRUD、报表语义搜索、推荐系统、RAG
数据规模百万到亿级记录万到百亿级向量
一致性强一致性(ACID)最终一致性(大部分)
查询结果精确结果集Top-K 近似结果
代表产品MySQL、PostgreSQL、OracleMilvus、Pinecone、Weaviate

关键区别总结

  • 关系数据库回答的是:“这个数据在哪里?”(精确查找)
  • 向量数据库回答的是:“哪些数据和这个最像?”(相似搜索)

1.4 为什么需要向量数据库?

你可能会问:我把所有向量存到 MySQL 里,遍历计算相似度不行吗?

答案是:可以,但很慢

假设你有 100 万个向量,每个 1536 维。每次查询要计算 100 万次余弦相似度,这在实时场景下是不可接受的。

向量数据库通过专用的 ANN 索引(如 HNSW、IVF),把搜索复杂度从 O(n) 降到 O(log n) 甚至更低,让亿级向量的毫秒级搜索成为可能。


第二章:主流向量数据库选型

2.1 全景图

┌─────────────────────────────────────────────────────────────┐
│                     向量数据库生态                           │
├──────────────┬──────────────┬──────────────┬────────────────┤
│   专用向量DB  │  云托管服务   │  传统DB扩展  │  向量计算库     │
├──────────────┼──────────────┼──────────────┼────────────────┤
│  Milvus      │  Pinecone    │  pgvector    │  FAISS (Meta)  │
│  Weaviate    │  Zilliz Cloud│  Redis Stack │  Annoy (Spotify)│
│  Qdrant      │  Supabase    │  Elasticsearch│ ScaNN (Google) │
│  Chroma      │  PlanetScale │  ClickHouse  │  hnswlib       │
└──────────────┴──────────────┴──────────────┴────────────────┘

2.2 主流产品详解

Milvus —— 开源向量数据库的标杆
  • 类型:开源分布式向量数据库
  • 开发语言:Go + C++
  • 部署方式:Docker 单机 / K8s 集群 / Zilliz Cloud 托管
  • 核心优势
    • 支持多种索引(IVF_FLAT、IVF_SQ8、HNSW、DISKANN 等)
    • 支持标量过滤 + 向量搜索混合查询
    • 支持分区、副本、容灾
    • 社区活跃,文档完善
  • 适用场景:中大型生产环境、需要高可用和可扩展性
  • GitHub Stars:30k+
Pinecone —— 最简单的全托管方案
  • 类型:全托管云服务(不开源)
  • 部署方式:纯 SaaS,无需部署
  • 核心优势
    • 零运维,开箱即用
    • 自动扩缩容
    • 与 LangChain 深度集成
  • 适用场景:快速原型、不想运维的团队
  • 缺点:数据必须上云,成本随数据量增长
Weaviate —— 内置向量化能力
  • 类型:开源向量数据库
  • 开发语言:Go
  • 核心优势
    • 内置 vectorizer(可直接传文本,自动 embedding)
    • 支持多模态(文本、图片)
    • GraphQL API
  • 适用场景:需要端到端向量化流程的项目
Qdrant —— Rust 编写的高性能方案
  • 类型:开源向量数据库
  • 开发语言:Rust
  • 核心优势
    • 性能极高(Rust 的优势)
    • 支持丰富的过滤条件
    • 支持 payload(附加元数据)
    • 提供云服务
  • 适用场景:对性能要求极高的场景
Chroma —— 最适合入门和原型开发
  • 类型:开源轻量级向量数据库
  • 开发语言:Python
  • 核心优势
    • 极简 API,几行代码搞定
    • 内嵌模式,无需独立部署
    • 与 LangChain、LlamaIndex 无缝集成
  • 适用场景:本地开发、快速原型、小规模应用
  • 缺点:不适合大规模生产环境
pgvector —— PostgreSQL 的向量扩展
  • 类型:PostgreSQL 扩展插件
  • 核心优势
    • 如果你已经在用 PostgreSQL,零额外基础设施
    • 向量搜索 + SQL 查询一体化
    • 支持 IVFFlat、HNSW 索引
  • 适用场景:已有 PG 基础设施、数据量中等(百万级以内)
FAISS —— Meta 的向量检索库
  • 类型:向量检索库(不是数据库)
  • 开发语言:C++(Python 绑定)
  • 核心优势
    • 极致性能,支持 GPU 加速
    • 索引类型最丰富
    • 适合研究和自定义场景
  • 缺点:没有持久化、没有分布式、需要自己封装

2.3 选型对比表

产品部署方式语言最适合场景学习成本社区活跃度生产就绪
MilvusDocker/K8s/云Go+C++中大型生产⭐⭐⭐⭐⭐
Pinecone纯 SaaS-快速上线⭐⭐⭐⭐
WeaviateDocker/云Go多模态场景⭐⭐⭐⭐
QdrantDocker/云Rust高性能需求⭐⭐⭐⭐
Chroma内嵌/DockerPython开发原型极低⭐⭐⭐⚠️ 小规模
pgvectorPG 扩展C已有 PG 基础设施⭐⭐⭐⭐
FAISS库引用C++研究/自定义⭐⭐⭐⭐⭐需封装

2.4 选型决策树

你的场景是什么?
│
├── 快速原型/学习/本地开发
│   └── → Chroma(最简单)或 FAISS(性能好)
│
├── 已有 PostgreSQL
│   └── → pgvector(零额外成本)
│
├── 不想运维,只要结果
│   └── → Pinecone(全托管)
│
├── 中大型生产环境
│   ├── 需要分布式 → Milvus
│   ├── 需要极致性能 → Qdrant
│   └── 需要多模态 → Weaviate
│
└── 超大规模(亿级+)
    └── → Milvus Cluster 或 Zilliz Cloud

第三章:快速上手(Chroma)

Chroma 是最适合入门的向量数据库,不需要任何部署,pip install 就能用。

3.1 安装

pip install chromadb

3.2 基本用法

import chromadb

# 1. 创建客户端(内存模式,数据不持久化)
client = chromadb.Client()

# 2. 创建一个集合(类似关系数据库的"表")
collection = client.create_collection(name="my_docs")

# 3. 添加文档
# Chroma 会自动帮你做 embedding(默认用 all-MiniLM-L6-v2)
collection.add(
    documents=[
        "红烧肉是一道经典的中国家常菜",
        "量子力学是物理学的一个分支",
        "番茄炒蛋是最简单的家常菜",
        "相对论由爱因斯坦提出",
    ],
    ids=["doc1", "doc2", "doc3", "doc4"],
    metadatas=[
        {"category": "cooking"},
        {"category": "physics"},
        {"category": "cooking"},
        {"category": "physics"},
    ]
)

# 4. 查询——找和"家常菜"最相似的文档
results = collection.query(
    query_texts=["怎么做家常菜"],
    n_results=2  # 返回最相似的 2 个
)

print(results)
# 输出:
# {
#   'documents': [['番茄炒蛋是最简单的家常菜', '红烧肉是一道经典的中国家常菜']],
#   'distances': [[0.35, 0.52]],
#   'metadatas': [[{'category': 'cooking'}, {'category': 'cooking'}]]
# }

3.3 持久化存储

# 数据保存到磁盘
client = chromadb.PersistentClient(path="./chroma_db")

# 下次启动时自动加载已有数据
collection = client.get_collection(name="my_docs")

3.4 带过滤条件的查询

# 只在 cooking 类别中搜索
results = collection.query(
    query_texts=["好吃的菜"],
    n_results=2,
    where={"category": "cooking"}  # 标量过滤
)

3.5 手动指定向量

如果你已经有 embedding(比如用 OpenAI 生成的),可以直接传入:

# 手动传入向量
collection.add(
    embeddings=[[0.1, 0.2, 0.3, ...], [0.4, 0.5, 0.6, ...]],
    documents=["文档1", "文档2"],
    ids=["id1", "id2"]
)

# 查询时也传入向量
results = collection.query(
    query_embeddings=[[0.1, 0.2, 0.3, ...]],
    n_results=2
)

第四章:进阶用法(Milvus)

当你需要生产级别的向量数据库时,Milvus 是最主流的选择。

4.1 Docker 部署

# 拉取并启动 Milvus 单机版(Standalone)
docker compose -f milvus-standalone-docker-compose.yml up -d

milvus-standalone-docker-compose.yml 文件内容:

version: '3.5'

services:
  etcd:
    image: quay.io/coreos/etcd:v3.5.5
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
    volumes:
      - etcd_data:/etcd
    command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd

  minio:
    image: minio/minio:RELEASE.2023-03-20T20-16-18Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    volumes:
      - minio_data:/minio_data
    command: minio server /minio_data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  standalone:
    image: milvusdb/milvus:v2.4.0
    command: ["milvus", "run", "standalone"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    volumes:
      - milvus_data:/var/lib/milvus
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
      interval: 30s
      start_period: 90s
      timeout: 20s
      retries: 3
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - "etcd"
      - "minio"

volumes:
  etcd_data:
  minio_data:
  milvus_data:

启动后访问 http://localhost:9091/healthz 确认服务正常。

4.2 Python SDK 基本用法

pip install pymilvus
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType, utility

# 1. 连接 Milvus
connections.connect("default", host="localhost", port="19530")

# 2. 定义 Schema
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
    FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=512),
    FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=64),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536),
]
schema = CollectionSchema(fields, description="文档向量集合")

# 3. 创建 Collection
collection = Collection("documents", schema)

# 4. 创建索引(HNSW 索引,适合高召回率场景)
index_params = {
    "metric_type": "COSINE",   # 余弦相似度
    "index_type": "HNSW",
    "params": {
        "M": 16,              # 每个节点的最大连接数
        "efConstruction": 200  # 构建时的搜索宽度
    }
}
collection.create_index("embedding", index_params)

# 5. 插入数据
import random

data = [
    ["红烧肉的做法", "番茄炒蛋的做法", "量子力学入门", "相对论简述"],
    ["cooking", "cooking", "physics", "physics"],
    [[random.random() for _ in range(1536)] for _ in range(4)]  # 模拟向量
]
collection.insert(data)
collection.flush()

# 6. 加载到内存(查询前必须)
collection.load()

# 7. 向量搜索
search_params = {"metric_type": "COSINE", "params": {"ef": 100}}

# 用一个模拟查询向量
query_vector = [[random.random() for _ in range(1536)]]

results = collection.search(
    data=query_vector,
    anns_field="embedding",
    param=search_params,
    limit=3,
    output_fields=["title", "category"]  # 返回附加字段
)

for hits in results:
    for hit in hits:
        print(f"ID: {hit.id}, Score: {hit.score:.4f}, Title: {hit.entity.get('title')}")

4.3 带标量过滤的向量搜索

# 只搜索 cooking 类别的文档
results = collection.search(
    data=query_vector,
    anns_field="embedding",
    param=search_params,
    limit=3,
    expr='category == "cooking"',  # 标量过滤表达式
    output_fields=["title", "category"]
)

4.4 常用索引类型对比

索引类型原理构建速度查询速度召回率内存占用适用场景
FLAT暴力搜索最快最慢100%最高小数据集(<10万)
IVF_FLAT倒排索引 + 暴力中等数据集
IVF_SQ8倒排 + 标量量化内存受限
HNSW图索引最快很高高召回率场景
DISKANN磁盘图索引超大数据集

选型建议

  • 数据量 < 10 万:用 FLAT(暴力搜索就够)
  • 需要高召回率:用 HNSW
  • 内存紧张:用 IVF_SQ8
  • 数据量超大(亿级+):用 DISKANN

第五章:如何部署

5.1 本地开发(零部署)

Chroma(内嵌模式)

import chromadb
client = chromadb.PersistentClient(path="./my_db")
# 完毕,不需要任何服务器

FAISS(纯库)

import faiss
import numpy as np

d = 128       # 向量维度
nb = 100000   # 数据量

index = faiss.IndexFlatL2(d)         # L2 距离的暴力索引
vectors = np.random.random((nb, d)).astype('float32')
index.add(vectors)                    # 插入向量

# 保存到磁盘
faiss.write_index(index, "my_index.faiss")

# 加载
index = faiss.read_index("my_index.faiss")

# 搜索
query = np.random.random((1, d)).astype('float32')
D, I = index.search(query, k=5)  # 返回距离和索引
print(f"最近的 5 个向量索引: {I[0]}")

5.2 Docker 单机部署

Milvus Standalone(见第四章 4.1)

Qdrant

docker run -p 6333:6333 -p 6334:6334 \
    -v $(pwd)/qdrant_storage:/qdrant/storage \
    qdrant/qdrant

Weaviate

docker run -p 8080:8080 \
    -e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true \
    -e PERSISTENCE_DATA_PATH=/var/lib/weaviate \
    semitechnologies/weaviate:latest

5.3 集群部署(Milvus)

生产环境推荐使用 Milvus Operator 部署到 Kubernetes:

# 1. 安装 Milvus Operator
kubectl apply -f https://raw.githubusercontent.com/milvus-io/milvus-operator/main/deploy/manifests/deployment.yaml

# 2. 创建 Milvus Cluster
cat <<EOF | kubectl apply -f -
apiVersion: milvus.io/v1beta1
kind: Milvus
metadata:
  name: my-milvus
spec:
  mode: cluster
  components:
    proxy:
      serviceType: LoadBalancer
  config:
    common:
      storageType: minio
  dependencies:
    etcd:
      inCluster:
        deletionPolicy: Delete
        pvcDeletion: true
    storage:
      inCluster:
        deletionPolicy: Delete
        pvcDeletion: true
    pulsar:
      inCluster:
        deletionPolicy: Delete
        pvcDeletion: true
EOF

5.4 全托管云服务

如果不想自己运维,可以选择:

服务提供方特点
Zilliz CloudMilvus 官方和 Milvus 完全兼容,全球多区域
PineconePinecone Inc.最简单的 SaaS,免费额度
SupabaseSupabasePG + pgvector,开发者友好
Weaviate CloudWeaviate托管 Weaviate

下篇预告

到这里,我们已经搞定了向量数据库的基础认知、产品选型、代码上手和部署方案。你已经能在本地跑通一个完整的向量搜索 demo 了。

但"能跑"和"能用在生产环境"之间,还隔着一道不小的鸿沟:

  • 索引参数怎么调才能兼顾速度和准确率?
  • 100 万条 1536 维的向量,服务器内存到底要多大?
  • 数据怎么备份?挂了怎么办?
  • 怎么和 LangChain Agent 配合,搭建一个真正的 RAG 问答系统?

这些问题,我们留到下篇一一解决。


本文为系列上篇,完整系列:

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐