一、项目前言&背景

1.1 业务痛点

日常企业数据场景存在两大核心痛点:

  1. 业务人员不会写SQL:运营、产品想要统计订单数据,必须依赖后端/DBA开发人员写查询,沟通成本高、报表交付慢;
  2. DBA重复低效工作:海量慢SQL人工分析EXPLAIN执行计划、手动设计索引,重复性运维工作占用大量精力;
  3. 传统NL2SQL工具安全性差:很多开源工具未做SQL拦截,存在删改表、篡改数据风险,密钥硬编码极易泄露。

1.2 项目核心价值

本项目基于openEuler国产操作系统+MySQL8.0+腾讯云TokenHub大模型聚合平台,打造轻量化一体化智能SQL工具:

  1. 自然语言一键生成只读SQL:仅允许SELECT语句,自动拦截INSERT/UPDATE/DELETE/ALTER等危险操作;
  2. 自动执行查询+AI业务解读:查询结果表格化输出,大模型自动生成通俗易懂的业务总结,替代人工报表;
  3. 全自动SQL性能调优:解析EXPLAIN执行计划,定位全表扫描、文件排序等瓶颈,直接输出可执行索引创建SQL与优化后语句;
  4. 双端交互入口:服务器终端交互式菜单 + Streamlit可视化Web面板,运维/业务人员按需使用;
  5. 完善安全机制:敏感账号密钥独立.env配置文件,文件权限设置600,全程不打印明文密码。

1.3 开发周期&人员

  • 开发人数:1~3人小组单人开发均可
  • 总周期:3个工作日(每日8小时)
    • Day1:openEuler环境部署、MySQL8.0搭建、大模型API申请、运维知识点梳理
    • Day2:Python分层脚本开发、NL2SQL、SQL调优、终端主程序联调
    • Day3:多场景测试、提示词优化、权限安全加固、整体验收

二、整体技术方案与四层架构

2.1 软硬件环境清单

硬件环境
类别 参数规格 用途
虚拟机/云ECS CPU≥2核,内存≥4GB,磁盘≥20GB 运行openEuler、MySQL、Python程序
软件环境
软件 版本 作用
操作系统 openEuler/RHEL9 底层运行系统,国产适配
MySQL 8.0.45 存储电商订单测试数据order_info
Python 3.11.9(源码编译) 项目开发主语言
大模型平台 腾讯云TokenHub 兼容DeepSeek V4 Pro、Qwen3.5-Plus
Web框架 Streamlit 零前端可视化网页面板
Python依赖 pymysql、python-dotenv、langchain-openai、tabulate 数据库连接、配置读取、大模型调用、表格渲染
网络&账号资源
  1. 服务器外网可访问443端口,用于调用大模型API;
  2. 腾讯云账号完成实名认证,获取TokenHub API Key。

2.2 四层分层架构详解

在这里插入图片描述

层级1:接入交互层(双入口)

面向运维、业务、开发人员,两种使用模式完全复用底层逻辑:

  1. 命令行终端python3 main.py交互式菜单,适合服务器本地运维快速排查;
  2. Web可视化页面:Streamlit web_main.py,浏览器访问,图形化输入、一键复制SQL、表格展示结果,非技术人员友好。
层级2:Python程序核心层(5个核心文件,解耦设计)
  1. main.py:项目总调度入口,封装NL2SQL查询、AI总结、SQL调优三大核心业务,终端/Web共用底层函数;
  2. mysql_client.py:数据库统一封装类,管理连接、安全校验、执行SQL、获取EXPLAIN执行计划;
  3. prompts.py:提示词工程统一管理,内置NL2SQL、SQL调优两套Prompt,附带正则提取纯净SQL工具;
  4. web_main.py:Streamlit前端页面,输入校验、页面美化、结果渲染;
  5. .env:独立配置文件,存放数据库账号、大模型密钥,敏感信息与代码隔离。
层级3:底层数据持久层

openEuler虚拟机部署MySQL8.0.45,创建testdb数据库、order_info电商订单表,预置20条测试订单数据,作为项目唯一数据源。

层级4:AI大模型服务层

腾讯云TokenHub聚合平台作为统一AI网关,一套代码无缝切换多款开源大模型,统一鉴权、计费、运维,兼容OpenAI标准接口。

三、完整环境搭建实操(openEuler)

3.1 openEuler系统初始化

1)关闭防火墙与SELinux
# 关闭SELinux永久生效
sed -i '7s/enforcing/disabled/' /etc/selinux/config
# 关闭并禁用防火墙
systemctl disable --now firewalld
systemctl status firewalld
# 修改主机名
hostnamectl set-hostname server
bash
2)时间同步+安装系统依赖
# 配置阿里云时间服务器
vim /etc/chrony.conf
server ntp.aliyun.com iburst
systemctl restart chronyd
chronyc sources

# 安装编译全套依赖
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

3.2 源码编译安装Python3.11.9

在这里插入图片描述

# 上传源码至/usr/local/src
cd /usr/local/src
tar -zxvf Python-3.11.9.tgz
cd Python-3.11.9

# 编译配置
./configure --prefix=/usr/local/python3.11 --enable-shared
make -j$(nproc) && make install

# 配置动态链接库
echo "/usr/local/python3.11/lib" > /etc/ld.so.conf.d/python311.conf
ldconfig

# 全局软链接,不覆盖系统Python
ln -s /usr/local/python3.11/bin/python3.11 /usr/local/bin/python3
ln -s /usr/local/python3.11/bin/pip3.11 /usr/local/bin/pip3
bash

# 验证安装
python3 -V
pip3 -V
# 校验SSL(大模型接口必备)
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
配置阿里pip镜像源
mkdir ~/.pip
vim ~/.pip/pip.conf
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host=mirrors.aliyun.com

# 安装项目依赖
pip3 install --upgrade pip
pip3 install pymysql python-dotenv tabulate langchain langchain-openai streamlit

3.3 MySQL8.0.45部署初始化

1)解压安装并初始化
# 上传MySQL压缩包,移动至/usr/local/mysql
tar -xvf mysql-8.0.45-linux-glibc2.28-x86_64.tar.xz
mv mysql-8.0.45-linux-glibc2.28-x86_64 /usr/local/mysql
cd /usr/local/mysql

# 创建mysql用户组与系统用户
groupadd mysql
useradd -r -g mysql -s /sbin/nologin mysql
mkdir data
chmod -R 750 data
chown -R mysql:mysql /usr/local/mysql

# 初始化数据库(保存输出的初始密码)
bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
# 后台启动
bin/mysqld_safe --user=mysql &
2)修改root密码、配置systemd服务
# 登录数据库修改密码
bin/mysql -u root -p
mysql> alter user 'root'@'localhost' identified with mysql_native_password by '123456';
mysql> flush privileges;
exit;

# 编写my.cnf配置
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

# systemd服务文件
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

# 重载并开机自启
systemctl daemon-reload
systemctl enable --now mysqld.service
# 配置环境变量
echo "export PATH=$PATH:/usr/local/mysql/bin" >> ~/.bash_profile
source ~/.bash_profile
mysql -V
3)创建业务库与订单测试表
create database testdb;
use testdb;
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条测试数据
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');

3.4 腾讯云TokenHub大模型API配置

在这里插入图片描述
在这里插入图片描述

  1. 访问腾讯云官网,注册并实名认证;
  2. 进入TokenHub控制台 → API Key管理 → 创建密钥,保存sk-xxx密钥;
  3. 模型推荐:deepseek-v4-pro / Qwen3.5-Plus(无多余思考链,避免SQL解析报错)。

四、项目核心代码分层讲解

4.1 项目目录创建

mkdir -p /opt/mysql_ai_tools
cd /opt/mysql_ai_tools
touch main.py mysql_client.py prompts.py web_main.py .env

4.2 .env 配置文件(安全加固 chmod 600)

# MySQL数据库配置
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=123456
MYSQL_DB=testdb

# 腾讯云TokenHub大模型配置
LLM_API_KEY=sk-jUJebmj56mEQhhBep04A3AIaVlVV2NA97F45iimZ***
LLM_BASE_URL=https://tokenhub.tencentmaas.com/v1
LLM_MODEL_NAME=deepseek-v4-pro
LLM_TEMPERATURE=0
权限加固(关键安全操作)
chmod 600 /opt/mysql_ai_tools/.env

4.3 mysql_client.py 数据库封装&SQL安全拦截

核心亮点:内置危险SQL黑名单,仅放行SELECT查询,防止数据误删改;统一管理连接释放,自动获取EXPLAIN执行计划。

# -*- coding: utf-8 -*-
import pymysql
import os
import re
from dotenv import load_dotenv
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',cursorclass=pymysql.cursors.DictCursor
            )
        except Exception as e:
            raise Exception(f"数据库连接失败:{str(e)}")

    @staticmethod
    def _check_sql_safety(sql: str) -> None:
        # 危险操作黑名单,拦截增删改、DDL语句
        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):
        self._check_sql_safety(sql)
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            columns = [desc[0] for desc in cursor.description]
            rows = cursor.fetchall()
            return columns, rows

    def get_explain_plan(self, sql: str):
        self._check_sql_safety(sql)
        explain_sql = f"EXPLAIN {sql}"
        with self.conn.cursor() as cursor:
            cursor.execute(explain_sql)
            columns = [desc[0] for desc in cursor.description]
            rows = cursor.fetchall()
            return columns, rows

    def close(self):
        if self.conn and not self.conn._closed:
            self.conn.close()

4.4 prompts.py 提示词工程+SQL提取工具

统一管理两套Prompt,严格约束大模型输出格式,搭配正则三层匹配提取纯净SQL,解决模型输出杂乱问题。

# -*- coding: utf-8 -*-
import re
class UnifiedPrompt:
    # 全局订单表结构,统一维护一处
    TABLE_SCHEMA = """
表名: order_info (订单信息表)
字段说明:
- id: 订单ID (主键,BIGINT)
- user_id: 用户ID (INT)
- order_name: 商品名称 (VARCHAR)
- pay_amount: 支付金额 (DECIMAL(10,2))
- create_time: 下单时间 (DATETIME)
"""
    # 自然语言转SQL提示词
    NL_TO_SQL_PROMPT = f"""
你是严谨MySQL8.0工程师,根据用户业务需求生成标准SELECT语句。
表结构:{TABLE_SCHEMA}
强制规则:
1. 仅输出SELECT,禁止任何增删改、建表语句;
2. 只能使用给定字段,禁止编造字段;
3. SQL关键字大写,中文别名无空格;
4. SQL包裹在```sql ```代码块,不输出多余解释文字;
用户需求:{{user_input}}
"""
    # SQL性能调优提示词
    SQL_TUNE_PROMPT = f"""
你是资深MySQL DBA,根据SQL+EXPLAIN执行计划输出优化方案。
表结构:{TABLE_SCHEMA}
待分析SQL:{{sql_input}}
执行计划数据:{{explain_data}}
输出要求:
1. 点明核心性能问题(全表扫描、文件排序、无索引等);
2. 给出可直接执行的建索引SQL;
3. 输出优化改写后的完整SQL;
4. 分点简洁输出。
"""
    # 三层正则提取纯净SQL
    @staticmethod
    def extract_sql(response_text: str) -> str:
        if not response_text:
            return ""
        # 优先级1:标准markdown sql代码块
        match = re.search(r"```sql\s*(.*?)\s*```", response_text, re.DOTALL | re.IGNORECASE)
        if match:
            return match.group(1).strip()
        # 优先级2:兜底匹配SELECT开头语句
        match = re.search(r"(SELECT\s+.*?;)", response_text, re.DOTALL | re.IGNORECASE)
        if match:
            return match.group(1).strip()
        return ""
prompt_helper = UnifiedPrompt()

4.5 main.py 核心调度+终端交互入口

实现两大核心业务:自然语言查询、SQL性能调优;内置SQL清洗工具,兼容各类模型输出格式,终端菜单循环交互。

完整代码见项目PDF文档,核心逻辑:

  1. nl2sql_query:自然语言生成SQL、执行查询、AI业务总结
  2. sql_tune_analyze:获取EXPLAIN、AI分析性能瓶颈、输出调优方案
  3. main_cli:终端交互式菜单

4.6 web_main.py Streamlit可视化网页

核心能力
  1. 左侧侧边栏导航,切换「数据查询」「SQL调优」两大页面;
  2. 输入前置校验:区分自然语言输入与SQL输入,防止用户操作混淆;
  3. 美化页面CSS、表格、代码复制按钮、加载动画;
  4. 完全复用main.py底层业务函数,无重复开发。
    在这里插入图片描述

4.7 Streamlit后台systemd常驻服务

vim /etc/systemd/system/mysql-ai-web.service
[Unit]
Description=InnoAI SQL Streamlit Web服务
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

# 重载并开机自启
systemctl daemon-reload
systemctl enable --now mysql-ai-web
# 查看服务器IP,浏览器访问 ip:8501
hostname -I

五、项目功能实测演示

5.1 自然语言查询测试用例

测试需求:1001、1002、1003 每个用户的订单总消费金额与订单笔数,按总消费从高到低排序

1)自动生成SQL
SELECT user_id AS 用户ID, SUM(pay_amount) AS 总消费金额, COUNT(id) AS 订单笔数 
FROM order_info 
WHERE user_id IN (1001, 1002, 1003) 
GROUP BY user_id 
ORDER BY 总消费金额 DESC
2)查询结果表格
用户ID 总消费金额 订单笔数
1002 5588.00 2
1001 3198.00 2
1003 1848.00 2
3)AI自动业务总结
  1. 用户分层明显:1002为高价值用户,总消费5588元,客单价远超其他两位用户;
  2. 三位用户订单笔数均为2单,复购节奏高度相似;
  3. 样本数据订单数量统一,建议扩大数据范围验证用户消费规律。

5.2 SQL性能调优实测

待优化SQL
SELECT user_id AS 用户ID, SUM(pay_amount) AS 总消费金额, COUNT(id) AS 订单笔数 
FROM order_info 
WHERE user_id IN (1001, 1002, 1003) 
GROUP BY user_id 
ORDER BY 总消费金额 DESC
执行计划问题

type=ALL全表扫描、Using temporary; Using filesort临时表+文件排序,无任何索引命中。

AI输出优化方案
  1. 创建覆盖索引
ALTER TABLE order_info ADD INDEX idx_user_id_pay_amount (user_id, pay_amount);
  1. 优化改写SQL
SELECT user_id AS 用户ID, SUM(pay_amount) AS 总消费金额,COUNT(*) AS 订单笔数
FROM order_info
WHERE user_id IN (1001, 1002, 1003)
GROUP BY user_id
ORDER BY 总消费金额 DESC;

六、项目安全&稳定性设计

6.1 数据安全防护

  1. SQL黑白名单拦截:仅放行SELECT,自动拦截所有增删改、DDL危险语句;
  2. 配置文件权限隔离.env设置600权限,仅root可读,不打印账号密钥明文;
  3. 数据库使用只读逻辑,无数据写入/修改操作,避免业务数据损坏。

6.2 程序稳定性保障

  1. 全流程异常捕获:数据库连接、大模型API、SQL语法错误统一捕获,程序不崩溃;
  2. 输入容错:空白输入、超长需求、无匹配数据友好提示;
  3. SQL标准化清洗:统一处理中文标点、全角空格、关键字粘连,解决模型输出语法报错;
  4. 数据库连接自动关闭,避免长连接占用资源。

6.3 系统兼容性

  1. 系统:openEuler/RHEL国产Linux兼容;
  2. 数据库:锁定MySQL8.0.45,适配InnoDB索引规范;
  3. 大模型:兼容所有OpenAI接口标准MaaS平台,一键切换DeepSeek/Qwen系列模型。

七、踩坑记录&解决方案

  1. Python编译后SSL缺失:编译时必须带上openssl-devel依赖,否则大模型HTTPS接口调用失败;
  2. 大模型输出携带思考链,SQL提取失败:选用不带推理思考的模型,增加正则过滤多余文本;
  3. Streamlit外部无法访问:启动参数添加--server.address 0.0.0.0,开放局域网访问;
  4. MySQL8.0认证插件报错:修改root账号认证方式为mysql_native_password
  5. .env密钥泄露风险:必须执行chmod 600,禁止其他用户读取配置文件。

八、项目拓展优化方向

  1. 权限精细化:增加Web页面登录鉴权,区分普通查询用户与调优管理员;
  2. 多表关联支持:扩展表结构,支持多表JOIN场景NL2SQL生成;
  3. 慢SQL批量分析:支持批量导入多条SQL,批量输出索引优化方案;
  4. Docker容器化:打包openEuler、MySQL、Python环境,一键部署;
  5. 本地私有大模型适配:兼容本地部署Qwen/DeepSeek离线模型,无需外网API;
  6. 导出报表:查询结果支持Excel下载,自动生成业务分析报告文件。

九、项目总结

  1. 落地价值:轻量化一站式AI数据库工具,零SQL基础业务人员可自主查询数据,解放DBA重复调优工作,适配中小企业轻量化数据平台;
  2. 技术学习点:覆盖国产openEuler运维、MySQL8.0深度运维、Python分层架构、大模型Prompt工程、NL2SQL落地、Streamlit低代码Web开发、systemd服务部署;
  3. 适用人群:计算机专业实训项目、运维工程师、后端开发、AI应用开发学习者完整实战案例;
  4. 部署门槛:低配虚拟机即可运行,3天完整从零搭建完成,代码模块化易二次开发改造。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐