最近在做一个基于RAG的私有知识库问答,之前用Milvus搭的demo效果还行,但为了省运维成本,把向量存储换到了PostgreSQL的pgvector扩展。同样用bge-large-zh的768维向量,数据量大概20万条,距离函数用的L2,建了IVFFlat索引。结果换过去之后,top-5召回的相关性明显变差,特别是长尾问题,感觉像是索引聚类没建好。我按默认的lists=100建的索引,probes也设了10,难道是数据分布的问题?还是说pgvector的IVFFlat对高维向量支持不太好,必须换HNSW?有没有大佬踩过类似的坑,求指点一下调参方向。
RAG项目从Milvus换到pgvector后,召回效果崩了,是我参数没调对吗?
全部回复
共 24 条20万条数据IVFFlat的lists确实太小了,按sqrt(n)试试,probes也得跟着涨。
说实话你这个情况我遇到过类似的,问题大概率不在pgvector本身,而是IVFFlat的lists和probes参数对20万条数据来说太不敏感了。我当初也是用默认配置,召回稀碎,后来把lists调到和数据量开根号差不多(大概450左右),probes提到20-30,效果才勉强能看。另外你用的是L2,对bge这种归一化向量来说其实不太合适,换成内积距离试试,差距挺明显的。如果还不行就直接上HNSW吧,pgvector的HNSW在768维上表现比IVFFlat稳得多,就是建索引慢点,但查询质量值回票价。
说到这个我太有感触了,之前也干过一模一样的事,为了省事从FAISS换到pgvector,结果召回质量掉得我怀疑人生。你这个问题大概率不是参数没调对,而是IVFFlat在高维空间里本身就容易翻车,768维真不是它擅长的领域,聚类中心一多,每个簇里的向量分布就特别稀疏,长尾查询很容易被分到错误的簇里。我当时试着把lists降到50,probes提到20,效果有改善但还是很勉强,后来直接换成HNSW,m设16,ef_construction设128,召回基本就回来八九成了。另外提醒一句,pgvector的HNSW构建时间比Milvus慢不少,20万条数据可能要跑一阵子,但一次性的成本可以接受。还有个小坑,你检查下是不是用的默认的maintenance_work_mem,构建索引时候内存不够会导致索引质量下降,建议调大到1GB以上再重建一次。如果实在不想换HNSW,也可以试试把向量降维到256或者用PCA预处理一下,但我觉得最省心的方案还是直接上HNSW,毕竟效果崩了后续调优更费时间。
你这情况我大概率猜到了,20万条数据用lists=100其实偏少了,一般建议lists约等于行数的平方根,也就是447左右,probes可以再往上调调看。另外pgvector的IVFFlat在数据分布不均匀时确实容易翻车,长尾问题大概率是被聚类中心带偏了,可以先试试重建索引时用更大的样本训练。如果还不行,直接换HNSW吧,虽然建索引慢点,但召回稳定性好太多,调参没那么玄学。