目录

点击展开目录

PostgreSQL 简介

PostgreSQL 是一个强大的开源对象关系数据库系统,以其可靠性、功能稳健性和性能著称。在 AI 时代,通过 pgvector 扩展,PostgreSQL 能够原生支持向量存储和检索,成为构建 AI 应用(如 RAG、Agent Memory)的理想选择。

pgvector 向量数据库实战

基于 pgvector 插件,我们可以将 PostgreSQL 转变为高性能的向量数据库。

环境准备与扩展启用

首先需要创建一个数据库,并启用 vector 扩展。

-- 创建数据库
CREATE DATABASE clawdbot;

-- 切换到该数据库后执行:
-- 启用 pgvector 扩展
CREATE EXTENSION IF NOT EXISTS vector;

向量表结构设计

设计一个用于存储 AI 记忆(Memories)的表,包含内容、向量嵌入(Embedding)、元数据等字段。

关键点

  • embedding vector(1536):根据使用的 Embedding 模型确定维度。例如 OpenAI text-embedding-3-small 为 1536 维。
  • metadata JSONB:使用 JSONB 存储灵活的元数据,支持高效查询。
CREATE TABLE IF NOT EXISTS memories (
  id BIGSERIAL PRIMARY KEY,
  content TEXT NOT NULL,          -- 原始文本内容
  embedding vector(1536),         -- 向量数据,1536维
  metadata JSONB DEFAULT '{}'::jsonb, -- 元数据
  source TEXT,                    -- 数据来源
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

索引类型与选择

pgvector 支持多种索引类型,主要包括 ivfflathnsw

  1. HNSW (Hierarchical Navigable Small World)

    • 特点:查询速度快,召回率高,但构建索引内存消耗大,构建时间长。
    • 适用场景:对性能要求高,数据量较大。
    • SQL
      CREATE INDEX IF NOT EXISTS idx_memories_embedding_hnsw
      ON memories USING hnsw (embedding vector_cosine_ops);
      
  2. IVFFlat (Inverted File Flat)

    • 特点:构建速度快,内存占用小,但查询召回率略低于 HNSW。
    • 适用场景:数据量巨大,内存受限。建议数据量达到一定规模(如几千条)后再构建。
    • SQL
      -- lists 参数通常设置为 rows / 1000
      CREATE INDEX IF NOT EXISTS idx_memories_embedding
      ON memories USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
      

自动更新时间戳机制

利用 PostgreSQL 的触发器(Trigger)实现 updated_at 字段的自动更新。

-- 定义触发器函数
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS trigger AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 绑定触发器
DROP TRIGGER IF EXISTS trg_memories_updated_at ON memories;
CREATE TRIGGER trg_memories_updated_at
BEFORE UPDATE ON memories
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

Python 交互实战 (DeepSeek + OpenAI)

本节展示如何通过 Python 脚本结合 DeepSeek(生成摘要)和 OpenAI(生成向量)并将数据写入 PostgreSQL。

完整流程架构

  1. 输入:读取原始数据(如每日记录、日志)。
  2. 摘要:调用 DeepSeek Chat API 生成“可学习的详细总结”。
  3. Embedding:调用 OpenAI Embedding API (text-embedding-3-small) 将摘要转换为 1536 维向量。
  4. 存储:将摘要文本和向量存入 PostgreSQL memories 表。
  5. 通知:通过 SMTP 发送处理结果邮件。

关键代码实现

1. 向量生成与入库逻辑

import psycopg2
from openai import OpenAI

# 数据库连接
conn = psycopg2.connect(
    dbname="clawdbot",
    user="postgres",
    password="password",
    host="localhost",
    port="5432"
)
cursor = conn.cursor()

# OpenAI 客户端初始化
client = OpenAI(api_key="sk-...")

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

def save_memory(content, source="script"):
    # 生成向量
    vector = get_embedding(content)
    
    # 插入数据库
    sql = """
    INSERT INTO memories (content, embedding, source)
    VALUES (%s, %s, %s)
    """
    cursor.execute(sql, (content, vector, source))
    conn.commit()

2. SMTP 邮件发送配置 (163邮箱示例)

为了避免环境变量漂移导致认证失败,关键配置建议在脚本中明确指定或使用安全的配置管理。

  • 服务器smtp.163.com
  • 端口465 (SSL)
import smtplib
from email.mime.text import MIMEText
from email.header import Header

def send_email(subject, body):
    sender = "[email protected]"
    password = "your_auth_code"  # 授权码,非登录密码
    receivers = ["[email protected]"]

    message = MIMEText(body, 'plain', 'utf-8')
    message['From'] = Header("ClawBot", 'utf-8')
    message['To'] = Header("Admin", 'utf-8')
    message['Subject'] = Header(subject, 'utf-8')

    try:
        smtp_obj = smtplib.SMTP_SSL("smtp.163.com", 465)
        smtp_obj.login(sender, password)
        smtp_obj.sendmail(sender, receivers, message.as_string())
        print("邮件发送成功")
    except smtplib.SMTPException as e:
        print(f"Error: 无法发送邮件, {e}")

生产环境最佳实践

索引构建策略

  • 维度匹配:创建表时必须指定与 Embedding 模型一致的维度(如 1536),否则索引无法构建或查询报错。
  • 重建索引:对于 ivfflat 索引,建议在数据量显著增长后重建索引(REINDEX INDEX),以更新聚类中心,提升召回率。

故障排查与解决

  1. pgvector embedding 为空

    • 检查 Embedding API 调用是否成功。
    • 确认数据库字段类型是否为 vector 且维度正确。
  2. SMTP 发送失败

    • 端口/加密不匹配:163 邮箱强制使用 SSL (465)。
    • 认证失败:检查是否使用了“授权码”而非邮箱密码。
    • 环境问题:进程可能读取到旧的环境变量,建议打印配置进行核对。
  3. 中文编码问题

    • 在 Windows PowerShell 中执行 SQL 文件时,建议显式指定编码:chcp 65001 或在 psql 命令中使用 -f 参数读取 UTF-8 编码的 SQL 文件。