引言:PostgreSQL 的 AI 时代转型
当 Milvus、Qdrant、Weaviate 等专用向量数据库在 AI 浪潮中崛起时,一个令人意外的事实是——全球开发者正在用 PostgreSQL 承载越来越多的 AI 工作负载。这不是技术怀旧,而是 pgvector 扩展带来的范式转移:2025 年,pgvector 0.8.0 引入的 HNSW 索引性能已经逼近专用向量数据库,同时保留了 PostgreSQL 生态数十年的可靠性、事务一致性和运维经验。
本文从生产环境出发,深入分析 PostgreSQL 在 AI 时代的多模态能力矩阵,结合真实场景给出完整的架构设计方案。
一、pgvector 核心原理:从 IVFFlat 到 HNSW
1.1 向量索引演进史
pgvector 经历三代索引算法的迭代:
| 索引类型 | 时间 | 算法 | 精度 | 速度 | 内存 |
|---|---|---|---|---|---|
| Flat (暴力搜索) | 2021 | 无索引 | 100% | 线性 | 低 |
| IVFFlat | 2021 | 倒排文件 | 95-99% | 快 | 中 |
| HNSW | 2023 | 分层小世界图 | 99%+ | 最快 | 高 |
| HNSW + SQ8 | 2025 | 量化压缩 | 97-99% | 极快 | 最低 |
HNSW(Hierarchical Navigable Small World)的核心思想是构建多层图结构:高层稀疏用于快速导航,底层稠密用于精确搜索。查询时从顶层开始,逐层细化,时间复杂度为 O(log n)。
1.2 创建向量列与索引
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}',
embedding vector(1536),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);
二、距离函数的正确选择
- cosine(余弦距离):OpenAI、Cohere、大多数现代 Embedding 模型。使用
vector_cosine_ops。 - L2 / euclidean(欧氏距离):CLIP 图像向量、部分专用模型。使用
vector_l2_ops。 - inner product(内积):某些检索模型输出未归一化向量时使用。使用
vector_ip_ops。
SELECT id, content,
1 - (embedding <=> '[0.0123, -0.0456,...]'::vector) AS similarity
FROM documents
ORDER BY embedding <=> '[0.0123, -0.0456,...]'::vector
LIMIT 10;
三、混合检索:向量搜索 + 全文搜索 + 结构化过滤
pgvector 的真正威力在于它能与 PostgreSQL 的全文搜索、B-tree 索引、GIN 索引无缝组合——实现所谓"混合检索"(Hybrid Search)。
3.1 tsvector 全文索引 + 向量搜索
ALTER TABLE documents ADD COLUMN search_vec tsvector
GENERATED ALWAYS AS (to_tsvector('english', content)) STORED;
CREATE INDEX idx_search_vec ON documents USING GIN(search_vec);
WITH vector_scores AS (
SELECT id, 1 - (embedding <=> query_vec) AS vec_score
FROM documents ORDER BY embedding <=> query_vec LIMIT 100
),
text_scores AS (
SELECT id, ts_rank(search_vec, query_tsquery) AS txt_score
FROM documents WHERE search_vec @@ query_tsquery
)
SELECT d.id, d.content,
(0.7 * v.vec_score + 0.3 * COALESCE(t.txt_score, 0)) AS combined_score
FROM vector_scores v
LEFT JOIN text_scores t USING (id)
JOIN documents d ON d.id = v.id
ORDER BY combined_score DESC LIMIT 10;
3.2 RRF(Reciprocal Rank Fusion)融合算法
WITH vector_recall AS (
SELECT id, ROW_NUMBER() OVER (ORDER BY embedding <=> query_vec) AS rank
FROM documents ORDER BY embedding <=> query_vec LIMIT 50
),
text_recall AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY ts_rank(search_vec, query_tsquery) DESC) AS rank
FROM documents WHERE search_vec @@ query_tsquery LIMIT 50
),
rrf_fusion AS (
SELECT id, SUM(1.0 / (60 + rank)) AS rrf_score
FROM (
SELECT id, rank FROM vector_recall
UNION ALL
SELECT id, rank FROM text_recall
) combined GROUP BY id
)
SELECT d.*, r.rrf_score
FROM rrf_fusion r
JOIN documents d ON d.id = r.id
ORDER BY r.rrf_score DESC LIMIT 10;
公式中常数 k=60 防止头部排名权重过高,确保低排名结果也有被选中的机会。
四、PostgreSQL vs 专用向量数据库:选型决策框架
4.1 性能基准对比(1000 万向量,1536 维,99% recall)
| 指标 | pgvector HNSW | Milvus 2.4 | Qdrant | Weaviate |
|---|---|---|---|---|
| P99 查询延迟 | 12ms | 8ms | 6ms | 15ms |
| 写入吞吐 | 3K docs/s | 8K docs/s | 5K docs/s | 2K docs/s |
| 最大向量数 | 5000万+ | 数十亿 | 数十亿 | 数亿 |
| 内存占用 | ~90GB | ~60GB | ~55GB | ~120GB |
| 混合检索 | 原生 SQL | DSL | gRPC API | GraphQL |
4.2 场景匹配
选择 PostgreSQL + pgvector 的场景:
- 向量规模在 5000 万以内
- 需要事务一致性(向量 + 业务数据在同一事务)
- 团队已有 PostgreSQL 运维经验
- 混合检索需求强(结构化过滤 + 向量 + 全文)
选择专用向量数据库的场景:
- 向量规模超过 5000 万,需水平扩展
- 纯向量检索,不需复杂关联查询
- 对 P99 延迟要求极苛刻(低于 5ms)
五、实战:构建 LLM 长期记忆存储架构
5.1 记忆模型
- Episodic Memory(情景记忆):用户对话历史和事件记录
- Semantic Memory(语义记忆):知识库和文档理解
- Procedural Memory(程序性记忆):工具使用的经验总结
CREATE TABLE memories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id BIGINT NOT NULL,
agent_id VARCHAR(100) NOT NULL,
memory_type VARCHAR(20) CHECK (memory_type IN ('episodic','semantic','procedural')),
content TEXT NOT NULL,
embedding vector(1536),
importance FLOAT DEFAULT 0.5,
access_count INT DEFAULT 0,
last_accessed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ,
metadata JSONB DEFAULT '{}'
);
CREATE INDEX idx_memories_user_agent
ON memories (user_id, agent_id, memory_type);
CREATE INDEX idx_memories_embedding
ON memories USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
5.2 记忆写入(LLM 提取 + pgvector 存储)
import openai
from pgvector.psycopg2 import register_vector
async def store_memory(user_id, agent_id, conversation, conn):
# 步骤 1: LLM 提取结构化记忆
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "从对话提取关键事实,JSON 格式"},
{"role": "user", "content": conversation}
],
response_format={"type": "json_object"}
)
memories = json.loads(response.choices[0].message.content)["memories"]
# 步骤 2: 批量 embedding
texts = [m["content"] for m in memories]
embeddings = openai.embeddings.create(
model="text-embedding-3-small", input=texts
).data
# 步骤 3: 写入 PostgreSQL
with conn.cursor() as cur:
register_vector(cur)
for mem, emb in zip(memories, embeddings):
cur.execute(
"INSERT INTO memories(user_id,agent_id,memory_type,content,embedding,importance) VALUES(%s,%s,%s,%s,%s,%s)",
[user_id, agent_id, mem["type"], mem["content"], emb.embedding, mem["importance"]]
)
conn.commit()
5.3 记忆检索(向量 + 时间衰减 + 访问频率)
async def recall_memories(user_id, agent_id, query, top_k=5, conn):
query_embedding = openai.embeddings.create(
model="text-embedding-3-small", input=[query]
).data[0].embedding
with conn.cursor() as cur:
register_vector(cur)
cur.execute("""
SELECT id, content, importance,
1 - (embedding <=> %s::vector) AS similarity,
EXP(-0.01 * EXTRACT(DAY FROM NOW() - last_accessed_at)) AS time_decay,
LEAST(access_count::float / 10, 1.0) AS access_boost
FROM memories
WHERE user_id = %s AND agent_id = %s
AND (expires_at IS NULL OR expires_at > NOW())
ORDER BY (
0.6 * (1 - (embedding <=> %s::vector)) +
0.2 * importance +
0.1 * EXP(-0.01 * EXTRACT(DAY FROM NOW() - last_accessed_at)) +
0.1 * LEAST(access_count::float / 10, 1.0)
) DESC LIMIT %s
""", [query_embedding, user_id, agent_id, query_embedding, top_k])
results = cur.fetchall()
# 更新访问统计
for row in results:
cur.execute(
"UPDATE memories SET access_count = access_count + 1, last_accessed_at = NOW() WHERE id = %s",
[row[0]]
)
conn.commit()
return results
六、生产运维:pgvector 性能调优
6.1 PostgreSQL 核心参数
# postgresql.conf work_mem = '256MB' shared_buffers = '8GB' max_parallel_workers_per_gather = 4 max_parallel_maintenance_workers = 4 max_connections = 200 max_wal_size = '4GB'
6.2 HNSW 运行时参数
-- ef_search 控制精度与速度权衡 SET hnsw.ef_search = 100; -- 实时低延迟场景 SET LOCAL hnsw.ef_search = 64; -- 离线高精度场景 SET LOCAL hnsw.ef_search = 200;
6.3 监控查询
-- 索引使用情况
SELECT schemaname, tablename,
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,
idx_scan AS times_used
FROM pg_stat_user_indexes
WHERE indexrelname LIKE 'hnsw%';
-- 表膨胀监控
SELECT relname, n_live_tup, n_dead_tup,
ROUND(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_ratio
FROM pg_stat_user_tables WHERE relname = 'memories';
七、AI Agent 完整多模态存储 Schema
-- 会话表
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id BIGINT NOT NULL,
messages JSONB NOT NULL DEFAULT '[]',
summary_embedding vector(1536),
created_at TIMESTAMPTZ DEFAULT NOW(),
ended_at TIMESTAMPTZ
);
-- 工具调用记忆
CREATE TABLE tool_memories (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT,
agent_id VARCHAR(100),
tool_name VARCHAR(100),
input_params JSONB,
output_result JSONB,
success BOOLEAN,
duration_ms INT,
embedding vector(1536),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Agent 配置
CREATE TABLE agent_configs (
id SERIAL PRIMARY KEY,
agent_name VARCHAR(100) UNIQUE NOT NULL,
system_prompt TEXT,
model VARCHAR(50) DEFAULT 'gpt-4o',
temperature FLOAT DEFAULT 0.7,
tools JSONB DEFAULT '[]',
is_active BOOLEAN DEFAULT true,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
八、2026 年展望
- DiskANN 支持:打破内存限制,支持十亿级向量在 SSD 上运行
- Sparse Vectors:原生稀疏向量,适配 Splade 等稀疏检索模型
- Bitwise Quantization:二进制量化,内存占用降 32 倍
- pg_bm25 扩展:纯 SQL 实现 BM25,与向量检索无缝融合
- Citus 分布式向量:向量数据自动分片到多节点
结语
PostgreSQL + pgvector 并不是要替代专用向量数据库,而是提供了一个务实的、一体化的解决方案。当团队已运行 PostgreSQL 时,引入 pgvector 意味着零额外运维成本就能获得生产可用的向量检索能力。
PostgreSQL 在 AI 时代的多模态转型,本质上是用数据库的"连接"能力来整合企业数据——让向量不再是孤岛,让 AI 能触达企业每一个角落的数据。

发表评论 取消回复