详解NL2SQL完整流程:schema introspection→表选择→SQL生成→安全检查→执行,强调五步缺一不可,附实际代码构建思路。
你是否曾希望只需用普通英语向数据库提问,就能得到真正的答案?不需要写 SQL,不需要等待数据团队。这就是自然语言转 SQL(简称 NL2SQL)的核心愿景,得益于 LLM,这项技术终于足够实用了。
但大多数人都搞错了一点:让 AI 写 SQL 是其中最简单的一部分。真正的魔法在于它周围发生的所有事情。在本文中,我们将一步步构建完整的图景。
我们将追踪一个问题的完整旅程。以下是 AI 必须按顺序完成的任务:
缺少任何一个环节,整个系统就会变得不可靠。所以这五步都很重要——我们接下来会逐一说明。先来看每一步。
AI 在了解所处理的数据之前无法回答任何问题。所以它首先会环顾四周——这个过程称为 schema introspection。好消息是:数据库可以自我描述。大多数数据库都通过一个名为 information_schema 的内置视图暴露它们的结构,我们只需要查询即可:

但仅凭名称有时会很晦涩。rev 这一列是什么意思?status 2 是好还是坏?所以 AI 还会获取一些提示信息——描述、注释和一些示例值——来理解这些内容。然后它会缓存这张「地图」,因为每次提问都重新构建会非常慢。
这里有一个陷阱:真实数据库可能有数百张表。直接把它们全部塞进 prompt 让 AI 自己判断很诱人。但不要这样做。LLM 的上下文窗口是有限的(它们一次能读取的文本量),塞入大量无关内容反而会让 AI 的表现更差——有用的表会淹没在噪声中。同时成本也很高。正确做法是只向 AI 提供它需要的表,通过语义搜索来实现:
提前准备:将每张表的描述转换成embedding并存储在向量数据库中。
问题到来时:同样将问题做 embedding,搜索匹配度最高的表。
引入关联表(通过外键),确保 join 仍然有效。
加入业务定义——比如你的公司里「活跃用户」或「收入」意味着什么。这一步是无名英雄。正是它保证了 SQL 的准确性,并在数据库庞大的时候控制成本。
现在是趣味环节。我们构建一个prompt——发送给模型的指令——其中包含它需要的所有信息:一些基本规则(哪种 SQL 方言、保持只读、禁止 SELECT *)、我们挑选出的表、几个示例,最后是问题本身。

展示几对「问题-SQL」示例这个技巧有一个名字:few-shot prompting。它的效果出奇地好——几个好的例子远胜过一长串指令,能让模型更好地理解你的数据库喜欢怎样的查询方式。
第一条规则:不要直接运行 AI 生成的任何内容。LLM 有时会幻觉——它们会编造不存在的表或列,或者写出有风险的语句。因此每条查询在执行前都要通过一道安全门。我们用 sqlglot 等工具解析它(读取其结构)来确认它是有效的单条语句、确认它是只读的、并检查涉及的表和列确实存在。

看到最后那行了吗?EXPLAIN 让数据库在真正执行之前先规划查询——这是一种廉价的错误检查方式,在读取任何数据行之前就能发现问题。只有全部通过后,我们才会在一个只读连接上真正运行它,并设置行数上限和超时限制,确保不会有任何异常行为。无论返回什么,那就是用户看到的答案。
我希望你能记住这一点:写 SQL 的 AI 不是最聪明的部分。那只是最后的一小步。真正让它值得信赖的工作——所有安静地发生在后台的事情。可以把 AI 想象成繁忙餐厅里一位非常优秀的翻译。它之所以能把工作做好,是因为它已经了解菜单(你的 schema)、它倾听你真正想要什么而不是墙上挂的所有东西(正确的上下文)、以及它在订单送进厨房之前会再次确认(验证)。缺少任何一环,你就会很快得到一道完全错误的菜——快速、自信、彻底错误。但如果这些都做对了,就会发生某种神奇的事情。提问的人不需要懂 SQL,不需要提工单,不需要等待任何人。他们只是……问了一个问题——然后真正的答案就回来了。这就是终极愿景,而且它已经比过去近得多了。
所以下次有人说「AI 只是写了条查询」,你会知道真相:查询本身很简单。真正有魔法的是它周围的一切。