说人话,查数据:构建一个自然语言驱动的 SQLite 后台

3 阅读7分钟

写在前面

AI First 时代:用自然语言操作数据库,让非技术人员也能“写”SQL

“未来,开发能力将不再局限于程序员。”——在大语言模型(LLM)的赋能下,这一设想正加速落地。

最近,我在一个探索性项目中尝试将自然语言转 SQL 的功能嵌入到日常数据操作流程中。通过集成 DeepSeek 等开源大模型,并搭配轻量级的 SQLite 数据库,我快速构建了一个简洁但富有潜力的 “AI 驱动型后台管理原型” 。今天就来聊聊这个思路及其初步实现。

📌 范式演进:从 “Mobile First” 到 “AI First”
回顾技术发展,我们经历了从 PC 优先到移动优先的转变;如今,随着大模型能力的成熟,“AI First” 正逐渐成为新一代应用设计的主流思维。

“以 AI 为核心,结合自然语言生成 SQL 的能力(如 Gemini、DeepSeek 等),将其深度整合进业务系统,让内容编辑、运营人员甚至普通用户都能自主完成数据查询与管理。”

这带来的变革是:不再依赖专业数据库知识或后端支持。用户只需用口语化表达需求——例如“显示上季度活跃用户最多的三个地区”——系统即可自动解析语义、生成合规的 SQL 语句,并返回所需结果。数据访问的门槛,正在被 AI 彻底打破。

让 LLM 看懂你的数据库:Schema 的正确打开方式

在 Text-to-SQL 系统中,给大模型提供表结构(Schema)的方式,直接决定了生成 SQL 的准确性。很多人习惯手写一段自然语言描述,比如:

“employees 表有 id、name、department 和 salary 字段……”

但这种方式既冗余又容易与实际表结构不一致。

我们来看一种更工程化的做法:

def get_schema_str(cursor):
    schema = cursor.execute("PRAGMA table_info(employees)").fetchall()
    return "CREATE TABLE EMPLOYEES (\n" + "\n".join([f"{col[1]} {col[2]}" for col in schema]) + "\n)"

这里利用了 SQLite 内置的 PRAGMA table_info 命令,动态获取真实表结构,并拼接成标准的 CREATE TABLE 语句。这不仅是语法上的“规范输出”,更是对 LLM 训练数据分布的精准对齐——LLM 在预训练阶段见过海量 CREATE TABLE 语句,远比自定义描述更熟悉。

同时,配合 init_db() 中的 CREATE TABLE IF NOT EXISTSINSERT OR IGNORE,整个初始化流程具备幂等性,支持反复运行而不污染数据。这种细节,正是从“能跑”到“可靠”的关键分水岭。

经验之谈:不要让 LLM 猜你的 Schema,要让它“看”到和数据库一模一样的定义。

db.py完整代码如下:

import sqlite3

def init_db():
    conn = sqlite3.connect("text.db")
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS employees(
            id INTEGER PRIMARY KEY,
            name TEXT,
            department TEXT,
            salary INTEGER
        )
    """)
    sample_data = [
        (6, "黄佳", "销售", 50000),
        (7, "宁宁", "工程", 75000),
        (8, "谦谦", "销售", 60000),
        (9, "悦悦", "工程", 80000),
        (10, "黄仁勋", "市场", 55000),
        (11, "刘苗苗", "工程", 55001)
    ]
    cursor.executemany("INSERT OR IGNORE INTO employees VALUES(?,?,?,?)", sample_data)
    conn.commit()
    return conn, cursor

def get_schema_str(cursor):
    schema = cursor.execute("PRAGMA table_info(employees)").fetchall()
    return "CREATE TABLE EMPLOYEES (\n" + "\n".join([f"{col[1]} {col[2]}" for col in schema]) + "\n)"

image.png


可靠的 SQL 不来自创意,而来自约束

在 Text-to-SQL 系统中,调用大模型的代码往往只占几行,但其背后的 Prompt 设计却决定了整个系统的上限。来看一个典型实现:

llm.py

from openai import OpenAI

client = OpenAI(
    api_key='your_api_key',
    base_url='https://api.deepseek.com/v1'
)

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

这段代码看似简单,实则体现了三个关键工程原则:

  1. 上下文精准注入:将动态生成的 CREATE TABLE Schema 直接嵌入 Prompt,确保 LLM 基于真实结构推理;
  2. 输出强约束:明确要求“只输出 SQL”,并禁止 Markdown、反引号等常见干扰项——这是后续直接执行 SQL 的前提;
  3. 确定性控制temperature=0 关闭随机性,保证相同输入始终返回相同 SQL,提升系统可预测性。

💡 很多开发者抱怨“LLM 生成的 SQL 不能直接用”,其实问题不在模型,而在 Prompt 没有强制规范输出格式。在这里,我们不是在“请求帮助”,而是在“下达指令”。

这种克制而精确的交互方式,正是 LLM 从玩具走向生产的关键一步。


🔗 让 LLM 成为你的“自然语言数据库接口

有了可靠的 Schema 上下文和精准的 Prompt 约束,LLM 就不再是“聊天机器人”,而是一个可编程的自然语言 SQL 引擎。主流程代码清晰展示了这一思想的落地:

main.py

from db import init_db, get_schema_str
from llm import ask_deepseek

conn, cursor = init_db()
schema_str = get_schema_str(cursor)

# 1. 查询
question = "工程部门员工的姓名和工资是多少?"
sql_query = ask_deepseek(question, schema_str)
print(sql_query)
results = cursor.execute(sql_query).fetchall()
print(results)

# 2. 插入
question = "在销售部门增加一个新员工,姓名为张三,工资为45000"
sql_query = ask_deepseek(question, schema_str)
print(sql_query)
cursor.execute(sql_query)
conn.commit()

# 3. 删除
question = "删除市场部门的黄仁勋"
sql_query = ask_deepseek(question, schema_str)
print(sql_query)
cursor.execute(sql_query)
conn.commit()

# 4. 查询所有
question = "查询所有员工的信息"
sql_query = ask_deepseek(question, schema_str)
print(sql_query)
results = cursor.execute(sql_query).fetchall()
print(results)

conn.close()

image.png 整个过程没有中间解析、没有后处理、没有格式转换——LLM 的输出即系统输入。这种端到端的集成,依赖两个前提:

  1. Schema 动态同步(来自 get_schema_str),确保 LLM “所见即库中所有”;
  2. Prompt 强约束(来自 ask_deepseek),确保输出是干净、合法的 SQLite 语句。

更值得注意的是,这套流程不仅支持 SELECT,还能处理 INSERTDELETE 等写操作——这意味着用户可以用自然语言完成完整的 CRUD 操作,而开发者只需维护一张表结构。

💡 这不是“AI 写 SQL”,而是用自然语言驱动数据库的新交互范式
而实现它的全部秘密,就藏在这十几行看似平凡的 glue code 中。

无需人工干预,从自然语言到数据库结果的完整链路如下:

image.png

这个原型足够轻量,非常适合作为你自己实验的起点。如有其他需求,也可在此基础上灵活扩展。

项目结构如下。你可以直接复制上文代码,运行 main.py,即可在控制台看到完整的输出结果。

image.png

🎯 自然语言,正在成为新一代数据库的“入口”

通过一个不到百行的原型,我们验证了一个关键趋势:大语言模型 + 精准上下文 + 强约束输出 = 可执行的自然语言数据接口

这不仅仅是“让 AI 写 SQL”,而是一次交互范式的迁移——
从“人适应数据库”(学语法、写查询、调接口),
转向“数据库适应人”(说需求、得结果、零编码)。

当然,当前方案仍是一个最小可行原型:它没有权限控制、不支持复杂 JOIN、也未处理模糊语义。但它的价值在于证明了:在特定领域内,LLM 已具备替代传统 CRUD 后端的能力

未来,随着模型对 Schema 理解更深、执行更安全、反馈更智能,我们或许不再需要为简单数据操作开发 API。运营人员一句“把上月离职的销售员工标红”,系统就能自动完成查询、更新甚至前端渲染。

而这,正是 AI First 时代最真实的模样
不是炫技,而是让技术消失在体验之中。

代码已开源,思路可复用。你,准备好构建自己的自然语言后台了吗?