AIGC 时代,用自然语言操作数据库:SQLite + LLM 的轻量级实践

AIGC 时代,用自然语言操作数据库:SQLite + LLM 的轻量级实践


一、为什么我们需要"自然语言查数据库"?

SQL 是结构化查询语言,精准但门槛不低。对于产品经理、运营、测试甚至初级开发者来说,写一条 JOINGROUP BY 可能比写周报还难。

而如今,大语言模型(如 DeepSeek、GPT、Claude 等)已经具备极强的语义理解与代码生成能力。只要给它清晰的数据库结构(Schema)和一句自然语言问题,它就能生成准确的 SQL。

这不仅是效率工具,更是人机协作范式的升级

你负责"想问什么",AI 负责"怎么查"。


二、为什么选择 SQLite?

在众多数据库中,SQLite 是轻量级场景的王者:

  • 零配置、单文件 :整个数据库就是一个 .db 文件,无需安装服务。
  • 嵌入式友好:微信、Chrome、Android 系统内部都用它做本地存储。
  • 标准 SQL 支持:支持大部分 SQL 语法,足以应对日常 CRUD。
  • Python 原生支持import sqlite3 即可开干,无额外依赖。

💡 对比 MySQL/PostgreSQL:它们适合高并发、分布式场景,但对本地工具、桌面应用、原型开发来说"杀鸡用牛刀"。


三、动手实践:5 分钟搭建"自然语言查库"系统

1. 创建数据库与表

python 复制代码
# 轻量级数据库
import sqlite3
from openai import OpenAI

# ========== 1. 连接数据库(仅一次)==========
conn = sqlite3.connect("test1.db")
cursor = conn.cursor()

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

2. 插入示例数据

scss 复制代码
# ========== 3. 插入示例数据 ==========
sample_data = [    (1, "陈", "开发部", 32000),    (2, "张", "销售部", 20000),    (3, "徐", "开发部", 33000),    (4, "李", "销售部", 15000)]
cursor.executemany('INSERT OR IGNORE INTO employees VALUES (?, ?, ?, ?)', sample_data)
conn.commit()

✅ 使用 INSERT OR IGNORE 避免重复插入导致主键冲突。

3. 获取表结构(Schema)

这是 LLM 理解数据库的关键上下文:

python 复制代码
# ========== 4. 获取 Schema(统一用小写表名)==========
schema = cursor.execute("PRAGMA table_info(employees)").fetchall()
schema_str = "CREATE TABLE employees (\n" + "\n".join([f"  {col[1]} {col[2]}" for col in schema]) + "\n);"
print("数据库Schema:")
print(schema_str)

输出:

sql 复制代码
数据库Schema:
CREATE TABLE employees (
  id INTEGER
  name TEXT
  department TEXT
  salary INTEGER
);

✅ 表名统一为小写 employees,符合 SQLite 实际建表习惯,避免大小写混淆。

4. 接入 LLM(以 DeepSeek 为例)

ini 复制代码
# ========== 5. 接入 LLM ==========
client = OpenAI(
    api_key='你的 API Key',
    base_url='https://api.deepseek.com/v1'
)

def ask_deepseek(query: str, schema: str) -> str:
    prompt = f"""
这是一个数据库的Schema:
{schema}
根据这个Schema,你能输出一个SQL查询来回答以下问题吗?
只输出SQL查询,不要输出任何其他内容,也不要带任何格式。
问题:{query}
"""
    response = client.chat.completions.create(
        model="deepseek-reasoner",
        max_tokens=256,
        messages=[{"role": "user", "content": prompt}]
    )
    # ✅ 关键:返回纯 SQL 字符串
    return response.choices[0].message.content.strip()

🔑 注意:函数最终返回的是 .content.strip(),确保是干净的 SQL 字符串,而非 ChatCompletionMessage 对象。

5. 自然语言提问 → 执行 SQL

python 复制代码
# ========== 6. 自然语言提问 → 生成并执行 SQL ==========
question = "开发部部门员工的姓名和工资是多少?"
generated_sql = ask_deepseek(question, schema_str)
print("\n生成的SQL查询:")
print(generated_sql)

# ✅ 安全提示:此处仅为演示!生产环境需校验SQL
try:
    result = cursor.execute(generated_sql).fetchall()
    print("\n查询结果:")
    for row in result:
        print(row)
except Exception as e:
    print(f"\n执行出错: {e}")

典型输出:

sql 复制代码
生成的SQL查询:
SELECT name, salary FROM employees WHERE department = '开发部';

查询结果:
('陈', 32000)
('徐', 33000)

✅ 成功!你用中文问问题,AI 自动生成 SQL 并返回结果。

6. 关闭连接(良好习惯)

bash 复制代码
# ========== 7. 关闭连接 ==========
conn.close()

四、Prompt 工程:让 LLM 更可靠

LLM 不是万能的,好的 Prompt 是稳定输出的关键。我们通过以下设计提升准确性:

技巧 说明
明确 Schema 上下文 必须提供表结构,否则 LLM 会"瞎猜字段"
限制输出格式 "只输出 SQL,不要其他内容" 避免冗余
指定大小写与引号 统一表名小写、字符串用单引号,减少语法错误
示例引导(Few-shot) 可追加 1~2 个输入-输出样例,效果更佳

🔒 安全警告

上述代码中的 cursor.execute(generated_sql) 直接执行 LLM 输出的 SQL,存在严重安全风险 (如 SQL 注入、DROP TABLE 等)。

在真实项目中,务必:

  • 使用 白名单机制(只允许 SELECT,禁止 DDL/DML)
  • 对生成的 SQL 进行 AST 解析校验
  • 或采用 参数化查询模板,仅让 LLM 填充 WHERE 条件部分
相关推荐
老鱼说AI1 小时前
BPE编码从零开始实现pytorch
开发语言·人工智能·python·机器学习·chatgpt·nlp·gpt-3
CoolerWu1 小时前
TRAE SOLO实战:一个所见即所得的笔记软体
前端·trae
没落英雄2 小时前
简单了解 shadowDom
前端·html
天才熊猫君2 小时前
vue3 基于 el-table 的无限滚动自定义指令实现
前端·javascript
BBB努力学习程序设计2 小时前
Bootstrap图片:让图片展示更优雅、更专业
前端·html
玉宇夕落2 小时前
深入理解 async/await:从原理到实战,彻底掌握 JavaScript 异步编程
前端
林炳然2 小时前
Python-Basic Day-4 函数-基础知识
python
FreeCode2 小时前
LangSmith Studio 调试智能体
python·langchain·agent
Sailing2 小时前
🚀 Promise.then 与 async/await 到底差在哪?(这次彻底讲明白)
前端·javascript·面试