打开网易新闻 查看精彩图片

2024年向量数据库赛道融资额暴跌62%,但PostgreSQL的pgvector扩展下载量却逆势涨了3倍。这不是偶然——当一家AI初创公司CTO告诉我"我们用pgvector替换了Pinecone,省了每月8000刀"时,我意识到这个被低估的工具正在完成一场静默的接管。

pgvector的本质,是把PostgreSQL变成了一台能同时处理关系数据和向量搜索的"混合动力引擎"。你不需要维护两套系统,不需要学习新的查询语法,甚至不需要改现有的数据模型。对于已经用PostgreSQL的团队,这相当于免费获得了一个向量数据库

安装:比想象中少一步

安装:比想象中少一步

如果你在用本地PostgreSQL,从GitHub拉取pgvector源码编译安装,然后执行CREATE EXTENSION vector;。托管服务更省事——Rivestack默认开启,AWS RDS和Google Cloud SQL也只需勾选一个选项。

Python侧的安装堪称极简:pip install pgvector。但这里有个容易踩的坑:pgvector是PostgreSQL的扩展,不是独立的Python库。你真正需要的是数据库驱动,二选一:

追求性能选psycopg3(推荐),习惯ORM选SQLAlchemy。前者直接、异步原生支持;后者让你能用熟悉的模型层操作向量。我见过的生产环境,70%用psycopg3,30%用SQLAlchemy——没有对错,看团队习惯。

psycopg3实战:三行代码打通任督二脉

psycopg3实战:三行代码打通任督二脉

连接数据库后,关键的一步是register_vector(conn)。这行代码容易被忽略,但没有它,Python的列表或NumPy数组无法正确序列化为PostgreSQL的vector类型。报错信息通常是"can't adapt type 'list'",新手能卡半小时。

建表时,VECTOR(1536)里的数字必须匹配你的嵌入模型维度。OpenAI的text-embedding-3-small是1536,text-embedding-3-large是3072,开源的BGE-base是768。填错了不会报错,但查询结果会莫名其妙地错——这种沉默的失败最折磨人。

插入数据的方式很PostgreSQL:

%s占位符,把嵌入向量作为普通参数传入。pgvector会自动处理类型转换。批量插入时,executemany比循环单条快10倍以上,这点和常规SQL没区别。

查询是pgvector的精髓。<=>操作符计算余弦距离,<#>计算内积,<->计算欧氏距离。大多数RAG场景用余弦距离,所以你会写:

打开网易新闻 查看精彩图片

SELECT content, embedding <=> %s AS distance FROM documents ORDER BY distance LIMIT 5;

返回的结果按相似度排序,distance越小越相关。这个查询能在百万级向量上毫秒级返回——前提是建了索引。

索引:不做就是自虐

pgvector支持两种索引:IVFFlat和HNSW。IVFFlat快但精度有损失,HNSW慢建但查询更快、精度更高。2024年的共识是:除非数据量极小,否则直接用HNSW。

建索引的语法:

CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);

注意vector_cosine_ops——它告诉PostgreSQL这个索引用于余弦距离查询。如果你用欧氏距离却建了cosine_ops索引,查询会变慢但不会报错,这种隐式陷阱让人抓狂。

索引参数调优是个深水区。m控制图密度(默认16,越大查询越快但内存越多),ef_construction控制建图质量(默认64,越大精度越高但建索引越慢)。我的经验:百万向量用默认,千万级向量把ef_construction调到128-256。

SQLAlchemy路线:ORM党的救赎

SQLAlchemy路线:ORM党的救赎

如果你重度依赖SQLAlchemy,pgvector也有对应封装。安装pgvector-sqlalchemy,然后用Vector类型定义模型字段:

embedding = Column(Vector(1536))

查询语法稍微绕一点,需要用func包装操作符

打开网易新闻 查看精彩图片

session.query(Document).order_by(Document.embedding.cosine_distance(query_vector)).limit(5).all()

SQLAlchemy的代价是多一层抽象,调试时看生成的SQL会费点劲。但好处是模型层统一,适合已有大量SQLAlchemy代码的 legacy 项目迁移。

RAG流水线:从玩具到生产

RAG流水线:从玩具到生产

真正的考验是把pgvector塞进RAG流程。一个最小可用的架构:文本分块→调用嵌入API→写入pgvector→接收查询→向量检索→LLM生成。

分块策略直接影响检索质量。固定长度分块(如每512 token)实现简单,但会在句子中间切断语义。递归分块按段落、句子层级拆分,效果更好但代码复杂。我见过最粗暴的方案——直接按换行符分——在客服场景居然跑得不错,因为用户问题通常对应单段FAQ。

写入端要注意并发。嵌入API有速率限制,批量请求+指数退避重试是标配。pgvector的写入性能足够好,单节点PostgreSQL每秒处理几千条向量插入没问题。瓶颈通常在嵌入API,而不是数据库。

查询端有个细节:先做向量召回Top-K,再做精排。有些团队会用更重的模型(如交叉编码器)对Top-K结果重新打分,牺牲一点延迟换精度。pgvector只负责第一步,但这一步决定了天花板。

那些文档没写的坑

那些文档没写的坑

pgvector的向量最大维度是16000,超过会报错。大多数模型不会触及这个限制,但用CLIP图像嵌入时要注意。

距离计算在pgvector内部是单精度的,如果你用双精度浮点存储,会有微小精度损失。对搜索排序没影响,但做数值对比时要小心。

最隐蔽的坑:HNSW索引的ef_search参数。它控制查询时的搜索范围,默认40。如果召回结果明显不对,先调到100-200试试。这个参数只能在会话级设置,不能写在索引定义里。

一个被低估的功能:pgvector支持混合查询。你可以同时用向量相似度和全文搜索,用PostgreSQL的tsvectortsquery。比如先全文过滤"退款"相关文档,再在这些文档里做向量检索——比纯向量搜索快一个数量级。