利用 PostgreSQL 构建 RAG 系统实现智能问答

在现代信息检索和自然语言处理的场景中,检索增强生成 (Retrieval-Augmented Generation, RAG) 系统因其结合了知识库检索和生成模型的优势,成为了一种非常流行的智能问答方法。在这篇博文中,我将展示如何利用PostgreSQL作为向量存储数据库,配合OpenAI嵌入模型LangChain库,构建一个完整的RAG系统。

RAG 系统简介

RAG 系统的核心理念是:首先从知识库中检索与问题相关的文档或片段,然后通过生成式语言模型(如GPT)生成基于检索结果的答案。这种方法不仅提升了模型的问答准确性,还能够在多种场景中扩展大语言模型的应用。

在本文中,我们将使用:

  • LangChain:一个为构建语言模型应用提供丰富工具的框架。
  • PostgreSQL:作为存储文本片段及其嵌入向量的数据库。
  • OpenAI API:为文档生成嵌入向量并使用 GPT 模型生成答案。

主要实现步骤

1. 环境准备与库的导入

我们首先需要导入必要的库,其中包括用于数据库连接的psycopg2,用于加载网页的bs4,以及LangChain相关的库。

import getpass
import os
import psycopg2
from psycopg2.extras import execute_values
import bs4
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
import numpy as np
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain_core.output_parsers import StrOutputParser

2. 加载网页内容

我们将网页内容加载为文本,并使用LangChain提供的WebBaseLoader来解析网页,并提取需要的内容。

# 加载网页内容
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(class_=("post-content", "post-title", "post-header"))
    ),
)
docs = loader.load()

3. 文本切分

由于大语言模型处理较长文本时会受到限制,因此我们需要对加载的文本进行切分。在此处,使用RecursiveCharacterTextSplitter按照指定的字符大小将文本切分为多个块。

# 文本切分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)

4. 连接 PostgreSQL 并存储嵌入向量

在这里,我们将利用PostgreSQL作为数据库,存储文本的嵌入向量。我们首先连接数据库,然后利用OpenAI的嵌入模型生成文本向量,并存储到数据库中。

# 连接到 PostgreSQL 数据库
conn = psycopg2.connect(
    host="localhost",  # 根据需要更改
    database="mydb",  # 更改为你的数据库名
    user="root",  # 更改为你的用户名
    password=getpass.getpass("请输入你的 PostgreSQL 密码: ")
)
cur = conn.cursor()

# 嵌入并存储向量
embedding_model = OpenAIEmbeddings()

def store_vectors_in_pg(splits):
    embeddings = embedding_model.embed_documents([doc.page_content for doc in splits])

    data = [
        (0, 0, doc.page_content, embedding)
        for doc, embedding in zip(splits, embeddings)
    ]

    insert_query = """
    INSERT INTO knowledge.vector_data_1 (user_id, file_id, content, featrue)
    VALUES %s
    """
    execute_values(cur, insert_query, data)
    conn.commit()

store_vectors_in_pg(splits)

5. 从数据库检索相似文档

通过查询PostgreSQL中的向量数据,基于余弦相似度查找与用户查询相似的文档。我们利用向量索引(HNSW)来高效检索相似文本片段。

# 检索相似文档
def retrieve_similar_docs(query, k=5):
    query_embedding = embedding_model.embed_query(query)

    embedding_str = f"'{str(query_embedding)}'"

    retrieve_query = f"""
        SELECT content, featrue
        FROM knowledge.vector_data_1
        ORDER BY featrue <-> {embedding_str}
        LIMIT %s
    """
    cur.execute(retrieve_query, (k,))

    results = cur.fetchall()

    return [result[0] for result in results]

6. 构建 RAG 链并生成答案

我们使用LangChain的ChatOpenAI模型和Prompt链来完成生成答案的过程。

# 定义 RAG 链
prompt = hub.pull("rlm/rag-prompt")

input_data = {
    "context": format_docs(retrieved_docs),
    "question": query
}

# 构建 RAG 链
rag_chain = (
    prompt
    | ChatOpenAI(model="gpt-4o-mini")
    | StrOutputParser()
)

# 生成答案
response = rag_chain.invoke(input_data)
print(response)

7. 关闭数据库连接

在程序结束时,别忘了关闭数据库连接。

cur.close()
conn.close()

完整代码实例

# 导入必要的库
import getpass
import os
import psycopg2
from psycopg2.extras import execute_values
import bs4
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
import numpy as np
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 设置 OpenAI API 密钥
os.environ["OPENAI_API_KEY"] = getpass.getpass("请输入你的 OpenAI API 密钥: ")

# 1. 加载网页内容
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(class_=("post-content", "post-title", "post-header"))
    ),
)
docs = loader.load()

# 2. 切分文本
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)

# 3. 连接到 PostgreSQL 数据库
conn = psycopg2.connect(
    host="localhost",  # 根据需要更改
    database="mydb",  # 更改为你的数据库名
    user="root",  # 更改为你的用户名
    password=getpass.getpass("请输入你的 PostgreSQL 密码: ")
)
cur = conn.cursor()

# 4. 嵌入并将分割后的文本和向量数据存储到 PostgreSQL
embedding_model = OpenAIEmbeddings()

def store_vectors_in_pg(splits):
    # 生成嵌入向量
    embeddings = embedding_model.embed_documents([doc.page_content for doc in splits])

    # 将 numpy.ndarray 转换为 Python 列表
    data = [
        (0, 0, doc.page_content, embedding)  # 假设 user_id 和 file_id 为 0,实际可以调整
        for doc, embedding in zip(splits, embeddings)
    ]

    # 插入数据到 PostgreSQL 表 knowledge.vector_data_1
    insert_query = """
    INSERT INTO knowledge.vector_data_1 (user_id, file_id, content, featrue)
    VALUES %s
    """
    execute_values(cur, insert_query, data)
    conn.commit()

store_vectors_in_pg(splits)

# 5. 从 PostgreSQL 中检索数据并计算相似度
def retrieve_similar_docs(query, k=5):
    # 将查询嵌入为向量
    query_embedding = embedding_model.embed_query(query)

    # 将 query_embedding 转换为 PostgreSQL 可识别的向量字符串格式
    embedding_str = f"'{str(query_embedding)}'"  # 将list转为vector字符串

    # SQL 查询:通过 HNSW 索引查找最相似的文档
    retrieve_query = f"""
        SELECT content, featrue
        FROM knowledge.vector_data_1
        ORDER BY featrue <-> {embedding_str}  -- 使用转换后的字符串进行余弦相似度计算
        LIMIT %s
        """
    cur.execute(retrieve_query, (k,))

    results = cur.fetchall()

    return [result[0] for result in results]  # 返回相似的内容

# 6. 检索并生成答案
query = "任务分解是什么?"
retrieved_docs = retrieve_similar_docs(query)

def format_docs(docs):
    return "\n\n".join(docs)

# 定义 RAG 链
prompt = hub.pull("rlm/rag-prompt")

# 构建 dict 输入
input_data = {
    "context": format_docs(retrieved_docs),
    "question": query
}

# 构建 RAG 链
rag_chain = (
    prompt  # 提示模板
    | ChatOpenAI(model="gpt-4o-mini")  # 使用 OpenAI 的 LLM 模型生成答案
    | StrOutputParser()  # 将输出解析为字符串格式
)

# 生成答案
response = rag_chain.invoke(input_data)

print(response)

# 7. 关闭连接
cur.close()
conn.close()

结论

通过本文,我们展示了如何使用PostgreSQL作为向量存储的数据库,配合OpenAI嵌入模型及LangChain库构建一个简单的RAG系统。这个系统能够高效检索文本片段,并基于检索结果生成回答。RAG 系统在知识问答、信息检索等领域具有广泛的应用前景,尤其是在处理大量结构化或非结构化数据时,结合自然语言处理模型的强大生成能力,可以显著提升用户体验。

希望这篇文章能为你构建自己的RAG系统提供参考!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/882436.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何将Excel表格嵌入Web网页在线预览、编辑并保存到自己服务器上?

猿大师办公助手作为一款专业级的网页编辑Office方案&#xff0c;不仅可以把微软Office、金山WPS和永中Office的Word文档内嵌到浏览器网页中实现在线预览、编辑保存等操作&#xff0c;还可以把微软Office、金山WPS和永中Office的Excel表格实现网页中在线预览、编辑并保存到服务器…

C++的哲学思想

C的哲学思想 文章目录 C的哲学思想&#x1f4a1;前言&#x1f4a1;C的哲学思想☁️C底层不应该基于任何其他语言&#xff08;汇编语言除外&#xff09;☁️只为使用的东西付费&#xff08;不需要为没有使用到的语言特性付费&#xff09;☁️以低成本提供高级抽象&#xff08;更…

在云渲染中3D工程文件安全性怎么样?

在云渲染中&#xff0c;3D工程文件的安全性是用户最关心的问题之一。随着企业对数据保护意识的增强&#xff0c;云渲染平台采取了严格的安全措施和加密技术&#xff0c;以确保用户数据的安全性和隐私性。 云渲染平台为了保障用户数据的安全&#xff0c;采取了多层次的安全措施。…

【VUE3.0】动手做一套像素风的前端UI组件库---Button

目录 引言做之前先仔细看看UI设计稿解读一下都有哪些元素&#xff1a;素材补充 代码编写1. 按钮四周边框2. 默认状态下按钮颜色立体效果3. 鼠标移入聚焦4. 模拟鼠标点击效果 组件封装1. 按类型设置颜色2. 设置按钮禁用状态3. 处理一个bug4. 看下整体组件效果5. 组件完整代码6. …

vue.js 展示一个树形结构的数据视图,并禁用其中默认选中的节点

功能描述 展示树形结构&#xff1a; 使用 Element UI 的 <el-tree> 组件展示树形结构数据。数据由 content 数组提供&#xff0c;树形结构包含了嵌套的节点及其子节点。 默认选中节点&#xff1a; 使用 defaultCheckedKeys 属性指定默认选中的节点。这些节点在树形结构渲…

求职Leetcode题目(11)

1.最长连续序列 解题思路: 方法一&#xff1a; • 首先对数组进行排序&#xff0c;这样我们可以直接比较相邻的元素是否连续。• 使用一个变量 cur_cnt 来记录当前的连续序列长度。• 遍历排序后的数组&#xff1a; 如果当前元素与前一个元素相等&#xff0c;则跳过&#xf…

Debian安装mysql遇到的问题解决及yum源配置

文章目录 一、安装mysql遇到的问题解决二、Debain系统mysql8.0的安装以及远程连接三、彻底卸载软件四、Python 操作 mysql五、debian软件源source.list文件格式说明1. 第一部分2. 第二部分3. 第三部分4. 第四部分5. 关于源的混用问题6. 按需修改自己的sources.list7. 更新软件包…

python爬虫案例——腾讯网新闻标题(异步加载网站数据抓取,post请求)(6)

文章目录 前言1、任务目标2、抓取流程2.1 分析网页2.2 编写代码2.3 思路分析前言 本篇案例主要讲解异步加载网站如何分析网页接口,以及如何观察post请求URL的参数,网站数据并不难抓取,主要是将要抓取的数据接口分析清楚,才能根据需求编写想要的代码。 1、任务目标 目标网…

LabVIEW提高开发效率技巧----使用LabVIEW工具

LabVIEW为开发者提供了多种工具和功能&#xff0c;不仅提高工作效率&#xff0c;还能确保项目的质量和可维护性。以下详细介绍几种关键工具&#xff0c;并结合实际案例说明它们的应用。 1. VI Analyzer&#xff1a;自动检查代码质量 VI Analyzer 是LabVIEW提供的一款强大的工…

Java — LeetCode 面试经典150题(一)

双指针 125.验证回文串 题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回…

验收测试:从需求到交付的全程把控!

在软件开发过程中&#xff0c;验收测试是一个至关重要的环节。它不仅是对软件质量的把关&#xff0c;也是对整个项目周期的全程把控。从需求分析到最终的软件交付&#xff0c;验收测试都需要严格进行&#xff0c;以确保软件能够符合预期的质量和性能要求。 一、需求分析阶段 在…

0-1开发自己的obsidian plugin DAY 1

官网教程有点mismatch&#xff0c;而且从0-100跨度较大&#xff0c;&#x1f4dd;记录一下自己的踩坑过程 首先&#xff0c;官网给的example里只有main.ts&#xff0c;需要自己编译成main.js 在视频教程&#xff08;https://www.youtube.com/watch?v9lA-jaMNS0k&#xff09;里…

K8S服务发布

一 、服务发布方式对比 二者主要区别在于&#xff1a; 1. 部署复杂性&#xff1a;传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等&#xff0c;过程相对复 杂且容易出错。相比之下&#xff0c;Kubernetes服务发布方式 通过使用容器编排和自动化部署工…

大数据新视界 --大数据大厂之 Reactjs 在大数据应用开发中的优势与实践

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

虚幻引擎的射线检测/射线追踪

射线检测在 FPS/TPS 游戏中被广泛应用 什么是射线检测? 两个点行成一条线 , 射线检测是从一个起始点发出一条到终点的射线 , 如果射线命中一个游戏对象&#xff0c;就可以获取到对象命中时的 位置、距离、角度、是否命中、骨骼 等非常多的信息 , 这些信息在射击游戏中至关重…

付费电表系统的通用功能和应用过程参考模型(上)

Generic functions and application process reference model for the Payment Metering System 付费电表系统的通用功能和应用过程参考模型 1. 参考模型 Reference model 1.1 在参考模型中的符号的说明 Legend of symbols used in the reference model 功能框 (function bo…

AWS 管理控制台

目录 控制台主页 AWS 账户信息 AWS 区域 AWS 服务选择器 AWS 搜索 AWS CloudShell AWS 控制面板小部件 控制台主页 注册新的 AWS 账户并登录后&#xff0c;您将看到控制台控制面板。这是与各种 AWS 服务以及其他重要控制台组件进行交互的起点。控制面板由页面顶部的导航…

mqtt网关数据接入rabbitmq,缓存离线数据,实现消息保留

应用场景&#xff1a;网关将设备数据发布至mqtt服务器后&#xff0c;数采程序因为重启或者升级等原因&#xff0c;未能接到到离线的订阅消息&#xff0c;利用rabbitmq-mqtt可将离线数据缓存&#xff0c;待上线后接收 启用mqtt插件 rabbitmq-plugins enable rabbitmq_mqtt

成为谷歌开发者专家(GDE)的经历

大家好&#xff0c;我是张海龙(Jason)。经过一年多的准备&#xff0c;GDE申请 终于正式成功通过面试&#xff0c;成为了国内第一位Firebase GDE。下面对整个过程做个总结&#xff0c;希望对大家有所帮助。 1.什么是 GDE&#xff1f; Google Developers上面有详细的说明&#x…

Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】

Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】 目录 Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】 一、简单介绍 二、状态模式&#xff08;State Pattern&#xff09; 1、什么时候使用状态模式 2、使用状态模式的…