🧮 向量数据库选型

LanceDB · ChromaDB · Pinecone · Weaviate · Qdrant · Milvus · pgvector · Vald
从嵌入式到云原生,选对向量数据库是 RAG 和 Agent 系统的地基

目录 01 为什么需要向量数据库? 02 向量搜索基础:Embedding、索引与距离度量 03 LanceDB — 嵌入式 Rust 向量数据库 04 ChromaDB — AI 原生的 Python 向量数据库 05 Pinecone — 全托管云向量数据库 06 Weaviate — 多模态知识图谱向量库 07 Qdrant — 高性能 Rust 向量搜索引擎 08 Milvus — 云原生分布式向量数据库 09 PostgreSQL + pgvector — 不加新组件的向量搜索 10 全面对比表 11 决策框架:我该选什么? 12 实战代码示例 13 进阶主题:混合搜索、多租户、过滤 14 与 Agent 研究的关联 15 关联模块

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

传统数据库用精确匹配和关键词搜索——你搜 "apple",它只返回包含 "apple" 的行。但语言不是这样工作的:

🔤 传统搜索的问题
  • 语义鸿沟:"手机" 和 "智能手机" 是同一概念,关键词搜不到
  • 同义词丢失:"便宜" vs "实惠" vs "高性价比",全靠同义词表
  • 跨语言不可用:中文文档搜英文查询,直接挂
  • 模糊查询不行:"类似这种风格的图片" 无法表达
🧮 向量搜索的解法
  • 语义匹配:用 Embedding 把文本映射到高维空间,近邻即语义相似
  • 自动同义词:训练好的模型天然理解 "便宜≈实惠"
  • 跨语言:多语言模型让中英文在同一空间可比
  • 多模态:文本、图片、音频统一嵌入同一向量空间
核心公式:把任何数据(文本/图片/音频)→ Embedding 模型 → 高维向量 (如 1536 维) → 向量数据库存储 + ANN 索引 → 查询时计算相似度 → 返回 Top-K 最相似结果。

什么时候 不需要 向量数据库?

02 向量搜索基础:Embedding、索引与距离度量

Embedding:数据的数字指纹

Embedding 模型将非结构化数据转化为固定维度的浮点向量。常见模型:

模型维度MTEB 排名特点
OpenAI text-embedding-3-large3072⭐⭐⭐⭐质量高、成本高、可降维
OpenAI text-embedding-3-small1536⭐⭐⭐性价比最佳
Cohere embed-v31024⭐⭐⭐⭐多语言优、支持搜索类型参数
BGE-M3 (BAAI)1024⭐⭐⭐⭐开源最强、多语言、多粒度
Nomic Embed768⭐⭐⭐开源、8192 上下文、小模型
all-MiniLM-L6-v2384⭐⭐极速、离线可用、质量一般

距离度量

Cosine Similarity(余弦相似度)

最常用。衡量方向相似性,忽略向量长度。范围 [-1, 1]。

cos(A, B) = (A · B) / (||A|| × ||B||)

✅ 归一化后等价于内积,计算快

✅ 对向量尺度不敏感,最通用

Euclidean Distance(欧几里得距离)

直线距离。对向量长度敏感。

L2(A, B) = sqrt(Σ(Ai - Bi)²)

⚠️ 归一化向量上等价于余弦

❌ 非归一化向量上,长度差异会干扰

实践建议:大多数场景用余弦相似度。如果 Embedding 模型已做归一化(OpenAI 的就是),内积 = 余弦,直接用 dot product 更快。

ANN 索引:速度的魔法

精确 KNN 搜索是 O(n),百万级以上不可接受。ANN (Approximate Nearest Neighbor) 用索引换取速度:

索引类型原理查询延迟召回率构建速度适用场景
HNSW多层跳表图~1ms99%+中等通用首选
IVF倒排聚类~5ms95%+超大规模
IVF-PQ聚类+量化~10ms90%+内存受限
Flat暴力搜索100%即开即用<10万条
DiskANN磁盘驻留图~5ms95%+超大规模+内存不够
2026 默认选择:HNSW。几乎所有向量数据库都支持,在百万级数据上 1ms 级延迟、99%+ 召回率。只有在 10 亿+ 级别才需要考虑 IVF + 量化。

03 LanceDB — 嵌入式 Rust 向量数据库

Rust 开源 嵌入式 Serverless

LanceDB 是一个基于 Lance 列式格式的嵌入式向量数据库,用 Rust 编写。它不运行服务器——你的应用直接读写磁盘上的文件。类似于 SQLite 之于传统数据库,LanceDB 是向量数据库的 "SQLite"。

核心架构

┌──────────────────────────────────────────┐ │ 你的应用 (Python/JS/RS) │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ LanceDB 引擎 │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ IVF-PQ │ │ HNSW │ │ Flat │ │ │ │ │ └────────┘ └────────┘ └────────┘ │ │ │ │ ↓ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ Lance 列式格式 (.lance) │ │ │ │ │ │ · 向量 + 元数据共存 │ │ │ │ │ │ · 零拷贝读取 │ │ │ │ │ │ · 版本化 (时间旅行) │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────────┘ │ │ ↓ 文件系统 / S3 / GCS / Azure │ └──────────────────────────────────────────┘

优势

劣势

代码示例

# pip install lancedb
import lancedb
import numpy as np

# 连接(本地目录,自动创建)
db = lancedb.connect("./my_lance_db")

# 创建表
data = [
    {"text": "向量数据库是 AI 应用的基础设施", "vector": np.random.rand(768).tolist(), "source": "doc1"},
    {"text": "LanceDB 用 Rust 编写,嵌入式架构", "vector": np.random.rand(768).tolist(), "source": "doc2"},
    {"text": "HNSW 索引在百万级数据上仅需 1ms", "vector": np.random.rand(768).tolist(), "source": "doc3"},
]
table = db.create_table("documents", data)

# 向量搜索
query_vector = np.random.rand(768).tolist()
results = table.search(query_vector).limit(5).to_pandas()
print(results[["text", "source", "_distance"]])

# 创建 IVF-PQ 索引加速(数据量大时)
table.create_index(
    num_partitions=256,   # IVF 聚类数
    num_sub_vectors=96,   # PQ 量化子向量数
)

# 过滤搜索:元数据过滤 + 向量搜索
results = (
    table.search(query_vector)
    .where("source = 'doc1'", prefilter=True)
    .limit(5)
    .to_pandas()
)

# 时间旅行:查看上一版本的数据
old_version = db.open_table("documents", version=0)
print(f"当前版本: {table.version}, 旧版本: 0")

# S3 远程存储
db_remote = lancedb.connect("s3://my-bucket/lancedb")

何时选 LanceDB

04 ChromaDB — AI 原生的 Python 向量数据库

Python 开源 嵌入式 CS 架构

ChromaDB(简称 Chroma)是为 AI 应用设计的开源向量数据库,最大特点是 内置 Embedding 函数——你不需要自己调 OpenAI API 做向量化,Chroma 自动帮你做。它是 LangChain 生态最紧密集成的向量数据库。

核心特性

优势

劣势

代码示例

# pip install chromadb
import chromadb

# 嵌入式模式(数据持久化到磁盘)
client = chromadb.PersistentClient(path="./chroma_db")

# 创建 Collection(自动使用默认 Embedding 函数)
collection = client.get_or_create_collection(
    name="knowledge_base",
    metadata={"hnsw:space": "cosine"}  # 距离度量
)

# 添加文档——Chroma 自动做 Embedding!
collection.add(
    documents=[
        "向量数据库是 AI 时代的存储基础设施",
        "ChromaDB 让你 3 行代码开始用向量搜索",
        "RAG 系统的核心是检索质量",
    ],
    metadatas=[
        {"source": "intro", "page": 1},
        {"source": "quickstart", "page": 1},
        {"source": "rag-guide", "page": 3},
    ],
    ids=["doc1", "doc2", "doc3"]
)

# 语义搜索——直接传文本,Chroma 自动 Embedding
results = collection.query(
    query_texts=["什么是向量数据库?"],
    n_results=3,
    where={"source": "intro"},  # 元数据过滤
)
print(results["documents"])

# 也可以手动传向量(用自己的 Embedding 模型)
import openai
resp = openai.embeddings.create(
    model="text-embedding-3-small",
    input="什么是向量数据库?"
)
query_vector = resp.data[0].embedding

results = collection.query(
    query_embeddings=[query_vector],
    n_results=3,
)

何时选 ChromaDB

05 Pinecone — 全托管云向量数据库

SaaS 全托管 闭源 免费层

Pinecone 是向量数据库领域的先行者和商业化最成功的案例。你不需要管理任何基础设施——注册账号、创建 Index、开始写入和查询。2024 年推出的 Serverless 模式更是零固定成本起步。

架构特点

优势

劣势

代码示例

# pip install pinecone
from pinecone import Pinecone

pc = Pinecone(api_key="your-api-key")

# 创建 Serverless Index
pc.create_index(
    name="knowledge",
    dimension=1536,
    metric="cosine",
    spec={
        "serverless": {
            "cloud": "aws",
            "region": "us-east-1"
        }
    }
)

index = pc.Index("knowledge")

# 批量 Upsert
index.upsert(
    vectors=[
        {"id": "doc1", "values": [0.1, 0.2, ...], "metadata": {"source": "wiki", "lang": "zh"}},
        {"id": "doc2", "values": [0.3, 0.4, ...], "metadata": {"source": "blog", "lang": "en"}},
    ],
    namespace="production"  # 多租户隔离
)

# 查询 + 元数据过滤
results = index.query(
    vector=[0.15, 0.25, ...],
    top_k=10,
    filter={"lang": {"$eq": "zh"}, "source": {"$in": ["wiki", "blog"]}},
    namespace="production",
    include_metadata=True,
)

# 混合搜索(Sparse-Dense Index)
results = index.query(
    vector={"values": [0.15, 0.25, ...], "sparse_values": {"indices": [2, 5, 10], "values": [0.3, 0.5, 0.2]}},
    top_k=10,
    include_metadata=True,
)

定价参考(2026)

模式写入查询存储免费层
Serverless$2.50/1M vectors$0.10/1K queries$0.096/GB/月1 Index, 5GB
Pod (s1)包含在 Pod 费包含在 Pod 费包含在 Pod 费

何时选 Pinecone

06 Weaviate — 多模态知识图谱向量库

Go 开源 CS 架构 多模态

Weaviate 是一个将向量搜索与知识图谱融合的数据库。它最独特的卖点是 Modules 系统——内置多种 Embedding 模型的集成(OpenAI、Cohere、HuggingFace、多模态 CLIP 等),以及 Generative Search(直接在数据库层调用 LLM 做 RAG)。

核心特性

优势

劣势

代码示例

# pip install weaviate-client
import weaviate
import weaviate.classes as wvc

# 连接本地 Weaviate
client = weaviate.connect_to_local()

# 创建 Collection
collection = client.collections.create(
    name="Article",
    properties=[
        wvc.config.Property(name="title", data_type=wvc.config.DataType.TEXT),
        wvc.config.Property(name="content", data_type=wvc.config.DataType.TEXT),
        wvc.config.Property(name="category", data_type=wvc.config.DataType.TEXT),
    ],
    vectorizer_config=wvc.config.Configure.Vectorizer.text2vec_openai(
        model="text-embedding-3-small"
    ),
    # 多租户
    multi_tenancy_config=wvc.config.Configure.multi_tenancy(enabled=True),
)

# 插入数据(自动向量化)
collection.with_tenant("tenant_A").data.insert({
    "title": "向量数据库入门",
    "content": "向量数据库是 AI 应用的核心基础设施...",
    "category": "tutorial",
})

# 语义搜索
results = collection.with_tenant("tenant_A").query.near_text(
    query="如何选择向量数据库?",
    limit=5,
    filters=wvc.query.Filter.by_property("category").equal("tutorial"),
)

# Generative Search(数据库层 RAG!)
from weaviate.classes.query import MetadataQuery
results = collection.with_tenant("tenant_A").generate.near_text(
    query="总结这些文章的关键要点",
    limit=5,
    grouped_task="请用中文总结以上文章的三个核心观点",
)
print(results.generated)

何时选 Weaviate

07 Qdrant — 高性能 Rust 向量搜索引擎

Rust 开源 CS 架构 WAL

Qdrant 是用 Rust 编写的高性能向量搜索引擎。它在内存效率和查询延迟方面表现优异,特别适合需要 复杂过滤 + 向量搜索 的场景——这是很多 SaaS 应用(电商、内容平台)的核心需求。

核心特性

优势

劣势

代码示例

# pip install qdrant-client
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue

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

# 创建 Collection
client.create_collection(
    collection_name="products",
    vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)

# 插入数据
client.upsert(
    collection_name="products",
    points=[
        PointStruct(
            id=1,
            vector=[0.1, 0.2, ...],
            payload={"name": "MacBook Pro", "category": "laptop", "price": 14999}
        ),
        PointStruct(
            id=2,
            vector=[0.3, 0.4, ...],
            payload={"name": "iPhone 18", "category": "phone", "price": 8999}
        ),
    ]
)

# 向量搜索 + 复杂过滤(Qdrant 的杀手锏!)
results = client.search(
    collection_name="products",
    query_vector=[0.15, 0.25, ...],
    query_filter=Filter(
        must=[
            FieldCondition(key="category", match=MatchValue(any=["laptop", "phone"])),
            FieldCondition(key="price", range={"lte": 15000}),
        ]
    ),
    limit=10,
)

# 启用量化节省内存
client.update_collection(
    collection_name="products",
    quantization_config=models.ScalarQuantization(
        scalar=models.ScalarQuantizationConfig(
            type=models.ScalarType.INT8,
            quantile=0.99,
            always_ram=True,
        ),
    ),
)

何时选 Qdrant

08 Milvus — 云原生分布式向量数据库

Go + C++ 开源 分布式 云原生

Milvus 是面向超大规模场景的分布式向量数据库,背靠 Zilliz 公司。当数据量超过 10 亿条、需要多机并行搜索时,Milvus 是最成熟的选择。Zilliz Cloud 提供全托管版本。

架构:存算分离

┌───────────────────────────────────────────────┐ │ Proxy (API 层) │ │ ┌───────┬───────┬───────┐ │ │ │Proxy 1│Proxy 2│Proxy N│ │ │ └───────┴───────┴───────┘ │ │ │ │ │ ┌────────────────────┼────────────────────┐ │ │ │ Coordinator (协调层) │ │ │ │ RootCoord │ QueryCoord │ DataCoord │ │ │ └────────────────────┼────────────────────┘ │ │ │ │ │ ┌────────────────────┼────────────────────┐ │ │ │ Worker (执行层) │ │ │ │ QueryNode (搜索) │ DataNode (写入) │ │ │ │ IndexNode (建索引)│ │ │ │ └────────────────────┼────────────────────┘ │ │ │ │ │ ┌────────────────────┼────────────────────┐ │ │ │ Storage (存储层) │ │ │ │ MinIO / S3 │ etcd (元数据) │ Pulsar/Kafka│ │ │ └─────────────────────────────────────────┘ │ └───────────────────────────────────────────────┘

优势

劣势

代码示例

# pip install pymilvus
from pymilvus import MilvusClient, DataType

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

# 创建 Collection
client.create_collection(
    collection_name="articles",
    dimension=1536,
    metric_type="COSINE",
    auto_id=True,
)

# 也可以用 Schema 定义(支持标量字段 + 向量字段)
from pymilvus import CollectionSchema, FieldSchema, Collection, AnnIndex
schema = CollectionSchema(fields=[
    FieldSchema("id", DataType.INT64, is_primary=True, auto_id=True),
    FieldSchema("title", DataType.VARCHAR, max_length=512),
    FieldSchema("category", DataType.VARCHAR, max_length=64),
    FieldSchema("embedding", DataType.FLOAT_VECTOR, dim=1536),
])
collection = Collection("articles_v2", schema)

# 创建索引
index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="HNSW",
    metric_type="COSINE",
    params={"M": 16, "efConstruction": 256}
)
client.create_index("articles_v2", index_params)

# 插入 + 搜索
data = [
    {"title": "向量数据库选型指南", "category": "tutorial", "embedding": [0.1, 0.2, ...]},
]
client.insert("articles_v2", data)

results = client.search(
    collection_name="articles_v2",
    data=[[0.15, 0.25, ...]],
    limit=10,
    filter='category == "tutorial"',
    output_fields=["title", "category"],
)

何时选 Milvus

09 PostgreSQL + pgvector — 不加新组件的向量搜索

C 开源 PostgreSQL 扩展 SQL

pgvector 是 PostgreSQL 的向量搜索扩展。如果你已经在用 PostgreSQL,它是加入向量搜索 成本最低 的方式——不需要新服务、新运维、新 SDK。

核心特性

优势

劣势

代码示例

-- 安装扩展
CREATE EXTENSION IF NOT EXISTS vector;

-- 创建表
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT,
    source VARCHAR(255),
    embedding vector(1536)
);

-- 插入数据
INSERT INTO documents (content, source, embedding)
VALUES ('向量数据库入门', 'tutorial', '[0.1, 0.2, ...]'::vector);

-- 创建 HNSW 索引
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

-- 向量搜索 + 过滤 + JOIN!
SELECT d.content, d.source, 1 - (d.embedding <=> '[0.15, 0.25, ...]'::vector) AS similarity
FROM documents d
JOIN user_permissions up ON d.source = up.allowed_source
WHERE up.user_id = 42
  AND d.source != 'internal'
ORDER BY d.embedding <=> '[0.15, 0.25, ...]'::vector
LIMIT 10;

-- 设置搜索参数
SET hnsw.ef_search = 100;  -- 越高召回率越好,越慢
# Python (SQLAlchemy)
from pgvector.sqlalchemy import Vector
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class Document(Base):
    __tablename__ = "documents"
    id = Column(Integer, primary_key=True)
    content = Column(String)
    source = Column(String)
    embedding = Column(Vector(1536))

# 查询
from sqlalchemy import select
stmt = (
    select(Document, Document.embedding.cosine_distance(query_vec).label("distance"))
    .order_by(Document.embedding.cosine_distance(query_vec))
    .limit(10)
)
results = session.execute(stmt).all()

何时选 pgvector

10 全面对比表

维度 LanceDB ChromaDB Pinecone Weaviate Qdrant Milvus pgvector
开源 ✅ Apache 2.0 ✅ Apache 2.0 ❌ 闭源 ✅ BSD-3 ✅ Apache 2.0 ✅ Apache 2.0 ✅ PostgreSQL
语言 Rust Python Go Rust Go+C++ C
部署模式 嵌入式 嵌入/CS 全托管 CS/托管 CS/托管 CS/托管 PG 扩展
数据规模 ~千万 ~百万 ~亿 ~亿 ~亿 百亿+ ~五百万
查询延迟 <1ms 1-5ms 20-50ms 5-20ms <1ms 10-50ms 5-20ms
内置 Embedding
混合搜索 ✅ Sparse-Dense ✅ BM25+向量 ❌ (仅过滤) ✅ 全文+向量 ✅ SQL+向量
多租户 ✅ Namespace ✅ 物理隔离 ✅ Payload ✅ Partition ✅ RLS
量化支持 IVF-PQ SQ/PQ/BQ SQ/PQ/GPU
运维复杂度
云托管 ✅ Zilliz ✅ Supabase

11 决策框架:我该选什么?

你需要向量数据库? │ ┌──────────┴──────────┐ │ │ 数据量 < 500万? 数据量 > 500万 │ │ ┌────────┴────────┐ ┌──────┴──────┐ │ │ │ │ 已有 PG? 无 PG / 想独立 │ > 10亿? │ │ │ │ ┌────┴────┐ ┌────┴────┐ │ ┌──────┴──────┐ │ │ │ │ │ │ │ pgvector LanceDB ChromaDB LanceDB │ Milvus Qdrant (最省事) (最快) (最简单) (最快) │ (分布式之王) (高性能) │ ┌──────┴──────┐ │ │ 想全托管? 能自建? │ │ Pinecone Qdrant (零运维) (自建最优)

场景速查

场景推荐理由
个人项目 / MVPLanceDB零部署,嵌入式,3 行代码
Jupyter 实验ChromaDB内置 Embedding,Python 原生
SaaS 产品(已有 PG)pgvector不加新组件,事务一致
SaaS 产品(独立向量服务)Qdrant高性能,过滤强,可自建
全托管 / 无运维能力Pinecone零运维,企业 SLA
多模态搜索Weaviate内置多模态,Generative Search
电商推荐(复杂过滤)QdrantFilterable HNSW 最强
超大规模(10亿+)Milvus分布式架构,水平扩展
Edge / ServerlessLanceDB嵌入式,S3 原生

12 实战代码示例:统一的向量搜索服务

以下是一个生产级的向量搜索服务,抽象了底层引擎,支持运行时切换:

# vector_service.py — 统一向量搜索服务
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import List, Dict, Optional
import numpy as np

@dataclass
class VectorDocument:
    id: str
    text: str
    vector: List[float]
    metadata: Dict

@dataclass
class SearchResult:
    id: str
    text: str
    score: float
    metadata: Dict

class VectorStore(ABC):
    """向量存储抽象层"""
    @abstractmethod
    def upsert(self, docs: List[VectorDocument]) -> int: ...
    @abstractmethod
    def search(self, query_vector: List[float], top_k: int = 10,
               filters: Optional[Dict] = None) -> List[SearchResult]: ...
    @abstractmethod
    def delete(self, ids: List[str]) -> int: ...


class QdrantStore(VectorStore):
    """Qdrant 实现 — 适合生产环境"""
    def __init__(self, collection_name: str, dim: int = 1536):
        from qdrant_client import QdrantClient
        from qdrant_client.models import Distance, VectorParams
        self.client = QdrantClient(host="localhost", port=6333)
        self.collection = collection_name
        # 自动创建 Collection
        try:
            self.client.create_collection(
                collection_name=collection_name,
                vectors_config=VectorParams(size=dim, distance=Distance.COSINE),
            )
        except Exception:
            pass  # Collection 已存在

    def upsert(self, docs: List[VectorDocument]) -> int:
        from qdrant_client.models import PointStruct
        points = [
            PointStruct(id=hash(d.id) % (2**63), vector=d.vector, payload={
                "text": d.text, **d.metadata
            })
            for d in docs
        ]
        self.client.upsert(self.collection, points)
        return len(points)

    def search(self, query_vector, top_k=10, filters=None) -> List[SearchResult]:
        from qdrant_client.models import Filter, FieldCondition, MatchValue
        qdrant_filter = None
        if filters:
            conditions = [
                FieldCondition(key=k, match=MatchValue(value=v))
                for k, v in filters.items()
            ]
            qdrant_filter = Filter(must=conditions)

        results = self.client.search(
            collection_name=self.collection,
            query_vector=query_vector,
            limit=top_k,
            query_filter=qdrant_filter,
        )
        return [
            SearchResult(id=str(r.id), text=r.payload.get("text", ""),
                        score=r.score, metadata=r.payload)
            for r in results
        ]

    def delete(self, ids: List[str]) -> int:
        self.client.delete(
            collection_name=self.collection,
            points_selector=[hash(id_) % (2**63) for id_ in ids],
        )
        return len(ids)


class LanceDBStore(VectorStore):
    """LanceDB 实现 — 适合开发/Edge"""
    def __init__(self, db_path: str = "./vectordb", dim: int = 1536):
        import lancedb
        self.db = lancedb.connect(db_path)
        self.dim = dim

    def upsert(self, docs: List[VectorDocument], table_name: str = "default") -> int:
        import pandas as pd
        df = pd.DataFrame([{
            "id": d.id, "text": d.text, "vector": d.vector, **d.metadata
        } for d in docs])
        try:
            table = self.db.open_table(table_name)
            table.add(df)
        except Exception:
            self.db.create_table(table_name, df)
        return len(docs)

    def search(self, query_vector, top_k=10, filters=None, table_name="default") -> List[SearchResult]:
        table = self.db.open_table(table_name)
        query = table.search(query_vector).limit(top_k)
        if filters:
            for k, v in filters.items():
                query = query.where(f"{k} = '{v}'")
        results = query.to_pandas()
        return [
            SearchResult(id=str(r["id"]), text=r["text"],
                        score=1 - r["_distance"], metadata={})
            for _, r in results.iterrows()
        ]

    def delete(self, ids: List[str], table_name: str = "default") -> int:
        # LanceDB 通过 SQL 删除
        table = self.db.open_table(table_name)
        ids_str = ", ".join(f"'{i}'" for i in ids)
        table.delete(f"id IN ({ids_str})")
        return len(ids)


# 使用示例
def main():
    # 开发环境用 LanceDB
    store = LanceDBStore() if os.getenv("ENV") == "dev" else QdrantStore("production")

    docs = [
        VectorDocument("1", "RAG 系统需要向量数据库", [0.1]*1536, {"source": "tutorial"}),
        VectorDocument("2", "LanceDB 是嵌入式向量数据库", [0.2]*1536, {"source": "docs"}),
    ]
    store.upsert(docs)

    results = store.search([0.15]*1536, top_k=5, filters={"source": "tutorial"})
    for r in results:
        print(f"[{r.score:.3f}] {r.text}")

13 进阶主题:混合搜索、多租户、过滤

混合搜索:关键词 + 语义的强强联合

纯向量搜索擅长语义匹配,但精确关键词(产品名、SKU、缩写)可能丢失。混合搜索是 2026 年的标准做法:

🔗 融合策略
  • Reciprocal Rank Fusion (RRF):最简单、最通用
    score_rrf = Σ 1/(k + rank_i)
    # k=60 是常用值
  • 线性加权score = α·score_vector + (1-α)·score_keyword
  • Cohere Rerank:两阶段检索后再排一遍
🛠️ 实现方式
  • Pinecone:Sparse-Dense Index,原生支持
  • Weaviate:BM25 + 向量,with_hybrid()
  • Milvus:全文索引 + 向量搜索
  • 自建:Meilisearch (关键词) + Qdrant (向量) + RRF 融合

多租户隔离

方案实现隔离级别性能影响
NamespacePinecone逻辑
Tenant Per CollectionWeaviate物理高(租户多时)
Payload FilterQdrant / Milvus逻辑
Partition KeyMilvus物理
RLSpgvector行级
多租户陷阱:逻辑隔离(Payload Filter)在高并发下可能泄漏数据——如果应用层忘记加过滤条件。Weaviate 的物理隔离最安全,但成本高。推荐 Qdrant Payload Filter + 应用层中间件强制注入。

过滤性能:Post-filter vs Pre-filter

14 与 Agent 研究的关联

向量数据库是 Agent 系统的"记忆层"。在 Agent 架构研究 中,多个项目展示了不同的向量存储策略:

🔗 来自 Agent 研究的关键发现

Agent 场景下的向量数据库选型建议

Agent 类型推荐理由
个人助手(本地运行)LanceDB嵌入式、零运维、S3 备份
多用户 Agent SaaSQdrant过滤强、性能好、多租户
研究 Agent(大量文档)Qdrant / Milvus大规模、混合搜索
对话 Agent(短期记忆)pgvector与业务数据同库
嵌入式 Agent(IoT/Edge)LanceDB无服务器、文件直存
📚 紧密关联
🔗 延伸阅读