通过自然语言查询数据库,让非技术人员也能轻松获取业务数据!RAGFlow SQL Assistant 工作流能帮你实现这一目标。本教程将详细讲解如何搭建一个 SQL Assistant 工作流,通过自然语言直接查询 SQL 数据库,无需编写复杂代码。
工作流简介
本教程通过搭建一个 SQL Assistant 工作流,实现利用自然语言查询 SQL 数据库的功能。企业中的市场运营、产品经理等非技术背景人员可使用此助手独立查询业务数据,减少对数据分析师的依赖;学校和编程教育机构也可将其用作 SQL 教学工具。
工作流编排完成后,整体效果如下(示意图):
工作流编排思路
将数据库的 Schema、数据库表各字段描述以及 SQL 示例,以知识库形式存入 RAGFlow。通过编排,将用户问题在三个知识库中检索,然后把检索后的内容传递给 Agent 生成 SQL 语句。最后,将生成的 SQL 语句传送给 SQL Executor 节点执行,获得最终结果。
搭建步骤
1. 创建三个知识库
1.1 准备知识库文件
您可以从 Hugging Face Datasets(文献 1)下载本样例的数据集。
| 知识库名称 | 用途 | 预置模板文件 | 推荐切片方法 |
|---|---|---|---|
| Schema | 存储数据库 Schema 定义 | Schema.txt | General,建议文本块大小:2,按 “ ; ” 切分 |
| Question to SQL | 存储「问题与 SQL」的示例对,作为模型的学习素材 | Question to SQL.csv | Q&A |
| Database Description | 存储表与字段的业务描述 | Database Description EN.txt | General,建议文本块大小:2,按 ### 切分 |
小提示: 建议提前准备好这三个文件,文件内容格式可参考下文示例片段。
1.2 知识库文件部分内容示例
Schema.txt(部分):
CREATE TABLE `users` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(50) NOT NULL, `password` VARCHAR(50) NOT NULL, `email` VARCHAR(100), `mobile` VARCHAR(20), `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`), UNIQUE KEY `uk_email` (`email`), UNIQUE KEY `uk_mobile` (`mobile`));
...
注意: 定义 Schema 字段时,应避免使用下划线等特殊符号,否则可能导致 LLM 生成的 SQL 语句出现错误。
Question to SQL.csv(部分):
What are the names of all the Cities in Canada
SELECT geo_name, id FROM data_commons_public_data.cybersyn.geo_index WHERE iso_name ilike '%can%
What is a verage Fertility Rate measure of Canada in 2002 ?
SELECT variable_name, a vg(value) as a verage_fertility_rate FROM data_commons_public_data.cybersyn.timeseries WHERE variable_name = 'Fertility Rate' and geo_id = 'country/CAN' and date >= '2002-01-01' and date < '2003-01-01' GROUP BY 1;
What 5 countries ha ve the highest life expectancy ?
SELECT geo_name, value FROM data_commons_public_data.cybersyn.timeseries join data_commons_public_data.cybersyn.geo_index ON timeseries.geo_id = geo_index.id WHERE variable_name = 'Life Expectancy' and date = '2020-01-01' ORDER BY value desc limit 5;
...
Database Description EN.txt(部分):
### Users Table (users)
The users table stores user information for the website or application. Below are the definitions of each column in this table:
- `id`: INTEGER, an auto-incrementing field that uniquely identifies each user (primary key). It automatically increases with every new user added, guaranteeing a distinct ID for every user.
- `username`: VARCHAR, stores the user’s login name; this value is typically the unique identifier used during authentication.
- `password`: VARCHAR, holds the user’s password; for security, the value must be encrypted (hashed) before persistence.
- `email`: VARCHAR, stores the user’s e-mail address; it can serve as an alternate login credential and is used for notifications or password-reset flows.
- `mobile`: VARCHAR, stores the user’s mobile phone number; it can be used for login, receiving SMS notifications, or identity verification.
- `create_time`: TIMESTAMP, records the timestamp when the user account was created; defaults to the current timestamp.
- `update_time`: TIMESTAMP, records the timestamp of the last update to the user’s information; automatically refreshed to the current timestamp on every update.
...
1.3 创建 Schema 知识库
创建知识库并命名为 “Schema”,然后上传 Schema.txt。
数据库表中不同 TABLE 长度各异,每张表都以 ; 结尾,如下所示:
CREATE TABLE `users` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(50) NOT NULL, `password` VARCHAR(50) NOT NULL, ... UNIQUE KEY `uk_mobile` (`mobile`));
CREATE TABLE `products` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `description` TEXT, `price` DECIMAL(10, 2) NOT NULL, `stock` INT NOT NULL, ... FOREIGN KEY (`merchant_id`) REFERENCES `merchants` (`id`));
CREATE TABLE `merchants` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `description` TEXT, `email` VARCHAR(100), ... UNIQUE KEY `uk_mobile` (`mobile`));
为实现将一个 TABLE 切割成一个 Chunk 且不包含其他 TABLE 的内容,需要设置此知识库的配置:
- 切片方法:General
- 文本块大小:2 Token
- 文本分段标识符:
;
小提示: General 方法适合切分结构简明的连续文本,具体效果可查看知识库配置中的 “General” 分块方法说明。设置文本块大小为 2,是因为所有 SQL 语句文本长度都会超过 2。
RAGFlow 会按照下面的流程图解析文本生成 Chunk(示意图省略)。解析结果如下(示意图):
也可以通过检索测试验证召回结果(示意图)。
1.4 创建 Question to SQL 知识库
新建知识库命名为 “Question to SQL”,然后上传 Question to SQL.csv。
配置切片方法为 Q&A,解析后产生如下结果(示意图):
检索测试验证召回结果如下(示意图)。
1.5 创建 Database Description 知识库
新建知识库命名为 “Database Description”,上传 Database Description EN.txt。
配置思路与 Schema 知识库相同:
- 切片方法:General
- 建议文本块大小:2 Token
- 文本分段标识符:
###
配置成功后解析 Database Description EN.txt 预览结果(示意图)。
通过检索测试验证召回结果(示意图)。
注意: 三个知识库独立维护、独立检索,Agent 节点会合并三路结果再做生成。
2. 编排工作流
2.1 创建工作流应用
创建成功后,画布上自动出现开始节点。可在开始节点配置问候语。例如:
Hi! I'm your SQL assistant, what can I do for you?
2.2 配置三个知识检索节点
在开始节点后添加三个并行的知识检索节点,分别命名为:
- Schema
- Question to SQL
- Database Description
每个知识检索节点的查询变量为 sys.query,勾选与节点名称相同的知识库。
2.3 配置 Agent 节点
在知识检索节点后添加 Agent 节点,命名为 “SQL Generator”,将 3 个知识检索节点全部连接到 SQL Generator。
撰写 System Prompt:
### ROLE
You are a Text-to-SQL assistant. Given a relational database schema and a natural-language request, you must produce a **single, syntactically-correct MySQL query** that answers the request. Return **nothing except the SQL statement itself**—no code fences, no commentary, no explanations, no comments, no trailing semicolon if not required.
### EXAMPLES
-- Example 1
User: List every product name and its unit price.
SQL:
SELECT name, unit_price FROM Products;
-- Example 2
User: Show the names and emails of customers who placed orders in January 2025.
SQL:
SELECT DISTINCT c.name, c.email
FROM Customers c
JOIN Orders o ON o.customer_id = c.id
WHERE o.order_date BETWEEN '2025-01-01' AND '2025-01-31';
-- Example 3
User: How many orders ha ve a status of "Completed" for each month in 2024?
SQL:
SELECT DATE_FORMAT(order_date, '%Y-%m') AS month,
COUNT(*) AS completed_orders
FROM Orders
WHERE status = 'Completed'
AND YEAR(order_date) = 2024
GROUP BY month
ORDER BY month;
-- Example 4
User: Which products generated at least $10 000 in total revenue?
SQL:
SELECT p.id, p.name, SUM(oi.quantity * oi.unit_price) AS revenue
FROM Products p
JOIN OrderItems oi ON oi.product_id = p.id
GROUP BY p.id, p.name
HA VING revenue >= 10000
ORDER BY revenue DESC;
### OUTPUT GUIDELINES
1. Think through the schema and the request.
2. Write **only** the final MySQL query.
3. Do **not** wrap the query in back-ticks or markdown fences.
4. Do **not** add explanations, comments, or additional text—just the SQL.
撰写 User Prompt:
User's query: /(Begin Input) sys.query
Schema: /(Schema) formalized_content
Samples about question to SQL: /(Question to SQL) formalized_content
Description about meanings of tables and files: /(Database Description) formalized_content
插入变量后填写效果如下(示意图)。
2.4 配置 ExeSQL 节点
在 SQL Generator 后添加 ExeSQL 节点,命名为 “SQL Executor”。
给 SQL Executor 配置数据库,指定数据库查询的 Query 是 SQL Generator 输出结果。
2.5 配置回复消息节点
给 SQL Executor 添加回复消息节点。
在消息中插入变量,让回复消息节点显示 SQL Executor 的输出内容:
/ ( SQL Executor ) formalized_content
2.6 保存并测试
点击保存 → 运行 → 输入自然语言问题 → 查看执行结果。
注意: NL2SQL 技术与当前的其他 Copilot 一样,无法做到 100% 正确。针对结构化数据的标准处理方案,我们建议将其操作收窄成部分 API,然后把这些 API 封装为 MCP ,再由 RAGFlow 进行调用。我们会在后续文章中,展示该方案的做法。
常见问题
Q1: 为什么在 Schema 知识库中要使用分号作为分段符?
因为每条 CREATE TABLE 语句都以分号结尾,使用分号切分可以确保每张表的完整结构作为一个独立的 Chunk,避免不同表的信息混杂在一起,从而提升检索准确率。
Q2: Question to SQL 知识库为什么用 Q&A 切片方法?
Q&A 切片方法专门用于处理问答对,它会把每个问题及其对应的答案(SQL)保持在一起,形成一个完整的问答对 Chunk。这样当用户提问时,Agent 能更准确地找到类似的问题范例。
Q3: 如果生成的 SQL 执行报错怎么办?
首先检查 Schema 知识库中的字段定义是否正确(字段名是否有特殊符号),其次确认 Question to SQL 中的示例 SQL 语法正确且与目标数据库兼容。另外可在 Agent 的 System Prompt 中详细说明数据库类型(如 MySQL 版本)。
Q4: 我可以直接使用示例中的数据集吗?
可以。示例中的数据集来自 Hugging Face Datasets,并且提供了预置文件(Schema.txt、Question to SQL.csv、Database Description EN.txt),你只需下载并按照教程配置即可快速体验。
Q5: 三个知识库检索出来的内容会不会重复影响生成结果?
不会。RAGFlow 的 Agent 节点会分别从三个知识库获取相关片段,并按照 User Prompt 中定义的变量顺序组合在一起,再交给 LLM 生成最终 SQL。三个知识库提供不同维度的信息(结构、示例、描述),互补而不冲突。
