智能问数NL2SQL(Natural Language to SQL)是一种基于人工智能技术的数据查询解决方案,它能够将用户的自然语言查询自动转换为结构化查询语言(SQL),实现对数据库的智能查询。该技术结合了大语言模型的理解能力和数据库的结构化数据管理,为非技术用户提供便捷的数据查询方式。

前置教程

如想快速掌握NL2SQL实现,你可能需要先完成以下前置教程:

资源下载

1. NL2SQL技术简介

NL2SQL技术是指将自然语言描述转换为SQL查询语句的技术,它弥合了人类语言与机器语言之间的鸿沟,让非技术人员也能轻松查询数据库。

NL2SQL的核心优势

  • 降低使用门槛:无需学习SQL语法,用自然语言即可查询
  • 提高查询效率:快速生成复杂SQL语句,节省开发时间
  • 智能理解能力:能够理解模糊查询和复杂的业务逻辑
  • 多表关联支持:支持多表联合查询和复杂关系处理
  • 实时交互:支持即时查询和结果反馈

NL2SQL的应用场景

企业数据分析:

  • 业务人员快速查询销售数据
  • 管理层获取关键业务指标
  • 财务人员进行数据核对

教育培训领域:

  • 学生学习数据库查询
  • 教师演示数据查询原理
  • 培训机构进行SQL教学

智能客服系统:

  • 用户查询订单信息
  • 客服查询客户数据
  • 自动化报表生成

2. NL2SQL实现架构

2.1 技术架构概述

NL2SQL系统的核心架构包含以下几个主要组件:

核心组件结构

graph LR A["用户输入
自然语言"] --> B["大语言模型
语义理解"] B --> C["SQL生成
结构化查询"] C --> D["数据库查询
数据执行"] D --> E["结果返回
格式化输出"]

技术栈说明

  • 前端界面:用户输入查询的自然语言
  • 大语言模型:负责语义理解和SQL生成
  • 查询引擎:执行生成的SQL语句
  • 数据库:存储和查询结构化数据
  • 结果处理器:格式化并返回查询结果

2.2 实现路径规划

实现版本 实现目标 技术特点
1.0 基础 单表查询支持
基础SQL语句生成
手动提示词配置
使用Ollama或LM Studio运行大模型
通过预置提示词指导模型生成SQL
手动将生成的SQL粘贴到数据库工具执行
2.0 进阶 集成Dify工作流
自动化SQL执行
Web界面交互
使用Dify构建工作流应用
集成HTTP请求自动执行SQL
构建本地Web服务处理数据库查询
3.0 高级 大量表结构管理
智能表结构识别
动态提示词生成
支持大量数据表的元数据管理
智能识别查询目标表
动态生成表结构信息与表关联关系
4.0 智能 更准确、更快速、更智能 会在后面的教程中详细介绍,敬请期待...

3. 基础环境准备

3.1 数据库环境配置

请参照MySQL数据库的安装与基本使用教程,并确保MySQL服务已启动,HeidiSQL已安装并能够成功连接数据库。

3.2 大模型环境配置

如使用本地大模型,请参照Ollama本地部署大语言模型完整教程,并确保Ollama服务已启动,可以通过Cherry Studio与其对话。需要特殊说明的是,请尽量使用参数量大的LLM模型,否则生成的SQL语句准确性较差。如果是qwen系列模型,请使用qwen3:8b及以上模型。

你也可以使用LLM的API服务,请参照大语言模型LLM服务商Api服务调用教程,并在Cherry Studio中配置相应的API服务。

3.3 Dify环境配置

请参照Dify安装与基于Embedding实现知识库RAG教程,并确保Dify服务已启动,Ollama或API服务已导入到Dify中作为LLM服务。

3.4 数据库准备

3.4.1 创建示例数据库

如果使用网盘提供的脚本文件:

  1. 在HeidiSQL中点击"文件" → "加载SQL文件"
  2. 选择网盘中的nl2sql.sql文件
  3. 点击"执行"按钮导入数据
  4. 验证数据表和数据的正确性:
  • 确保数据库nl2sql已创建
  • 确保表users已创建
  • 确保数据已正确插入

4. NL2SQL基础实现

4.1 提示词工程

4.1.1 提示词设计原则

有效的提示词是NL2SQL成功的关键,需要包含以下核心要素:

提示词核心结构: 1. 角色定义:明确模型的角色定位 2. 任务描述:清楚说明需要完成的任务 3. 上下文信息:提供数据库表结构信息 4. 输出格式:明确指定输出格式要求 5. 约束条件:设置查询的约束和限制

4.1.2 基础提示词模板

## 角色
你是一名专业的数据库数据查询人员

## 工作内容
你需要实现将你接收到的自然语言转换为MySQL查询语句,以便于用户能够查询数据库中的数据

## 被查询的数据表结构
CREATE TABLE `users` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
    `name` VARCHAR(50) NOT NULL COMMENT '姓名' COLLATE 'utf8_unicode_ci',
    `age` INT(11) NULL DEFAULT NULL COMMENT '年龄',
    `hobby` VARCHAR(50) NULL DEFAULT NULL COMMENT '爱好' COLLATE 'utf8_unicode_ci',
    `city` VARCHAR(50) NULL DEFAULT NULL COMMENT '所在城市' COLLATE 'utf8_unicode_ci',
    `high_school_score` FLOAT(12) NULL DEFAULT NULL COMMENT '高考成绩',
    `cutoff_score` FLOAT(12) NULL DEFAULT NULL COMMENT '分数线',
    PRIMARY KEY (`id`) USING BTREE
) COMMENT='用户表' COLLATE='utf8_unicode_ci' ENGINE=InnoDB AUTO_INCREMENT=5;

## 可用的查询方法
- 当用户询问"求和"或"总和"时,使用SUM()函数
- 当用户询问"平均数"或"平均"时,使用AVG()函数
- 当用户询问"最大值"时,使用MAX()函数
- 当用户询问"最小值"时,使用MIN()函数
- 当用户询问"计数"时,使用COUNT()函数

## 输出要求
1. 如果用户输入无法生成SQL语句,请回复:"抱歉,该命令无法形成数据库查询操作"
2. 生成的SQL语句必须完整且可直接执行
3. 对于字符串查询,使用LIKE操作符而不是等号
4. 只输出SQL语句,不要包含任何其他内容

4.2 基础查询实现

4.2.1 配置Cherry Studio

  1. 打开Cherry Studio
  2. 点击右上角助手,右键编辑助手
  3. 提示词中粘贴上述提示词
  4. 保存配置

4.2.2 执行查询测试

基础查询示例

  1. 用户输入:张三几岁了
  2. 预期输出:SELECT age FROM users WHERE name LIKE '张三';

  3. 用户输入:所有用户的平均年龄

  4. 预期输出:SELECT AVG(age) FROM users;

  5. 用户输入:有多少个用户来自北京

  6. 预期输出:SELECT COUNT(*) FROM users WHERE city LIKE '北京';

4.2.3 查询结果验证

  1. 复制生成的SQL语句
  2. 在HeidiSQL中打开查询窗口
  3. 粘贴SQL语句并执行
  4. 验证查询结果的正确性

结果显示示意图

5. 进阶实现:Dify集成

5.1 创建工作流应用

你可以直接将nl2sql/nl2sql.yml中的工作流设计文件导入到Dify中。

在浏览器中输入localhost → 工作室 → 创建 → 导入DSL文件 → 导入nl2sql/nl2sql.yml文件

创建工作流应用示意图

你可能需要下载一个名为Database的插件,下载完成后你将获得如下的工作流:

创建工作流应用示意图

核心配置项说明

创建工作流应用示意图

mysql+pymysql://root:root@host.docker.internal:3306/nl2sql

  • root:root 为数据库用户名
  • host.docker.internal 为宿主机地址(从Docker容器内部访问宿主机时使用)
  • 3306 为MySQL数据库端口
  • nl2sql 为数据库名称

你可以对照自己的数据库配置进行修改。

发布和运行

  1. 在Dify中点击"发布"
  2. 选择"更新"应用
  3. 点击"运行"按钮
  4. 在弹出的对话框中输入测试查询

查询测试

  1. 输入:张三几岁了
  2. 预期流程:
  • LLM生成:SELECT age FROM users WHERE name LIKE '张三';
  • 输出结果:age 25
  1. 输入:所有用户的平均高考成绩
  2. 预期流程:
  • LLM生成:SELECT AVG(high_school_score) FROM users;
  • 输出结果:AVG(high_school_score) 632.5

创建工作流应用示意图

6. 高级实现:多表及关联表查询

6.1 数据表元数据管理

元数据表与其它关联表设计:

你可以将nl2sql/nl2sql_higher.sql,复制到HeidiSQL中运行以新增相应的数据表。

理念介绍

由于表的数量众多,而LLM能够承载的上下文窗口是有限的,因而就不能一次性将所有的表结构信息通过提示词的方式全部给到LLM,于是我们希望通过分步走-时间换空间的方式,将用户的数据查询任务先判定到可能在哪张(组)数据表中,再将对应的数据表的表结构信息以提示词的形式给到LLM,最后由LLM根据提示词生成对应的SQL查询语句,进而完成查询。

元数据表中,记录着所有数据表的表结构信息及其关联关系,这样既可以保证数据内容的完整性,也降低了LLM生成SQL语句的难度。

需要说明的是:涉及到关联关系较为复杂的查询,本地的小模型可能无法满足需求,需要使用更大参数量的模型或通过API进行测试。

动态提示词生成

你可以直接将nl2sql/nl2sql_higher.yml中的工作流设计文件导入到Dify中:

数据表元数据管理示意图

以下是LLM1的提示词:

## 角色
你是一名数据库管理人员

## 工作内容
你需要根据"{{#context#}}"的判定主体是什么,并根据我给出的下面的数据表结构内容生成查询对应table_name(表名)的table_structure字段中内容的mysql查询语句

## 你可用于判定主体的数据表的表名为
| id | table_name | comment |
| --- | --- | --- |
| 1 | users | 用户表 |
| 2 | orders | 订单表 |
| 3 | goods| 产品表 |

## 被查询的数据表的结构
CREATE TABLE `data_table_structure` (
    `id` VARCHAR(50) NULL DEFAULT NULL COMMENT 'ID',
    `table_name` VARCHAR(50) NULL DEFAULT NULL COMMENT '数据表名',
    `table_structure` VARCHAR(50) NULL DEFAULT NULL COMMENT '数据表结构'
    )
    COMMENT='数据表结构'
    COLLATE='utf8_unicode_ci'
;

## 主要目的
你生成的sql语句不是直接用于查询数据而是获取完整的数据表名、数据表结构的信息
例如:
我输入:张三几岁了
你输出:SELECT table_structure FROM data_table_structure WHERE table_name = 'users';

## 注意
1.你要查询表结构的表名为"data_table_structure"。

以下是LLM2的提示词:

## 角色
你是一名数据库数据查询人员

## 工作内容
你需要将"{{#context#}}"转换为SQL查询语句去MySql数据库中查找数据,请根据下方表结构准确判断用户所需要查询的字段信息

## 被查询的数据表的表结构
{{#1746794342206.body#}}

## 你可以使用的其他方法
用户输入类似于“求和”或“总和”时,则在sql语句中使用SUM()。
用户输入类似于“平均数”或“平均”时,在sql语句中使用AVG()。

## 要求
1.如果用户输入的内容无法生成为sql语句,请直接说“抱歉,该命令无法形成数据库查询操作”。
2.当可以生成sql语句时,请确保输出的内容为完整正确的sql语句,不要输出此外的其他任何字符,确保你生成的内容用户可以直接执行查询操作。
3.对于字符串内容的查询请使用LIKE操作而不是等于操作。
4.请不要在回复中包括除sql语句之外的任何内容。

表结构识别阶段

首先识别用户查询涉及的数据表:

## 第一阶段:表结构识别
你需要根据用户查询内容,识别出需要查询的数据表,并获取该表的完整结构信息。

例如:
用户输入:"张三的订单信息"
你需要识别出需要查询users表和orders表,并获取这两个表的结构信息

SQL生成阶段

基于识别出的表结构生成最终的SQL查询:

## 第二阶段:SQL生成
基于第一阶段获取的表结构信息,生成完整的SQL查询语句

要求:
1. 正确处理表关联关系
2. 使用适当的JOIN语句
3. 确保字段名称和表名称的准确性

6.2 测试多表关联查询

为了验证系统的多表关联查询功能,我们可以测试以下查询:

  • 查询所有用户的订单信息(包括用户姓名、订单ID、订单金额等)
  • 查询用户张三的所有订单信息(包括订单ID、订单金额、订单日期等)
  • 查询所有订单中金额大于200的订单信息(包括订单ID、订单金额、订单日期等)

7. 总结

通过本教程,你应该掌握了智能问数NL2SQL系统的完整实现路径,从基础的单表查询到复杂的多表关联查询。由于篇幅限制,我们将在后面的教程中通过智能体的方式实现智能问数的智能阶段的实现。