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
- Debian/Ubuntu:
- 从源代码编译安装: 如果包管理器没有提供
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 搜索的关键步骤:
- 安装和启用
pgvector扩展。 - 设计包含
vector字段的数据库表。 - 使用 embedding 模型将文本数据转换为向量。
- 将文本和向量存储到数据库中。
- 创建向量索引以提高搜索效率。
- 实现 RAG 搜索流程:问题 embedding -> 向量相似度搜索 -> 检索文档 -> LLM 生成回答。
优势:
- 利用 PostgreSQL 的成熟功能: 可以利用 PostgreSQL 的事务、备份、复制等功能。
- 统一数据存储: 将文本数据和向量数据存储在同一个数据库中,简化管理。
- 可扩展性: PostgreSQL 可以通过各种方式进行扩展,以处理大规模数据。
需要考虑的因素:
- Embedding 模型选择: 不同的 embedding 模型性能和成本不同,需要根据需求选择。
- 向量维度: 向量维度会影响存储空间和计算效率。
- 索引调优: 向量索引的参数需要根据数据进行调优,以获得最佳性能。
- LLM 集成: 需要选择合适的 LLM 并进行集成。
- 数据更新和同步: 如何高效地更新和同步文本数据和对应的向量。
通过以上步骤,你就可以在 PostgreSQL 数据库中增加 vector 结构,并实现基于向量相似度搜索的 RAG 系统。