一、PGVector
为什么推荐 PGVector 作为 RAG 的入门首选?
理由很直接——你的项目大概率已经在用 PostgreSQL。
直接加一个扩展,不需要引入新的数据库组件,运维成本最低。DBA 会用 PG,就会维护 PGVector。这种“复用已有基础设施”的价值,在实际项目里非常实在。
1.1 PGVector 能做什么(本质)
PGVector 给 PostgreSQL 加了一个新的数据类型VECTOR,你可以在普通的表里加一列向量,然后对这列向量做相似度搜索。
查询时,用“向量相似度排序”替代普通 SQL 的ORDER BY。
三种距离算法
| 运算符 | 距离类型 | 适用场景 |
|---|---|---|
<-> | 欧氏距离(L2) | 坐标空间,对向量幅度敏感 |
<=> | 余弦距离 | 文本语义搜索首选(只看方向,不看幅度) |
<#> | 内积(负数) | 向量已归一化时等效于余弦距离 |
文本 RAG 场景几乎都用余弦距离。因为不同长度的文本,Embedding 向量的幅度可能不同,但语义方向是相似的。余弦距离只看方向,不受幅度影响,更适合语义搜索。
1.2索引类型:HNSW vs IVFFlat
这是 PGVector最重要的选择之一,直接影响搜索速度和精度。
什么是向量索引?
没有索引时,向量搜索要把查询向量和库里每一条记录都算一次距离(全量扫描)。100 万条数据,就要算 100 万次距离,O(n) 复杂度,数据量大了根本跑不动。
向量索引通过构建特殊的数据结构,让搜索时只计算一小部分候选向量的距离。代价是:不保证找到“最精确”的结果,只保证找到“足够好”的近似结果——即ANN(近似最近邻)搜索。
1.2.1 HNSW(层级小世界网络)
HNSW 构建了一个多层的图结构:
HNSW 索引结构(简化示意) 层 2(稀疏): A ←————→ F ←——→ K ↑ 层 1(中等): A ←——→ D ←——→ F ←——→ H ←——→ K ↑ 层 0(密集): A-B-C-D-E-F-G-H-I-J-K(所有节点)查询时从高层稀疏图开始找大方向,逐层往下精化,最终在底层找到精确候选——就像在地图上先定位到城市,再找街道,再找门牌号,高效且准确。
HNSW 的优点:
查询速度快,延迟低
召回率高(精度好)
支持增量插入(随时插入新数据,不需要重建索引)
HNSW 的缺点:
建索引较慢(但通常是一次性操作)
内存占用较大(索引结构要常驻内存)
大多数 RAG 场景推荐 HNSW。
1.2.2 IVFFlat(倒排文件 + 扁平量化)
IVFFlat 的思路:先把向量空间划分成若干个“桶”(Cluster),每次查询只搜最近的几个桶,不搜全部。
IVFFlat 索引结构(简化示意) 向量空间 ┌──────────────────────────────────┐ │ 桶1 桶2 桶3 桶4 桶5 │ │ ··· ··· ··· ··· ··· │ └──────────────────────────────────┘ ↑ 查询向量先判断属于哪个桶附近,只在附近桶里搜IVFFlat 的优点:
建索引快
内存占用小
IVFFlat 的缺点:
查询速度相对较慢
召回率略低(向量被错分到错误桶的情况不可避免)
需要先有足够量的数据才能建索引(通常要求 > 1000 条,聚类才有意义)
适合 IVFFlat 的场景:数据量百万级以上、批量入库(非实时插入)、对内存比较敏感。
1.2.3两者对比
| 维度 | HNSW | IVFFlat |
|---|---|---|
| 查询速度 | 快 | 较慢 |
| 查询精度(召回率) | 高 | 中等 |
| 建索引速度 | 慢 | 快 |
| 内存占用 | 大 | 小 |
| 增量插入 | 友好 | 较麻烦(需定期重建) |
| 数据量要求 | 无特殊要求 | > 1000 条才有意义 |
| 推荐场景 | 大多数 RAG 场景 | 大规模批量场景 |
1.3 HNSW 的关键参数:m 和 ef_construction
HNSW 有两个建索引时的关键参数,影响精度和资源消耗的权衡。
参数 m:每个节点的最大连接数
m决定了 HNSW 图的“密度”——每个节点最多连接几个邻居。
m越大:图越密,搜索越准,但内存占用越大、建索引越慢m越小:内存省,但精度降低
通用推荐值:m = 16
调大 m(如 32~64):对召回率要求极高(如法律文档检索),代价是内存翻倍
调小 m(如 8):内存极度紧张时,精度会下降但速度更快
参数 ef_construction:建索引时的搜索宽度
ef_construction控制建索引时的精度——在往图里插入每个节点时,搜索多少候选邻居来决定最终连接。
ef_construction越大:索引越精确,但建索引越慢ef_construction越小:建索引快,但索引质量略低
通用推荐值:ef_construction = 64
建议:这两个参数入门时不要纠结,
16/64就是很好的默认值。等到真正遇到性能瓶颈,再基于实际测量调整。
1.4查询时的 ef_search:精度和速度的旋钮
建好索引后,查询时还有一个参数ef_search,控制查询时搜索的候选数量。
ef_search越大:查询越准(召回率高),但耗时越长ef_search越小:查询越快,但可能漏掉一些相关结果
默认值通常是40。
这个参数的意义是:你可以在不重建索引的情况下,灵活地在查询精度和速度之间调整。
| 场景 | 推荐 ef_search |
|---|---|
| 精度优先(如法律条文检索) | 100–200 |
| 速度精度平衡(大多数场景) | 40–100(默认附近) |
| 速度优先(高并发低延迟) | 20–40 |
1.5距离算法和相似度分数的关系
这里有个容易混淆的地方,鸡哥单独说清楚。
余弦距离的范围是[0, 2]:
0→ 完全相同2→ 完全相反
但 RAG 框架里通常展示的是相似度分数,它是对余弦距离的转换:
相似度 = 1 - 余弦距离完全相同 → 余弦距离 = 0 → 相似度 = 1.0
不相关 → 余弦距离 ≈ 1 → 相似度 ≈ 0.0
完全相反 → 余弦距离 = 2 → 相似度 = -1.0
所以设置“相似度阈值”时,例如similarityThreshold = 0.6,表示“只要余弦相似度 ≥ 0.6 的结果”。
阈值怎么设?
没有通用答案,要根据数据和模型实测。鸡哥的经验:
中文业务文档(通义千问 Embedding):
0.5–0.7比较合理英文技术文档(OpenAI Embedding):
0.6–0.8第一次调试:先设
0.3,看能不能搜到东西,再逐步调高
阈值设太高(比如 0.9),会过滤掉大量相关结果,知识库形同虚设。
阈值设太低,会引入大量噪音,浪费 LLM 的上下文窗口。
1.6 Metadata 过滤:向量搜索 + 结构化过滤组合
PGVector 支持在向量搜索的同时按 Metadata 过滤。这个功能看起来简单,但设计得好可以大幅提升检索精度。
1.6.1场景举例
知识库里有:产品手册(category=manual)、FAQ(category=faq)、政策文档(category=policy)。
用户提问:“退款要多久?”
普通向量搜索:可能找到来自产品手册的内容(里面也提到了退款)
加 Metadata 过滤:只在
category=faq里搜,精准命中 FAQ 里的退款条款
1.6.2Metadata 设计建议
建议入库时至少标注:
{ "source": "文件名或 URL", "category": "文档类别", "version": "版本号", "upload_date": "入库时间" }注意:Metadata 过滤和向量搜索是“先过滤后搜索”——先通过 Metadata 缩小候选集,再在候选集内搜向量。
过滤条件越严格,候选集越小,TopK 能找到的结果就越少(甚至可能不足 K 个)。合理设计 Metadata 粒度很重要。
1.7性能基准:PGVector 在不同规模下的表现
测试环境:HNSW 索引(m=16, ef_construction=64),1536 维向量,普通 4 核 8G 服务器。
| 数据量 | 查询延迟(TopK=5) | 内存占用(向量索引) | 推荐场景 |
|---|---|---|---|
| 1 万条 | < 10ms | ~100MB | Demo、小型工具 |
| 10 万条 | 10–30ms | ~1GB | 企业知识库 |
| 100 万条 | 30–100ms | ~10GB | 平台级中型产品 |
| 1000 万条 | 100ms+ | 内存可能撑不住 | 考虑换专业向量库 |
对于中小型企业知识库(文档数百到数千个,分块后数万条向量),PGVector 性能完全够用,查询延迟可以控制在 30ms 以内。
PGVector 的实际瓶颈通常不在向量搜索,而在写入速度。
大规模批量入库时,Embedding 模型的调用速度(每条都要调用一次 API)才是真正的瓶颈。
1.8什么时候 PGVector 开始显现局限?
见过一些开始觉得 PGVector 不够用的情况:
数据量超过几百万条:查询延迟开始超出要求,HNSW 索引的内存占用可能超出单机可用内存。
多租户向量隔离需求:比如 SaaS 产品,每个客户的知识库要完全隔离。PGVector 只能靠 Metadata 过滤实现“逻辑隔离”,没有真正的物理隔离。专业向量库的 Collection 概念更适合这个场景。
向量 + 复杂结构化条件的混合查询:例如“在最近 7 天上传的、来自技术部门的、内容和问题相关的文档块”。这类复杂混合查询,PGVector 的过滤性能不如专业向量库。
极高并发:PGVector 依赖 PostgreSQL 的连接池,高并发场景下会遇到连接数上限和锁竞争问题。
1.9生产部署的几个要点
1. 不要用initialize-schema: true管理生产 DDL
让框架自动建表只适合开发和 Demo。生产环境的表结构变更要纳入版本管理(Flyway、Liquibase 或手动维护 SQL 文件),方便追踪和回滚。
2. 向量表要定期做 VACUUM
大量删除和更新向量后,PG 的 MVCC 机制会留下“死元组”,占用磁盘空间并影响查询性能。定期执行:
VACUUM ANALYZE vector_store;3. 监控向量表大小和索引状态
特别是 HNSW 索引在内存里的占用。如果机器内存不足,索引会被频繁换入换出,查询延迟会大幅上升。
4. 数据备份和恢复策略
向量库里存的是 Embedding 结果。如果 Embedding 模型没变,数据丢失可以通过重新入库恢复(只是费时间)。但建议还是纳入常规备份。
二、Qdrant——高性能、现代感强的专业向量库
Qdrant 是用Rust写的,这一点非常重要——Rust 的内存安全特性和零成本抽象让 Qdrant 在性能和稳定性上有天然优势,单机可以支撑千万级向量,内存占用还比同等 Java/Go 实现低。
2.1Qdrant 相比 PGVector 的核心优势
多 Collection 原生支持:每个 Collection 是独立的向量空间,有独立的维度和索引。
鸡哥见过的一个场景:一个平台有“产品手册”、“FAQ”、“政策文档”三个知识库,用 Qdrant 就是三个 Collection,天然隔离;用 PGVector 只能靠 Metadata 字段区分,查询时加过滤条件,不够干净。Payload 过滤性能优秀:Qdrant 的过滤机制是专门为“向量+过滤”组合查询设计的,支持在过滤之前或之后做向量搜索,有复杂优化器。在同样的数据量下,复杂过滤条件的性能比 PGVector 好很多。
Rust 实现的性能和稳定性:高并发场景下,Qdrant 的延迟抖动很小。PGVector 在高并发下可能因为 PG 锁机制出现延迟毛刺。
自带图形化界面:启动后就有 Dashboard,可以直接在界面里看 Collection、查数据、测搜索,调试很方便。鸡哥每次接触新知识库,先在 Qdrant 的界面里搜几个测试问题看看效果。
2.2 Qdrant 的适用场景
场景 A:中大型企业知识库(数百万条向量)
→ 单机 Qdrant 就够,比 PGVector 有明显性能优势场景 B:SaaS 平台的多租户知识库
→ 每个租户一个 Collection,物理隔离,简洁清晰场景 C:从 PGVector 升级的首选
→ 部署简单(单 Docker),Spring AI 支持好,代码层不用改场景 D:对运维复杂度有约束的团队
→ Qdrant 单进程就能跑,不像 Milvus 需要多个组件
2.3 Qdrant 的局限
Qdrant 不适合“数据量亿级以上 + 需要水平扩展”的场景——它的分布式模式(Qdrant Cloud 或自建集群)相对复杂,不如 Milvus 在分布式层面成熟。
三、Milvus——分布式大规模场景的重炮
Milvus 是由 Zilliz 开源的分布式向量数据库,支持十亿级向量,内置分布式能力,是向量数据库领域的“大规模场景专家”。
3.1Milvus 的架构特点
Milvus 是真正的分布式系统,组件分离:
┌─────────────────────────────────────────────────────────────┐ │ Milvus 分布式架构 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Query │ │ Data │ │ Index │ ← 计算节点 │ │ │ Node │ │ Node │ │ Node │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ ↓ ↓ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ 消息队列(Pulsar/Kafka) │ ← 数据流 │ │ └─────────────────────────────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ 对象存储(MinIO/S3) │ ← 持久化 │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘这个架构的好处:每一层可以独立扩展,计算和存储分离,扛得住真正的大规模。
代价:部署复杂度很高。一个完整的 Milvus 集群需要:协调节点(Coordinator)、查询节点、数据节点、索引节点、消息队列(Pulsar 或 Kafka)、对象存储(MinIO 或 S3)。对一个没有专职运维的中小团队来说,光是搭起来就要花不少时间。
3.2Milvus 的适用场景
场景 A:数据量亿级以上的大规模系统
→ 电商推荐系统(商品 Embedding + 用户行为 Embedding)
→ 大型内容平台的语义搜索(文章、视频描述)
→ 超大规模企业文档库(集团级、跨公司的知识管理平台)场景 B:需要水平扩展能力
→ 业务增长快,向量量每月翻倍
→ 需要在线扩容不停服场景 C:有专职运维团队
→ 公司有 DBA/SRE,能维护多组件分布式系统
对大多数企业知识库项目,Milvus 是过度设计。如何判断:如果你的知识库文档不超过几十万,团队没有专职运维,用 Milvus 是给自己找麻烦。
四、三个向量库的全面对比
| 维度 | PGVector | Qdrant | Milvus |
|---|---|---|---|
| 数据量级上限 | 百万条以内(舒适) | 千万级(单机) | 十亿级(分布式) |
| 部署复杂度 | 极低(已有 PG 直接用) | 低(单 Docker) | 高(多组件) |
| Payload/Metadata 过滤 | 一般 | 优秀(专门优化) | 优秀 |
| 多租户隔离 | 靠 Metadata 过滤(逻辑隔离) | Collection 原生隔离 | Collection 原生隔离 |
| 写入吞吐 | 中 | 高 | 极高 |
| 查询延迟 | 中(10万条 < 30ms) | 低(Rust 实现) | 低(分布式优化) |
| 内存占用 | 中(随 PG 共享) | 低(Rust 高效利用) | 高(多节点) |
| 运维成本 | 低(复用 DBA 技能) | 中(需要学习 Qdrant) | 高(分布式运维) |
| Spring AI 支持 | 完整 | 完整 | 完整 |
| 图形化界面 | 需要额外工具(pgAdmin) | 内置 Dashboard | 需要 Attu 等工具 |
| 云托管 | RDS for PG(各云厂商) | Qdrant Cloud | Zilliz Cloud |
| 开源协议 | Apache 2.0 | Apache 2.0 | Apache 2.0 |
| 适用场景 | 中小项目,已有 PG | 中大型项目,性能有要求 | 超大规模,分布式 |
五、选型决策树
你的 RAG 系统数据量是多少? │ ├── < 50 万条,且已有 PostgreSQL │ → PGVector(复用已有基础设施,最省事) │ ├── 50 万 - 1000 万条,或有多租户需求 │ → Qdrant(高性能,运维简单,Collection 隔离) │ → 也可以 PGVector + 垂直扩容先撑一段时间 │ └── > 1000 万条,或需要水平扩展 │ ├── 有专职运维团队,数据量亿级 │ → Milvus(真分布式,扛得住) │ └── 没有专职运维,但数据量大 → Qdrant Cloud 或 Zilliz Cloud(云托管,省运维) 其他约束条件: │ ├── 数据不能上云,必须私有化部署 │ → Qdrant 单机(运维最简单) │ → Milvus 单机版(比集群版简单,但组件还是多) │ ├── 团队熟悉 SQL,不想学新查询语言 │ → PGVector(SQL 查向量) │ └── 需要最快速的 Demo / 验证 → PGVector(docker 一行,最快)