数据库平权时代:如何让运营、产品像聊天一样管理数据?

93 阅读7分钟

🧠 AI First 时代:用自然语言操作数据库,让业务人员也能写 SQL

“未来,每个人都是开发者。” —— 在 LLM(大语言模型)加持下,这句话正加速成为现实。

最近我在一个实验性项目中尝试将 自然语言生成 SQL 的能力嵌入到日常的数据操作流程中。通过 DeepSeek 等开源大模型,配合 SQLite 数据库,我构建了一个极简但极具潜力的 “AI 驱动后台管理系统” 原型。今天就来和大家分享这个想法与实现过程。


📌 背景:从 “Mobile First” 到 “AI First”

在传统的 Web 开发范式中,我们经历了 PC First → Mobile First 的转变。而如今,随着大模型能力的普及,“AI First” 正在成为新的开发哲学。

“AI First vibe coding + gemini 等自然语言生成 SQL,和我们的应用结合起来……让小编、业务、任何人加入后台运营和维护。”

这意味着:不再需要懂 SQL 的 DBA 或后端工程师,普通用户只需用自然语言描述需求,系统就能自动生成并执行正确的数据库操作。


🔧 技术实现:Text-to-SQL 的轻量级实践

初始化一个与 DeepSeek 大模型 API 通信的客户端对象

from openai import OpenAI

client = OpenAI(
    api_key="sk-8e9b4d6c8a0f4c3b9e1a2d5f7g6h5j4k",
    base_url="https://api.deepseek.com/v1"
)

1. 搭建本地 SQLite 数据库并插入数据

# coding 
import sqlite3
# 连接数据库
conn = sqlite3.connect("test.db")
# 创建一个游标对象
# 用于执行sql 获取查询结果
cursor = conn.cursor()
# 员工表
cursor.execute("""
CREATE TABLE IF NOT EXISTS employees(
    id INTEGER PRIMARY KEY,
    name TEXT,
    department TEXT,
    salary INTEGER
)
""")
# list 
sample_data = [ 
    # 元祖类型 有顺序的  tuple 
    (6, "黄佳", "销售", 50000), 
    (7, "宁宁", "工程", 75000), 
    (8, "谦谦", "销售", 60000), 
    (9, "悦悦", "工程", 80000), 
    (10, "黄仁勋", "市场", 55000),
    (11, "枫枫", "工程", 80000)
]
# 插入sql
cursor.executemany(
    "INSERT INTO employees VALUES(?,?,?,?)",
    sample_data
)
# 提交sql事务
conn.commit()

关键点分析:

  1. 游标是操作数据库的关键,在操作之前,先创建一个游标对象方便后续操作cursor =conn.cursor()
  2. 当执行的sql语句是增删改等操作时,需要进行事务提交-->conn.commit()
  3. executemany() 可以一次插入多条数据,后面接受的一个参数,可以是列表

2. 提取 Schema 作为上下文

为了让 LLM 理解数据库结构,我们将表结构转换为标准的 CREATE TABLE 语句:

# text2sql 给llm什么? context
# 表结构 作为上下文给prompt schema
schema = cursor.execute("PRAGMA table_info(employees)").fetchall()
print(schema)
# 列表推导式
schema_str = "CREATE TABLE EMPLOYEES (\n"+"\n".join([f"{col[1]} {col[2]}" for col in schema]) + "\n)"
print(schema_str)

这个 Schema 会被拼接到 Prompt 中,作为模型生成 SQL 的依据。

image.png 关键点解析:

  1. PRAGMA table_info(employees):这是 SQLite 特有的元数据查询命令 PRAGMA 是 SQLite 提供的一种用于获取或设置数据库内部状态/结构信息的机制。

  2. table_info(表名) 会返回该表的完整列定义信息,包括:

    • 列序号(cid)
    • 列名(name)
    • 数据类型(type)
    • 是否允许为空(notnull)
    • 默认值(dflt_value)
    • 是否为主键(pk,1代表是主键,0代表不是)
  3. .fetchall() 获取所有返回行,组成一个 Python 列表

  4. 列表推导式:从数据库元数据中提取每列的名称和类型,生成格式化的字段定义列表,用于构建 LLM 可理解的表结构描述

schema_str = "CREATE TABLE EMPLOYEES (\n"+"\n".join([f"{col[1]} {col[2]}" for col in schema]) + "\n)" 

3. 调用 DeepSeek 大模型生成 SQL

使用 OpenAI 兼容的 API(这里接入的是 DeepSeek 的 endpoint),构造如下 Prompt:

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

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

例如,当用户问:

“工程部门员工的姓名和工资是多少?”

模型返回:

SELECT name, salary FROM EMPLOYEES WHERE department = '工程';

程序直接执行该语句,得到结果:

[('宁宁', 75000), ('悦悦', 80000), ('枫枫', 80000)]

关键点解析:

  1. 提供精确的上下文:将表结构作为固定上下文注入prompt。让 LLM 知道数据库有哪些表、字段和类型,避免“凭空猜测”
  2. 明确指令约束输出格式:明确输出格式,确保返回结果可直接被 cursor.execute() 安全执行,无需后处理。
  3. 采用标准 Chat Completion 接口:使用 OpenAI 兼容的 chat.completions.create 调用 DeepSeek,便于切换不同 LLM(如换成 Qwen、Gemini 等),只需改 endpoint 和 key。
  4. 使用低 temperature=0:相同输入始终生成相同 SQL,提升系统可靠性

4. 支持增删改查全操作

更令人兴奋的是,这套机制不仅能查,还能

  • 新增:“在销售部门增加一个新员工,姓名为刘锦苗,工资为45000”
    → 生成 INSERT INTO ...
  • 删除:“删除市场部门的黄仁勋”
    → 生成 DELETE FROM ... WHERE ...

image.png 只要权限控制得当,这几乎就是一个 自然语言驱动的数据库管理界面


🚀 应用场景:让非技术人员参与系统维护

想象一下这些场景:

  • 运营同学:想临时加一个促销员工账号?直接说“在市场部加一个叫小美的员工,工资6000”,系统自动执行。
  • 产品经理:想看某部门薪资分布?问一句即可,无需提工单等后端支持。
  • 小程序后台:结合前端语音/文本输入,打造“对话式管理面板”。

这正是 “数据库平权” 的体现——把技术门槛降到最低,释放业务创造力。


⚠️ 注意事项与未来方向

当然,当前方案仍有局限:

  • 安全性:必须严格限制可执行的 SQL 类型(如禁止 DROP),最好通过白名单或沙箱机制。
  • 准确性:复杂查询(多表 JOIN、子查询)可能出错,需人工校验或引入 RAG 增强上下文。
  • 权限控制:不同角色应有不同的操作范围(如销售只能看本部门)。

未来,我们可以:

  • 将此能力封装为 AI Agent,集成到钉钉/企微/飞书机器人中;
  • 结合 ModelScope(魔搭) 微调专属 Text-to-SQL 模型;
  • 扩展至 MySQL / PostgreSQL 等生产级数据库;
  • 加入 自然语言反馈:“共找到3人,是否导出为 Excel?”

💡 结语:编程的尽头是自然语言

过去,我们学 SQL 是为了和机器沟通;
现在,机器学会了我们的语言。

在这个 AI First 的时代,代码不再是壁垒,而是桥梁。
而我们要做的,就是搭建更多这样的桥,让更多人轻松跨越。

让技术隐形,让价值凸显。


附:完整代码参考

from openai import OpenAI

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




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
)
""")


sample_data = [
    (6, "黄佳", "销售", 50000),
    (7, "宁宁", "工程", 75000),
    (8, "谦谦", "销售", 60000),
    (9, "悦悦", "工程", 80000),
    (10, "黄仁勋", "市场", 55000),
    (11, "枫枫", "工程", 80000)
]

cursor.executemany("INSERT INTO employees VALUES(?,?,?,?)", sample_data)
conn.commit()


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)"



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


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


question = "在销售部门增加一个新员工,姓名为刘锦苗,工资为45000"
sql_question = ask_deepseek(question, schema_str)
cursor.execute(sql_question)
conn.commit()


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


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