本地大模型编程实战(23)用智能体(Agent)实现基于SQL数据构建问答系统(2)

本文将用 智能体(Agent) 实现对 SQLite 数据库的查询:用户用自然语言提出问题,智能体也用自然语言根据数据库的查询结果回答问题。

本次将分别在英文、中文环境下,使用 qwen2.5MFDoom/deepseek-r1-tool-calling:7b 以及 llama3.1 做实验。

准备

您可以按下面的步骤准备本地编程环境。

  1. 计算机
    本文涉及的代码可以在没有显存的环境中执行。建议最低配置为:
  • CPU: Intel i5-8400 2.80GHz
  • 内存: 16GB
  1. Visual Studio Code 和 venv
    Visual Studio Code 是很受欢迎的开发工具,建议用 venv 创建虚拟环境, 详见:
    在Visual Studio Code中配置venv。

  2. Ollama
    基于 Ollama 平台,我们可以在本地方便的使用 llama3.1qwen2.5deepseek 等各种 LLM(大语言模型)。详见:
    在langchian中使用本地部署的llama3.1大模型 。

创建 SQLite

我们直接使用之前创建好的 SQLite 数据库:

# 获取当前执行的程序文件的文件夹路径
current_folder = os.path.dirname(os.path.abspath(__file__))db_file_path = os.path.join(current_folder, 'assert/Chinook.db')from langchain_community.utilities import SQLDatabasedb = SQLDatabase.from_uri(f"sqlite:///{db_file_path}")

智能体(Agent)

LangChain 有一个 SQL智能体,它提供了一种比链更灵活的与 SQL 数据库交互的方式。使用 SQL智能体 的主要优点是:

  • 它可以根据数据库的架构以及数据库的内容(如描述特定表)回答问题
  • 它可以通过运行生成的查询、捕获执行栈并正确地重新生成它来从错误中恢复
  • 它可以根据需要多次查询数据库以回答用户问题
    … 等等

创建 SQLite 工具

为了初始化智能体,我们将使用 SQLDatabaseToolkit 创建一组工具:

  • 创建和执行查询
  • 检查查询语法
  • 检索表描述
    … 等等
def create_tools(llm_model_name):"""创建工具"""llm = ChatOllama(model=llm_model_name,temperature=0, verbose=True)toolkit = SQLDatabaseToolkit(db=db, llm=llm)tools = toolkit.get_tools()print(tools)return tools

系统提示词

我们来创建指导智能体的中英文提示词。

  • 英文版
system = """You are an agent designed to interact with a SQL database.
Given an input question, create a syntactically correct SQLite query to run, then look at the results of the query and return the answer.
Unless the user specifies a specific number of examples they wish to obtain, always limit your query to at most 5 results.
You can order the results by a relevant column to return the most interesting examples in the database.
Never query for all the columns from a specific table, only ask for the relevant columns given the question.
You have access to tools for interacting with the database.
Only use the given tools. Only use the information returned by the tools to construct your final answer.
You MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.DO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database.You have access to the following tables: {table_names}
""".format(table_names=db.get_usable_table_names()
)system_message = SystemMessage(content=system)
  • 中文版
system = """您是设计用于与 SQL 数据库交互的代理。用中文回答问题。
给定一个输入问题,创建一个语法正确的 SQLite 查询来运行,然后查看查询结果并返回答案。
除非用户指定他们希望获得的特定数量的示例,否则请始终将查询限制为最多 5 个结果。
您可以按相关列对结果进行排序,以返回数据库中最有趣的示例。
切勿查询特定表中的所有列,仅询问给定问题的相关列。
您可以使用与数据库交互的工具。
仅使用给定的工具。仅使用工具返回的信息来构建最终答案。
在执行查询之前,您必须仔细检查查询。如果在执行查询时出现错误,请重写查询并重试。请勿对数据库执行任何 DML 语句(INSERT、UPDATE、DELETE、DROP 等)。您有权访问以下数据库表: {table_names}
""".format(table_names=db.get_usable_table_names()
)system_message = SystemMessage(content=system)

上述提示词对大模型生成SQL语句的行为做了比较严格的限制,以防止生成错误的SQL破坏数据库。

初始化智能体

使用 create_react_agent 方法初始化智能体,定义问答方法。

def ask(llm_model_name,question):"""询问智能体"""tools = create_tools(llm_model_name)llm = ChatOllama(model=llm_model_name,temperature=0, verbose=True)agent_executor = create_react_agent(llm, tools, state_modifier=system_message)for s in agent_executor.stream({"messages": [HumanMessage(content=question)]}):print(s)print("----")

React智能体React Agent)指的是一种能自主决策和执行任务的AI智能体,它结合了大语言模型(LLM)和工具调用,可以根据环境和任务需求动态调整自己的行为。
简单理解:

  1. React = 解释 + 计算(Reason + Act)
    • 先分析当前的任务和数据(Reason)
    • 然后做出相应的行动(Act)
  2. 如何工作?
    • 先阅读输入信息
    • 决定是否调用某个工具(如数据库查询、API 调用)
    • 处理返回的结果,再次分析,继续执行任务
  3. 示例:
    • 您输入:“明天的天气如何?”
    • 智能体会先思考:“这个问题需要调用天气 API。”
    • 然后它调用天气 API,获取数据后再回复你:“明天是晴天,气温 20°C。”

见证效果

下面我们出3个同样的中文、英文问题,看看这三款大模型的表现如何。

当用中文提问时,系统提示词也用中文版;反之亦然。

英文问题

    questions = ["How many Employees are there?","Which country's customers spent the most?","Describe the PlaylistTrack table"]

我们先看看 qwen2.5 是如何思考回答 “How many Employees are there?” 的:

[QuerySQLDatabaseTool(description="Input to this tool is a detailed and correct SQL query, output is a result from the database. If the query is not correct, an error message will be returned. If an error is returned, rewrite the query, check the query, and try again. If you encounter an issue with Unknown column 'xxxx' in 'field list', use sql_db_schema to query the correct table fields.", ...)]
{'agent': {'messages': [AIMessage(content='',..., tool_calls=[{'name': 'sql_db_schema', 'args': {'table_names': 'Employee'}, ..., 'type': 'tool_call'}], ...)]}}
----
{'tools': {'messages': [ToolMessage(content='\nCREATE TABLE "Employee" (\n\t"EmployeeId" INTEGER NOT NULL, \n\t"LastName" NVARCHAR(20) NOT NULL, \n\t"FirstName" NVARCHAR(20) NOT NULL, \n\t"Title" NVARCHAR(30), \n\t"ReportsTo" INTEGER, \n\t"BirthDate" DATETIME, \n\t"HireDate" DATETIME, \n\t"Address" NVARCHAR(70), \n\t"City" NVARCHAR(40), \n\t"State" NVARCHAR(40), \n\t"Country" NVARCHAR(40), \n\t"PostalCode" NVARCHAR(10), \n\t"Phone" NVARCHAR(24), \n\t"Fax" NVARCHAR(24), \n\t"Email" NVARCHAR(60), \n\tPRIMARY KEY ("EmployeeId"), \n\tFOREIGN KEY("ReportsTo") REFERENCES "Employee" ("EmployeeId")\n)\n\n/*\n3 rows from Employee table:\nEmployeeId\tLastName\tFirstName\tTitle\tReportsTo\tBirthDate\tHireDate\tAddress\tCity\tState\tCountry\tPostalCode\tPhone\tFax\tEmail\n1\tAdams\tAndrew\tGeneral Manager\tNone\t1962-02-18 00:00:00\t2002-08-14 00:00:00\t11120 Jasper Ave NW\tEdmonton\tAB\tCanada\tT5K 2N1\t+1 (780) 428-9482\t+1 (780) 428-3457\tandrew@chinookcorp.com\n2\tEdwards\tNancy\tSales Manager\t1\t1958-12-08 00:00:00\t2002-05-01 00:00:00\t825 8 Ave SW\tCalgary\tAB\tCanada\tT2P 2T3\t+1 (403) 262-3443\t+1 (403) 262-3322\tnancy@chinookcorp.com\n3\tPeacock\tJane\tSales Support Agent\t2\t1973-08-29 00:00:00\t2002-04-01 00:00:00\t1111 6 Ave SW\tCalgary\tAB\tCanada\tT2P 5M5\t+1 (403) 262-3443\t+1 (403) 262-6712\tjane@chinookcorp.com\n*/', name='sql_db_schema',...)]}}
----
{'agent': {'messages': [AIMessage(content='', ..., tool_calls=[{'name': 'sql_db_query_checker', 'args': {'query': 'SELECT COUNT(*) FROM Employee'}, ..., 'type': 'tool_call'}], ...)]}}
----
{'tools': {'messages': [ToolMessage(content='The provided SQL query is:\n\n```sql\nSELECT COUNT(*) FROM Employee\n```\n\nThis query appears to be correct and does not contain any of the common mistakes listed. It simply counts all rows in the `Employee` table.\n\nTherefore, the final SQL query remains:\n\n```sql\nSELECT COUNT(*) FROM Employee\n```', name='sql_db_query_checker', ...)]}}
----
{'agent': {'messages': [AIMessage(content='', ..., tool_calls=[{'name': 'sql_db_query', 'args': {'query': 'SELECT COUNT(*) FROM Employee'}, ..., 'type': 'tool_call'}], ...)]}}
----
{'tools': {'messages': [ToolMessage(content='[(8,)]', name='sql_db_query', ...)]}}
----
{'agent': {'messages': [AIMessage(content='There are 8 employees in the database.', ...)]}}
----

从上面的输出来看,智能体是一步一步推理出最终的答案的:

  • QuerySQLDatabaseTool
    给出提示:此工具的输入是详细且正确的 SQL 查询,输出是数据库的结果。如果查询不正确,将返回错误消息。如果返回错误,请重写查询,检查查询,然后重试。如果您遇到“字段列表”中未知列“xxxx”的问题,请使用 sql_db_schema 查询正确的表字段。
  • agent
    生成名为 sql_db_schematool_call ,确定表名为 Employee
  • tools
    执行前面tool_call,生成名为 sql_db_schemaToolMessage ,找出了表 EmployeeDML ,并成功查询出3条信息。
  • agent
    生成名为 sql_db_query_checkertool_call,其中包含 SQL语句。
  • tools
    验证前面 tool_call 中的SQL是否正确。生成名为 sql_db_query_checkerToolMessage,其内容显示最终确定了正确的SQL语句。
  • agent
    生成名为 sql_db_querytool_call,其中包含SQL语句:SELECT COUNT(*) FROM Employee
  • tools
    执行前面的 tool_call ,生成名为 sql_db_queryToolMessage ,其中已经包含了 SQLite的返回值。
  • agent
    基于前面的结果生成了最终回答。

通过上述的推理过程显示:智能体与工具进行了多轮交互后才给出最终回答。

下表直接列出各个大模型针对这3个问题的处理结果:

How many Employees are there?Which country’s customers spent the most?Describe the PlaylistTrack table
qwen2.5There are 8 employees in the database.The country with the highest spending by customers is USA, followed by Canada, France, Brazil, and Germany.\n\nHere are the top 5 countries based on total invoice amount:\n\n1. USA - $523.06\n…The PlaylistTrack table has two columns: PlaylistId and TrackId. It is a junction table used to establish a many-to-many relationship between the Playlist and Track tables…
llama3.1There are 8 Employees.The country’s customers that spent the most are from the USA, with a total spend of $523.06.The PlaylistTrack table contains information about the tracks in each playlist. It has two columns: PlaylistId and TrackId,…
MFDoom/deepseek-r1-tool-calling:7bThere are \boxed{8} Employees in the database.未推理出正确的的SQLAlright, …, it looks like this table has two main columns: PlaylistId and TrackId…

从上述结果来看,qwen2.5给出的回答最清晰全面,llama3.1也不错,MFDoom/deepseek-r1-tool-calling:7b 未能正确回答第2个问题。

中文问题

    questions = ["有多少名员工?","哪个国家的顾客花费最多?","描述 PlaylistTrack 表" ]
有多少名员工?哪个国家的顾客花费最多?描述 PlaylistTrack 表
qwen2.5数据库中一共有 8 名员工。花费最多的国家及其总金额如下:\n\n1. 美国 (USA) - 总\金额: $523.06…\n\n因此,顾客花费最多的国家是美国。PlaylistTrack 表包含两个列:PlaylistIdTrackId。这两个列共同作为主键,表示播放列表和其中的歌曲之间的关系。…
llama3.1有 8 名员工。答案是:美国。根据工具的输出,PlaylistTrack 表是一个连接表,它将Playlist和Track两个表关联起来。它有两个列:PlaylistId和TrackId,…
MFDoom/deepseek-r1-tool-calling:7b未正确做答未正确做答未正确做答

总结

我们实现了用 智能体(Agent)SQlite 对话的功能,通过中英文环境的简单对比实验发现,qwen2.5 表现最稳健。

代码

本文涉及的所有代码以及相关资源都已经共享,参见:

  • github
  • gitee

为便于找到代码,程序文件名称最前面的编号与本系列文章的文档编号相同。

参考

  • Build a Question/Answering system over SQL data

🪐感谢您观看,祝好运🪐

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nodejs npm install、npm run dev运行的坎坷之路

1、前面的种种都不说了,好不容易运行起来oap-portal项目,运行idm-ui项目死活运行不起来,各种报错,各种安装,各种卸载nodejs,卸载nvm,重装,都不好使。 2、甚至后来运行npm install会…

gotool在线工具集

1. 包含各种 sql 处理 2. 包含 json 处理 3. 包含 图片处理 4. 跨平台传输 gotool

猿大师播放器:智慧交通Web网页低延迟播放监控RTSP H.265视频解决方案

在智慧城市建设加速推进的今天,智慧交通作为城市"神经系统"正面临前所未有的发展机遇。据统计,2023年全国交通视频监控设备保有量已突破4500万台,日均产生的视频数据量超50PB。但在这些庞大数字背后,行业却普遍面临着&q…

Web自动化之Selenium控制已经打开的浏览器(Chrome,Edge)

在使用selenium进行web自动化或爬虫的时候,经常会面临登录的情况,对于这种情况,我们可以利用Selenium控制已经打开的浏览器,从而避免每次都需要重新打开浏览器并进行登录的繁琐步骤。 目录 说明 启动浏览器 注意 --user-data-dir说明 代码设定 代码 改进代…

【Alertmanager】Alertmanager告警路由,告警静默,告警抑制,高可用的实现

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

Vue3 + Vite + TS,使用 配置项目别名属性:resolve

使用 resolve 配置全局项目路径别名 1.优化了开发中单页面引用其他模块的路径复杂性 2.妥妥解决了,组件复用当中提高开发效率 // 不使用配置 import { useStore } from ../../../stores // 使用配置 可根据开发者需求任意定义,较多 import { useStore…

Linux主机用户登陆安全配置

Linux主机用户登陆安全配置 在Linux主机上进行用户登录安全配置是一个重要的安全措施,可以防止未经授权的访问。以下是如何创建用户hbu、赋予其sudo权限,以及禁止root用户SSH登录,以及通过ssh key管理主机用户登陆。 创建用户hbu 使用具有…

基于 SpringBoot Vue 的生鲜商城系统设计和实现(源码+文档+部署讲解)

技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

设计模式-结构性模式

结构型模式主要关注类或对象的组合,旨在通过识别简单的结构关系来设计更复杂的结构。以下是几种常见的结构型设计模式: 1. 适配器模式(Adapter Pattern) 将一个类的接口转换成客户端所期望的另一个接口,使得原本由于接…

VantUI官网更新2025,移动端前端开发

Vant 2 - Mobile UI Components built on Vue https://vant-ui.github.io/vant/v2/#/zh-CN/quickstart Vant 4 - A lightweight, customizable Vue UI library for mobile web apps. https://vant-ui.github.io/vant/#/zh-CN Vant Weapp - 轻量、可靠的小程序 UI 组件库,微…

《我的AUTOSAR之路》Det 解析

Det 解析 1. 引言和功能概述2. Errors2.1 开发错误(Development Errors)2.2 运行时错误(Runtime Errors)2.3 临时故障(Transient Faults)3 错误查询默认错误追踪器(Default Error Tracer,DET) 1. 引言和功能概述 默认错误追踪器(DET):该规范描述了默认错误追踪器(…

电脑连接示波器显示波形

通过网线连接示波器和电脑,将示波器波形显示在电脑上直接复制图片至报告中,以下是配置步骤。 一、设备 网线,Tektronix示波器,电脑 二、使用步骤 1.用网线连接电脑和示波器 2.电脑关掉WiFi,查看IPv4网关地址&#xf…

npm i 失败权限问题

安装完node之后, 测试全局安装一个最常用的 express 模块进行测试 失败,但是用管理员权限打开cmd 安装就成功。 报错如下: npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and …

上海创智学院(测试)算法笔试(ACM赛制)部分例题

1.第一个题,大概题目意思是求n句话中最长的单词和最短的单词 这个题目做的有点磕巴,好几年没有写过c/c了,连string的复制都不会写了,哈哈哈,太笨了 后面一点点捡起来,还是写出来了,本身没啥&…

编写一个程序,输出 “Hello, World!“(Python版)

编写一个程序,输出 "Hello, World!" 在 Python 中,输出 “Hello, World!” 的程序非常简单。你只需要使用 print 函数即可。以下是代码示例: print("Hello, World!")将这段代码保存为一个 .py 文件(例如 hel…

python实战项目58:采集蜻蜓FM热门音频top排行榜

python实战项目58:采集蜻蜓FM热门音频top排行榜 一、采集流程介绍二、数据接口采集三、使用xpath提取页面数据1、抓包,找到数据接口2、发送请求,获取数据3、提取数据4、保存数据一、采集流程介绍 蜻蜓FM热门音频top排行榜的链接为: https://m.qingting.fm/rank/,首页如下图…

【Matlab仿真】Matlab Function中如何使用静态变量?

背景 根据Simulink的运行机制,每个采样点会调用一次MATLAB Function的函数,两次调用之间,同一个变量的前次计算的终值如何传递到当前计算周期来?其实可以使用persistent变量实现函数退出和进入时内部变量值的保持。 persistent变…

LaneATT环境配置步骤

本文介绍Ubuntu下配置车道线检测算法LaneATT代码运行环境,步骤如下。 1. 从LaneATT官方代码仓库下载源码。也可git直接拉取。 2. 安装Anaconda或miniconda 。 参考:https://docs.anaconda.com/miniconda/ 3. 创建conda虚拟环境LaneATT(环…

【AIGC】使用Python实现科大讯飞语音服务ASR转录功能:完整指南

文章目录 讯飞ASR转写API完整指南1. 引言2. 讯飞ASR API介绍3. API参数说明3.1 认证参数3.2 上传参数3.3 查询结果参数3.4 orderResult 字段3.5 Lattice 字段3.6 json_1best 字段3.7 st 字段 4. Python代码实现4.1 生成签名4.2 上传音频文件4.3 获取转写结果4.4 解析转写结果 5…

大学本科教务系统设计方案,涵盖需求分析、架构设计、核心模块和技术实现要点

以下是大学本科教务系统的设计方案,涵盖需求分析、架构设计、核心模块和技术实现要点: 大学本科教务系统设计方案 一、需求分析 1. 核心用户角色 角色功能需求学生选课/退课、成绩查询、课表查看、学分统计、考试报名、学业预警教师成绩录入、课程大纲上传、教学进度管理、…