Skip to main content

1. 项目概览

现代应用越来越多地采用自然语言交互界面,让用户更轻松地操作系统。这在数据查询场景中尤为实用,非技术人员可以直接用日常语言提问。 文本转 SQL 聊天机器人正是这样的典型应用。它在人类语言和数据库之间搭建了沟通桥梁。我们通常借助大语言模型(LLM)将用户的自然语言问题转换为可执行的 SQL 查询语句,然后在数据库中执行查询并返回结果。 本教程将指导你使用 Spring AI 框架构建一个文本转 SQL 聊天机器人。我们会先配置数据库架构并填入测试数据,然后实现支持自然语言查询的聊天机器人功能。

2. 项目搭建

2.1. 添加依赖

首先在项目的 pom.xml 文件中添加必要的依赖:
这里我们添加了:
  • OpenAI 兼容启动器依赖,可以与 DeepSeek API 兼容使用
  • Spring Boot JDBC 启动器,提供 JdbcClient 支持
  • MySQL 驱动程序
  • Flyway 数据库迁移工具
接下来在 application.yaml 文件中配置 DeepSeek API 密钥、聊天模型和数据库连接:
我们使用 ${} 占位符语法从环境变量中读取 API 密钥和数据库配置。 同时指定使用 DeepSeek Chat 模型,并配置 DeepSeek 的 API 基础 URL。DeepSeek 提供了强大的中文和代码理解能力,非常适合文本转 SQL 的场景。数据库配置包括连接 URL、用户名和密码,以及 Flyway 迁移设置。 配置完成后,Spring AI 会自动创建 ChatModel 类型的 Bean,让我们能够与指定的模型进行交互。

2.2. 使用 Flyway 设计数据库表结构

接下来配置数据库结构。我们使用 Flyway 来管理数据库迁移脚本。 我们将创建一个简单的学校管理数据库,使用 MySQL 作为数据库。和 AI 模型选择一样,数据库类型对实现方案没有影响。 首先,在 src/main/resources/db/migration 目录下创建名为 V01__creating_database_tables.sql 的迁移脚本来建立主要数据库表:
这里我们创建了四个主要表:
  • classes 表存储班级信息
  • courses 表存储课程信息
  • students 表存储学生信息,通过外键与班级关联
  • student_courses 表作为学生和课程的多对多关联表,存储选课信息和成绩
接下来,创建 V02__adding_classes_data.sql 文件来填充 classes 表:
这里我们用 INSERT 语句创建六个班级,涵盖高一到高三各个年级。 接着,创建 V03__adding_courses_data.sql 迁移脚本填充 courses 表:
然后创建 V04__adding_students_data.sql 迁移脚本填充 students 表:
定义好迁移脚本后,Flyway 会在应用启动时自动发现并执行这些脚本。

3. 配置 AI 提示词

接下来,为了确保 LLM 能够针对我们的数据库架构生成准确的 SQL 查询,需要定义详细的系统提示词。 src/main/resources 目录下创建 system-prompt.st 文件:
在系统提示词中,我们指示 LLM 只生成 SELECT SQL 查询,并检测 SQL 注入和 DoS 攻击尝试。 我们在系统提示词模板中留了一个 ddl 占位符用于数据库架构。稍后我们会用实际值替换它。 此外,为了进一步保护数据库免受修改,应该只给配置的 MySQL 用户必要的权限。

4. 构建文本转 SQL 聊天机器人

完成配置后,让我们使用配置好的 DeepSeek 模型构建文本转 SQL 聊天机器人。

4.1. 定义聊天机器人 Bean

首先定义聊天机器人所需的 Bean:
首先,我们定义一个 PromptTemplate Bean。通过 @Value 注解注入系统提示词模板文件和数据库架构 DDL 迁移脚本。同时,我们用数据库架构内容填充 ddl 占位符。这确保了 LLM 在生成 SQL 查询时始终能访问我们的数据库结构。 接下来,我们使用 ChatModelPromptTemplate Bean 创建一个 ChatClient Bean。ChatClient 类是我们与配置的 DeepSeek 模型交互的主要入口点。

4.2. 实现服务类

现在,让我们实现服务类来处理 SQL 生成和执行过程。 首先,创建一个 SqlGenerator 服务类,将自然语言问题转换为 SQL 查询:
generate() 方法中,我们接收自然语言问题作为输入,使用 chatClient Bean 将其发送给配置的 LLM。 接下来,我们验证响应确实是 SELECT 查询。如果 LLM 返回 SELECT 查询以外的任何内容,我们抛出带有错误消息的自定义 InvalidQueryException 接下来,为了对数据库执行生成的 SQL 查询,创建一个 SqlExecutor 服务类:
execute() 方法中,我们使用 Spring Boot 3.1+ 引入的 JdbcClient 来运行原生 SQL 查询并返回结果。JdbcClient 提供了更简洁的 API 和更好的类型安全性。如果查询没有返回结果,我们抛出自定义的 EmptyResultException

4.3. 暴露 REST API

现在我们已经实现了服务层,让我们在其上暴露一个 REST API:
POST /query 端点接受自然语言问题,使用 sqlGenerator Bean 生成相应的 SQL 查询,将其传递给 sqlExecutor Bean 从数据库获取结果,最后将数据包装在 QueryResponse 记录中并返回。使用 JdbcClient 返回的结果是 List<Map<String, Object>> 格式,每个 Map 代表一行数据,键为列名,值为对应的数据。

5. 与聊天机器人交互

最后,让我们使用暴露的 API 端点与文本转 SQL 聊天机器人进行交互。 但首先,在 application.yaml 文件中启用 SQL 日志记录,以在日志中查看生成的查询:
接下来,使用 curl 命令调用 API 端点并与聊天机器人交互:
如我们所见,聊天机器人成功理解了我们对高三学生的查询请求,并返回了学生姓名和对应的班级信息。 让我们再试一个更复杂的查询:
最后,让我们检查应用日志,查看 LLM 生成的 SQL 查询:
生成的 SQL 查询正确解释了我们的自然语言请求,连接了 studentsclasses 表来查找高三年级的学生信息。DeepSeek 模型展现了出色的中文理解和 SQL 生成能力。

6. 总结

本教程展示了如何使用 Spring AI 框架构建一个功能完整的文本转 SQL 聊天机器人。 虽然我们已经构建了一个基础的文本转 SQL 系统,但仍有许多改进空间:
  1. 权限控制:根据用户角色限制可访问的数据范围
  2. 结果可视化:将查询结果以图表形式展示
  3. LLM生成优化:通过JSON格式化和JSON修复支持稳定输出
通过本教程的学习,已经体现了构建文本转 SQL 聊天机器人的核心技术。Spring AI 框架的强大功能,结合 DeepSeek 等先进的大语言模型,为我们提供了构建智能数据查询系统的完整解决方案。这种技术组合不仅简化了数据访问流程,也为未来的智能化应用奠定了坚实基础。