pgvector 实战:用 PostgreSQL 搞定向量检索与 RAG

pgvector 是 PostgreSQL 的向量检索扩展,让你不用额外引入 Chroma、Milvus 这类专用向量数据库,就能用早已熟悉的关系型数据库完成 Embedding 存储与相似度搜索。本文从安装到生产落地,手把手带你在 PostgreSQL 上跑通向量检索,并接进 RAG 知识库。

一、为什么要用 pgvector,而不是再装一个向量库

做 RAG(检索增强生成)时,最核心的一步是把文本切成片段、转成向量(Embedding),再按语义相似度找出最相关的几段。pgvector 的价值在于:你团队里大概率已经有一套稳定运行的 PostgreSQL,为什么还要为「向量」单独养一个组件?多一个向量库,就意味着多一套部署、备份、监控和权限体系。pgvector 以扩展形式寄生在已有 PG 里,运维成本几乎为零。

当然它并非银弹:超大规模(十亿级向量)场景专用向量库仍有优势。但对绝大多数中小型知识库、企业内部检索、原型验证来说,pgvector 的性价比极高。关于 RAG 召回的进阶玩法,可参考我们之前的《大模型 RAG 进阶:混合检索与重排序优化实战》。

要诚实地说,pgvector 不是万能锤。当向量规模冲到十亿级、或需要极致写入吞吐与多副本分片时,专用向量库(如 Milvus、Qdrant)仍有优势。但这类场景在中小企业和大多数产品早期根本碰不到——别为想象中的规模提前买单,先用好手里的 PostgreSQL 才是务实选择。

二、环境准备与扩展安装

pgvector 要求 PostgreSQL 12 及以上,推荐 14+。索引方面,0.5 版本起支持 HNSW 近似索引,查询性能比早期 IVFFlat 好很多。最常见的安装方式是用官方镜像或包管理器,下面以 Docker 为例:

# 直接使用带 pgvector 的 PostgreSQL 镜像
docker run -d --name pgvector \
  -e POSTGRES_PASSWORD=yourpassword \
  -p 5432:5432 \
  ankane/pgvector:latest

# 进入数据库后启用扩展
docker exec -it pgvector psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS vector;"

若你是自建 PG,Debian/Ubuntu 可直接 apt install postgresql-16-pgvector,再执行上面的 CREATE EXTENSION。安装后可用 SELECT vector_version(); 确认版本。

三、定义向量列与基础表结构

向量在 pgvector 里是一种新数据类型 vector(n)n 是维度,必须提前固定,且全表所有向量维度须一致(例如 OpenAI text-embedding-3-small 是 1536 维,bge-m3 是 1024 维)。

CREATE TABLE documents (
    id          BIGSERIAL PRIMARY KEY,
    content     TEXT,                       -- 原始文本
    embedding   vector(1536),              -- 1536 维向量
    created_at  TIMESTAMPTZ DEFAULT now()
);

-- 插入一条:直接用方括号写法表示向量
INSERT INTO documents (content, embedding)
VALUES (
    'PostgreSQL 是最流行的开源关系型数据库',
    '[0.12, -0.03, 0.88, ... , 0.21]'      -- 实际应填入 1536 个浮点数
);

四、写入 Embedding 与相似度计算

pgvector 提供三种距离运算符,对应不同相似度定义:<-> 是欧氏距离(L2),<#> 是负内积,<=> 是余弦距离。一般语义检索用余弦距离最稳妥。下面的 SQL 找出与给定问题向量最相似的 5 条:

-- :query_vec 为问题文本的 1536 维向量
SELECT id, content, embedding <=> :query_vec AS distance
FROM documents
ORDER BY embedding <=> :query_vec
LIMIT 5;

距离越小越相似,排序后取 Top-K 即可作为上下文喂给大模型。这一步的召回质量是否够好,建议用《向量检索评测实战:Recall@K 与 RAG 质量度量》里的方法量化。

实战提醒:送入 Embedding 的文本最好先做好切块与清洗——去重、去噪、控制单段长度在模型 token 上限内。否则向量质量上不去,召回再快也是 garbage in garbage out。切块策略(按段落、按固定字数、按语义边界)本身也会显著影响 RAG 最终效果,值得单独调优。

五、给向量列加索引:IVFFlat 与 HNSW

没有索引时,相似度查询是全表扫描,数据量大了会非常慢。pgvector 支持两种索引,选型差异明显:

维度IVFFlatHNSW
查询精度近似,召回略低近似,召回更高
查询速度极快
构建成本低,需先采样 lists较高,写入变慢
适用规模百万级以下百万到亿级

新项目无脑选 HNSW 即可,语法如下:

CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops);

-- 注意:HNSW 索引需在有一定数据后创建,
-- 并适当调大构建内存以避免落盘变慢
SET maintenance_work_mem = '2GB';

5.1 HNSW 关键参数调优

HNSW 有两个常用调优参数:m 控制每个节点的连接数(默认 16,越大召回越高但越占内存),ef_construction 控制建索引时的搜索宽度(默认 64,越大索引质量越高、构建越慢)。数据量不大时默认值已够用,追求极致召回再逐步上调:

CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

六、把它接进 RAG:一个最小可运行示例

下面用 Python(psycopg + OpenAI 兼容接口)演示「入库 + 检索」闭环,其余 LLM 调用部分可套用《2026 年搭建私有 AI 知识库:Dify + Ollama 本地部署》的架构。

import openai, psycopg
from pgvector.psycopg import register_vector

client = openai.OpenAI(base_url="https://your-endpoint/v1", api_key="sk-xxx")
conn = psycopg.connect("dbname=postgres user=postgres password=xxx")
register_vector(conn)

def embed(text):
    r = client.embeddings.create(model="text-embedding-3-small", input=text)
    return r.data[0].embedding

# 入库
with conn.cursor() as cur:
    cur.execute("INSERT INTO documents(content, embedding) VALUES (%s, %s)",
                ("pgvector 让 PG 支持向量检索", embed("pgvector 让 PG 支持向量检索")))
    conn.commit()

# 检索 Top-5
q = embed("PostgreSQL 怎么做语义搜索?")
with conn.cursor() as cur:
    cur.execute("SELECT content FROM documents ORDER BY embedding <=> %s LIMIT 5", (q,))
    for row in cur.fetchall():
        print(row[0])

七、生产落地注意事项

1. 索引构建时机。 空表上直接建 HNSW 索引,写入会明显变慢。建议先灌入全量数据,再建索引;之后的增量写入影响可控。

2. 查询计划与性能。 向量检索慢时,先确认是否真的走了索引(EXPLAIN 看是否出现 Index Scan)。PG 的慢查询排查套路与本站《PostgreSQL 慢查询优化:执行计划解读与索引调优》一致,核心都是读懂执行计划。

3. 维度统一与迁移。 一旦表定下 1536 维,后续换 Embedding 模型就要重建列,早期规划好很重要。若你已在用独立向量库,可参考《Chroma 向量数据库实战》对比两者的取舍。

4. 混合检索。 纯向量召回容易漏掉关键词精确匹配,线上往往把向量检索与全文检索(tsvector)结合,这正是高质量 RAG 的标配。

5. 备份与容灾。 好消息是 pgvector 的向量就存在普通表里,你既有的 PG 备份方案(逻辑 dump 或 PITR)天然能覆盖它,无需额外操心。具体做法可直接复用《PostgreSQL 备份与 PITR 时间点恢复实战》里的脚本。

八、小结

pgvector 用极低的接入成本,把「向量检索」这一 RAG 关键能力塞进了你本来就有的 PostgreSQL。落地清单:① 选 PG 14+ 并装扩展;② 固定向量维度建表;③ 用余弦距离做相似度;④ 数据就绪后建 HNSW 索引;⑤ Python 侧入库+检索闭环;⑥ 配合混合检索与评测持续优化。当你不想为向量再养一套系统时,pgvector 就是那把最顺手的锤子。

上一篇 Java 模式匹配实战:instanceof 与 switch 模式进化
下一篇 OOMKilled 排查实战:容器内存限制与 JVM 堆外