运维项目:InnoAI SQL 助手

一、**项目说明
1.本项目以 MySQL 8.0 DBA 运维核心知识点为基础,结合硅基流动开源大模型 API,构建一套
电商订单库智****能查询与性能调优系统**。
2.系统可接收业务自然语言自动生成合规 MySQL 查询语句,自动执行查询并输出结构化表格,依托大模型完成订单数据业务解读,同时解析 SQL 执行计划输出标准化索引优化方案,全程无需人工手写、分析 SQL。
核心价值:无需专业 SQL 开发能力即可完成业务数据查询,自动替代人工统计报表、手工分析执行计划等
重复性运维工作;深度融合 MySQL 数据库运维能力与大模型自然语言解析能力,适配企业轻量化数据查
询、SQL 性能优化、AI 智能解读一体化落地场景。

**二、**项目背景知识
**2.1.**系统需求
功能需求
① 支持自然语言转MySQL 只读查询语句,仅生成 SELECT,拦截所有增删改 DDL/DML 语句;
② 自动执行生成 SQL,格式化输出表格化查询结果,调用大模型输出通俗易懂业务总结;
③ 输入任意业务 SQL,自动解析 EXPLAIN 执行计划,输出分级性能问题、可直接执行索引、改写方案;
④ 配置独立环境文件存储数据库账号、大模型密钥,避免代码硬编码,保障敏感信息安全
非功能需求
① 兼容性:适配 openEuler/RHEL Linux 系统,兼容 MySQL 8.0.45,适配Qwen、DeepSeek 系列开源模
型;
② 稳定性:自然语言识别容错率高,无匹配数据可正常提示,API、数据库异常捕获不崩溃;
③ 安全性:仅开放只读查询权限,密钥文件设置 600 权限,不打印明文账号密钥
**2.2.数据库&**运维核心知识点

|--------------------------|-------------------------------|
| 知识点 | 应用场景 |
| 系统部署及初始化 | 生产级别系统部署及优化 |
| MySQL 8.0 基础语法 | 约束 AI 生成规范 SQL,区分聚合、排序、模糊匹配语法 |
| EXPLAIN 执行计划分析 | 识别全表扫描、文件排序、无索引等性能风险点 |
| InnoDB 索引设计规范 | 指导大模型输出联合索引、覆盖索引优化语句 |
| Python MySQL 连接(pymysql) | 封装统一数据库操作类,统一管理连接释放 |

2.3.大模型API
腾讯云TokenHub大模型平台:是腾讯云 MaaS(Model as a Service)生态下的大模型统一接入与分发平
台,核心定位是「多模型聚合网关」------ 将国内主流厂商的大模型能力整合到同一套标准接口中,开发者
只需一套代码、一个密钥,即可调用不同品牌的大模型,无需分别对接各家 SDK 与接口。


**2.4.**技术架构
**2.4.1.**流程图

**2.4.2.**架构说明
接入交互层(左侧)
面向运维、开发、业务运营人员,提供两种使用入口,适配不同场景:
命令行终端模式:在 openEuler 服务器终端执行 python3 main.py 进入交互式菜单,支持自然语言
查数据、SQL 性能调优两大功能。
Web 可视化模式:浏览器访问 Streamlit 面板,通过图形化界面完成查询与调优操作,自带输入校
验、结果表格、代码复制等易用性功能。
Python 程序核心层
采用分层解耦设计,共 4 个核心文件 + 1 个配置文件,职责边界清晰,便于教学与二次开发:
main.py:总调度入口与公共服务层。封装自然语言转 SQL 查询、AI 业务总结、SQL 性能调优三大核 心业务流程,同时提供命令行交互入口,Web 端统一调用该文件的公共函数,避免代码重复。
底层数据持久服务层
运行于 openEuler 虚拟机的 MySQL 8.0.45 数据库,作为项目唯一数据源,存储
testdb.order_info 电商订单测试数据,支撑查询与性能调优全流程。
AI 大模型服务层
采用腾讯云 TokenHub 大模型聚合平台作为统一 AI 能力出口,同时为 NL2SQL 生成、业务数据总
结、SQL 性能分析三类场景提供大模型能力:
平台兼容 OpenAI 接口标准,一套代码可无缝切换 DeepSeek V4 Pro、Qwen3.5-Plus 等多款主流模

统一鉴权、统一计费、统一运维,避免多厂商对接成本
依托腾讯云基础设施提供高可用保障,满足生产环境使用要求
**3.**软硬件环境清单

|-------|------------------------|-------------------------|----------------------------|-----------------------------------------|
| 类别 | 名称**/ | 版本/**参数 | 用途 | 备注 |
| 硬件 环境 | 虚拟机 | CPU≥2 核,内存 ≥4GB,磁盘≥20GB | 运行 Linux、 MySQL、Python 程 序 | 本地虚拟机或云 ECS 均可 |
| 软件 环境 | 操作系统 | openEuler / RHEL9 | 项目底层运行系统 | 需配置外网访问AP |
| | MySQL | 8.0.45 | 存储电商订单测试业 务数据 | 内置 order_info 订单表 |
| | Python | 3.11.9(源码编译) | 项目主开发语言 | 依赖 pymysql、python、dotenv、openaitabulate |
| | Shell | Bash | 系统环境操作、编译 Python | 系统默认自带 |
| 网络 环境 | 外网访问 | 可访问大模型 API | 调用大模型接口 | 防火墙放行 443 端口或者关 闭 |
| 账号 资源 | 创建平台 账号 | 完成实名认证 | 获取 API Key,调用 大模型 | 官网:https://cloud.tencen t.com/ |

**4.**任务清单
**4.1.**项目环境搭建
部署 openEuler 服务器,关闭 SELinux、配置可用 yum 源,编译安装 Python3.11.9;
安装 MySQL8.0.45,创建 testdb 库、order_info 订单业务表,导入20 条标准测试订单数据;
登录并开通腾讯云 TokenHub 大模型聚合平台,申请 API 密钥,领取免费额度,编写.env 配置文件并加固
文件权限;
安装项目全部 Python 依赖包,测试数据库连通性、大模型接口连通性。
**4.2.**脚本开发
mysql_client.py:封装 MySQL 连接、查询与执行计划获取,拦截危险 SQL 保障数据库安全。
prompts.py:统一存放生成 SQL、调优分析两套 AI 提示词,并提供提取纯净 SQL 的工具函数。
main.py:项目总调度,串联数据库、大模型、提示词,提供终端菜单交互,实现完整业务逻辑。
web_main.py:Streamlit 可视化网页界面,做输入校验、图形化展示结果,复用 main 核心逻辑。
.env:存放数据库、腾讯云 TokenHub 大模型密钥等配置,分离敏感信息与业务代码。
**4.3.**功能测试
多业务自然语言用例全覆盖测试,校验生成 SQL 安全、逻辑准确,模糊匹配无 bug;
性能调优模块测试,校验 EXPLAIN 解析完整、输出索引与改写方案可直接执行;
边界场景测试:无匹配用户 / 商品、空白输入、超长复合需求,程序无崩溃报错;
安全测试:验证不会生成任何 DELETE/UPDATE/ALTER 等危险 SQL,密钥无明文打印。

**5.**项目实施
**5.1.**环境搭建
**5.1.1.**系统搭建及初始化
安装1台虚拟机及OpenEuler2203_SP4系统 ,过程略
关闭selinx:

bash 复制代码
[root@localhost ~]# sed -i '7s/enforcing/disabled/' /etc/selinux/config
[root@localhost ~]# systemctl disable --now firewalld
[root@localhost ~]# systemctl status firewalld

修改主机名:

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname server
[root@localhost ~]# bash

更换时间同步服务器:

bash 复制代码
[root@server ~]# vim /etc/chrony.conf
server ntp.aliyun.com iburst
stratumweight 0
driftfile /var/lib/chrony/drift
rtcsync
makestep 10 3
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
keyfile /etc/chrony.keys
commandkey 1
generatecommandkey
logchange 0.5
logdir /var/log/chrony
[root@server ~]# systemctl restart chronyd
[root@server ~]# chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* 203.107.6.88 2 6 7 1 +738us[-8730us] +/- 30ms

下载所需软件及依赖:

bash 复制代码
[root@localhost ~]# dnf install -y gcc gcc-c++ make cmake zlib-devel bzip2-devel
openssl-devel ncurses-devel sqlite-devel readline-devel libffi-devel tk-devel wget tar
vim tree net-tools openssh-server

5.1.2.源码编译安装Python3.11.9
下载:https://www.python.org/downloads/release/python-3119/
下载完毕后使用XFTP将源码包上传到/usr/local/src路径下

bash 复制代码
# 进入源码存放目录
[root@server ~]# cd /usr/local/src
# 解压
[root@server src]# tar -zxvf Python-3.11.9.tgz
[root@server src]# cd Python-3.11.9
# 编译配置
[root@server Python-3.11.9]# ./configure --prefix=/usr/local/python3.11 --enable-shared
bash 复制代码
# 多核编译安装
[root@server Python-3.11.9]# make -j$(nproc) && make install
# 配置动态链接库,解决libpython缺失报错
[root@server Python-3.11.9]# echo "/usr/local/python3.11/lib" >
/etc/ld.so.conf.d/python311.conf
[root@server Python-3.11.9]# ldconfig
# 建立全局软链接,不覆盖系统自带Python3
[root@server Python-3.11.9]# ln -s /usr/local/python3.11/bin/python3.11
/usr/local/bin/python3
[root@server Python-3.11.9]# ln -s /usr/local/python3.11/bin/pip3.11 /usr/local/bin/pip3
[root@server Python-3.11.9]# bash # 或者reboot重启
# 验证安装
[root@server Python-3.11.9]# python3 -V
[root@server Python-3.11.9]# pip3 -V
# 校验SSL模块(AI接口必备)
[root@server Python-3.11.9]# python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"

5.1.3.配置国内pip****源及安装项目依赖
配置pip仓库为阿里镜像站,提高下载速度

bash 复制代码
[root@server Python-3.11.9]# cd
[root@server ~]# mkdir .pip
[root@server ~]# vim ~/.pip/pip.conf
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host=mirrors.aliyun.com

安装python及ai所需依赖

bash 复制代码
[root@server ~]# pip3 install --upgrade pip
[root@server ~]# pip3 install pymysql python-dotenv tabulate langchain langchain-openai

5.1.4.部署并初始化MySQL 8.0.45
下载:https://downloads.mysql.com/archives/community/
使用xftp将软件包上传到根目录

部署数据库:

bash 复制代码
# 解压缩
[root@server /]# tar -xvf mysql-8.0.45-linux-glibc2.28-x86_64.tar.xz
[root@server /]# cd mysql-8.0.45-linux-glibc2.28-x86_64
[root@server mysql-8.0.45-linux-glibc2.28-x86_64]# ls
bin docs include lib LICENSE man README share support-files
bash 复制代码
# 使用前的准备
[root@server mysql-8.0.45-linux-glibc2.28-x86_64] cd /
[root@server /]# mv mysql-8.0.45-linux-glibc2.28-x86_64 /usr/local/mysql
[root@server /]# cd /usr/local/mysql
[root@server mysql]# groupadd mysql # 创建名为mysql的用户组
# 创建mysql的系统用户,将其添加到mysql组中,并设置其不可登录,以限制该用户的登录权限
[root@server mysql]# useradd -r -g mysql -s /sbin/nologin mysql
[root@server mysql]# mkdir data # 创建用于存放MySQL数据文件目录
[root@server mysql]# chmod -R 750 data
# 设置mysql目录的账户及工作组,生产环境中不要使用root
[root@server mysql]# chown -R mysql:mysql /usr/local/mysql
# 初始化软件
[root@server mysql]# bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --
datadir=/usr/local/mysql/data # 注意:需要复制密码
[root@server mysql]# bin/mysqld_safe --user=mysql & # 使用后台方式以mysql用户身份启动 MySQL
服务器,mysqld_safe 是一个用于启动和监控 MySQL 服务器的脚本
# 注意:此时上述命令执行完毕处于后台运行状态,需要另行启动一个终端
[root@server ~]# ps -ef | grep mysql # 查看进程运行状态
[root@server ~]# cd /usr/local/mysql
[root@server mysql]# bin/mysql -u root -p # 登录,可能报错
# ============可选,若报错,需要找到下面的文件进行软连接============
[root@server mysql]# ln -s /usr/lib64/libncurses.so.6.3 /usr/lib64/libncurses.so.5
[root@server mysql]# ln -s /usr/lib64/libtinfo.so.6.3 /usr/lib64/libtinfo.so.5
[root@server mysql]# bin/mysql -u root -p
Enter password: # 粘贴之前的初始密码
# ===========================以上可选=========================
mysql> alter user 'root'@'localhost' identified with mysql_native_password by
'123456'; # 修改密码
mysql> flush privileges; # 刷新
mysql> use mysql; # 查看账户信息
mysql> select user, host, plugin from mysql.user;
+------------------+-----------+-----------------------+
| user | host | plugin |
+------------------+-----------+-----------------------+
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session | localhost | caching_sha2_password |
| mysql.sys | localhost | caching_sha2_password |
| root | localhost | mysql_native_password |
+------------------+-----------+-----------------------+
4 rows in set (0.00 sec)
mysql>exit
[root@server mysql]# ps -ef | grep mysql
[root@server mysql]# kill -9 pid号 # 在当前终端关闭运行的mysql
# 设置mysql的配置文件
# 回到之前的终端,敲一个回车,显示进程以杀死
[root@server mysql]# vim /etc/my.cnf # 新建配置文件,输入以下内容:
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
port = 3306
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
tmpdir = /tmp
socket = /tmp/mysql.sock
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
default-storage-engine=INNODB
log_error = error.log
# 配置启动脚本
[root@master mysql]# vim /usr/lib/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
After=network.target remote-fs.target nss-lookup.target
[Service]
创建库 / 表
Type=notify
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
LimitNOFILE=65535
LimitNPROC=65535
Restart=on-failure
RestartPreventExitStatus=1
TimeoutSec=0
[Install]
WantedBy=multi-user.target
[root@master mysql]# systemctl daemon-reload
[root@master mysql]# systemctl enable --now mysqld.service
# 设置mysql命令识别
[root@server mysql]# vim ~/.bash_profile # 设置环境变量需添加如下语句
export PATH=$PATH:/usr/local/mysql/bin
[root@server mysql]# source ~/.bash_profile
# 测试
[root@server mysql]# mysql -V
mysql Ver 8.0.45 for Linux on x86_64 (MySQL Community Server - GPL)
[root@server mysql]# systemctl is-active mysqld
active
[root@server ~]# mysql -uroot -p
Enter password: # 123456
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)

创建库 / 表:

bash 复制代码
mysql> create database testdb;
mysql> use testdb;
-- 创建订单业务表
mysql> create table order_info(
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '订单ID',
user_id INT COMMENT '用户ID',
order_name VARCHAR(200) COMMENT '商品名称',
pay_amount DECIMAL(10,2) COMMENT '支付金额',
create_time DATETIME COMMENT '下单时间'
) ENGINE=InnoDB COMMENT='电商订单业务表';
-- 导入20条标准测试数据
mysql> INSERT INTO order_info(user_id,order_name,pay_amount,create_time)
VALUES
(1001,'智能手机',2999.00,'2026-05-01 10:20:00'),
(1001,'有线入耳耳机',199.00,'2026-05-02 14:10:00'),
(1002,'14英寸轻薄笔记本电脑',5499.00,'2026-05-03 09:30:00'),
(1002,'无线蓝牙鼠标',89.00,'2026-05-03 09:35:00'),
(1003,'平板学习机',1799.00,'2026-05-04 11:05:00'),
(1003,'平板专用保护壳',49.00,'2026-05-04 11:08:00'),
(1004,'机械游戏键盘',349.00,'2026-05-05 16:42:00'),
(1004,'电竞头戴耳机',459.00,'2026-05-05 16:48:00'),
(1005,'大屏智能电视',3299.00,'2026-05-06 08:15:00'),
(1005,'电视壁挂支架',129.00,'2026-05-06 08:20:00'),
(1006,'无线快充充电器',129.00,'2026-05-03 13:22:00'),
(1006,'降噪蓝牙耳机',399.00,'2026-05-03 13:25:00'),
(1007,'电竞显示器',1899.00,'2026-05-07 10:10:00'),
(1007,'显示器增高支架',79.00,'2026-05-07 10:15:00'),
(1008,'折叠平板支架',39.00,'2026-05-04 15:30:00'),
(1008,'便携充电宝',159.00,'2026-05-04 15:33:00'),
(1009,'台式游戏主机',6999.00,'2026-05-08 09:05:00'),
(1009,'电竞防滑鼠标垫',59.00,'2026-05-08 09:08:00'),
(1010,'手机钢化膜',29.00,'2026-05-05 17:12:00'),
(1010,'桌面收纳支架',45.00,'2026-05-05 17:16:00');
-- 验证数据
mysql> select * from order_info;
+----+---------+-------------------------------+------------+---------------------+
| id | user_id | order_name | pay_amount | create_time |
+----+---------+-------------------------------+------------+---------------------+
| 1 | 1001 | 智能手机 | 2999.00 | 2026-05-01 10:20:00 |
| 2 | 1001 | 有线入耳耳机 | 199.00 | 2026-05-02 14:10:00 |
| 3 | 1002 | 14英寸轻薄笔记本电脑 | 5499.00 | 2026-05-03 09:30:00 |
| 4 | 1002 | 无线蓝牙鼠标 | 89.00 | 2026-05-03 09:35:00 |
| 5 | 1003 | 平板学习机 | 1799.00 | 2026-05-04 11:05:00 |
| 6 | 1003 | 平板专用保护壳 | 49.00 | 2026-05-04 11:08:00 |
| 7 | 1004 | 机械游戏键盘 | 349.00 | 2026-05-05 16:42:00 |
| 8 | 1004 | 电竞头戴耳机 | 459.00 | 2026-05-05 16:48:00 |
| 9 | 1005 | 大屏智能电视 | 3299.00 | 2026-05-06 08:15:00 |
| 10 | 1005 | 电视壁挂支架 | 129.00 | 2026-05-06 08:20:00 |
| 11 | 1006 | 无线快充充电器 | 129.00 | 2026-05-03 13:22:00 |
| 12 | 1006 | 降噪蓝牙耳机 | 399.00 | 2026-05-03 13:25:00 |
| 13 | 1007 | 电竞显示器 | 1899.00 | 2026-05-07 10:10:00 |
| 14 | 1007 | 显示器增高支架 | 79.00 | 2026-05-07 10:15:00 |
| 15 | 1008 | 折叠平板支架 | 39.00 | 2026-05-04 15:30:00 |
| 16 | 1008 | 便携充电宝 | 159.00 |2026-05-04 15:33:00 |
| 17 | 1009 | 台式游戏主机 | 6999.00 | 2026-05-08 09:05:00 |
| 18 | 1009 | 电竞防滑鼠标垫 | 59.00 | 2026-05-08 09:08:00 |
| 19 | 1010 | 手机钢化膜 | 29.00 | 2026-05-05 7:12:00 |
| 20 | 1010 | 桌面收纳支架 | 45.00 | 2026-05-05 17:16:00 |
+----+---------+-------------------------------+------------+---------------------+
20 rows in set (0.00 sec)
mysql> exit;

5.2.获取API Key
**5.2.1.**网址:
访问腾讯云官网,手机号注册并完成实名认证
登录后进入 "API Key管理"→"新建 API 密钥",填写密钥名称并保存

选一种模型:

注意:
选择模型最好不带有"思考链"的,否则会把思考的内容一通发给mysql就会报错
适合本项目的模型有
Qwen3.5-Plus
deepseek-v4-pro
若需要更换模型,需要测试,若有思考链内容返回就行修改代码,进行信息过滤
**5.3.**脚本开发阶段
**5.3.1.**新建目录及脚本

bash 复制代码
[root@server mysql]# cd
[root@server ~]# mkdir -p /opt/mysql_ai_tools
[root@server ~]# cd /opt/mysql_ai_tools
[root@server mysql_ai_tools]# touch main.py mysql_client.py prompts.py web_main.py
.env
[root@server mysql_ai_tools]# tree -La 1
.
5.3.2. 编写环境变量脚本
5.3.3. 编写数据库连接脚本
├── backup
├── .env
├── main.py
├── mysql_client.py
├── prompts.py
└── web_main.py
[root@server mysql_ai_tools]# cd

**5.3.2.**编写环境变量脚本

bash 复制代码
[root@server ~]# vim /opt/mysql_ai_tools/.env
# ===================== MySQL 数据库连接配置 =====================
# 数据库服务IP,本地运行填127.0.0.1,远程服务器替换对应公网/内网地址
MYSQL_HOST=127.0.0.1
# MySQL默认通信端口,未手动修改固定3306
MYSQL_PORT=3306
# 数据库登录用户名,测试环境默认root
MYSQL_USER=root
# 数据库登录密码,根据自己本地MySQL密码修改
MYSQL_PASSWORD=123456
# 项目专用数据库名,SQL查询仅操作该库下order_info表
MYSQL_DB=testdb
# ===================== 腾讯云TokenHub大模型配置 =====================
# TokenHub平台分配的API密钥,用于鉴权调用大模型,切勿泄露
LLM_API_KEY=sk-jUJebmj56mEQhhBep04A3AIaVlVV2NA97F45iimZ***
# TokenHub统一接口地址,固定/v1后缀,兼容OpenAI标准SDK
LLM_BASE_URL=https://tokenhub.tencentmaas.com/v1
# 当前调用模型标识,切换DeepSeek v4 Pro只需改为deepseek-v4-pro
LLM_MODEL_NAME=deepseek-v4-pro
# 模型温度参数,0代表输出最严谨稳定,适合生成标准SQL,不产生随机偏差
LLM_TEMPERATURE=0
[root@server ~]# chmod 600 /opt/mysql_ai_tools/.env

**5.3.3.**编写数据库连接脚本

bash 复制代码
[root@server ~]# vim /opt/mysql_ai_tools/mysql_client.py
# -*- coding: utf-8 -*-
# 文件名:mysql_client.py
# 功能:MySQL8.0数据库统一封装类
# 作用:封装数据库连接、普通查询、EXPLAIN执行计划、SQL安全拦截,统一抛出友好异常,给上层业务调用
import pymysql
import os
import re
from dotenv import load_dotenv
# 加载项目根目录下.env文件的数据库配置
load_dotenv()
class Mysql80Client:
# 数据库操作封装类,所有数据库相关操作统一在此管理
def __init__(self):
# 初始化时读取环境变量,参数缺失则设置兜底默认值,防止程序直接崩溃
self.host = os.getenv("MYSQL_HOST", "127.0.0.1")
self.port = int(os.getenv("MYSQL_PORT", "3306"))
self.user = os.getenv("MYSQL_USER", "root")
self.password = os.getenv("MYSQL_PASSWORD", "")
self.database = os.getenv("MYSQL_DB", "testdb")
# 数据库连接对象,初始为空
self.conn = None
# 实例创建后自动建立数据库连接
self.connect()
def connect(self):
"""创建数据库连接,捕获连接异常并抛出可读错误信息"""
try:
self.conn = pymysql.connect(
host=self.host,
port=self.port,
user=self.user,
password=self.password,
database=self.database,
charset='utf8mb4', # 支持中文、emoji完整字符集
cursorclass=pymysql.cursors.DictCursor # 查询结果以字典返回,方便按字段取值
)
except pymysql.MySQLError as e:
# MySQL专属连接错误,提示账号、地址、密码排查方向
raise Exception(f"数据库连接失败,请检查地址/账号/密码:{e.args[1]}")
except Exception as e:
# 其余未知连接异常统一捕获
raise Exception(f"数据库连接异常:{str(e)}")
@staticmethod
def _check_sql_safety(sql: str) -> None:
"""
静态私有安全校验方法
核心防护:拦截增删改、建表删表等危险操作,仅允许SELECT查询,防止AI生成危险SQL篡改数据
"""
# 去除首尾空格并转为大写,统一匹配规则
sql_trim = sql.strip().upper()
# 危险操作关键字黑名单
danger_keywords = ["INSERT", "UPDATE", "DELETE", "DROP", "ALTER", "CREATE",
"TRUNCATE", "REPLACE"]
for kw in danger_keywords:
# 单词边界匹配,避免字段名包含关键字时误拦截
if re.search(r'\b' + re.escape(kw) + r'\b', sql_trim):
raise Exception(f"安全拦截:禁止执行 {kw} 类型语句,仅支持 SELECT 查询")
def execute_query(self, sql: str):
"""
执行普通SELECT查询
:param sql: 待执行查询语句
:return: (字段名列表, 全部数据行字典列表)
"""
# 执行SQL前先做安全校验,拦截危险语句
self._check_sql_safety(sql)
try:
# with自动管理游标,用完自动释放资源
with self.conn.cursor() as cursor:
cursor.execute(sql)
# 提取查询结果表头字段
columns = [desc[0] for desc in cursor.description]
# 读取全部查询数据
rows = cursor.fetchall()
return columns, rows
except pymysql.MySQLError as e:
5.3.4. 编写sql转换脚本
# 捕获SQL语法、表不存在等数据库执行错误
raise Exception(f"SQL执行失败(错误码 {e.args[0]}):{e.args[1]}")
except Exception as e:
# 通用查询异常兜底
raise Exception(f"查询异常:{str(e)}")
def get_explain_plan(self, sql: str):
"""
获取SQL执行计划EXPLAIN,用于性能调优分析
:param sql: 待分析SELECT语句
:return: (执行计划表头, 执行计划详情数据)
"""
# 同样先校验SQL安全性
self._check_sql_safety(sql)
# 拼接EXPLAIN关键字,生成分析语句
explain_sql = f"EXPLAIN {sql}"
try:
with self.conn.cursor() as cursor:
cursor.execute(explain_sql)
columns = [desc[0] for desc in cursor.description]
rows = cursor.fetchall()
return columns, rows
except pymysql.MySQLError as e:
raise Exception(f"获取执行计划失败:{e.args[1]}")
except Exception as e:
raise Exception(f"执行计划异常:{str(e)}")
def close(self):
"""安全关闭数据库连接,释放资源,避免长时间占用连接池"""
# 判断连接存在且未关闭才执行关闭操作
if self.conn and not self.conn._closed:
self.conn.close()

5.3.4.编写sql****转换脚本

bash 复制代码
[root@server ~]# vim /opt/mysql_ai_tools/prompts.py
# -*- coding: utf-8 -*-
# 文件名:prompts.py
# 功能:统一管理项目全部大模型提示词模板,附带SQL提取工具静态方法
# 作用:把AI提示词和业务代码解耦,统一约束模型输出格式,降低SQL解析报错概率
import re
class UnifiedPrompt:
"""
提示词统一管理类
优势:所有SQL生成、性能分析提示词集中存放,表结构仅维护一处,修改不用多处同步;
通过严格规则约束大模型输出,减少格式错乱、编造字段、危险SQL等幻觉问题
"""
# ===================== 全局共用数据表结构 =====================
# 只在此维护订单表字段,下方两套提示词会自动引用,改表结构只需改这里一处
TABLE_SCHEMA = """
表名: order_info (订单信息表)
字段说明:
- id: 订单ID (主键,INT类型)
- user_id: 用户ID (INT类型)
- order_name: 商品名称 (VARCHAR类型)
- pay_amount: 支付金额 (DECIMAL类型)
- create_time: 下单时间 (DATETIME类型)
"""
# ===================== 模板1:自然语言转SQL专用提示词 =====================
NL_TO_SQL_PROMPT = f"""
你是严谨的 MySQL 8.0 数据库开发工程师。
【任务目标】
根据用户自然语言描述的业务需求,生成可直接执行、无语法错误的MySQL查询SQL。
【表结构参考】
{TABLE_SCHEMA}
【强制输出规则】
1. 只能生成 SELECT 查询语句,绝对不允许生成 INSERT/UPDATE/DELETE/DROP 等修改、删除数据的语
句。
2. 只能使用上面列出的5个字段,禁止自己编造不存在的字段名。
3. 查询字段可使用中文别名,格式固定为:字段 AS 别名。
4 SQL语法遵循MySQL8.0标准,所有关键字统一大写,方便程序解析。
5. 最终SQL必须包裹在 ```sql ``` Markdown代码块内,方便代码提取。
6. 禁止输出任何解释、说明文字,只返回纯SQL代码块,减少解析干扰。
7. 中文别名内部不能带空格,例:订单ID(正确)、订单 ID(错误),避免数据库语法报错。
【用户需求】
{{user_input}}
"""
# ===================== 模板2:SQL性能调优分析专用提示词 =====================
SQL_TUNE_PROMPT = f"""
你是资深 MySQL DBA 性能优化专家。
【任务目标】
根据原始SQL + EXPLAIN执行计划数据,定位查询性能问题并给出可直接落地的优化方案。
【表结构参考】
{TABLE_SCHEMA}
【待分析SQL】
{{sql_input}}
【执行计划数据】
{{explain_data}}
【输出要求】
1. 先点明核心性能问题:全表扫描、无索引、索引失效、扫描行数过多等。
2. 给出完整建索引SQL语句,可直接复制执行。
3. 若原SQL写法存在缺陷,提供改写后的完整优化SQL。
4. 内容简洁、分点罗列,不输出多余废话,便于用户快速阅读。
"""
@staticmethod
def extract_sql(response_text: str) -> str:
"""
静态工具方法:从大模型返回的完整文本里剥离出纯净SQL语句
三层匹配优先级,兼容不同大模型的输出格式,提升提取成功率
:param response_text: 大模型原始完整返回内容
:return: 清洗后的纯SQL字符串,提取失败返回空字符串
"""
# 空文本直接返回
if not response_text:
return ""
5.3.5. 编写程序入口脚本
# 优先级1:匹配最标准markdown sql代码块(项目提示词强制要求的格式)
match = re.search(r"```sql\s*(.*?)\s*```", response_text, re.DOTALL |
re.IGNORECASE)
if match:
return match.group(1).strip()
# 优先级2:兼容自定义<sql>标签格式(备用兼容方案)
match = re.search(r"<sql>\s*(.*?)\s*</sql>", response_text, re.DOTALL |
re.IGNORECASE)
if match:
return match.group(1).strip()
# 优先级3:兜底匹配,直接抓取以SELECT开头、分号结尾的SQL片段
match = re.search(r"(SELECT\s+.*?;)", response_text, re.DOTALL | re.IGNORECASE)
if match:
return match.group(1).strip()
# 三层规则全部匹配不到,说明无有效SQL,返回空
return ""
# 全局单例实例,外部文件导入后直接调用 prompt_helper.方法名,无需重复实例化
prompt_helper = UnifiedPrompt()

**5.3.5.**编写程序入口脚本

bash 复制代码
[root@server ~]# vim /opt/mysql_ai_tools/main.py
# -*- coding: utf-8 -*-
# 文件名:main.py
# 功能:项目核心业务逻辑 + 终端交互式菜单入口
# 作用:统一封装大模型调用、SQL清洗、数据库交互两大核心业务,命令行/网页共用底层函数
import os
import re
import logging
from dotenv import load_dotenv
# 兼容OpenAI标准大模型接口(适配腾讯云TokenHub)
from langchain_openai import ChatOpenAI
# 导入数据库操作封装类
from mysql_client import Mysql80Client
# 表格格式化打印工具,美化终端输出查询结果
from tabulate import tabulate
# 导入提示词管理类与全局实例
from prompts import UnifiedPrompt, prompt_helper
# 加载.env文件里所有数据库、大模型配置
load_dotenv()
# 全局日志配置,替代print,记录运行时间、日志级别、报错信息,方便排障
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %
(message)s")
logger = logging.getLogger(__name__)
def check_config() -> None:
"""
程序启动前置配置校验函数
作用:提前检测.env必填参数是否存在,避免运行中途缺参数崩溃
"""
# 大模型必填参数列表
required_llm = ["LLM_API_KEY", "LLM_BASE_URL", "LLM_MODEL_NAME"]
missing = [k for k in required_llm if not os.getenv(k)]
if missing:
raise ValueError(f"配置缺失:请在 .env 文件中填写 {', '.join(missing)}")
# 数据库必填参数列表
required_db = ["MYSQL_HOST", "MYSQL_USER", "MYSQL_DB"]
missing_db = [k for k in required_db if not os.getenv(k)]
if missing_db:
raise ValueError(f"数据库配置缺失:请检查 {', '.join(missing_db)}")
def get_llm() -> ChatOpenAI:
"""
初始化大模型客户端
适配腾讯云TokenHub等全部兼容OpenAI接口规范的MaaS平台
返回:可直接调用的大模型实例
"""
# 从环境变量读取大模型连接信息
api_key = os.getenv("LLM_API_KEY")
base_url = os.getenv("LLM_BASE_URL")
model_name = os.getenv("LLM_MODEL_NAME")
# 温度不存在则默认0.1,数值越低输出越严谨稳定
temperature = float(os.getenv("LLM_TEMPERATURE", 0.1))
return ChatOpenAI(
api_key=api_key,
base_url=base_url,
model=model_name,
temperature=temperature
)
def clean_sql_spacing(sql: str) -> str:
"""
SQL标准化清洗工具函数(兜底修复各大模型输出格式)
解决:中文空格别名、中文标点、特殊空白、关键字连写等语法报错问题
入参:大模型原始SQL字符串
返回:清洗后可直接执行的标准英文SQL
"""
if not sql:
return ""
# 1. 统一替换各类中文全角空格、换行、制表符为普通半角空格
special_spaces = [
'\xa0', '\u200b', '\u200c', '\u200d', '\u200e', '\u200f',
'\u3000', '\t', '\n', '\r'
]
for sp in special_spaces:
sql = sql.replace(sp, ' ')
# 2. 删除不可见控制字符,防止解析异常
sql = re.sub(r'[\x00-\x1f\x7f]', '', sql)
# 3. 中文标点批量替换为英文标点(解决Qwen等模型输出中文逗号报错)
sql = sql.replace(',', ',').replace(';', ';').replace('(', '(').replace(')', ')')
# 4. 多个连续空格合并为单个,去除首尾多余空格
sql = re.sub(r'\s+', ' ', sql).strip()
# 5. 精准处理AS别名内部空格,只删别名里空格,保留AS与别名之间分隔空格
def _clean_alias_space(match):
prefix = match.group(1) # 捕获AS关键字
alias = match.group(2) # 捕获后面全部别名文本
alias_clean = re.sub(r'\s+', '', alias)
return f"{prefix} {alias_clean}"
# 匹配AS后别名,截止逗号、FROM、WHERE等关键字前停止匹配
sql = re.sub(
r'\b(AS)\s+(.+?)(?
=\s*,\s*|\s+FROM\b|\s+WHERE\b|\s+ORDER\b|\s+GROUP\b|\s+LIMIT\b|\s*;)',
_clean_alias_space,
sql,
flags=re.IGNORECASE
)
# 6. 自动给连写的关键字补空格(字段/中文+关键字粘连自动拆分)
keywords_upper = [
"SELECT", "FROM", "WHERE", "ORDER BY", "GROUP BY",
"AND", "OR", "LIMIT", "DESC", "ASC", "AS",
"INNER JOIN", "LEFT JOIN", "RIGHT JOIN", "ON",
"INSERT INTO", "UPDATE", "SET", "DELETE FROM",
"VALUES", "LIKE", "IN", "BETWEEN", "IS NULL",
"COUNT", "SUM", "AVG", "MAX", "MIN", "OVER"
]
for kw in keywords_upper:
# 字母下划线+关键字粘连拆分,补充第三个参数sql
pattern = r'([a-z_])(' + re.escape(kw) + r')'
sql = re.sub(pattern, r'\1 \2', sql)
# 中文文字+关键字粘连拆分,补充第三个参数sql
pattern_cn = r'([\u4e00-\u9fa5])(' + re.escape(kw) + r')'
sql = re.sub(pattern_cn, r'\1 \2', sql)
# 7. 统一所有SQL关键字大写,格式标准化
keywords_lower = [kw.lower() for kw in keywords_upper]
for kw in keywords_lower:
sql = re.sub(
r'\b' + re.escape(kw) + r'\b',
kw.upper(),
sql,
flags=re.IGNORECASE
)
# 最终再清理一遍多余空格
sql = re.sub(r'\s+', ' ', sql).strip()
return sql
def nl2sql_query(user_input: str) -> dict:
"""
核心业务1:自然语言转SQL、执行查询、AI生成业务总结
对外统一标准返回字典,终端/网页程序均可直接调用,无重复代码
入参:用户自然语言查询需求
返回:包含执行状态、SQL、字段、数据、AI总结、模型原始输出
"""
# 初始化大模型、数据库客户端
llm = get_llm()
db = Mysql80Client()
try:
logger.info("正在生成SQL语句...")
# 1. 加载NL2SQL提示词,填充用户需求传给大模型
prompt = UnifiedPrompt.NL_TO_SQL_PROMPT.format(user_input=user_input)
response = llm.invoke(prompt)
raw_content = response.content.strip()
# 2. 从模型返回文本提取纯净SQL,提取失败直接抛异常
extracted_sql = prompt_helper.extract_sql(raw_content)
if not extracted_sql:
raise Exception("大模型未返回有效SQL,请重新描述需求")
# 3. 清洗SQL修复各类格式问题
clean_sql = clean_sql_spacing(extracted_sql)
logger.info(f"生成SQL:{clean_sql}")
# 4. 数据库执行查询,拿到表头与数据
columns, rows = db.execute_query(clean_sql)
# 5. 如果有数据,调用大模型生成业务解读总结
summary = ""
if rows:
logger.info("正在生成数据总结...")
summary_prompt = f"""
以下是真实的SQL查询结果,请作为电商数据分析师给出简练的业务总结。
SQL语句:{clean_sql}
查询数据:{str(rows)}
重点说明数据反映的业务含义,如有异常值请指出。
"""
summary_resp = llm.invoke(summary_prompt)
summary = summary_resp.content.strip()
# 成功结果返回
return {
"success": True,
"sql": clean_sql,
"columns": columns,
"rows": rows,
"summary": summary,
"raw_llm": raw_content
}
except Exception as e:
# 捕获全流程所有异常,记录日志并返回错误信息
logger.error(f"查询处理失败:{str(e)}")
return {
"success": False,
"error": str(e),
"raw_llm": raw_content if 'raw_content' in dir() else ""
}
finally:
# 无论成功失败,都关闭数据库连接释放资源
db.close()
def sql_tune_analyze(raw_sql: str) -> dict:
"""
核心业务2:SQL性能调优分析
流程:清洗SQL → 获取EXPLAIN执行计划 → AI分析给出优化方案
入参:用户输入待优化SQL
返回:执行状态、清洗后SQL、执行计划字段/内容、调优建议
"""
llm = get_llm()
db = Mysql80Client()
try:
# 先标准化清洗SQL
clean_sql = clean_sql_spacing(raw_sql)
logger.info("正在获取执行计划...")
# 调用数据库封装方法获取EXPLAIN执行计划
columns, plan_rows = db.get_explain_plan(clean_sql)
# 填充调优提示词,传入SQL和执行计划让AI分析瓶颈
logger.info("正在分析性能瓶颈...")
prompt = UnifiedPrompt.SQL_TUNE_PROMPT.format(
sql_input=clean_sql,
explain_data=str(plan_rows)
)
response = llm.invoke(prompt)
return {
"success": True,
"sql": clean_sql,
"plan_columns": columns,
"plan_rows": plan_rows,
"suggestion": response.content.strip()
}
except Exception as e:
logger.error(f"调优分析失败:{str(e)}")
return {
"success": False,
"error": str(e)
}
finally:
# 操作结束关闭数据库连接
db.close()
def main_cli():
"""
终端交互入口主函数
提供循环菜单,支持用户选择查询/调优/退出,纯终端操作
"""
# 程序启动先校验全部配置,失败直接退出菜单
try:
check_config()
except ValueError as e:
print(f"❌ {e}")
return
# 循环交互,不退出可持续多次使用
while True:
print("\n=============== InnoAI SQL 助手 ===============")
print("1. 自然语言生成SQL,自动查询并AI总结数据")
print("2. 输入SQL语句,AI分析执行计划并给出调优方案")
print("0. 退出程序")
choice = input("请输入功能序号: ").strip()
# 功能1:自然语言查数据
if choice == '1':
query = input("请输入你的数据查询需求: ").strip()
if not query:
print("⚠️ 请输入有效需求")
continue
result = nl2sql_query(query)
# 处理失败场景,打印错误与模型原始输出
if not result["success"]:
print(f"\n❌ 处理失败:{result['error']}")
if result.get("raw_llm"):
print(f"大模型原始回复:\n{result['raw_llm']}")
continue
# 成功:打印SQL、格式化表格展示数据、输出业务总结
print(f"\n✅ 生成SQL:")
print(result["sql"])
if result["rows"]:
print(f"\n📊 查询结果(共 {len(result['rows'])} 条):")
print(tabulate(result["rows"], headers="keys", tablefmt="pretty"))
if result["summary"]:
print(f"\n💡 业务总结:\n{result['summary']}")
else:
print("\n⚠️ 未查询到匹配数据")
# 功能2:SQL性能调优
elif choice == '2':
sql_input = input("\n请输入需要分析的 SQL 语句: ").strip()
if not sql_input:
print("⚠️ 请输入有效SQL")
continue
result = sql_tune_analyze(sql_input)
if not result["success"]:
print(f"\n❌ 分析失败:{result['error']}")
continue
# 打印执行计划表格和AI优化建议
print(f"\n📊 执行计划详情:")
print(tabulate(result["plan_rows"], headers="keys", tablefmt="pretty"))
print(f"\n📈 调优建议:\n{result['suggestion']}")
# 0 退出循环,结束程序
elif choice == '0':
print("程序已安全退出。")
break
# 无效数字输入提示
else:
print("无效输入,请重试。")
print("\n" + "-" * 40)
# 程序入口:直接运行main.py则启动终端菜单
if __name__ == "__main__":
main_cli()

6. web****可视化版本
6.1. Streamlit****介绍
Streamlit 是开源、纯 Python Web 开发库,核心定位:不用写 HTML/CSS/JS,只用 Python 就能快速做交
互式网页,专门面向数据分析师、后端、AI 工程师,把本地脚本一键变成可视化 Web 面板。
特点
协议:MIT 开源,商用免费
运行原理:执行 Python 脚本,自动转网页 UI;用户操作时整段脚本从上到下重新运行刷新页面
最贴合当前场景:把原本命令行 Shell MySQL-AI 工具,低成本改成浏览器可视化界面
组件开箱即用,内置全套交互控件
开发热重载,改代码自动刷新页面
部署极其简单,支持服务器system常驻
无缝兼容 Python 全生态
局限性
并发性能一般,单进程模型
自定义 UI 能力弱
原生无登录权限控制
6.2.部署流程
**6.2.1.原则
已有业务文件: main.py mysql_client.py prompts.py .env文件不变
需要编写web_main.py入口文件即可
**6.2.2.安装Python
依赖

注意:必须给python3.11.9安装依赖

bash 复制代码
# 使用python3.11的pip安装,否则会安装到默认的python3.9中
[root@server ~]# /usr/local/python3.11/bin/pip3 install langchain-openai streamlit
pymysql python-dotenv sqlparse tabulate
# 检查
[root@server ~]# /usr/local/python3.11/bin/python3 -c "import
langchain_openai;print('3.11依赖全部正常')"
3.11依赖全部正常

6.2.3.创建Streamlit可视化入口web_main.py

bash 复制代码
[root@server ~]# vim /opt/mysql_ai_tools/web_main.py
# -*- coding: utf-8 -*-
# 文件名:web_main.py
# 功能:Streamlit网页可视化界面
# 说明:前端交互页面,完全复用main.py封装好的业务函数,无需重复编写AI、数据库逻辑
# 两大页面:自然语言查数据、SQL性能调优,做输入前置校验、美化结果展示
import streamlit as st
import os
import re
# 从核心主程序导入通用业务函数、配置校验方法
from main import check_config, nl2sql_query, sql_tune_analyze
# 全局页面基础配置:页面标题、页面宽度铺满屏幕
st.set_page_config(page_title="InnoAI SQL 助手", layout="wide")
# ====================== 全局CSS样式定制:优化字体、间距、按钮、代码块、表格展示
======================
# 使用markdown注入前端样式,统一页面视觉效果,方便演示观看
st.markdown("""
<style>
/* 全局文字基础样式:统一字体、字号、行间距,适配Windows/Mac中文显示 */
html, body, [class*="css"] {
font-size: 15px;
line-height: 1.6;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Microsoft YaHei", sans-serif;
}
/* 页面主体容器:左右留白收窄,太宽的数据表格阅读疲劳 */
.block-container {
padding-top: 2.5rem;
padding-bottom: 3rem;
max-width: 1100px;
margin: 0 auto;
}
/* 各级标题字号、粗细、边距统一优化 */
h1 {
font-size: 2rem !important;
font-weight: 600;
margin-bottom: 1.8rem;
letter-spacing: 0.5px;
}
h2, h3 {
font-weight: 600;
margin-top: 1.5rem;
margin-bottom: 1rem;
}
h3 {
font-size: 1.25rem !important;
}
/* 文本输入框标签样式美化 */
.stTextArea label p {
font-size: 15px;
font-weight: 500;
color: #1f2937;
margin-bottom: 0.5rem;
}
/* 输入框内部样式:字号、圆角、内边距 */
textarea {
font-size: 15px !important;
line-height: 1.6 !important;
border-radius: 8px !important;
padding: 12px 14px !important;
}
/* 全局操作按钮统一尺寸、圆角、内边距,视觉统一 */
.stButton > button {
font-size: 15px !important;
font-weight: 500;
padding: 0.65rem 2.2rem !important;
border-radius: 8px !important;
min-width: 160px;
}
/* 左侧侧边栏样式调整 */
section[data-testid="stSidebar"] {
font-size: 14.5px;
}
/* 侧边大标题禁止自动换行 */
section[data-testid="stSidebar"] h1 {
font-size: 1.5rem !important;
white-space: nowrap;
margin-bottom: 1.2rem;
}
/* 侧边单选按钮间距放大 */
section[data-testid="stSidebar"] .stRadio > div {
gap: 0.8rem;
}
/* 提示警告框字号统一 */
.stAlert {
font-size: 14.5px;
border-radius: 8px !important;
}
/* ========== 重点修复:代码块复制按钮失效问题 ========== */
.stCodeBlock {
position: relative !important;
border-radius: 8px !important;
}
/* 强制显示复制按钮,提高层级防止被遮挡 */
.stCodeBlock button {
opacity: 1 !important;
visibility: visible !important;
pointer-events: auto !important;
z-index: 999 !important;
width: 36px;
height: 36px;
top: 10px;
right: 10px;
border-radius: 6px;
background: #f3f4f6 !important;
color: #374151 !important;
border: 1px solid #e5e7eb !important;
}
/* 按钮悬浮变色提升交互感 */
.stCodeBlock button:hover {
background: #e5e7eb !important;
}
/* SQL代码等宽字体优化,提升代码可读性 */
.stCodeBlock code, .stCodeBlock pre {
font-size: 14.5px !important;
line-height: 1.7 !important;
font-family: "JetBrains Mono", Consolas, Monaco, monospace;
}
/* 数据表格单元格内边距放大,避免文字拥挤 */
.stDataFrame {
font-size: 14.5px;
border-radius: 8px;
overflow: hidden;
}
.stDataFrame [data-testid="table"] td {
padding: 10px 12px;
}
</style>
""", unsafe_allow_html=True)
# 全局一次性配置校验,会话缓存避免重复校验
# st.session_state:streamlit会话全局存储,页面刷新前一直生效
if "config_checked" not in st.session_state:
try:
# 调用main.py的配置校验函数,检测.env文件必填参数
check_config()
# 标记已校验,下次页面刷新不再重复执行
st.session_state.config_checked = True
except ValueError as e:
# 配置缺失直接弹窗报错,终止页面加载
st.error(f"配置错误:{e}")
st.stop()
# ========== 左侧侧边栏区域:系统标题、当前模型展示、页面切换导航 ==========
with st.sidebar:
st.title("🚀 InnoAI SQL 助手")
# 读取环境变量,展示当前正在使用的大模型名称
st.info(f"当前模型:{os.getenv('LLM_MODEL_NAME', '未知')}")
# 单选框切换两大功能页面
page = st.radio("功能导航", ["🔍 数据查询与总结", "⚙️ SQL 性能调优"])
# ====================== 页面1:自然语言转SQL查询页面 ======================
if page == "🔍 数据查询与总结":
st.header("💬 自然语言转 SQL 查询")
# 多行文本输入框,接收用户中文业务需求
user_input = st.text_area("请输入你的业务查询需求:", height=150)
# 点击提交按钮触发查询逻辑
if st.button("🚀 生成并执行", type="primary"):
input_trim = user_input.strip()
# 校验1:输入为空拦截
if not input_trim:
st.warning("请输入有效的业务查询需求后再提交")
# 校验2:禁止直接粘贴SQL,区分两个页面的使用场景
elif re.match(r'(?i)^\s*SELECT\s+', input_trim):
st.warning("此处请输入自然语言描述的查询需求(例如:查询用户 1001 的所有订单),请勿直接
粘贴 SQL 语句。")
# 输入校验全部通过,执行AI查询逻辑
else:
# 加载动画提示用户等待
with st.spinner("AI 正在生成 SQL 并查询数据..."):
# 调用main封装好的核心业务方法
result = nl2sql_query(user_input)
# 分支1:业务执行失败,展示错误信息
if not result["success"]:
st.error(f"处理失败:{result['error']}")
# 折叠面板展示大模型原始返回内容,方便排错
if result.get("raw_llm"):
with st.expander("查看大模型原始回复"):
st.code(result["raw_llm"])
# 分支2:执行成功,分层展示结果
else:
st.success("SQL 生成并执行成功")
# 高亮展示生成后的标准SQL语句
st.code(result["sql"], language="sql")
# 存在查询数据则渲染表格
if result["rows"]:
st.dataframe(result["rows"], use_container_width=True)
# 存在AI业务总结则展示解读文本
if result["summary"]:
st.markdown("### 💡 业务总结")
st.info(result["summary"])
# 无匹配订单提示
else:
st.info("未查询到匹配的数据")
# ====================== 页面2:SQL性能调优分析页面 ======================
else:
st.header("🔧 SQL 性能调优分析")
# 输入框接收用户待优化SELECT语句
raw_sql = st.text_area("请输入待分析的 SQL 语句:", height=200)
# 点击分析按钮执行调优流程
if st.button("📊 开始分析", type="primary"):
input_trim = raw_sql.strip()
# 校验1:空输入拦截
if not input_trim:
st.warning("请输入有效的 SQL 语句后再提交")
# 校验2:必须是SELECT语句,禁止其他类型SQL
elif not re.match(r'(?i)^\s*SELECT\s+', input_trim):
st.warning("此处请输入待分析的 SELECT SQL 语句,请勿输入自然语言描述。如需自然语言转
SQL,请切换到「数据查询与总结」页面。")
# 校验通过,执行调优分析
else:
with st.spinner("正在获取执行计划并分析..."):
# 调用main封装的调优函数
result = sql_tune_analyze(raw_sql)
# 分析失败展示错误
if not result["success"]:
st.error(f"分析失败:{result['error']}")
# 分析成功,展示执行计划表格+AI优化建议
else:
st.success("执行计划获取成功")
st.dataframe(result["plan_rows"], use_container_width=True)
st.markdown("### 💡 调优建议")
7.2.4. 创建 systemd 后台常驻服务
建立streamlit为后台服务
启动服务
7.2.5. Windows网页访问测试
查看ip
浏览器访问:192.168.88.130:8501
st.markdown(result["suggestion"])

6.2.4.创建systemd****后台常驻服务
建立streamlit为后台服务

bash 复制代码
[root@server ~]# vim /etc/systemd/system/mysql-ai-web.service
[Unit]
Description=INDODB AI Streamlit Web Tool
After=network.target mysqld.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/mysql_ai_tools
ExecStart=/usr/local/python3.11/bin/python3 -m streamlit run web_main.py --
server.address 0.0.0.0 --server.port 8501 --server.headless true
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

启动服务:

bash 复制代码
[root@server ~]# systemctl daemon-reload
[root@server ~]# systemctl enable --now mysql-ai-web

6.2.5. Windows****网页访问测试
查看ip:

bash 复制代码
[root@server ~]# hostname -I

浏览器访问ip:

bash 复制代码
[root@server mysql_ai_tools]# tree
.
├── backup
│ ├── explain_optimize.py
│ ├── main.py
│ ├── mysql_client.py
│ └── nl2sql_summary.py
├── main.py
├── mysql_client.py
├── prompts.py
├── __pycache__
│ ├── main.cpython-311.pyc
│ ├── mysql_client.cpython-311.pyc
│ └── prompts.cpython-311.pyc
├── test_runner.py
└── web_main.py
2 directories, 12 files
相关推荐
万悉科技1 小时前
时尚品牌GEO技术选型指南:LLM原生优化与AI记忆构建全解析
数据库·人工智能·搜索引擎
养海绵宝宝的小蜗2 小时前
LVS(Linux Virtual Server)项目知识点总结
linux·运维·lvs
lb29172 小时前
在window上安装orcale数据库流程(快速,简洁)
数据库
IT小盘2 小时前
09-使用Redis保存大模型多轮对话上下文
数据库·redis·缓存
秋田君2 小时前
QT_QT布局常用类QSplitter窗口分割类与QDockWidget窗口停靠类
开发语言·数据库·qt
小果因子实验室2 小时前
策略研究--qmt实现新股自动申购卖出策略
数据库
Darling噜啦啦2 小时前
从零实战Milvus向量数据库:用RAG打造你的AI日记助手
数据库
淼澄研学3 小时前
PyTorch深度学习实战:5个核心方法从0到1构建神经网络
前端·数据库·python
脑子进水养啥鱼?3 小时前
where id > ‘5‘ 的查询 sql 查不到 id = ‘10‘ 的数据?
数据库·sql·postgresql