首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >PostgreSQL+pgvector:大模型 RAG 的「结构化 + 向量」混合检索

PostgreSQL+pgvector:大模型 RAG 的「结构化 + 向量」混合检索

作者头像
玄同765
发布2026-01-14 13:18:52
发布2026-01-14 13:18:52
290
举报

🔗 系列前情回顾

前 3 篇我们完成了「大模型应用 SQL 基础→对话历史存储」的落地:

  1. 第 1 篇明确「大模型 RAG 必须同时用 SQL 和向量库」(纯向量库无法过滤结构化条件);
  2. 第 2 篇学会了 PostgreSQL 的JSONB动态元数据、CREATE INDEX索引优化;
  3. 第 3 篇用 FastAPI+SQL 实现了大模型对话历史的结构化存储。

今天我们升级到企业级 RAG 场景:用「PostgreSQL+pgvector」实现结构化元数据过滤 + 向量语义检索混合检索—— 这是当前大模型 RAG 的标准生产架构


📌 核心背景:为什么需要「混合检索」?

纯向量检索只能解决「找和提问语义相似的文档」,但企业级场景常需结构化条件过滤

例 1:检索「2024 年发布的、关于「大模型推理加速」的技术文档」 例 2:检索「VIP 用户可见的、关于「PostgreSQL 优化」的知识库」

此时必须将「SQL 结构化过滤(年份 / VIP 权限)」和「向量语义检索(内容相似性)」结合,这就是「混合检索」—— 而PostgreSQL+pgvector可以在数据库层面完成混合检索,避免跨系统数据传输的性能损耗。


✅ 前置准备(Docker 一键部署,零环境配置)

为了避免 PostgreSQL 和 pgvector 的安装复杂度,我们用Docker 一键部署(已内置 pgvector 0.6.2):

1. 安装 Docker
  • 下载地址:Docker Desktop(Windows/Mac/Linux 通用);
  • 安装后启动 Docker,确保docker --version命令可执行。
2. 一键启动 PostgreSQL+pgvector

新建docker-compose.yml文件:

代码语言:javascript
复制
version: '3.8'
services:
  pgvector:
    image: pgvector/pgvector:pg15
    container_name: pgvector-llm
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: llm_user     # 数据库用户(后续代码用)
      POSTGRES_PASSWORD: llm_pass # 数据库密码(后续代码用)
      POSTGRES_DB: llm_db         # 数据库名(后续代码用)
    volumes:
      - pgvector-data:/var/lib/postgresql/data # 数据持久化
volumes:
  pgvector-data:

启动命令(终端运行):

代码语言:javascript
复制
docker-compose up -d

验证:终端运行docker ps,看到pgvector-llm容器运行即成功。


📝 步骤 1:创建「RAG 文档表」

我们创建带向量字段 + JSONB 动态元数据的文档表 ——复用系列第 2 篇的 SQL 语法

1.1 连接 PostgreSQL

psql工具连接(或用 DBeaver/Navicat 可视化工具):

代码语言:javascript
复制
# 连接命令(替换为你的密码/端口)
psql -h localhost -p 5432 -U llm_user -d llm_db
1.2 创建表结构(关联系列第 2 篇的 JSONB / 索引知识点)
代码语言:javascript
复制
-- 1. 启用pgvector扩展(PostgreSQL 15+自动安装,仅需启用)
CREATE EXTENSION IF NOT EXISTS vector;

-- 2. 创建RAG文档表【严格复用系列第2篇的SQL语法】
CREATE TABLE rag_documents (
    id SERIAL PRIMARY KEY,                -- 自增ID(系列第2篇:SERIAL语法)
    doc_title VARCHAR(255) NOT NULL,      -- 文档标题(VARCHAR:短文本)
    doc_content TEXT NOT NULL,            -- 文档内容(TEXT:长文本,系列第2篇知识点)
    doc_meta JSONB NOT NULL,              -- 动态元数据(JSONB:系列第2篇核心知识点)
    doc_embedding VECTOR(1536) NOT NULL   -- 向量字段:1536维(OpenAI/智谱等主流模型)
);

-- 3. 创建索引【严格复用系列第2篇的索引优化知识点】
-- ① JSONB元数据索引:用于结构化过滤
CREATE INDEX idx_doc_meta ON rag_documents USING GIN(doc_meta);
-- ② 向量索引:用于语义检索(IVFFlat:pgvector推荐的近似索引,召回率≥95%)
CREATE INDEX idx_doc_embedding ON rag_documents USING ivfflat(doc_embedding vector_cosine_ops) WITH (nlist=100);
-- ③ 复合索引:加速混合检索的前过滤
CREATE INDEX idx_doc_meta_year ON rag_documents ((doc_meta ->> 'year')::INT);

🔍 系列知识点关联

代码语句

对应系列第 2 篇所学 SQL 知识点

CREATE EXTENSION

PostgreSQL 扩展安装语法

JSONB NOT NULL

大模型 RAG 动态元数据存储(系列第 2 篇核心)

CREATE INDEX USING GIN

JSONB 字段的索引优化(系列第 2 篇知识点)

VECTOR(1536)

向量数据类型(前序第 1 篇已说明向量库与 SQL 的结合)

vector_cosine_ops

余弦相似度计算(符合大模型语义检索的需求)


🚀 步骤 2:插入测试数据 + 实现「混合检索」

2.1 插入带向量 + 元数据的测试数据

我们插入 3 条带结构化元数据模拟向量的文档:

代码语言:javascript
复制
-- 插入测试数据:模拟3篇关于大模型的文档
INSERT INTO rag_documents (doc_title, doc_content, doc_meta, doc_embedding)
VALUES 
-- 文档1:2024年发布的大模型推理加速文档
('大模型推理加速指南', 'vLLM是一款高性能大模型推理框架...', '{"year": 2024, "type": "技术文档", "visible": "all"}', '[0.123, 0.456, 0.789, ...]'::VECTOR(1536)),
-- 文档2:2023年发布的大模型训练文档
('大模型训练调参手册', 'LoRA是一种高效的模型微调技术...', '{"year": 2023, "type": "技术文档", "visible": "all"}', '[0.234, 0.567, 0.890, ...]'::VECTOR(1536)),
-- 文档3:2024年发布的VIP专属文档
('大模型RAG企业级落地方案', 'PostgreSQL+pgvector是企业级RAG的最佳选择...', '{"year": 2024, "type": "解决方案", "visible": "vip"}', '[0.345, 0.678, 0.901, ...]'::VECTOR(1536));

注意:[0.123, ...]需替换为真实模型生成的 1536 维向量,这里用模拟值演示语法。

2.2 实现「混合检索」(核心功能)

我们实现系列第 1 篇提到的核心需求:「检索 2024 年发布的、关于「大模型推理加速」的文档」

代码语言:javascript
复制
-- 【混合检索核心SQL】
-- 1. 结构化过滤:先筛选2024年发布的文档(前过滤,减少向量检索的数据量)
-- 2. 向量检索:再查找与「大模型推理加速」语义相似的文档
-- 3. 排序:按相似度降序,取前3条
SELECT 
    doc_title, 
    doc_content,
    doc_meta ->> 'year' AS publish_year,
    1 - (doc_embedding <=> '[0.123, 0.456, ...]'::VECTOR(1536)) AS similarity  -- 余弦相似度(1-距离=相似度)
FROM rag_documents
WHERE 
    doc_meta ->> 'year' = '2024'  -- 结构化过滤:2024年发布
    AND doc_meta ->> 'visible' = 'all'  -- 结构化过滤:所有人可见
ORDER BY similarity DESC  -- 按语义相似度排序
LIMIT 3;

🎯 检索结果说明

  • 仅返回「2024 年发布 + 所有人可见」的文档;
  • 按与「大模型推理加速」的语义相似度排序;
  • 所有检索逻辑在数据库层面完成,无需在应用层做二次过滤。

🔧 步骤 3:用 Python+FastAPI 实现「混合检索接口」(落地 RAG 服务)

我们将混合检索封装为 FastAPI 接口,复用系列第 3 篇的 FastAPI 架构

3.1 依赖安装

新建requirements.txt

代码语言:javascript
复制
fastapi==0.104.1
uvicorn[standard]==0.24.0
sqlalchemy==2.0.23
psycopg2-binary==2.9.9  # PostgreSQL的Python驱动
pydantic==2.5.0

安装命令:

代码语言:javascript
复制
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
3.2 实现混合检索接口

新建main.py复用系列第 3 篇的数据库连接 / 接口规范

代码语言:javascript
复制
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy import create_engine, JSON, Text, String, Integer, Column, Index, VECTOR
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from pydantic import BaseModel
from typing import List

# --------------------------
# 1. 数据库连接(复用系列第3篇的架构)
# --------------------------
DATABASE_URL = "postgresql://llm_user:llm_pass@localhost:5432/llm_db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

# --------------------------
# 2. 定义RAG文档表ORM模型(复用系列第2篇的结构)
# --------------------------
class RagDocument(Base):
    __tablename__ = "rag_documents"
    id = Column(Integer, primary_key=True, index=True)
    doc_title = Column(String(255), index=True)
    doc_content = Column(Text)
    doc_meta = Column(JSON)  # 对应SQL的JSONB类型
    doc_embedding = Column(VECTOR(length=1536))  # 向量字段,1536维

# --------------------------
# 3. FastAPI初始化+依赖
# --------------------------
app = FastAPI(title="大模型RAG混合检索API", version="1.0")

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# --------------------------
# 4. 请求/响应模型
# --------------------------
class RAGRequest(BaseModel):
    prompt: str  # 用户提问
    year: int  # 结构化过滤:发布年份
    visible: str = "all"  # 结构化过滤:可见权限

class RAGResponse(BaseModel):
    doc_title: str
    publish_year: str
    content: str
    similarity: float

# --------------------------
# 5. 混合检索接口(核心功能)
# --------------------------
@app.post(
    "/rag/hybrid",
    response_model=List[RAGResponse],
    summary="大模型RAG混合检索接口",
    description="结构化元数据过滤+向量语义检索"
)
async def rag_hybrid_search(request: RAGRequest, db: Session = Depends(get_db)):
    try:
        # 模拟生成用户提问的向量(真实场景用OpenAI/智谱API生成)
        user_embedding = [0.123, 0.456, ...]  # 替换为真实向量
        
        # 【混合检索】执行SQL(ORM自动生成对应SQL语句)
        # 对应前面的核心SQL:WHERE year=2024 AND visible=all ORDER BY similarity DESC
        docs = db.query(RagDocument)\
                .filter(RagDocument.doc_meta["year"] == request.year)\
                .filter(RagDocument.doc_meta["visible"] == request.visible)\
                .order_by(RagDocument.doc_embedding <=> user_embedding)\
                .limit(3)\
                .all()
        
        # 转换为响应格式
        return [
            RAGResponse(
                doc_title=doc.doc_title,
                publish_year=str(doc.doc_meta["year"]),
                content=doc.doc_content,
                similarity=float(1 - (doc.doc_embedding <=> user_embedding))
            ) for doc in docs
        ]
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"检索失败:{str(e)}")

# --------------------------
# 启动命令:uvicorn main:app --reload
# --------------------------

🧪 测试验证

启动接口uvicorn main:app --reload

测试混合检索:访问http://127.0.0.1:8000/docs,点击POST /rag/hybrid,输入参数:

代码语言:javascript
复制
{
  "prompt": "大模型推理加速",
  "year": 2024,
  "visible": "all"
}

验证结果:仅返回「2024 年发布 + 所有人可见」的文档,且按语义相似度排序;

SQL 层面验证:在 PostgreSQL 中执行前面的混合检索 SQL,结果与接口返回一致。


📌 企业级优化建议

1. 索引优化
  • 对高频结构化过滤字段(如year)创建表达式索引CREATE INDEX idx_doc_year ON rag_documents ((doc_meta ->> 'year')::INT);
  • 向量索引的nlist参数建议设置为sqrt(数据总量)(如 10 万条数据设为 316)。
2. 性能优化
  • 前过滤优先:先做结构化过滤,减少向量检索的数据量;
  • 向量维度压缩:用PGVectorTRUNC()函数压缩向量维度(如从 1536 维压缩到 256 维);
  • 批量检索:用BATCH模式批量处理检索请求。

🔮 系列预告与知识点承接
  • 已学:大模型为什么用 SQL→大模型必备 SQL 语法→对话历史存储→RAG 混合检索落地
  • 下篇:《大模型 RAG 的工程化优化:从 1 秒到 100 毫秒》—— 优化检索性能、缓存策略、错误处理。

配套工具DBeaver(免费的 PostgreSQL 可视化工具) 系列专栏CSDN・从零学 SQL + 大模型应用落地

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 📌 核心背景:为什么需要「混合检索」?
  • ✅ 前置准备(Docker 一键部署,零环境配置)
    • 1. 安装 Docker
    • 2. 一键启动 PostgreSQL+pgvector
  • 📝 步骤 1:创建「RAG 文档表」
    • 1.1 连接 PostgreSQL
    • 1.2 创建表结构(关联系列第 2 篇的 JSONB / 索引知识点)
  • 🚀 步骤 2:插入测试数据 + 实现「混合检索」
    • 2.1 插入带向量 + 元数据的测试数据
    • 2.2 实现「混合检索」(核心功能)
  • 🔧 步骤 3:用 Python+FastAPI 实现「混合检索接口」(落地 RAG 服务)
    • 3.1 依赖安装
    • 3.2 实现混合检索接口
  • 🧪 测试验证
  • 📌 企业级优化建议
    • 1. 索引优化
    • 2. 性能优化
    • 🔮 系列预告与知识点承接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档