《AIGC 时代下的 Text-to-SQL 实践》

93 阅读5分钟

AIGC 时代下的 Text-to-SQL 实践:用自然语言操作 SQLite 数据库

引言:当数据库遇上自然语言

在传统的软件开发流程中,与数据库交互通常意味着编写精确的 SQL 语句。这不仅要求开发者熟悉 SQL 语法,还需对目标数据库的表结构(Schema)有清晰认知。然而,在 AIGC(人工智能生成内容)迅猛发展的今天,我们是否可以让 AI “听懂”人类语言,并自动将其转化为有效的数据库查询?

答案是肯定的。本文将通过一个轻量级的 Python + SQLite 示例,展示如何借助大语言模型(LLM)实现 Text-to-SQL 功能——即用户只需输入一句类似“销售部门员工的姓名和工资是多少?”这样的自然语言,系统便能自动生成并执行对应的 SQL 查询。


为什么选择 SQLite?

在众多数据库系统中,SQLite 凭借其轻量、无服务依赖、单文件存储等特性,成为本地开发、原型验证和小型应用的理想选择:

  • 零配置:无需安装数据库服务,开箱即用;
  • 标准兼容:支持大部分 ANSI SQL 语法;
  • Python 原生支持:通过内置的 sqlite3 模块即可无缝操作;
  • 沙盒友好:非常适合用于 LLM 的实验环境,避免对生产数据造成影响。

正因如此,本文选用 SQLite 作为底层数据存储引擎。


核心思路:Prompt Engineering + Schema 上下文

要让大语言模型准确生成 SQL,关键在于提供充分且结构化的上下文信息。具体而言,我们需要在提示(Prompt)中明确包含以下三部分:

  1. 数据库表结构(Schema) :字段名、数据类型、主键等;
  2. 用户的自然语言问题
  3. 输出格式约束:仅返回 SQL 语句,不包含解释、注释或其他内容。

这种设计正是 Prompt Engineering(提示工程) 的典型应用——通过精心构造输入,引导模型输出符合预期的结果。

示例 Schema

假设我们有一个名为 employees 的员工表:

CREATE TABLE employees (
    id INTEGER PRIMARY KEY,
    name TEXT,
    department TEXT,
    salary INTEGER
);

当用户提问:“销售部门员工的姓名和工资是多少?”,理想输出应为:

SELECT name, salary FROM employees WHERE department = '销售部';

注意:由于示例数据使用中文部门名(如“销售部”),模型必须基于实际值生成查询,而非英文翻译。


技术实现步骤

以下是一个完整的端到端实现流程(基于 Jupyter Notebook 或 Python 脚本):

1. 创建并连接 SQLite 数据库

import sqlite3
conn = sqlite3.connect("test.db")
cursor = conn.cursor()

2. 定义表结构并插入示例数据

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

sample_data = [
    (6, "薛名强", "销售部", 100),
    (7, "刘锦苗", "保洁部", 101),
    (8, "田晨枫", "小卖部", 198),
    (9, "刘松韬", "春日部", 129)
]
#插入多条语句
cursor.executemany('INSERT INTO employees VALUES (?, ?, ?, ?)', sample_data)
conn.commit()

⚠️ 注意:中文字段值(如“销售部”)需与用户提问中的表述保持一致,否则查询将无法命中结果。

3. 动态获取并格式化表 Schema

利用 SQLite 的 PRAGMA table_info 获取元数据,并构造出可读的 CREATE 语句:

schema_rows = cursor.execute("PRAGMA table_info(employees)").fetchall()
schema_str = "CREATE TABLE employees (\n" + \
             ",\n".join([f"  {row[1]} {row[2]}" for row in schema_rows]) + "\n);"

这样生成的 schema_str 可直接嵌入 Prompt,帮助模型理解表结构。

4. 调用大模型生成 SQL

以 DeepSeek API 为例(也可替换为其他支持的 LLM),构造如下函数:

def ask_deepseek(query,schema):
    prompt = f"""
    这是一个数据库表Schema:
    {schema}
    根据这个Schema,你能输出一个sql查询来回答以下问题吗?
    只输出sql查询语句,不要输出任何其他内容。
    问题:{query}
    """
    response = client.chat.completions.create(
        model= "deepseek-reasoner",
        max_tokens=2048,
        messages=[{
            "role": "user",
            "content": prompt
        
        }]
    
    )
    return response.choices[0].message


调用示例:

question = "销售部门员工的姓名和工资是多少"
sql = ask_deepseek(question,schema_str)
print("生成的sql查询:")
print(sql)

输出:

image.png

挑战与思考

尽管 Text-to-SQL 在简单场景下已初具实用价值,但仍面临诸多挑战:

  • 值域歧义:用户说“销售”,但数据库中是“销售部”,需建立同义词映射或引入模糊匹配;
  • 复杂查询支持有限:涉及多表 JOIN、子查询、聚合函数(如 GROUP BY)时,模型容易出错;
  • Schema 动态适应性差:每次表结构变更都需重新注入上下文;
  • 缺乏反馈闭环:当前方案为“一次性生成”,无法根据执行结果自动修正错误。

不过,对于内部工具、BI 助手、低代码平台或数据分析初学者,Text-to-SQL 已能显著提升效率。


结语:AI 不是取代,而是增强

Text-to-SQL 并非要取代 DBA 或后端工程师,而是作为一种智能辅助工具,降低数据库操作门槛,让产品经理、运营人员甚至普通用户也能快速获取所需数据。在 AIGC 时代, “如何与 AI 协作” 正逐渐成为一项核心技能。

展望未来,我们可以进一步探索:

  • 利用向量数据库存储 Schema 元信息,实现语义检索;
  • 支持多轮对话,逐步澄清模糊意图;
  • 结合执行反馈进行自我修正(Self-Correction);
  • 集成 SQL 优化器,自动推荐高效执行计划。

而这一切创新的起点,或许就藏在那一行看似平凡的代码中:

conn = sqlite3.connect("test.db")