
上周帮朋友排查他的金融 RAG 知识库系统 bug:他用 Milvus 向量库做文档检索,要求查「2024 年发布的 vLLM 推理优化文档」,结果要么返回 2019 年的老教程(向量库先全量检索再后过滤,过滤后无有效结果时返回原始 topN),要么因过滤基数过大直接超时(遍历 120w + 文档后过滤)。
他挠头:「向量库不是号称能搞定所有检索吗?为啥连个年份过滤都搞不定?」
这是大模型开发者的普遍误区:把「向量库 = 大模型存储」,但真实大模型应用的存储需求分 3 类,向量库只解决 1 类,剩下的 2 类必须靠 SQL—— 因为向量库是「语义相似性检索(模糊匹配,找 “像的”)」,SQL 是「结构化约束检索(精确匹配,找 “对的”+ 管 “全的”)」。
先明确大模型应用的核心数据分层,以及对应的技术选型逻辑:
数据类型 | 核心需求 | 最优技术选型 |
|---|---|---|
非结构化内容(文档 / 图片) | 语义相似性检索、多模态匹配 | 向量库(Milvus/Weaviate/pgvector) |
结构化元数据(时间 / 用户 / 权限) | 精准过滤、排序分页、低延迟检索 | SQL(PostgreSQL 11+,推荐 14+) |
运营 / 合规数据(对话历史 / 调用日志) | ACID 事务、精细权限、审计溯源、业务统计 | SQL(必须支持强事务) |
关键结论:向量库仅能覆盖「非结构化内容检索」,而「上下文回溯、混合检索、合规审计」三大核心场景,向量库天生做不好、甚至做不了。
大模型实现「连续对话」需加载当前用户的最近 N 条对话历史,但向量库的「元数据过滤」依赖自研索引(效率远低于 SQL 的 B-Tree),且无法保证「按 user_id 精确过滤 + 按时间排序」的低延迟 —— 当用户量过 10w,向量库的上下文加载耗时是 SQL 的 5~10 倍。
用 SQL 存储对话历史,加复合索引保证核心查询的低延迟:
-- PostgreSQL 14+ 对话历史表(适配分布式场景:用UTC时间)
CREATE TABLE llm_chat_history (
id SERIAL PRIMARY KEY,
user_id VARCHAR(255) NOT NULL, -- 用户唯一标识
prompt TEXT NOT NULL, -- 用户提问
answer TEXT NOT NULL, -- 大模型回答
model_name VARCHAR(50) NOT NULL, -- 调用模型(如gpt-3.5-turbo)
create_time TIMESTAMP WITH TIME ZONE DEFAULT NOW() -- 保存UTC时间,避免时区偏移
);
-- 【核心优化】为上下文查询创建复合索引:user_id+create_time DESC
-- 直接命中B-Tree索引,无需全表扫描,延迟≤10ms
CREATE INDEX idx_chat_user_time ON llm_chat_history(user_id, create_time DESC);
-- 【业务核心SQL】加载当前用户最近5条对话(用于大模型上下文拼接)
SELECT prompt, answer
FROM llm_chat_history
WHERE user_id = 'user_001'
ORDER BY create_time DESC
LIMIT 5;纯向量库的混合检索逻辑是「先全量向量检索→再后过滤结构化条件」,当过滤基数≥10% 总数据量时,性能暴跌。而金融、教育等行业的 RAG 场景,90% 以上需要「结构化条件 + 向量检索」的融合查询(如「2024 年的 vLLM 文档」「VIP 用户可见的技术手册」)。
用PostgreSQL+pgvector 插件(支持 PG11+),依托 PG 成熟的 B-Tree 索引实现高效前过滤(先过滤结构化条件,再对小数据集做向量检索),性能比纯向量库提升 100 倍以上:
-- 1. 安装pgvector插件(PG11+支持,14+索引性能更优)
CREATE EXTENSION IF NOT EXISTS vector;
-- 2. RAG文档表:结构化元数据+向量字段(适配OpenAI/智谱1536维embedding)
CREATE TABLE rag_documents (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
publish_year INT NOT NULL, -- 结构化条件:发布年份(需加B-Tree索引)
embedding VECTOR(1536) NOT NULL -- 向量字段:1536维embedding
);
-- 【前过滤核心】为publish_year创建B-Tree索引
CREATE INDEX idx_doc_publish_year ON rag_documents(publish_year);
-- 【混合检索核心SQL】:2024年发布的、与「vLLM推理加速」最相似的5篇文档
-- 注意:[0.123, 0.456, ...]需替换为OpenAI/智谱生成的**实际1536维embedding数组**
SELECT
title, content, publish_year,
1 - (embedding <=> '[0.123, 0.456, ...]') AS similarity -- 余弦相似度计算(1-距离=相似度)
FROM rag_documents
WHERE publish_year = 2024 -- B-Tree前过滤:仅处理符合条件的小数据集
ORDER BY similarity DESC -- 向量相似性排序
LIMIT 5;技术差异解释:pgvector 的混合检索是「融合执行」,依托 PG 的执行计划优化器自动选择最优路径;而多数向量库的混合检索是「分阶段执行」,索引效率远低于 PG 的 B-Tree。
金融、政务场景的大模型应用必须满足等保 2.0、GDPR等合规要求,需支持:
用 SQL 的成熟合规特性:
-- 1. 创建大模型服务专用账号(仅能查对话历史,强化最小权限原则)
CREATE ROLE llm_service WITH LOGIN PASSWORD 'llm_service_2024_pwd';
-- 2. 仅授权该账号查询对话历史表
GRANT SELECT ON llm_chat_history TO llm_service;
-- 3. 禁止修改数据(默认新建role无修改权限,此处为合规强化)
REVOKE INSERT, UPDATE, DELETE ON llm_chat_history FROM llm_service;
-- 【合规核心】开启PostgreSQL持久化操作日志(修改postgresql.conf)
-- log_statement = 'all' -- 记录所有SQL操作,满足审计要求关键补充:pg_stat_activity 仅为实时会话监控,重启即清空,需依托 postgresql.conf 的日志配置才能满足合规审计要求。
有人会问:用 MongoDB 存结构化数据不行吗?答案是可以但没必要,因为:
graph LR
A[前端对话/检索界面] -->|用户请求| B[FastAPI后端<br/>(异步架构)]
B -->|生成embedding| D[(PostgreSQL 14+<br/>+ pgvector)]
B -->|调用大模型| C[大模型API<br/>(GPT-4/智谱/文心)]
C -->|大模型结果| B
B -->|上下文/元数据查询| D
B -->|混合检索| D
B -->|对话历史存入| D
D -->|结果返回| B
B -->|最终结果| AQ:数据量过亿时,pgvector 性能会不够吗? A:可通过PG 表分区(按时间 / 用户分表)+ pgvector IVFFlat 索引(近似向量检索)优化;或结合 Milvus 做分布式向量检索,SQL 仍负责结构化数据管理。
Q:pgvector 的向量维度支持上限是多少? A:官方支持16384 维,完全覆盖主流 embedding 模型(OpenAI 1536 维、智谱 1024 维)。
Q:用 MySQL + 向量插件可以吗? A:MySQL 8.0.32 + 支持 MyRocks 向量索引,但成熟度、社区生态远不如 PostgreSQL+pgvector。
总结核心逻辑:
下一篇我将带来《2 小时学会大模型应用必备 SQL:最小语法子集》——仅讲大模型应用中必须用的语法,跳过存储过程、触发器等无用知识点。