一文搞懂 Text2SQL:用大模型让自然语言直接查数据库

不写一行 SQL,用中文问一句话,数据库自动返回结果------这篇文章带你从 SQLite 基础到完整实现跑通。

前言

最近在学大模型应用开发,发现 Text2SQL 这个方向特别有意思------把自然语言翻译成 SQL 语句,让不懂技术的人也能查数据库。踩了不少坑,从 SQLite 建表到 prompt 模板设计,把整个流程走通了,整理出来分享给大家。

你将会收获:

  • SQLite 基础操作:建库、建表、增删改查
  • Text2SQL 的完整实现流程:从用户提问到拿到查询结果
  • 两种 schema 提取方式的对比与选择
  • Prompt 模板设计的核心技巧
  • 面试时能讲清楚 Text2SQL 的原理和实现

技术栈: Python + SQLite + DeepSeek API(兼容 OpenAI 接口)


一、SQLite:一个文件就是一个数据库

为什么选 SQLite?

在学 Text2SQL 之前,得先搞清楚我们要查的数据库长什么样。这里用的是 SQLite------它最大的特点是零配置、单文件

特性 SQLite MySQL / PostgreSQL
安装 不需要,Python 内置 需要安装服务
配置 零配置 需要配置用户、权限、端口
存储 一个 .db 文件 服务端进程管理
适用场景 本地开发、教学、嵌入式 生产环境、高并发

💡 一句话记住: SQLite 就是把整个数据库塞进一个文件里,打开就能用。

建库建表:5 行代码搞定

python 复制代码
import sqlite3

# 连接数据库(文件不存在会自动创建)
conn = sqlite3.connect("test.db")
cursor = conn.cursor()

# 建表
cursor.execute("""
CREATE TABLE IF NOT EXISTS employees(
    id INTEGER PRIMARY KEY,
    name TEXT,
    department TEXT,
    salary INTEGER
)
""")

逐行拆解:

  1. sqlite3.connect("test.db") --- 连接到 test.db 文件,不存在就新建
  2. conn.cursor() --- 创建游标对象,所有 SQL 操作都通过它执行
  3. CREATE TABLE IF NOT EXISTS --- 如果表已存在就跳过,避免报错
  4. INTEGER PRIMARY KEY --- 整数主键,自动递增
  5. TEXT --- SQLite 的字符串类型

插入数据:批量插入用 executemany

python 复制代码
sample_data = [
    (1, "张三", "销售", 50000),
    (2, "李四", "工程", 84000),
    (3, "王五", "销售", 60000),
    (4, "赵六", "工程", 80000),
    (5, "钱七", "市场", 55000),
]

cursor.executemany("INSERT INTO employees VALUES (?,?,?,?)", sample_data)
conn.commit()  # ⚠️ 不 commit 数据就丢了

⚠️ 面试考点: execute 执行单条 SQL,executemany 批量插入。用 ? 占位符而不是字符串拼接,是为了防止 SQL 注入

commit 的作用

sql 复制代码
内存中的修改  ──commit──→  磁盘上的 .db 文件
  (临时的)                (持久化的)

不调用 conn.commit(),所有修改只在内存里,程序一退出就丢失。一句话:commit 是把"草稿"变成"定稿"。


二、Text2SQL:让大模型帮你写 SQL

核心思路

Text2SQL 的本质就一件事:把人话翻译成 SQL

sql 复制代码
用户提问:"工程部门员工的姓名和工资是多少?"
        ↓
┌─────────────────────────────────────────┐
│  Prompt = 数据库结构(schema)+ 用户问题  │
│                                         │
│  "这是一个数据库的 schema:               │
│   CREATE TABLE employees (...);         │
│   根据这个 schema,请输出 SQL 查询..."   │
└─────────────────────────────────────────┘
        ↓
大模型输出:SELECT name, salary FROM employees WHERE department='工程'
        ↓
执行 SQL → 返回结果

💡 一句话记住: Text2SQL = schema(告诉模型数据库长啥样)+ 问题(告诉模型要查啥)→ SQL。

完整代码实现

python 复制代码
from openai import OpenAI

# 初始化客户端(DeepSeek 兼容 OpenAI 接口)
client = OpenAI(
    api_key="你的 API Key",
    base_url="https://api.deepseek.com"
)

def ask_deepseek(query, schema):
    """自然语言 → SQL"""
    prompt = f"""
这是一个数据库的schema:
{schema}
根据这个schema,请输出一个SQL查询来回答以下问题。
只输出SQL查询语句本身,不要使用任何Markdown格式,
不要包含反引号、代码块标记或额外说明。
问题:{query}
"""
    response = client.chat.completions.create(
        model="deepseek-v4-flash",
        max_tokens=2048,
        messages=[{
            "role": "user",
            "content": prompt
        }]
    )
    return response.choices[0].message.content

逐行拆解:

  1. base_url="https://api.deepseek.com" --- DeepSeek 用自己的地址,但接口格式和 OpenAI 一样
  2. prompt 里明确要求"只输出 SQL 本身"------防止模型输出一堆解释文字,后续没法直接执行
  3. max_tokens=2048 --- 限制输出长度,简单的 SQL 查询不需要太长

串联运行:从提问到拿结果

python 复制代码
import sqlite3
from test2 import ask_deepseek

# 1. 连接数据库
conn = sqlite3.connect("test.db")
cursor = conn.cursor()

# 2. 获取 schema
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
schema_str = "\n".join([table[0] for table in tables])

# 3. 提问
question = "工程部门员工的姓名和工资是多少?"
sql_query = ask_deepseek(question, schema_str)
print(f"生成的 SQL: {sql_query}")

# 4. 执行 SQL,拿结果
results = cursor.execute(sql_query).fetchall()
for row in results:
    print(row)

conn.close()

运行结果:

sql 复制代码
生成的 SQL: SELECT name, salary FROM employees WHERE department='工程'
('李四', 84000)
('赵六', 80000)

三、Schema 提取:怎么告诉模型数据库长啥样?

大模型没见过你的数据库,你得把**表结构(schema)**告诉它,它才能写出正确的 SQL。提取 schema 有两种方式:

方式一:sqlite_master 直接拿建表语句

python 复制代码
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
schema_str = "\n".join([table[0] for table in tables])

输出:

sql 复制代码
CREATE TABLE employees(id INTEGER PRIMARY KEY, name TEXT, department TEXT, salary INTEGER)
CREATE TABLE departments(id INTEGER PRIMARY KEY, name TEXT, manager TEXT)

方式二:PRAGMA table_info 自己拼

python 复制代码
tables = ["employees", "departments"]
schema_str = ""
for table in tables:
    schema = cursor.execute(f"PRAGMA table_info({table})").fetchall()
    schema_str += f"CREATE TABLE {table} (\n"
    schema_str += "\n".join([f"  {col[1]} {col[2]}" for col in schema])
    schema_str += "\n);\n\n"

输出:

sql 复制代码
CREATE TABLE employees (
  id INTEGER
  name TEXT
  department TEXT
  salary INTEGER
);

两种方式对比

特性 sqlite_master PRAGMA table_info
代码量 2 行 5+ 行
输出完整性 完整建表语句(含约束) 只有列名和类型
可定制性 低,原样输出 高,可以自由拼接格式
适用场景 快速原型 需要精简 schema 时

💡 面试回答: sqlite_master 适合快速拿到完整 schema,PRAGMA 适合需要定制输出格式的场景。实际项目中,如果表结构复杂,还会做进一步精简,只保留模型需要的字段信息。


四、Prompt 模板设计:让模型输出靠谱的 SQL

Prompt 是 Text2SQL 的灵魂。模板设计得好,模型输出的 SQL 就准;设计得烂,模型可能给你输出一堆废话。

核心要素

一个好的 Text2SQL prompt 必须包含:

sql 复制代码
┌─────────────────────────────────────┐
│  1. 角色定义(可选但推荐)            │
│     "你是一个 SQL 专家"              │
│                                     │
│  2. 数据库 schema                    │
│     CREATE TABLE employees (...)    │
│                                     │
│  3. 输出约束                         │
│     "只输出 SQL,不要 Markdown"      │
│                                     │
│  4. 用户问题                         │
│     "工程部门员工的姓名和工资是多少?" │
└─────────────────────────────────────┘

❌/✅ 对比

python 复制代码
# ❌ 错误:prompt 太模糊,模型可能输出一堆解释
prompt = f"帮我写个 SQL,查:{query}"

# ❌ 错误:没有给 schema,模型不知道表结构
prompt = f"根据以下问题写 SQL:{query}"

# ✅ 正确:有 schema、有输出约束、有问题
prompt = f"""
这是一个数据库的schema:
{schema}
根据这个schema,请输出一个SQL查询来回答以下问题。
只输出SQL查询语句本身,不要使用任何Markdown格式,
不要包含反引号、代码块标记或额外说明。
问题:{query}
"""

进阶技巧

技巧 说明 示例
Few-shot 示例 给几个问答对,让模型学格式 "问题:平均工资?→ SQL:SELECT AVG(salary)..."
限定输出格式 严格约束输出内容 "只输出 SQL,不要任何解释"
复杂查询提示 提前告知可能用到的语法 "可能需要用到 JOIN 和 GROUP BY"
错误修正 拿到 SQL 后验证,报错再让模型修 执行报错 → 把错误信息再喂给模型

⚠️ 面试考点: Text2SQL 的核心难点不在代码实现,而在 prompt 工程schema 设计。如何让模型准确理解用户的意图、如何处理多表关联、如何应对模糊查询,这些才是实际项目中需要解决的问题。


五、常见坑 / 易错点

1. 忘记 commit

python 复制代码
cursor.execute("INSERT INTO employees VALUES (1, '张三', '销售', 50000)")
# ❌ 忘了 commit,数据没写进去
conn.commit()  # ✅ 加上这行

2. UNIQUE constraint failed

python 复制代码
# ❌ 重复插入相同 ID
cursor.executemany("INSERT INTO employees VALUES (?,?,?,?)", sample_data)

# ✅ 方案一:先清空
cursor.execute("DELETE FROM employees")

# ✅ 方案二:跳过重复
cursor.executemany("INSERT OR IGNORE INTO employees VALUES (?,?,?,?)", sample_data)

3. 中文逗号

python 复制代码
# ❌ 中文逗号,SyntaxError
data = [(1, "张三","销售", 50000)]

# ✅ 英文逗号
data = [(1, "张三", "销售", 50000)]

4. 模型输出带 Markdown

模型有时会输出 sql ... 包裹的代码块,没法直接执行。解决办法:

  • prompt 里明确写"不要使用任何 Markdown 格式"
  • 或者拿到结果后用正则提取

六、面试高频 N 问

Q1:Text2SQL 的核心流程是什么?

三个步骤:

  1. 提取 Schema --- 从数据库获取表结构信息
  2. 构造 Prompt --- 把 Schema + 用户问题组装成 prompt 发给大模型
  3. 执行 SQL --- 拿到模型生成的 SQL,在数据库上执行并返回结果
    Q2:为什么要把 Schema 喂给模型?

大模型的训练数据里没有你的数据库信息,它不知道你有哪些表、哪些字段。Schema 就是告诉模型"数据库长什么样",它是模型写出正确 SQL 的前提。没有 Schema,模型只能瞎猜。
Q3:如何提高 Text2SQL 的准确率?

几个方向:

  • 优化 Prompt:加 few-shot 示例、明确输出约束

  • 精简 Schema:只给相关表和字段,减少干扰

  • 多轮对话:SQL 不对时,把报错信息反馈给模型修正

  • 后处理:对生成的 SQL 做语法检查和安全校验
    Q4:Text2SQL 有哪些局限性?

  • 复杂查询(多层嵌套、子查询)准确率下降

  • 模糊表述("最近的订单"------"最近"是多久?)需要额外处理

  • 安全风险:生成的 SQL 可能包含 DROP、DELETE 等危险操作,需要做权限控制和 SQL 审计
    Q5:为什么用 SQLite 而不是 MySQL?

教学和原型阶段用 SQLite 最方便------零配置、Python 内置、一个文件就是数据库。生产环境当然会换成 MySQL/PostgreSQL,但 Text2SQL 的核心逻辑(提取 Schema → 构造 Prompt → 生成 SQL → 执行)是通用的,换数据库只需要改连接方式。


总结

核心概念速查表

概念 一句话解释
SQLite 一个文件就是一个数据库,零配置,Python 内置
Schema 数据库的表结构描述,告诉模型"有哪些表、哪些字段"
Text2SQL 用大模型把自然语言翻译成 SQL 语句
Prompt 模板 Schema + 输出约束 + 用户问题,三者缺一不可
commit 把内存中的修改写入磁盘,不 commit 数据就丢了
executemany 批量插入,比 execute 逐条插更高效

核心代码骨架

python 复制代码
# 1. 提取 Schema
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table'")
schema = "\n".join([t[0] for t in cursor.fetchall()])

# 2. 构造 Prompt
prompt = f"数据库 schema:\n{schema}\n问题:{question}\n只输出 SQL。"

# 3. 调用大模型
response = client.chat.completions.create(model="deepseek-v4-flash", messages=[...])
sql = response.choices[0].message.content

# 4. 执行 SQL
results = cursor.execute(sql).fetchall()

一句话总结

Text2SQL 的本质 = 给模型一份"数据库说明书"(Schema)+ 一个问题 → 模型帮你写出 SQL。


结尾

这篇文章基于我学习 Text2SQL 的完整过程,从 SQLite 基础到完整实现,希望能帮到同样在学大模型应用开发的同学。

完整代码已整理到项目中,有问题欢迎在评论区交流 🔥

如果觉得有帮助,点个赞收藏一下,后续会继续更新大模型应用开发的实战内容~

相关推荐
ocean21035 小时前
2025-2026年AI算法与模型研发面试高频知识点洞察
人工智能·算法·面试
ShineWinsu7 小时前
对于MySQL:数据库的操作的解析
linux·数据库·c++·mysql·面试·笔试·库的操作
黄敬峰7 小时前
一文搞懂 LLM 结构化输出:从"抠 JSON"到"吐 JSON"的进化之路
面试
L小航呀9 小时前
代码随想录刷题 Day16
leetcode·面试
苦瓜小生11 小时前
【前端】【力扣与手撕】十天带你刷完前端算法与手撕,全是最简单好记的最优解法!day4
前端·数据结构·算法·leetcode·面试
AIsoft_868812 小时前
最好用的会议纪要APP怎么选?功能横评
面试·职场和发展·iphone
小白羊丨13 小时前
问数 Agent 整体架构、意图识别、历史上下文与 NL2SQL
java·面试·架构
ocean21031 天前
2025-2026年AI部署与MLOps大厂面试高频问题
人工智能·面试·大模型推理·ai部署
洋不写bug1 天前
链表面试笔试经典题目详细解析,题目多解法,复杂度分析
数据结构·链表·面试