华为云 GaussDB + ChatGPT 5.5:构建自然语言到 SQL 的动态查询工作流
周一早上,业务同学丢来一句:“帮我看看上周各城市新增付费用户的趋势,顺便排除测试账号。”对数据库开发者来说,这不是难题,但真正消耗时间的是反复确认口径、拼 SQL、检查字段、跑结果、再改条件。现在大模型已经能把自然语言转成结构化查询,我们更关心的是:它能不能稳定、可控、可验证地接入生产数据分析链路?在做原型验证时,如果希望快速体验不同模型的自然语言理解与代码生成能力,也可以借助 KULAAI(https传://ouai送.me门)镜像平台进行前期测试和提示词调优。
一、为什么不是“让 AI 直接写 SQL”这么简单
自然语言查询听起来很直接:用户提问,大模型生成 SQL,数据库执行,返回结果。
但在真实业务里,这条链路有几个关键风险:
-
字段理解可能错误
用户说“付费用户”,模型可能理解成pay_user,但真实表里叫is_paid或order_status。 -
SQL 可能存在语法问题
不同数据库语法差异明显,GaussDB 与其他数据库在函数、分页、时间处理上都有细节区别。 -
查询可能越权或过重
如果生成了全表扫描、跨大表笛卡尔积,可能影响数据库性能。 -
结果可能无法解释
SQL 能跑不代表业务口径正确。开发者还需要知道模型为什么这样写。
因此,更合理的方案不是“AI 直接连数据库”,而是设计一个动态工作流:
自然语言理解 → 元数据检索 → SQL 生成 → 规则校验 → 执行计划检查 → 安全执行 → 结果解释。
二、整体架构:让大模型参与,但不让它失控
在华为云开发者社区的技术语境下,我们可以把这个方案拆成三层:
- 业务交互层:接收用户自然语言问题,返回数据结果和解释。
- 智能编排层:调用 ChatGPT 5.5 完成意图识别、SQL 生成、结果摘要。
- 数据执行层:连接华为云 GaussDB,执行经过验证的 SQL。
核心原则是:
大模型负责“理解与生成”,工作流负责“约束与验证”,GaussDB 负责“可靠执行”。
一个典型流程如下:
用户问题 ↓ 意图识别 ↓ 检索表结构、字段注释、业务口径 ↓ 生成候选 SQL ↓ SQL 静态检查 ↓ EXPLAIN 执行计划评估 ↓ 只读查询执行 ↓ 结果摘要与口径说明

三、在 GaussDB 中准备一份可理解的元数据
大模型生成 SQL 的质量,很大程度取决于它拿到的上下文。
如果只告诉它“有一张 user 表”,它很容易猜错。更稳妥的做法是维护一份业务元数据。
例如,我们有一张用户订单宽表:
CREATE TABLE dws_user_order_summary (
user_id BIGINT,
city VARCHAR(64),
register_time TIMESTAMP,
order_id BIGINT,
order_amount NUMERIC(18,2),
order_status VARCHAR(32),
is_test_user BOOLEAN,
pay_time TIMESTAMP
);
同时准备字段说明:
{
"table": "dws_user_order_summary",
"description": "用户订单汇总表,用于分析用户注册、付费、城市分布等指标",
"columns": {
"user_id": "用户唯一ID",
"city": "用户所在城市",
"register_time": "用户注册时间",
"order_amount": "订单金额",
"order_status": "订单状态,PAID表示已支付",
"is_test_user": "是否测试用户,true为测试账号",
"pay_time": "支付完成时间"
},
"rules": [
"分析真实用户时必须过滤 is_test_user = false",
"付费用户以 order_status = 'PAID' 且 pay_time 不为空为准"
]
}
这份元数据可以存放在配置中心、文档库,或者单独建表。
当用户提问时,工作流先根据关键词检索相关表和字段,再把它们注入到提示词中。
四、提示词设计:让模型输出可校验对象
不要让模型只返回一段 SQL。
更好的方式是要求它返回结构化 JSON,便于程序继续处理。
示例提示词可以这样设计:
你是数据库开发助手,请根据用户问题和表结构生成 GaussDB 可执行的只读 SQL。
要求:
1. 只能生成 SELECT 查询。
2. 必须遵守业务规则。
3. 不允许使用 DELETE、UPDATE、INSERT、DROP、ALTER。
4. 返回 JSON,包含 intent、sql、filters、assumptions、risk_level。
用户问题:
统计上周各城市新增付费用户数量,并排除测试账号。
表结构与业务规则:
{metadata}
期望输出:
{
"intent": "按城市统计上周新增且已付费的真实用户数量",
"sql": "SELECT city, COUNT(DISTINCT user_id) AS paid_user_count FROM dws_user_order_summary WHERE register_time >= date_trunc('week', current_date) - interval '7 days' AND register_time < date_trunc('week', current_date) AND order_status = 'PAID' AND pay_time IS NOT NULL AND is_test_user = false GROUP BY city ORDER BY paid_user_count DESC;",
"filters": [
"上周注册",
"已支付订单",
"排除测试用户"
],
"assumptions": [
"新增用户以register_time为准",
"付费用户以order_status和pay_time共同判断"
],
"risk_level": "low"
}
这样做有两个好处。
第一,SQL 可以单独拿出来校验。
第二,假设条件可以展示给用户,避免“看似正确但口径不明”的结果。
五、SQL 验证:动态工作流的关键一环
自然语言转 SQL 的核心不只是“生成”,而是“验证”。
这里建议至少做三类检查。
1. 静态安全检查
可以使用 SQL 解析器判断是否为只读查询,并拦截危险关键字。
伪代码如下:
FORBIDDEN = ["delete", "update", "insert", "drop", "alter", "truncate", "grant"]
def validate_sql_text(sql: str):
sql_lower = sql.lower()
if not sql_lower.strip().startswith("select"):
raise ValueError("仅允许 SELECT 查询")
for word in FORBIDDEN:
if word in sql_lower:
raise ValueError(f"SQL 包含禁止关键字: {word}")
return True
2. 业务规则检查
例如分析用户数据时,必须排除测试账号。
如果 SQL 中没有 is_test_user = false,则要求模型重写,而不是直接执行。
def validate_business_rules(sql: str):
required = "is_test_user = false"
if required not in sql.lower():
raise ValueError("缺少测试账号过滤条件")
return True
3. 执行计划检查
在 GaussDB 中,可以先执行 EXPLAIN,观察是否出现明显高风险计划。
例如扫描行数过大、缺少过滤条件、存在不合理 Join 等。
EXPLAIN
SELECT city, COUNT(DISTINCT user_id) AS paid_user_count
FROM dws_user_order_summary
WHERE register_time >= date_trunc('week', current_date) - interval '7 days'
AND register_time < date_trunc('week', current_date)
AND order_status = 'PAID'
AND pay_time IS NOT NULL
AND is_test_user = false
GROUP BY city;
如果执行计划超过预设阈值,可以让工作流返回:“该问题涉及数据量较大,建议补充时间范围或增加筛选条件。”

六、一个简化版动态工作流示例
下面给出一个简化版 Python 编排思路。
真实项目中可以接入华为云函数工作流、后端服务或数据分析平台。
def nl_to_sql_workflow(user_question):
# 1. 检索元数据
metadata = retrieve_metadata(user_question)
# 2. 调用大模型生成结构化结果
llm_result = call_llm(
question=user_question,
metadata=metadata,
dialect="GaussDB"
)
sql = llm_result["sql"]
# 3. 静态校验
validate_sql_text(sql)
# 4. 业务规则校验
validate_business_rules(sql)
# 5. 执行计划检查
plan = explain_gaussdb(sql)
if is_high_risk_plan(plan):
return {
"status": "need_refine",
"message": "查询范围较大,请补充时间、城市或用户分组条件。"
}
# 6. 执行查询
rows = execute_readonly_query(sql)
# 7. 结果解释
summary = summarize_result(
question=user_question,
sql=sql,
rows=rows,
assumptions=llm_result.get("assumptions", [])
)
return {
"status": "success",
"sql": sql,
"data": rows,
"summary": summary
}
这个流程的重点在于,每一步都可以被观察、记录和回放。
当结果异常时,开发者能知道问题出在提示词、元数据、SQL 生成,还是执行计划。
七、在生产环境落地时的几个建议
第一,数据库账号必须只读化。
自然语言查询服务不应使用高权限账号,建议单独创建只读用户,并限制可访问 schema。
第二,建立查询白名单与表级权限。
不是所有表都适合开放给自然语言查询。用户画像、订单明细、财务汇总等数据,应按角色控制。
第三,给大模型输入“少而准”的上下文。
一次性塞入全部表结构并不可靠。更好的方式是先检索相关表,再注入必要字段和业务规则。
第四,保存 SQL 与自然语言问题的映射。
这能帮助团队持续优化提示词,也能沉淀高频分析模板。
第五,对结果加解释,不只返回数字。
例如返回“上周新增付费用户共 3,216 人,口径为注册时间在上周、订单状态已支付、排除测试账号”。
这比单纯给一张表更容易被业务方理解。
八、总结:让 AI 成为数据库开发者的协作者
华为云 GaussDB 提供稳定的数据底座,ChatGPT 5.5 负责自然语言理解与 SQL 生成,而动态工作流承担安全校验、业务约束和执行控制。
真正可落地的自然语言查询系统,不是把数据库完全交给 AI,而是让 AI 在明确边界内完成提效工作。
当开发者把元数据、权限、校验、执行计划这些环节设计好,自然语言查询就不再只是演示效果,而可以成为数据分析链路中的可靠组件。
对于数据库开发者来说,这类探索的价值并不在于少写几行 SQL,而在于把重复的口径确认、查询拼装和结果解释流程自动化。
这也是 GaussDB 与大模型结合时,最值得深入实践的方向之一。
注:本文配图由ChatGpt Image-2 辅助生成。
【本文完】
- 点赞
- 收藏
- 关注作者
评论(0)