目录
点击展开目录
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 模型确定维度。例如 OpenAItext-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 支持多种索引类型,主要包括 ivfflat 和 hnsw。
HNSW (Hierarchical Navigable Small World):
- 特点:查询速度快,召回率高,但构建索引内存消耗大,构建时间长。
- 适用场景:对性能要求高,数据量较大。
- SQL:
CREATE INDEX IF NOT EXISTS idx_memories_embedding_hnsw ON memories USING hnsw (embedding vector_cosine_ops);
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。
完整流程架构
- 输入:读取原始数据(如每日记录、日志)。
- 摘要:调用 DeepSeek Chat API 生成“可学习的详细总结”。
- Embedding:调用 OpenAI Embedding API (
text-embedding-3-small) 将摘要转换为 1536 维向量。 - 存储:将摘要文本和向量存入 PostgreSQL
memories表。 - 通知:通过 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),以更新聚类中心,提升召回率。
故障排查与解决
pgvector embedding 为空:
- 检查 Embedding API 调用是否成功。
- 确认数据库字段类型是否为
vector且维度正确。
SMTP 发送失败:
- 端口/加密不匹配:163 邮箱强制使用 SSL (465)。
- 认证失败:检查是否使用了“授权码”而非邮箱密码。
- 环境问题:进程可能读取到旧的环境变量,建议打印配置进行核对。
中文编码问题:
- 在 Windows PowerShell 中执行 SQL 文件时,建议显式指定编码:
chcp 65001或在 psql 命令中使用-f参数读取 UTF-8 编码的 SQL 文件。
- 在 Windows PowerShell 中执行 SQL 文件时,建议显式指定编码: