开发
悠悠
2026年5月24日

别再问我向量数据库是啥了,看完这篇你就全明白了

最近一两年,只要跟AI沾边的东西都火得一塌糊涂,什么大模型、RAG、Agent,天天刷屏。但有一个东西,很多人天天在用,却说不清楚它到底是个啥——向量数据库。

我自己第一次接触向量数据库的时候也是一脸懵,心想这不就是个数据库吗,跟MySQL有啥区别?后来真正在项目里用上了,才发现这玩意儿跟传统数据库完全是两个物种。今天我就把自己踩过的坑、理解的过程、还有生产环境里的一些实践经验,一股脑全倒出来,希望能帮你们少走点弯路。

先搞明白一个前提:什么是向量

聊向量数据库之前,得先搞清楚"向量"这个词。不然你连它存的是啥都不知道,更别提怎么用了。

image-20260524220333642

向量这东西说白了就是一组数字。比如 [0.12, -0.34, 0.56, 0.78, ...],就这么简单。但别小看这组数字,它可以用来表示任何东西——一段文字、一张图片、一段音频、甚至一个用户的行为特征。

举个最接地气的例子。你把"苹果"这个词丢给一个embedding模型(比如OpenAI的text-embedding-ada-002),它会吐出来一个1536维的向量,大概长这样:[0.0023, -0.0145, 0.0876, ...],一共1536个浮点数。这1536个数字就是"苹果"这个概念在数学空间里的"坐标"。

你可能会问,这有啥用?妙就妙在这里——语义相近的词,它们在向量空间里的距离也近。"苹果"和"水果"的向量距离,肯定比"苹果"和"汽车"的向量距离要近得多。这就叫语义相似性。

再想象一下,如果你把公司里所有的文档、知识库、FAQ全都转成向量,然后当用户提问的时候,把问题也转成向量,在所有文档向量里找最近的那些——这不就是语义搜索吗?这比关键词搜索强太多了,用户问"怎么重置密码",你能匹配到"忘记密码怎么办",关键词搜索可做不到这个。

那向量数据库到底是干嘛的

理解了向量是什么,向量数据库就好理解了。它就是专门用来存这些向量,并且能快速做"相似性搜索"的数据库。

传统数据库比如MySQL,你查数据基本就是精确匹配或者范围查询。SELECT * FROM users WHERE age > 18 AND city = '北京',这种查询是确定性的,条件写死了,结果也是确定的。

但向量数据库不一样,它的核心操作是:给我一个向量,找出跟它最相似的K个向量。这叫ANN查询,全称是Approximate Nearest Neighbor,近似最近邻搜索。注意那个"Approximate",是近似的,不是精确的。为了速度,向量数据库牺牲了一点点精度,换来了数量级的性能提升。

我之前在项目里做过一个测试,200万条768维的向量,用暴力搜索(也就是逐个比较),一次查询要好几秒。换成Milvus的IVF_FLAT索引,查询时间降到毫秒级。这个差距,在生产环境里就是可用和不可用的区别。

向量数据库的核心概念

这个部分可能有点枯燥,但我尽量用大白话讲。你要是用向量数据库,这几个概念绕不过去。

Collection / 表

跟MySQL里的表差不多,一个Collection就是存一类向量的容器。比如你有一个"产品描述"的Collection,一个"用户画像"的Collection。

向量字段 + 标量字段

这是向量数据库跟传统数据库一个很大的区别。一条记录里,既有向量字段(用来做相似性搜索),也有标量字段(就是普通的字符串、数字、布尔值,用来做过滤)。比如一条记录可能是这样的:

{
  "id": "doc_001",
  "content": "我们的产品支持7天无理由退货",
  "vector": [0.12, -0.34, 0.56, ...],  // 768维
  "category": "售后政策",
  "department": "客服部",
  "created_at": "2024-01-15"
}

vector字段用来做语义搜索,category、department这些标量字段用来做过滤。这就是所谓的"混合搜索",后面会细讲。

索引类型

这个是向量数据库最核心也最容易踩坑的地方。不同的索引类型,在查询速度、召回率、内存占用之间做不同的权衡。

image-20260524220433430

常见的几种:

FLAT:暴力搜索,逐个比较。最准,但最慢。数据量小的时候(几万条以内)可以用,数据量大了就别想了。

IVF_FLAT:先把所有向量聚成N个簇(用K-Means),查询的时候只在最近的几个簇里搜索。速度比FLAT快很多,召回率会有点损失,但可以通过调节nprobe参数来平衡。我生产环境里200万条数据用的就是这个,nprobe设的16,召回率大概95%左右,够用了。

IVF_PQ:在IVF的基础上加了Product Quantization(乘积量化),把向量压缩存储。内存占用大幅降低,但召回率也会进一步下降。数据量特别大、内存又不够的时候可以考虑。

HNSW:基于图结构的索引,目前综合性能最好的之一。查询速度极快,召回率也很高,但构建索引慢,内存占用大。如果你对查询延迟要求特别高,HNSW是首选。Pinecone底层就是用的类似HNSW的算法。

DiskANN:微软开源的方案,把索引放在磁盘上,内存只放一部分。适合超大规模数据集(上亿级别),但查询延迟会比纯内存方案高一些。

怎么选?我给个简单的建议:数据量10万以内用FLAT就行;10万到500万用IVF_FLAT或HNSW;500万以上考虑IVF_PQ或DiskANN。当然这只是粗略的参考,具体还得看你的硬件资源和性能要求。

距离度量

image-20260524220528311

计算两个向量之间的相似度,常用的有三种:

L2距离(欧氏距离):两个向量在空间中的直线距离。值越小越相似。

内积(IP, Inner Product):两个向量的点积。值越大越相似。如果你用的embedding模型输出的向量是归一化的(模长为1),那内积就等于余弦相似度。

余弦相似度:两个向量夹角的余弦值。范围[-1, 1],值越大越相似。这是NLP领域最常用的度量方式。

这里有个坑要注意:你在选距离度量的时候,一定要跟你embedding模型训练时用的度量方式一致。比如OpenAI的embedding模型用的是余弦相似度,你在向量数据库里就得用余弦或者内积(归一化向量情况下)。用L2的话效果会打折扣,别问我怎么知道的。

主流向量数据库横评

现在市面上的向量数据库一大堆,我挑几个有代表性的说说。

Milvus

image-20260524220557816

开源界的扛把子,最早是浙大和Zilliz搞的,现在已经是LF AI基金会毕业项目了。支持分布式部署,生态完善,各种索引类型都支持。我们公司生产环境用的就是Milvus,跑了快两年了,整体还算稳定。

优点:功能全面、社区活跃、支持分布式、云原生架构。
缺点:架构比较重,组件多(etcd、MinIO、Pulsar),部署运维有一定复杂度。小团队用起来有点杀鸡用牛刀的感觉。

如果你数据量在百万级以上,需要分布式,Milvus是个很稳的选择。

Qdrant

image-20260524220623882

Rust写的,性能很好,轻量级。单节点部署特别简单,docker一行命令就起来了。也支持分布式集群。

优点:轻量、性能好、API设计优雅、过滤功能强大。
缺点:生态不如Milvus完善,大规模集群的生产案例相对少一些。

中小规模项目我挺推荐Qdrant的,上手快,性能也不差。

Weaviate

Go写的,内置了跟各种embedding模型的集成(OpenAI、Cohere、HuggingFace等),你可以直接把原始文本丢进去,它自动帮你做embedding。

优点:集成度高、支持多模态、GraphQL查询接口。
缺点:性能在大规模场景下不如Milvus和Qdrant,灵活性稍差。

pgvector

PostgreSQL的向量搜索扩展。如果你已经有PG了,只是想加个向量搜索功能,pgvector是最省事的选择。不用引入新组件,直接在PG里建表、建索引就行。但性能跟专业向量数据库比有差距,数据量大了(百万级以上)会比较吃力。

我个人建议:新项目、数据量大的,选Milvus或Qdrant;已有PG、数据量不大的,pgvector够用;不想运维的,Pinecone或者Zilliz Cloud(Milvus的商业版)。

混合搜索:向量数据库的杀手锏

纯向量搜索其实有局限性的。我举个真实的例子。

我们做智能客服的时候,用户问"退货流程是什么",纯向量搜索能找到语义相近的文档,这没问题。但用户如果问"2024年1月之后的退货政策",纯向量搜索就傻了——"2024年1月之后"这是个时间范围过滤,语义搜索搞不定这种精确条件。

这时候就需要混合搜索了:先通过标量字段(created_at)过滤出2024年1月之后的记录,再在过滤后的结果里做向量相似性搜索。

Milvus和Qdrant都原生支持这种"先过滤再搜索"的模式。语法大概长这样(Milvus的Python SDK):

results = collection.search(
    data=[query_vector],
    anns_field="vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 16}},
    limit=10,
    expr='created_at > "2024-01-01" and category == "售后政策"'  # 标量过滤
)

这个expr参数就是标量过滤条件,跟SQL的WHERE子句差不多。向量数据库先执行这个过滤,缩小候选集,再做ANN搜索。这样既保证了语义相关性,又满足了精确过滤的需求。

还有一种混合搜索是向量搜索+关键词搜索(BM25),把两路结果做融合排序。这个在RAG场景里特别有用,因为有些关键词(比如产品型号、专有名词)语义搜索反而匹配不好,BM25能补上这个短板。Weaviate和Qdrant都支持这种多路召回融合。

一个完整的RAG实战案例

说了这么多,来个实际的例子。假设我们要给公司内部知识库做一个智能问答系统,大概流程是这样的:

第一步:数据准备

把公司知识库的文档(PDF、Word、Markdown等)全部解析出来,按段落切分。切分的时候注意,不能太长也不能太短。太长了embedding会丢失细节信息,太短了上下文不够。一般建议200-500个token一段,段落之间可以有少量重叠。

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", "!", "?", ".", " "]
)

chunks = splitter.split_text(document_text)

第二步:生成向量

把每个chunk丢给embedding模型,拿到向量。

from sentence_transformers import SentenceTransformer

model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
vectors = model.encode(chunks, normalize_embeddings=True)

这里normalize_embeddings=True很关键,归一化之后内积就等于余弦相似度,后面搜索的时候用内积就行,计算更快。

第三步:写入向量数据库

from pymilvus import Collection, FieldSchema, CollectionSchema, DataType

# 定义schema
fields = [
    FieldSchema(name="id", dtype=DataType.VARCHAR, max_length=64, is_primary=True),
    FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=1024),
    FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=2048),
    FieldSchema(name="source", dtype=DataType.VARCHAR, max_length=256),
    FieldSchema(name="department", dtype=DataType.VARCHAR, max_length=64),
]
schema = CollectionSchema(fields=fields)
collection = Collection(name="knowledge_base", schema=schema)

# 创建索引
index_params = {
    "metric_type": "IP",  # 内积,因为向量已经归一化了
    "index_type": "HNSW",
    "params": {"M": 16, "efConstruction": 256}
}
collection.create_index(field_name="vector", index_params=index_params)

# 插入数据
data = [
    ids,        # id列表
    vectors,    # 向量列表
    contents,   # 原文列表
    sources,    # 来源列表
    departments # 部门列表
]
collection.insert(data)
collection.load()  # 加载到内存

第四步:查询

query = "公司年假怎么请"
query_vector = model.encode([query], normalize_embeddings=True)[0]

results = collection.search(
    data=[query_vector.tolist()],
    anns_field="vector",
    param={"metric_type": "IP", "params": {"ef": 128}},
    limit=5,
    output_fields=["content", "source", "department"]
)

for hit in results[0]:
    print(f"相似度: {hit.distance:.4f}, 内容: {hit.entity.get('content')[:100]}")
    print(f"来源: {hit.entity.get('source')}")

第五步:把搜索结果喂给大模型

把top-K的搜索结果拼在一起,作为上下文,跟用户的问题一起发给大模型,让它生成回答。这就是RAG(Retrieval-Augmented Generation)的核心流程。

context = "\n\n".join([hit.entity.get('content') for hit in results[0]])
prompt = f"""基于以下参考资料回答用户的问题。如果参考资料中没有相关信息,请说"我不确定"。

参考资料:
{context}

用户问题:{query}

回答:"""

# 然后把prompt发给GPT或其他大模型

整个流程跑通不难,但要做出好效果,每个环节都有优化空间。切分策略怎么调、embedding模型怎么选、检索参数怎么设、prompt怎么写、要不要加rerank……这些细节决定了最终体验的好坏。

向量数据库的未来趋势

最后聊几点我观察到的趋势。

多模态是方向。现在大部分向量数据库还是以文本为主,但图片、视频、音频的向量搜索需求在快速增长。比如"以图搜图"、"哼唱找歌"这些场景。Milvus和Qdrant都在加强多模态支持。

Serverless化。Pinecone已经推出了Serverless方案,按查询量计费,不用预置资源。Zilliz Cloud也有Serverless选项。对中小团队来说,这种模式能大幅降低成本和运维负担。

跟AI框架的深度集成。LangChain、LlamaIndex这些框架已经内置了对主流向量数据库的支持,未来集成只会越来越深。向量数据库正在成为AI应用基础设施的一部分,就像MySQL之于Web应用。

向量数据库+传统数据库的融合。pgvector这种方案是一种思路,把向量搜索能力加到传统数据库里。另一种思路是向量数据库加强标量查询能力。两个方向都在演进,未来可能会出现更统一的方案。


写在最后

向量数据库这东西,说复杂也复杂,说简单也简单。核心就是存向量、搜向量,但要做好,每个环节都有讲究。embedding模型的选择、索引类型的配置、距离度量的匹配、混合搜索的设计、生产环境的运维,这些都需要你在实践中慢慢摸索。

我自己的体会是,别被各种概念和术语吓到。先从一个小的场景入手,比如给团队的知识库做个语义搜索,把整个链路跑通。然后逐步优化,加过滤、加rerank、调参数。跑过一遍之后,很多之前不理解的东西自然就明白了。

向量数据库不是万能的,它只是AI应用技术栈中的一环。但这一环在RAG场景里确实不可替代。大模型有知识截止日期、有幻觉问题,向量数据库提供的精准检索能力,是缓解这些问题的重要手段。

如果你正在做AI相关的项目,还没接触过向量数据库,建议赶紧动手试试。光看文章不动手,永远都是纸上谈兵。

觉得这篇文章对你有帮助的话,点个赞、转发一下呗,让更多人看到。有什么问题也欢迎留言讨论,我尽量回复。


公众号:耕云躬行录

个人博客:躬行笔记

文章目录

博主介绍

热爱技术的云计算运维工程师,Python全栈工程师,分享开发经验与生活感悟。
欢迎关注我的微信公众号@运维躬行录,领取海量学习资料

微信二维码