Skip to content

Instantly share code, notes, and snippets.

@luojiyin1987
Created May 18, 2025 12:24
Show Gist options
  • Save luojiyin1987/67c72187c05fb1feda80adbee22434cc to your computer and use it in GitHub Desktop.
Save luojiyin1987/67c72187c05fb1feda80adbee22434cc to your computer and use it in GitHub Desktop.

PostgreSQL 数据库增加 vector 结构并实现 RAG (Retrieval Augmented Generation) 搜索,主要依赖于 PostgreSQL 的扩展能力,特别是 pgvector 扩展。pgvector 扩展为 PostgreSQL 提供了存储和操作向量数据类型的功能,并支持向量相似度搜索。

下面是实现这一目标的详细步骤和说明:

1. 安装 pgvector 扩展

这是实现向量存储和搜索的基础。

  • 前提条件: 你需要一个运行中的 PostgreSQL 数据库实例,并且有权限安装扩展。
  • 安装步骤:
    • 通过包管理器安装 (推荐): 这是最简单的方式。根据你的操作系统,使用相应的包管理器安装 pgvector
      • Debian/Ubuntu:
        sudo apt update
        sudo apt install postgresql-$(pg_config --version | sed 's/.* //')-pgvector
      • CentOS/RHEL/Fedora:
        sudo yum install pgvector_$(pg_config --version | sed 's/.* //')
        # 或者
        sudo dnf install pgvector_$(pg_config --version | sed 's/.* //')
      • macOS (使用 Homebrew):
        brew install pgvector
    • 从源代码编译安装: 如果包管理器没有提供 pgvector,或者你需要特定版本,可以从源代码编译安装。这需要 PostgreSQL 的开发头文件。
      git clone --branch v0.5.0 https://github.com/pgvector/pgvector.git # 替换 v0.5.0 为你需要的版本
      cd pgvector
      make
      sudo make install
  • 在数据库中启用扩展: 安装完成后,需要在你的 PostgreSQL 数据库中启用 pgvector 扩展。连接到你的数据库,然后执行以下 SQL 命令:
    CREATE EXTENSION vector;

2. 设计数据库表结构

你需要一个表来存储你的文本数据和对应的向量表示。

CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT, -- 存储原始文本内容
    embedding vector(1536) -- 存储文本的向量表示,1536 是 OpenAI text-embedding-ada-002 的维度,根据你使用的 embedding 模型调整
);
  • id: 唯一标识符。
  • content: 存储原始的文本内容,这是 RAG 中检索到的信息。
  • embedding: 存储文本内容的向量表示。vector(维度) 指定了向量的维度。你需要根据你使用的 embedding 模型来确定这个维度。例如,OpenAI 的 text-embedding-ada-002 模型生成的向量维度是 1536。

3. 生成文本的向量表示 (Embedding)

在将文本数据插入到数据库之前,你需要使用一个 embedding 模型将文本转换为向量。常用的 embedding 模型包括:

  • OpenAI Embedding API: 易于使用,性能好。
  • Hugging Face Transformers: 提供了大量的开源 embedding 模型,可以在本地运行。
  • Google AI Platform: 提供了 embedding 模型服务。

你需要编写代码来调用这些模型,将你的文本数据转换为向量。

示例 (使用 Python 和 OpenAI):

import openai

# 假设你已经设置了 OpenAI API 密钥
openai.api_key = "YOUR_OPENAI_API_KEY"

def get_embedding(text):
    response = openai.Embedding.create(
        input=text,
        model="text-embedding-ada-002" # 根据你使用的模型调整
    )
    return response['data'][0]['embedding']

# 示例用法
text_to_embed = "这是一个示例文本,用于生成向量。"
embedding = get_embedding(text_to_embed)
print(embedding)

4. 将文本和向量插入数据库

将生成的向量与原始文本一起插入到 documents 表中。

-- 假设你已经获取了文本内容和对应的向量
INSERT INTO documents (content, embedding) VALUES
('这是第一篇文档的内容。', '[0.1, 0.2, 0.3, ...]'), -- 替换 [...] 为实际的向量值
('这是第二篇文档的内容。', '[0.4, 0.5, 0.6, ...]');

在实际应用中,你会通过编程方式批量插入数据。

5. 创建向量索引 (提高搜索效率)

对于大规模的向量数据,创建索引可以显著提高相似度搜索的速度。pgvector 支持多种索引类型,常用的有:

  • IVFFlat (Inverted File Index with Flat compression): 适用于中等规模的数据集,查询速度较快。
  • HNSW (Hierarchical Navigable Small World): 适用于大规模数据集,查询速度和召回率都很好。

选择哪种索引类型取决于你的数据规模和性能需求。

创建 IVFFlat 索引:

CREATE INDEX ON documents USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
-- vector_l2_ops 使用 L2 距离(欧氏距离)进行相似度计算
-- lists 参数影响索引的构建和查询性能,需要根据数据进行调优

创建 HNSW 索引:

CREATE INDEX ON documents USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64);
-- m 和 ef_construction 参数影响索引的构建和查询性能,需要根据数据进行调优

注意:

  • vector_l2_ops 使用 L2 距离(欧氏距离)进行相似度计算。你也可以使用 vector_cosine_ops 进行余弦相似度计算,这在文本相似度搜索中更常用。
  • 索引的构建可能需要一些时间,特别是对于大规模数据。

6. 实现 RAG 搜索流程

RAG 搜索流程通常包括以下步骤:

  • 用户提问: 用户输入一个问题或查询。
  • 问题 Embedding: 使用与文档 embedding 相同的 embedding 模型,将用户的问题转换为向量。
  • 向量相似度搜索: 在数据库中执行向量相似度搜索,找到与问题向量最相似的文档向量。
    • 使用 pgvector 提供的相似度运算符进行查询。
    • 常用的相似度运算符:
      • <->: L2 距离(欧氏距离),距离越小越相似。
      • <#>: 内积,值越大越相似(如果向量是归一化的,内积等于余弦相似度)。
      • <=>: 余弦距离,距离越小越相似(1 - 余弦相似度)。
  • 检索相关文档: 根据相似度搜索结果,获取最相关的 K 篇文档的原始文本内容。
  • 生成回答: 将用户的问题和检索到的相关文档作为输入,发送给一个大型语言模型 (LLM),让 LLM 根据这些信息生成一个回答。

示例 SQL 查询 (使用余弦相似度):

-- 假设 @query_embedding 是用户问题生成的向量
SELECT content
FROM documents
ORDER BY embedding <=> @query_embedding
LIMIT 5; -- 检索最相似的 5 篇文档

示例 Python 代码 (结合数据库查询和 LLM):

import psycopg2
import openai # 或其他 LLM 库

# 数据库连接信息
db_params = {
    "database": "your_db",
    "user": "your_user",
    "password": "your_password",
    "host": "localhost",
    "port": "5432"
}

def get_embedding(text):
    # 调用 embedding 模型生成向量
    response = openai.Embedding.create(
        input=text,
        model="text-embedding-ada-002"
    )
    return response['data'][0]['embedding']

def retrieve_documents(query_embedding, k=5):
    conn = None
    try:
        conn = psycopg2.connect(**db_params)
        cur = conn.cursor()
        # 将向量转换为 PostgreSQL 接受的格式
        embedding_str = '[' + ','.join(map(str, query_embedding)) + ']'
        cur.execute(
            "SELECT content FROM documents ORDER BY embedding <=> %s LIMIT %s",
            (embedding_str, k)
        )
        documents = [row[0] for row in cur.fetchall()]
        return documents
    except (Exception, psycopg2.Error) as error:
        print("Error while fetching data from PostgreSQL", error)
    finally:
        if conn:
            cur.close()
            conn.close()

def generate_answer(question, retrieved_docs):
    # 构建 LLM 输入
    context = "\n".join(retrieved_docs)
    prompt = f"根据以下信息回答问题:\n\n{context}\n\n问题:{question}\n\n回答:"

    # 调用 LLM 生成回答
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo", # 或其他 LLM 模型
        messages=[
            {"role": "system", "content": "你是一个有帮助的助手。"},
            {"role": "user", "content": prompt}
        ]
    )
    return response.choices[0].message['content']

# RAG 搜索示例
user_question = "关于人工智能的最新进展是什么?"
query_embedding = get_embedding(user_question)
retrieved_docs = retrieve_documents(query_embedding)
answer = generate_answer(user_question, retrieved_docs)

print("检索到的文档:")
for doc in retrieved_docs:
    print(f"- {doc[:100]}...") # 打印部分文档内容
print("\n生成的回答:")
print(answer)

总结实现 RAG 搜索的关键步骤:

  1. 安装和启用 pgvector 扩展。
  2. 设计包含 vector 字段的数据库表。
  3. 使用 embedding 模型将文本数据转换为向量。
  4. 将文本和向量存储到数据库中。
  5. 创建向量索引以提高搜索效率。
  6. 实现 RAG 搜索流程:问题 embedding -> 向量相似度搜索 -> 检索文档 -> LLM 生成回答。

优势:

  • 利用 PostgreSQL 的成熟功能: 可以利用 PostgreSQL 的事务、备份、复制等功能。
  • 统一数据存储: 将文本数据和向量数据存储在同一个数据库中,简化管理。
  • 可扩展性: PostgreSQL 可以通过各种方式进行扩展,以处理大规模数据。

需要考虑的因素:

  • Embedding 模型选择: 不同的 embedding 模型性能和成本不同,需要根据需求选择。
  • 向量维度: 向量维度会影响存储空间和计算效率。
  • 索引调优: 向量索引的参数需要根据数据进行调优,以获得最佳性能。
  • LLM 集成: 需要选择合适的 LLM 并进行集成。
  • 数据更新和同步: 如何高效地更新和同步文本数据和对应的向量。

通过以上步骤,你就可以在 PostgreSQL 数据库中增加 vector 结构,并实现基于向量相似度搜索的 RAG 系统。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment