去年做一个RAG项目的时候,我在向量数据库选型上花了整整一个月的时间,最后得出的结论是:放弃专门的向量数据库,改用PostgreSQL的pgvector扩展。

这一个月里我调研了几乎所有主流的向量数据库,做了大量的测试和对比,踩了很多坑,也走了很多弯路。这篇文章就来聊聊这段经历,聊聊我从入门到放弃的全过程,以及一些反思和建议。

项目背景

先说说项目背景。我们要做一个企业内部的知识库问答系统,基于RAG技术,让员工可以用自然语言提问,系统从公司的内部文档(产品手册、技术文档、规章制度、FAQ等)中检索相关内容,然后用大模型生成回答。

文档量大概是一万篇左右,每篇切分成几个到几十个chunk,总共有大概十万个向量。这个数据量说大不大说小不小,正好处于一个比较尴尬的位置。

项目的需求很明确:检索准确、响应快、稳定可靠、运维简单、成本低。听起来很简单,但真正做起来才发现每一条都不简单。

最开始我想当然地觉得,做RAG肯定要用专门的向量数据库啊,这不是标配吗。于是就开始了漫长的选型之旅。

入门阶段:调研和测试

最开始我列了一个候选清单,把市面上主流的向量数据库都列了进去:Milvus、Qdrant、Weaviate、Pinecone、pgvector、Elasticsearch kNN、Redis Vector Search、Chroma、FAISS。

然后我开始逐个调研,看文档,看评测文章,看GitHub,看社区讨论。越看越觉得每个都不错,每个都有自己的优势,也都有自己的不足。越看越纠结,不知道该选哪个。

光看文档不够,还得实际测试。我写了一个测试脚本,用我们真实的文档数据生成了十万个测试向量,然后在每个候选数据库上做同样的测试:导入数据、建索引、做相似度搜索、测延迟、测吞吐量、测召回率、测资源消耗。

这个测试过程花了我大概两周的时间。测试的结果让我更加纠结了,因为每个数据库在不同的维度上表现不一样,没有一个是全能的。

Milvus性能最强,功能最丰富,支持分布式,但部署太复杂了,组件一大堆,依赖etcd、MinIO、Pulsar,运维成本很高。对于我们这个只有十万向量的小项目来说,用Milvus就像用大炮打蚊子,太重了。

Qdrant性能也很好,部署相对简单,API友好,是我最看好的一个。但它是一个比较新的项目,生态还不够成熟,企业级用户案例相对少一些。而且我们团队没有人有Qdrant的运维经验,心里没底。

Weaviate功能很丰富,内置了Embedding和生成功能,一站式解决方案很方便。但性能在我们的测试中不如Qdrant和Milvus,而且概念比较多,学习成本高一些。

Pinecone是托管服务,零运维,性能也很好,用起来最省心。但价格不便宜,我们这个数据量一个月也要几十美元,而且数据存在第三方,公司的安全合规部门有顾虑,国内访问也有延迟问题。

pgvector最简单,因为我们已经在用PostgreSQL了,装个扩展就能用,零额外运维成本。但性能在我们的测试中不如专门的向量数据库,特别是在高并发的时候延迟比较高。

Elasticsearch我们也在用,做全文搜索。它的kNN搜索功能也能用,而且可以把全文搜索和向量搜索结合起来做混合搜索。但向量搜索的性能不如专门的向量数据库,而且Elasticsearch本身就比较重,资源消耗大。

Redis Vector Search速度很快,延迟很低,但内存成本高,十万个向量就要占不少内存,而且功能相对基础。

Chroma最轻量,部署最简单,适合原型开发,但生产环境用心里没底,功能和性能都有限。

FAISS性能最好,是很多向量数据库的底层基础,但它只是一个库,不是完整的数据库,需要自己处理持久化、API服务、分布式等,开发成本高。

测试完之后我陷入了选择困难症。每个都有道理,每个都有不足。选Milvus吧太重,选Qdrant吧没经验,选Pinecone吧太贵有合规问题,选pgvector吧性能不够。我就这样纠结了一周,项目进度也耽误了。

踩坑阶段:实际部署遇到的问题

纠结了一周之后,我决定先选Qdrant试试,因为它综合来看最均衡,性能好,部署相对简单,API友好。我花了两天时间在测试环境部署了Qdrant,导入了数据,做了一些基本的功能测试,感觉还不错。

然后我开始做更深入的测试,这时候问题就来了。

第一个问题是内存消耗比预期大。十万个向量,每个维度1536(用的text-embedding-3-small),我以为内存消耗应该不大,结果Qdrant的HNSW索引占了好几个G的内存。我们的测试服务器内存本来就不大,一下子就吃紧了。我查了文档,调了索引参数,降低了M和ef_construct,内存是降下来了,但召回率也跟着降了,检索效果变差了。这就陷入了一个两难:要召回率就要高内存,要省内存就要牺牲召回率。

第二个问题是标量过滤的性能。我们的业务需要在向量搜索的同时根据部门、文档类型、权限等做标量过滤。最开始我以为这很简单,Qdrant支持payload过滤,直接加过滤条件就行。结果测试发现,当过滤条件比较复杂、过滤后的结果集比较大的时候,搜索延迟明显升高,有时候甚至比不过滤还慢。我查了很多资料,试了各种优化方法,比如建payload索引、调整过滤条件的顺序、用分区等,效果都不理想。这个问题困扰了我好几天。

第三个问题是更新和删除的性能。企业知识库的文档是经常更新的,旧的文档要删除,新的文档要插入。我测试了批量更新和删除的性能,发现Qdrant在更新的时候会影响查询性能,因为HNSW索引在不断调整。而且删除不是立即生效的,是软删除,需要后台清理,这会导致数据不一致的问题,有时候删除了还能搜到。这些问题虽然不是不能解决,但需要额外的开发和处理,增加了系统的复杂度。

第四个问题是运维和监控。Qdrant虽然部署相对简单,但生产环境用还是需要做很多运维工作,比如监控、备份、扩容、升级、故障排查等。我们团队很小,没有专门的运维人员,开发人员兼职运维,本来就忙不过来。再增加一个新的数据库要运维,确实有点吃力。而且Qdrant的监控指标和日志体系还不够完善,出了问题排查起来比较费劲。

这些问题加在一起,让我开始重新思考:我们真的需要一个专门的向量数据库吗?

转折点:重新评估需求

就在我被Qdrant的各种问题搞得焦头烂额的时候,一件事情让我重新审视了整个选型过程。

那天我和一个做过类似项目的朋友聊天,跟他吐槽向量数据库选型的痛苦。他听了之后问了我几个问题:你们的数据量有多大?查询并发有多高?对延迟的要求是多少?团队有几个人?运维能力怎么样?

我一一回答:十万向量,并发不高(内部系统,同时在线几十人),延迟要求一两秒就行(大模型生成本身就要几秒),团队三个开发,没有专门运维。

朋友听完笑了,说:你这需求,用pgvector完全够了啊,为什么要折腾专门的向量数据库?

我当时还不服气,说pgvector性能不行啊,测试的时候延迟比Qdrant高。朋友问:高多少?我说:Qdrant平均50毫秒,pgvector平均200毫秒。朋友说:大模型生成要3到5秒,你差这150毫秒用户能感觉出来吗?

我一下子就愣住了。对啊,我们整个系统的响应时间主要花在大模型生成上,要3到5秒。向量检索那几十毫秒和几百毫秒的差距,在整个响应时间里占比很小,用户根本感觉不出来。我为了这微不足道的性能差距,折腾了一个月,值得吗?

朋友又说:你想想,你引入一个新的数据库,要学习,要部署,要运维,要监控,要备份,出了问题要排查。这些成本加起来,比那点性能差距大得多。你们团队小,运维能力有限,应该尽量简化技术栈,用已经熟悉的技术解决问题,而不是为了追求极致性能引入新的复杂度。

这番话点醒了我。我回头看了看这一个月的经历,发现自己确实陷入了一个误区:为了技术而技术,为了追求所谓的"最佳实践"而忽略了实际需求。做RAG就一定要用专门的向量数据库吗?不一定。技术选型应该从实际需求出发,选择最适合的,而不是选择最流行的、性能最强的。

放弃:改用pgvector

想明白之后,我决定放弃专门的向量数据库,改用pgvector。

我们已经在用PostgreSQL了,pgvector只是一个扩展,装一下就能用,零额外运维成本。数据存在现有的PostgreSQL里,备份、监控、高可用都是现成的,不需要额外做任何事情。

我花了半天时间把向量检索从Qdrant迁移到了pgvector。建表、加vector字段、建HNSW索引、写查询SQL,都很简单,因为我们团队对PostgreSQL很熟悉。

迁移完成之后做了测试,结果让我很满意。

检索延迟方面,pgvector平均200毫秒左右,比Qdrant的50毫秒慢一些,但在整个系统3到5秒的响应时间里完全可以忽略,用户根本感觉不到差别。

召回率方面,pgvector的HNSW索引召回率和Qdrant差不多,都在95%以上,检索效果没有明显差别。

标量过滤方面,pgvector用SQL的WHERE子句做过滤,和普通的SQL查询一样,灵活强大,性能也不错。因为我们对PostgreSQL的查询优化很熟悉,调起性能来得心应手,比在Qdrant里摸索高效多了。

更新和删除方面,pgvector就是普通的数据库操作,UPDATE和DELETE直接生效,没有软删除、数据不一致的问题,事务支持也很完善。

运维方面,零额外成本,因为就是现有的PostgreSQL,监控、备份、高可用都是现成的。出了问题我们也能快速排查,因为对PostgreSQL很熟悉。

资源消耗方面,pgvector的HNSW索引也占内存,但因为我们对PostgreSQL的内存管理很熟悉,可以通过调整sharedbuffers、workmem等参数来优化,比在Qdrant里摸索高效多了。

总的来说,改用pgvector之后,系统更简单了,运维成本更低了,开发效率更高了,而性能和效果完全满足需求。我之前折腾了一个月的向量数据库选型,最后发现最简单的方案才是最适合我们的。

反思:我犯了哪些错误

回顾这段从入门到放弃的经历,我反思了一下自己犯的错误,希望能给大家一些警示。

第一个错误是盲目追新。向量数据库是最近两年火起来的新技术,各种文章、各种分享都在说做RAG一定要用向量数据库。我就想当然地觉得必须用专门的向量数据库,没有认真思考自己的实际需求是否真的需要。新技术不一定适合所有场景,适合自己的才是最好的。

第二个错误是过度追求性能。我在测试的时候过于关注向量检索的延迟,把50毫秒和200毫秒的差距看得很重,却忽略了整个系统的响应时间主要花在大模型生成上。在整个系统的视角下,这点性能差距根本不重要。性能优化应该放在瓶颈上,而不是放在无关紧要的地方。

第三个错误是忽略了运维成本。我在选型的时候主要看性能和功能,忽略了部署、运维、监控、备份等成本。对于小团队来说,运维成本往往比性能更重要。引入一个新的数据库,学习成本、运维成本、故障排查成本,这些加起来可能比那点性能差距大得多。

第四个错误是技术栈复杂化。我们已经在用PostgreSQL了,pgvector完全能满足需求,但我却想引入一个新的数据库,增加了技术栈的复杂度。技术栈越复杂,维护成本越高,出问题的概率越大。小团队应该尽量简化技术栈,用已经熟悉的技术解决问题。

第五个错误是没有先做最小可行性验证。我最开始应该先用最简单的方案(比如pgvector)做一个原型,验证一下是否满足需求,如果满足就直接用,不满足再考虑更复杂的方案。而不是一上来就调研所有的向量数据库,做大量的测试,浪费了很多时间。先简单后复杂,先验证后优化,这才是正确的思路。

这些错误说起来都很简单,但真正做的时候很容易犯。希望大家在做技术选型的时候能引以为戒,不要像我一样走弯路。

给正在做向量数据库选型的朋友的建议

最后给正在做向量数据库选型的朋友一些建议,这些都是我用一个月时间和无数坑换来的经验。

第一,先想清楚自己的需求。在选型之前,先把自己的需求想清楚:数据量有多大?查询并发有多高?对延迟的要求是多少?对召回率的要求是多少?团队有多少人?运维能力怎么样?预算有多少?有没有安全合规要求?把这些问题想清楚了,再去选型,就不会那么纠结了。

第二,从最简单的方案开始。不要一上来就考虑最复杂、性能最强的方案。先从最简单的方案开始,比如如果你已经在用PostgreSQL就先试试pgvector,如果已经在用Elasticsearch就先试试kNN搜索。用最简单的方案做一个原型,验证一下是否满足需求。如果满足,就直接用,不要折腾更复杂的方案。如果不满足,再考虑更复杂的方案。

第三,不要忽略运维成本。选型的时候不要只看性能和功能,还要看部署、运维、监控、备份、升级、故障排查等成本。特别是对于小团队来说,运维成本往往比性能更重要。一个性能稍差但运维简单的方案,往往比一个性能很强但运维复杂的方案更适合小团队。

第四,考虑整个系统的性能,而不是单个组件的性能。向量检索只是整个RAG系统的一部分,整个系统的响应时间还包括Embedding、大模型生成、网络传输等。不要只看向量检索的延迟,要看整个系统的端到端延迟。如果向量检索只占整个响应时间的很小一部分,那优化它的意义就不大。

第五,做真实场景的测试,不要只看 benchmark。网上的各种benchmark评测文章可以参考,但不要全信。因为benchmark的测试场景和你的真实场景可能不一样,数据量、数据分布、查询模式、过滤条件、并发量等都可能不同。一定要用自己的真实数据和真实查询做测试,这样得出的结论才可靠。

第六,不要害怕放弃。如果你选了一个方案,用了一段时间发现不合适,不要舍不得放弃,不要觉得已经投入了很多时间和精力就硬撑着。及时止损,换一个更合适的方案,比硬撑着要好得多。我放弃Qdrant改用pgvector之后,开发效率提高了很多,系统也更稳定了。放弃不是失败,而是明智的选择。

这些建议希望能帮到正在做向量数据库选型的朋友,少走弯路,少踩坑。

写在最后

向量数据库选型从入门到放弃,这一个月的经历让我学到了很多。

我学到了技术选型要从实际需求出发,不要盲目追新,不要过度追求性能,不要忽略运维成本,不要让技术栈过度复杂。

我学到了最简单的方案往往是最好的方案,特别是对于小团队来说。能用现有技术解决的问题,就不要引入新的技术。能简单解决的问题,就不要搞复杂。

我也学到了放弃不是一件丢人的事情。发现方案不合适,及时放弃,及时调整,比硬撑着要好得多。技术人员有时候容易陷入"技术情结",觉得用了新技术就很厉害,用了简单方案就很low。其实不是的,能解决问题、满足需求、成本最低的方案,才是最好的方案,不管它是新的还是旧的,是复杂的还是简单的。

现在我们的系统用pgvector跑得很稳定,性能完全满足需求,运维成本几乎为零,开发效率也很高。我很庆幸自己最终放弃了专门的向量数据库,选择了最简单的方案。

当然,我不是说向量数据库不好,也不是说大家都不要用向量数据库。如果你的数据量很大(百万级以上),并发很高,对延迟要求很严格,团队有运维能力,那专门的向量数据库(比如Milvus、Qdrant)确实是更好的选择。但如果你的需求和我们类似,数据量不大,并发不高,团队小,运维能力有限,那pgvector可能就足够了,没必要折腾更复杂的方案。

技术选型没有标准答案,适合自己的才是最好的。希望大家都能根据自己的实际需求,做出最合适的选择。

以上就是我向量数据库选型从入门到放弃的全部经历,希望对大家有所帮助。