检索增强生成 (RAG) 涉及从外部数据库获取当前或上下文相关信息,并在请求大型语言模型 (LLM) 生成响应时将其呈现给大型语言模型 (LLM) 的过程。 这种方法有效地解决了生成不正确或误导性信息的问题。 你能够存储专有业务数据或全局知识,并使你的应用程序能够在响应生成阶段为 LLM 检索此数据。

1、RAG有什么帮助?

LLM 缺乏领域知识,但我们可以通过利用 RAG 从数据库中检索上下文信息并将其与用户输入一起传递给 LLM 并生成丰富的相关响应来填补这一空白。

在本文中,我们将了解如何使用 LangChain 连接到我们的 SQL 数据库、检索上下文信息、将用户查询和上下文一起传递给 LLM 并生成准确的响应。

2、案例概览

我们将为职业介绍所构建一个定制的 QA 聊天机器人,帮助用户获取就业市场的相关信息。 用户可能想了解热门职位、特定角色在特定领域的受欢迎程度等。

我们使用 Langchain 作为框架、MySQL 数据库和 OpenAI 的 LLM 来构建我们的应用程序。

我们的数据库由一个包含以下列的表组成:

让我们从实施开始。

安装依赖项:

pip install langchain langchain-experimental openai pymysql

导入必要的包:

from langchain.utilities import SQLDatabase
from langchain.llms import OpenAI
from langchain_experimental.sql import SQLDatabaseChain
from langchain.prompts import PromptTemplate
from langchain.prompts.chat import HumanMessagePromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage

初始化LLM:

OPENAI_API_KEY = "your-key-here"
llm = ChatOpenAI(temperature=0, openai_api_key=OPENAI_API_KEY)

我们使用 Langchain 的 ChatOpenAI,它使用 OpenAI 的 gpt3.5-turbo 模型。

数据库设置:

host = 'localhost'
port = '3306'
username = 'root'
password = 'password'
database_schema = 'agency_db'
mysql_uri = f"mysql+pymysql://{username}:{password}@{host}:{port}/{database_schema}"

db = SQLDatabase.from_uri(mysql_uri, include_tables=['job_details'],sample_rows_in_table_info=2)

db_chain = SQLDatabaseChain.from_llm(llm, db, verbose=True)

我们首先构造一个 URI 来连接数据库,这里我使用 pymysql 作为连接 mysql 的驱动程序,但你可以根据你的数据库方言更改它,例如 - postgresql 数据库的连接字符串将与以下完全相同 上面给出的,你只需要将“mysql+pymysql”替换为“postgresql+psycopg2”并通过pip安装psycopg2。

初始化数据库时,我们使用 langchain 中的 SQLDatabase.from_uri() 方法,并传递 URI 和其他一些参数,它们的作用如下:

  • include_tables:我们仅引用 job_details 表并仅查询该表
  • Sample_rows_in_table_info:与数据库交互时,langchain 将接收该表的前 2 行作为示例,以提供额外的上下文和更好的检索

最后一步是设置一个数据库链,这将帮助我们的 LLM 与数据库交互,我们使用 SQLDatabaseChain 来完成此操作。

设置检索功能:

def retrieve_from_db(query: str) -> str:
    db_context = db_chain(query)
    db_context = db_context['result'].strip()
    return db_context

该函数会将用户提供的查询作为输入,将其传递到我们的数据库链,并从数据库中检索相关信息并将其作为字符串返回。

我们将使用提示模板来保持其简洁和易于理解。 提示模板帮助我们构建提示的骨架,我们可以根据用户输入和用例填写模板。

system_message = """You are a professional representative of an employment agency.
        You have to answer user's queries and provide relevant information to help in their job search. 
        Example:
        
        Input:
        Where are the most number of jobs for an English Teacher in Canada?
        
        Context:
        The most number of jobs for an English Teacher in Canada is in the following cities:
        1. Ontario
        2. British Columbia
        
        Output:
        The most number of jobs for an English Teacher in Canada is in Toronto and British Columbia
        """
human_qry_template = HumanMessagePromptTemplate.from_template(
        """Input:
        {human_input}
        
        Context:
        {db_context}
        
        Output:
        """
    )
messages = [
      SystemMessage(content=system_message),
      human_qry_template.format(human_input=query, db_context=db_context)
    ]
response = chat(messages).content

由于我们使用的是聊天模型,因此我们在系统消息中提供说明和示例,使其成为一次性推理任务。

在人类消息中,我们将从数据库检索到的数据与用户查询一起提供给模型。

最后,使用用户输入的查询和从我们的数据库检索的上下文来格式化人工消息模板,并点击聊天模型来生成响应。

将一切拼凑在一起:

def generate(query: str) -> str:
    db_context = retrieve_from_db(query)
    
    system_message = """You are a professional representative of an employment agency.
        You have to answer user's queries and provide relevant information to help in their job search. 
        Example:
        
        Input:
        Where are the most number of jobs for an English Teacher in Canada?
        
        Context:
        The most number of jobs for an English Teacher in Canada is in the following cities:
        1. Ontario
        2. British Columbia
        
        Output:
        The most number of jobs for an English Teacher in Canada is in Toronto and British Columbia
        """
    
    human_qry_template = HumanMessagePromptTemplate.from_template(
        """Input:
        {human_input}
        
        Context:
        {db_context}
        
        Output:
        """
    )
    messages = [
      SystemMessage(content=system_message),
      human_qry_template.format(human_input=query, db_context=db_context)
    ]
    response = llm(messages).content
    return response

输入和输出示例:

在这里,我们可以看到数据库链获取了多伦多最受欢迎的工作,并将其作为上下文传递给我们的法学硕士,为我们提供了自然语言的正确答案。

3、结束语

在本文中,我们探讨了检索增强生成 (RAG) 如何在构建特定领域的聊天机器人时改变游戏规则。 RAG 弥合了大型语言模型 (LLM) 和外部数据库之间的差距,确保做出更明智、更准确的响应。

我们讨论了 RAG 通过从数据库动态检索上下文信息来弥补LLM缺乏领域知识的能力。 实际示例是就业机构的 ChatBot,展示了 Langchain 在连接 SQL 数据库并利用 OpenAI 的 LLM 进行精确响应方面的作用。

通过采用 RAG 和 Langchain 等框架,我们为更多上下文感知的人工智能应用程序铺平了道路。 通过提供准确、上下文丰富的信息,可以实现更好的用户体验和决策。 充分利用 RAG 的潜力,释放数据驱动的对话式 AI 的财富。


原文链接:基于SQL库的RAG实现 - BimAnt

相关文章

Redis高并发分布锁实战

Redis分布式锁自己去实现可能会出现几个问题没有在finally显示释放锁,当客户端挂掉了,锁没有被及时删除,这样会导致死锁问题,它这个是需要我们显示的释放锁假如此时我们设置过期时间,但是我们用的是同一个key,就可能出现下一个线程删除上一个线程的锁,但是上一个线程还没有执行完,它这个需要key是不能重复的假如我们既设置了过期时间也指定了不同的key,此时可能因为网络延迟出现上一个线程删除下一个线程的锁,也就是说业务执行的时间超过了锁过期的时间,它这个需要一个锁续命的功能。

Redis是否为单线程?

在深入讨论Redis是否为单线程之前,我们先来了解一下Redis的基本架构。Redis采用了基于内存的数据存储方式,数据存储在内存中,并通过持久化机制将数据定期写入磁盘。客户端:与Redis进行通信的应用程序。Server:负责处理客户端请求、执行命令和管理数据。数据结构:Redis支持多种数据结构,如字符串、列表、哈希表等。事件处理器:用于处理网络事件和命令请求。

MySQL中的高级查询

通过条件查询可以查询到符合条件的数据,但如同要实现对字段的值进行计算、根据一个或多个字段对查询结果进行分组等操作时,就需要使用更高级的查询,MySQL提供了聚合函数、分组查询、排序查询、限量查询、内置函数以实现更复杂的查询需求。接下来将针对这些高级查询的知识进行讲解。

ubuntu20.04安装实时内核补丁PREEMPT_RT

下载实时内核补丁,我下载patch-5.15.148-rt74.patch.sign和patch-5.15.148-rt74.patch.xz。通过以下指令看具体报错并输出日志到make.log:make -j1 deb-pkg 2>&1 | tee ~/make.log。比较幸运没遇到问题,重启进入后,启动页面没有变化,还是进入ubuntu,但是查看内核版本已经自动变到5.15.148。我下载linux-5.15.148.tar.xz和linux-5.15.148.tar.sign。

mysql中文首字母排序查询

MySQL中的排序涉及到字符集和排序规则。默认情况下,MySQL按照ASCII码对字符进行排序,数字>字母>中文。但是,特殊字符(非字母、数字、中文)的排序需要一些额外处理。匹配到非字母数字中文的内容,做排序,字母数字中文为null,排序优先级最高,排在上面。为什么用HEX()函数做十六进制编码?因为中文用常规的正则不能匹配到结果。试过SUBSTRING、LEFT等,都不能完美实现多中文的首字母排序。为什么要把字母数字中文放在一起匹配?因为处理复杂度会更高。这样可以处理更复杂的排序需求。

使用redis-insight连接到服务器上的redis数据库

我们现在虽然安装好了redis数据库,但是外界是连接不到的,我们需要打破这个限制!设置完之后,可以按以下图的命令查看,redis的密码是不是起作用了。的更改,并退出编辑器。在网上下载好redis-insight的客户端,打开。默认情况下,它可能被设置为只监听本地连接,如。这允许在没有进行身份验证的情况下接受外部连接。(3)为了增强安全性,强烈建议设置访问密码。三、使用redis-insight连接数据库。1.查找redis的配置文件。指令,并确保将其设置为。替换为你自己的强密码。

linux docker 部署mysql8以上版本时弹出Access denied for user root @ localhost (using password: YES)的解决方案

mysql8登录第一次遇到MYSQL_ROOT_PASSWORD时会自动把该密码尽兴登录,生成一个秘钥放在mysql的数据文件里面,命令里带的MYSQL_ROOT_PASSWORD密码是个参数,除了第一次运行mysql带上会设置密码生成秘钥,其他次启动而不是设置mysql的密码,而是作为参数去验证这个最初的秘钥是否核对正确,于是我进入挂载的data目录,发现我的猜想是对的。通过docker将服务部署完后,navicat连接报错,密码错误,于是我尝试进入mysql容器登录 发现也报错。

数据湖Paimon入门指南

如果用户建表时指定'merge-engine' = 'partial-update',那么就会使用部分更新表引擎,可以做到多个 Flink 流任务去更新同一张表,每条流任务只更新一张表的部分列,最终实现一行完整的数据的更新,对于需要拉宽表的业务场景,partial-update 非常适合此场景,而且构建宽表的操作也相对简单。这种方式的成本相对较高,同时官方不建议这样使用,因为下游任务在 State 中存储一份全量的数据,即每条数据以及其变更记录都需要保存在状态中。流式查询将不断产生最新的更改。

MySQL运行在docker容器中会损失多少性能

自从使用docker以来,就经常听说MySQL数据库最好别运行在容器中,性能会损失很多。一些之前没使用过容器的同事,对数据库运行在容器中也是忌讳莫深,甚至只要数据库跑在容器中出现性能问题时,首先就把问题推到容器上。

Mysql大数据量分页优化

之前有看过到mysql大数据量分页情况下性能会很差,但是没有探究过它的原因,今天讲一讲mysql大数据量下偏移量很大,性能很差的问题,并附上解决方式。

oracle data block , extent 和segment区别

总结来说,Data block是数据库中最小的逻辑存储单位,用于存储实际的数据记录;Extent是由若干个连续的Data blocks组成的区域,表示一段连续的存储空间;data block是数据库中最小的逻辑存储单元。当数据库的对象需要更多的物理存储空间时,连续的data block就组成了extent . 一个数据库对象拥有的所有extents被称为该对象的segment.Data block、extent和segment是数据库中不同层次的数据存储和管理单位,它们各自具有不同的功能和特点。

Centos系统上安装PostgreSQL和常用PostgreSQL功能

PostgreSQL安装成功之后,会默认创建一个名为postgres的Linux用户,初始化数据库后,会有名为postgres的数据库,来存储数据库的基础信息,例如用户信息等等,相当于MySQL中默认的名为mysql数据库。权限代码:SELECT、INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES、TRIGGER、CREATE、CONNECT、TEMPORARY、EXECUTE、USAGE。为了方便我们使用postgres账号进行管理,我们可以修改该账号的密码。

MySQL数据库主从复制集群原理概念以及搭建流程

主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。MySQL支持一台主库同时向多台从库进行复制, 从库同时也可以作为其他从服务器的主库,实现链状复制。主库出现问题,可以快速切换到从库提供服务。实现读写分离,降低主库的访问压力。可以在从库中执行备份,以避免备份期间影响主库服务。

CentOS本地部署SQL Server数据库无公网ip环境实现远程访问

GeoServer是OGC Web服务器规范的J2EE实现,利用GeoServer可以方便地发布地图数据,允许用户对要素数据进行更新、删除、插入操作,通过GeoServer可以比较容易地在用户之间迅速共享空间地理信息。另外,GeoServer是开源软件。下面介绍GeoServer web ui 管理界面 结合cpolar 内网穿透工具实现远程访问,

[redis] redis的安装,配置与简单操作

Redis是一个开源、基于内存、使用C语言编写的key-value数据库,并提供了多种语言的API。它的数据结构十分丰富,主要可以用于数据库、缓存、分布式锁、消息队列等...Redis服务器程序是单进程模型,也就是在一台服务器上可以同时启动多个Redis进程,Redis的实际处理速度则是完全依靠于主进程的执行效率。若在服务器上只运行一个Redis进程,当多个客户端同时访问时,服务器的处理能力是会有一定程度的下降;

Redis的IO多路复用原理解析

模拟一个tcp服务器处理30个客户socket,一个监考老师监考多个学生,谁举手就应答谁。假设你是一个监考老师,让30个学生解答一道竞赛考题,然后负责验收学生答卷,你有下面几个选择:第一种选择:按顺序逐个验收,先验收A,然后是B,之后是C、D。。。这中间如果有一个学生卡住,全班都会被耽误,你用循环挨个处理socket,根本不具有并发能力。第二种选择:你创建30个分身线程,每个分身线程检查一个学生的答案是否正确。这种类似于为每一个用户创建一个进程或者线程处理连接。

在 Docker 中配置 MySQL 数据库并初始化 Project 项目

这样,您就完成了在 Docker 中配置 MySQL 数据库并初始化 Project 项目的过程。希望这篇博客对您有所帮助!创建目录 /project/mysql 以及 /project/mysql_data。在每个 SQL 文件中,将 AUTO_INCREMENT 修改为 1。将准备好的 SQL 文件复制到 /project/mysql 目录。将 init.sql 放到 /project/mysql 目录。在 SQL 文件中插入管理员相关数据。在 SQL 文件中插入机型相关数据。1.4. 插入管理员。

深入理解Mysql事务隔离级别与锁机制

我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事务隔离机制、锁机制、MVCC多版本并发控制隔离机制,用一整套机制来解决多事务并发问题。接下来,我们会深入讲解这些机制,让大家彻底理解数据库内部的执行原理。

Redis数据一致解决方案

在高并发的业务场景下redis与mysql数据库非常容易产生数据不一致的情况,我们可以采用redis缓存延迟双删除策略达到数据的最终一致性,也可以采用一部缓存更新自定义监听mysql binblog和采用canal开源中间件实现缓存的实时一致性方案。总的来说,都是比较简单的,而且都能够达到良好的效果。

如何在Linux设置JumpServer实现无公网ip远程访问管理界面

JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。JumpServer 帮助企业以更安全的方式管控和登录所有类型的资产,实现事前授权、事中监察、事后审计,满足等保合规要求。下面介绍如何简单设置即可使本地jump server 结合cpolar 内网穿透实现远程访问jump server 管理界面.

复杂 SQL 实现分组分情况分页查询

在处理数据库查询时,分页是一个常见的需求。尤其是在处理大量数据时,一次性返回所有结果可能会导致性能问题。因此,我们需要使用分页查询来限制返回的结果数量。同时,根据特定的条件筛选数据也是非常常见的需求。在本博客中,我们将探讨如何根据 camp_status 字段分为 6 种情况进行分页查询,并根据 camp_type 字段区分活动类型,返回不同的字段。我们将使用 SQL 变量来实现这一功能,并通过示例进行详细解释。
返回
顶部