Text-to-SQL 是什么
把自然语言问题翻成 SQL 再执行,是数据问答助手与自助取数的常见做法。它的成败往往不取决于模型强弱,而取决于上下文给得够不够准:表结构、字段业务含义、枚举取值、方言版本与时间口径都要写进提示词。生成结果必须当作不可信输入处理,先做语法与权限校验,再放进只读环境执行。
基本信息
| 必要输入 | 表名与字段类型、字段业务含义、枚举取值、数据库方言与版本 |
|---|---|
| 输出约束 | 只输出一条可执行 SQL,指定方言,不许带解释与代码块 |
| 执行权限 | 只读账号加表白名单加强制 LIMIT,禁止任何 DDL 与 DML |
| 校验方式 | 先用解析器做语法检查,再 EXPLAIN 或沙箱库试跑 |
| 歧义处理 | 要求反问澄清并输出固定标记,而不是猜一个表名 |
| 评测口径 | 准备问题与标准 SQL 对照集,统计执行成功率与结果一致率 |
典型使用场景
- 内部数据助手上做自助取数,降低业务方手写 SQL 的门槛
- 运营后台把自然语言筛选条件翻译成查询语句
- 数据问答机器人针对固定的几张宽表回答指标问题
- 口径核对:把业务描述与既有 SQL 对照,暴露双方理解差异
- 把配置化的自然语言规则落成可复用 SQL 模板,减少人工改写
含口径约束的提示模板
含口径约束的提示模板
你是 PostgreSQL 专家,只依据下面的表结构回答问题。 # 先限定角色与方言
orders(id bigint, user_id bigint, amount numeric, status text, created_at timestamptz)
users(id bigint, name text, city text)
# status 取值为 pending/paid/shipped/done/cancelled
# created_at 存 UTC,统计“2026 年”指北京时间自然年 # 时间口径必须显式写明
问题:统计 2026 年各城市的已完成订单总金额。
要求:只输出一条可执行 SQL;已完成用 status='done';跨表要显式 JOIN; # 枚举值直接给死
必须带时间范围与 LIMIT;不要输出解释或 Markdown 代码块。 # 约束输出形态
无法确定时只输出 NEED_CLARIFY: 原因。 # 不确定就反问,不要猜高频错误与规避
| 常见错误 | 根因 | 规避做法 |
|---|---|---|
| 猜表名字段名 | schema 没给全,模型按常识编 | 注入完整建表语句与字段注释 |
| 枚举值写错 | 库里是 done,模型写 completed | 提示词里列出取值集合 |
| 方言不符 | 拿 MySQL 写法跑 PostgreSQL | 明确方言并给两三个范例 |
| 全表扫描 | 缺时间过滤或 LIMIT | 强制时间范围与 LIMIT 约束 |
| 越权执行 | 直连可写账号 | 只读账号加白名单加审计日志 |
表很多时不要全塞进提示词:先用关键词或向量召回相关表,只注入命中表的建表语句,既省 token 也减少干扰字段造成的错选。
生成 SQL 与用户输入同样不可信:拼接进语句的自然语言值必须参数化或白名单校验,否则一次提示注入就能把只读问答变成越权查询。