56.实战PostgreSQL-pgvector-FastAPI构建轻量级RAG

实战:PostgreSQL + pgvector + FastAPI 构建轻量级 RAG

码海寻道 · 大模型、智能体与 RAG 工程组件系列第 56 篇

本篇用一个轻量方案串起 RAG 最小闭环:PostgreSQL 保存 Chunk 和业务元数据,pgvector 保存向量,FastAPI 提供检索接口。示例省略真实模型调用,但保留可替换的 Embedding 边界。

一、依赖和数据库准备

bash 复制代码
pip install fastapi uvicorn psycopg[binary] pgvector pydantic

PostgreSQL 启用扩展:

sql 复制代码
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE knowledge_chunks (
    id          bigserial PRIMARY KEY,
    tenant_id   text NOT NULL,
    document_id text NOT NULL,
    content     text NOT NULL,
    embedding   vector(768) NOT NULL,
    status      text NOT NULL DEFAULT 'published',
    created_at  timestamptz NOT NULL DEFAULT now()
);

768 只是示例,必须与实际 Embedding 模型维度一致。

二、创建向量索引

开发阶段可以先用精确检索:

sql 复制代码
SELECT id, document_id, content,
       1 - (embedding <=> '[0.1,0.2,0.3]'::vector) AS similarity
FROM knowledge_chunks
WHERE tenant_id = 'tenant-a'
  AND status = 'published'
ORDER BY embedding <=> '[0.1,0.2,0.3]'::vector
LIMIT 5;

生产环境再根据数据规模和压测选择 HNSW 或 IVFFlat,并注意过滤条件、维护成本和召回率。

索引选择要用固定评测集和真实过滤条件压测,至少比较 Recall@K、P95 延迟、构建时间、内存和更新成本。向量维度、距离度量和归一化方式必须与 Embedding 服务契约一致,改变其中任何一项都应创建新版本索引。

三、Embedding 服务边界

python 复制代码
class EmbeddingService:
    def embed_documents(self, texts: list[str]) -> list[list[float]]:
        # 替换为实际模型或供应商 SDK
        return [[0.0] * 768 for _ in texts]

    def embed_query(self, text: str) -> list[float]:
        return self.embed_documents([text])[0]

服务边界应记录模型名、维度、归一化方式和版本。不要让入库和查询使用不同模型。

四、FastAPI 检索接口

python 复制代码
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from psycopg import AsyncConnection

app = FastAPI()

class SearchRequest(BaseModel):
    query: str = Field(min_length=1, max_length=4000)
    top_k: int = Field(default=5, ge=1, le=20)

@app.post("/api/v1/search")
async def search(request: SearchRequest, tenant_id: str):
    vector = embedding_service.embed_query(request.query)
    async with await AsyncConnection.connect(DATABASE_URL) as conn:
        rows = await conn.execute(
            """
            SELECT id, document_id, content,
                   embedding <=> %s::vector AS distance
            FROM knowledge_chunks
            WHERE tenant_id = %s AND status = 'published'
            ORDER BY embedding <=> %s::vector
            LIMIT %s
            """,
            (str(vector), tenant_id, str(vector), request.top_k),
        )
        return {"items": [dict(row) for row in await rows.fetchall()]}

示例中的 tenant_id 在生产代码中必须来自认证上下文,不能由普通客户端随意传入。

检索接口还应限制 top_k、查询长度、超时和返回字段,并在向量命中后用 PostgreSQL 重新确认文档状态、租户和权限。不要把完整 Chunk 原文无上限返回给前端或模型。

五、从检索到生成

python 复制代码
def build_context(items: list[dict]) -> str:
    return "\n\n".join(
        f"[来源 {i+1}] {item['content']}"
        for i, item in enumerate(items)
    )

def build_prompt(question: str, context: str) -> str:
    return f"""只根据参考资料回答问题。
如果资料不足,请明确说明。

参考资料:
{context}

问题:{question}
"""

实际项目还要加入引用元数据、Reranker、Token 限制和答案持久化。

六、入库接口和幂等

入库时使用 document_id + chunk_index + embedding_model 作为业务唯一键,重复任务不会产生重复 Chunk。正文发生变化时,应生成新版本而不是直接覆盖旧向量。

入库事务应先写业务事实和幂等记录,再异步生成 Embedding;向量写入成功后更新索引状态,最后切换服务版本。Embedding 失败、维度不匹配和数据库提交成功但向量写入失败,都要进入可重试或补偿状态。

七、轻量方案的边界

适合:

  • 原型和小规模生产;
  • 业务过滤和 JOIN 很多;
  • 团队已有 PostgreSQL 运维能力;
  • 查询并发和向量规模可控。

需要评估拆分到 Milvus 的信号:向量搜索明显影响业务 SQL、需要独立扩展、并发和索引规模持续增长。

八、测试清单

  • Embedding 维度与数据库一致;

  • 空查询和超长查询被拒绝;

  • 查询必须带认证租户范围;

  • 新文档写入后可见性可解释;

  • 删除和版本更新有补偿;

  • Recall@K 和 P95 延迟有基线;

  • 数据库参数化查询防止注入。

  • 查询超时、结果数量和上下文长度有上限;

  • 权限过滤和删除后的向量清理可验证;

  • Embedding、Chunk 和索引版本可以回滚。

结语

PostgreSQL + pgvector + FastAPI 是验证轻量 RAG 的好起点:组件少、业务关联方便,也能覆盖上传后的 Chunk 存储、向量检索和回答生成。等指标证明需要独立扩展时,再迁移到专用向量数据库。

下一篇将把 Milvus、Redis 和 MinIO 加入架构,构建更接近企业场景的知识库。

参考资料

  1. pgvector 官方项目
  2. PostgreSQL 官方文档
  3. FastAPI 官方文档

本文为"码海寻道"原创技术文章。SQL、pgvector 和 Embedding 示例需结合实际版本、维度和索引配置验证。

相关推荐
2401_832298101 小时前
人工智能时代,我们如何与机器同行
人工智能
田里的水稻1 小时前
PyTorch_TensorBoard展示
人工智能·pytorch·python·深度学习·神经网络
环境栈笔记1 小时前
指纹浏览器 WebRTC 怎么设置?从 ICE 候选、代理出口到功能验证
前端·人工智能·后端·自动化
枯木◊靠推文躺平版1 小时前
Work Agent深度解读:AI长程任务的执行机制与落地边界
人工智能
安睿杰翻译(上海)有限公司1 小时前
涉外商务合同翻译项目复盘:高风险条款、质控链路与交付校验清单
人工智能
Rosanci1 小时前
多个 AI 会话同时改一个项目,怎样避免任务互相踩?
人工智能·agent·ai 编程
张张123y1 小时前
后端第九课:部署上线(把你的 FastAPI 后端真正跑起来给别人用)
python·docker·部署·fastapi
User_芊芊君子2 小时前
KFS异构同步_260条链路DDL自动转换解析
数据库·ai·大模型
xiancai_xianyu2 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架