NL2SQL:从自然语言到SQL的智能转换技术深度解析

NL2SQL:从自然语言到SQL的智能转换技术深度解析

本文深入解析了 NL2SQL(自然语言到 SQL)技术,探讨其在数据驱动决策中的关键作用。通过将自然语言查询自动转换为结构化查询语言(SQL),NL2SQL 使业务分析师无需掌握复杂编程技能即可高效访问和处理数据。

文章从技术背景、发展历程、核心挑战与解决方案等多个维度,系统性地介绍了 NL2SQL 的工作原理及优化策略,涵盖模式链接、提示词工程、检索增强生成(RAG)、语义层构建等关键技术,并结合实际应用场景展示了其在提升数据分析效率与准确性方面的巨大潜力。

1. 引言

数据驱动决策一直在各行各业中至关重要,业务分析师常常面临繁重的数据查询任务。通过自然语言生成结构化查询语言(SQL)的技术,即 NL2SQL,业务分析师不再需要掌握复杂的编程技能,便能够轻松访问和处理数据。

这篇文章将探讨如何利用 NL2SQL 技术来自动化处理常见的数据查询任务。

想象一个典型的场景:一位业务分析师需要提供上个月销售额最高的前 10 个商品。如果用传统方法,首先分析师需要知道销售额相关的基础数据表是哪些,接着得确认销售额的具体口径定义,最后需要按照一定方式编写复杂的 SQL 查询得到结果。这不仅需要对 SQL 语言有深刻的理解,还要对指标的定义、业务数据来源非常熟悉。

如果将 NL2SQL 技术和日常数据分析结合,可以帮助业务分析师显著减少完成数据分析所需的时间,同时还可以借助 NL2SQL 纠正发现的语法问题,减少人为错误,甚至即使没有技术背景的用户也能通过自然语言简单地进行复杂的数据查询,提高运营自助分析查询的效率。

2. 技术背景与发展历程

2.1 问题定义

图片

2.1.1 什么是 NL2SQL

NL2SQL 是「Natural Language to SQL」的缩写,指的是将自然语言查询转化为 SQL 查询语句的技术。它主要用于将用户以自然语言提出的问题自动转换成能够被数据库系统理解并执行的 SQL 查询,从而实现从数据库中检索相关信息的目的。

图片

2.1.2 问题拆解

2.1.2.1 语义理解

自然语言通常具有很高的复杂性和多义性。语义理解要求系统能够准确地捕捉用户查询的意图,并处理自然语言中的模糊和歧义。这包括理解自然语言中的上下文、处理指代、识别关键实体和关系,以及解析复杂的句子结构。

2.1.2.2 Schema 映射

Schema 映射涉及将自然语言查询映射到数据库模式中的具体表和列。数据库的模式通常非常结构化,而自然语言查询可能没那么直接地指明这些结构。例如,一个查询可能使用同义词或间接提及而不是明示的列名或表名。系统需要具备将自然语言中提到的概念正确映射到数据库结构上的能力。

2.1.2.3 SQL 生成

SQL 生成是将处理过的自然语言意图和映射到数据库元素的信息转换为合法的 SQL 查询的过程。生成的 SQL 不仅需要语法正确,而且在语义上准确地代表原始的用户需求。挑战在于生成的 SQL 需要处理不同的查询形式和复杂度,包括聚合、嵌套查询、连接等功能。此外,生成的 SQL 还必须满足高性能、合规性和安全性方面的要求。

2.1.3 核心挑战

2.1.3.1 语法正确

数据库架构本身的复杂性和庞大体量的数据对 NL2SQL 构成了明显的挑战,比如数据库语法的多元性、表之间的关系复杂性、列名的相似性、以及大数据量下的不完整性。

2.1.3.2 语义正确

自然语言可能因歧义和不明确性而含有不确定性,例如词义歧义、句法歧义、信息不足和用户错误。与此同时,当实际应用到业务场景时,不同团队对同一术语的定义也可能不同。比如「成交」可能意味着产生订单,也可能意味着必须支付。

2.1.3.3 效果稳定

NL2SQL 与编程语言不同,因为输入的 NL 和输出的 SQL 查询之间通常存在一对多的映射。即使是完全一样的问题,也可能输出各种不同的 SQL 结果。

2.2 发展历史

image

2.2.1 基于规则的方法

早期研究主要集中在使用预定义规则或语义解析器来理解自然语言查询并将其转换为 SQL 查询。

2.2.2 基于神经网络的方法

为了解决基于规则的方法的局限性,研究者开始利用神经网络来解决 NL2SQL,例如使用序列到序列模型或图神经网络。

2.2.3 基于预训练语言模型的方法

随着 BERT 和 T5 等预训练语言模型的出现,基于 PLM 的 NL2SQL 方法在多个基准数据集上取得了显著的性能提升。

2.3 大型语言模型时代

随着 LLMs 的出现,NL2SQL 技术取得了显著进展,LLMs 具有卓越的语言理解和新涌现的能力,例如使用提示来执行 NL2SQL 任务。

3. 关键技术挑战与解决方案

3.1 Schema Linking(模式链接)

Schema Linking 旨在理解自然语言查询与数据库模式(schema)之间的语义关系,以帮助生成准确的 SQL 查询。

自然语言问题 → 表选择器 → 相关表集合 → 列选择器 → 最终 SQL

3.1.1 检索模块

用户提问 → 含有小样本的命名实体识别 prompt + LLM → 得到关键词和实体 → 根据关键词的语义相似性匹配 top k 列;基于局部敏感哈希(LSH)和语义相似性的两阶段检索策略检索值 → 得到最终列和值。

3.1.2 表选择器

表选择器的作用是识别哪些表与查询最相关、需要在 SQL 查询中使用。

表选择器通常通过以下几步实现:

  1. 自然语言理解:分析用户的查询,提取关键实体和操作动词。
  2. Schema 分析:了解数据库模式中有哪些表、字段以及它们之间的关系。
  3. 语义匹配:将用户查询的关键部分与数据库的表和字段进行匹配,以识别相关的表。
  4. 表优先级排序:根据相关性对表进行排序,优先选择最相关的表参与 SQL 构建。

3.1.3 列选择器

含有小样本的 prompt + LLM → 仅选择与用户提问最相关的最少列。

3.2 复杂查询理解

3.2.1 Chain-of-thought(CoT)

思维链(CoT)与大型语言模型(LLM)相结合,能在复杂的推理任务上取得不错的结果。

  • Divide and Conquer CoT(分而治之 CoT):让模型把查询任务拆解成更细粒度的任务,然后用 SQL 伪代码写出对这些子任务的查询,最终将结果合成一个完整的 SQL。直接写 SQL 效果不好是因为模型可能没有见过这样的数据分布,但是它肯定见过简单任务的数据分布,在 SQL 子语句都写出来了的前提下,SQL 的组合就显得没那么复杂了。
  • Query Plan CoT(查询/执行计划 CoT):让模型先把 SQL 的执行计划描述出来,再通过执行计划来生成 SQL。这么做可以让模型换个角度思考问题,将数据分布切换到了另外一个领域,能让模型更多地关注具体要用的表、列,能补足「分而治之」方法对细节把控不足的缺点。

3.3 提示词工程

在利用 LLM 完成 NL2SQL 任务时,提示词工程的关键在于将自然语言问题与必要的数据库信息转化为适用于 LLM 的自然语言序列输入,即问题表示。同时,当允许输入一些样例以利用 LLM 的 in-context learning 能力时,还需要考虑如何选择样例以及如何将这些样例有机地组织到输入序列中。

3.3.1 基本提示

基本提示(Basic Prompt)是一种简单的 Prompt 模板,它由表模式、以 Q: 为前缀的自然语言问题、以及提示 LLM 生成 SQL 的响应前缀 A:SELECT 组成。之所以命名为基本提示,是因为它并未包含任何指令内容。

3.3.2 文本表示提示

文本表示法提示(Text Representation Prompt)相比于基本提示,在提示的开头添加了指导 LLM 的指令。

3.3.3 OpenAI 范式提示

OpenAI 示范提示(OpenAI Demonstration Prompt)首次在 OpenAI 的官方 NL2SQL 演示中使用,它由指令、表模式和问题组成,其中所有信息都用 # 进行注释。与文本表示提示相比,OpenAI 示范提示中的指令更具体,而且还有一条规则约束,「仅完成 sqlite SQL 查询,无需解释」。

3.3.4 代码表示提示

代码表示提示(Code Representation Prompt)是一种基于 SQL 语法实现 NL2SQL 任务的方式。具体来说,它直接将表创建语句 CREATE TABLE … 放到 Prompt 中。相较于其他的问题表示方法,代码表示提示的独特之处在于,它能够提供创建数据库所需的全面信息,例如列名、列类型、主键/外键等。

3.3.5 通用方案总结

综合考虑上述 Prompt 策略,可以总结出一套通用且有效的 NL2SQL Prompt 策略。这一策略由六个关键要素构成,每个要素在提升模型生成 SQL 的准确性和效率中发挥着重要作用。以下是各个要素的详细说明:

  1. 指令(Instruction):为模型提供清晰而具体的指导方针。例如,「你是一个 SQL 生成专家。请参考如下的表格结构,直接输出 SQL 语句,不要提供多余的解释。」
  2. 数据结构(Table Schema):类似于语言翻译中的「词汇表」,这是你需要嵌入到 Prompt 中的数据库表结构。由于大模型无法直接访问数据库,你需手动提供包括表名、列名、列的类型、列的意义,以及主键和外键信息。
  3. 参考样例(Sample):这是一种启发模型生成 SQL 的可选技巧。你可以提供一个类似任务的 SQL 样例作为参考,以帮助模型更好地理解应该如何构建查询。
  4. 其他提示(Tips)/约束条件(Constraint):这些是你认为必要的额外指示。例如,要求生成的 SQL 中不允许出现某些表达式,或者要求列名必须采用「table.column」的形式。
  5. 领域知识(Knowledge):在某些特定问题中,这是一个可选要素。例如,如果用户的问题涉及「谁是这个月最厉害的销售」,你需要告诉模型,「最厉害」是指「销售单量最多」还是「销售金额最多」。
  6. 用户问题(Question):这是以自然语言形式表达的查询需求,如「统计上个月的平均订单额」。这一部分用于明确用户的意图和需求,以便模型生成正确的 SQL 语句。

3.4 多轮对话

3.4.1 SQL 候选生成和优选

候选优选(Candidate Selection)是为了从候选 SQLs 中选出最好、最正确的一个,常见方法包括:

  • self-consistency:以 N 个候选 SQL 中最常见的(非空)答案为准
  • selection agent:用模型来挑选最好的 SQL,可以用提示词或 fine-tuning 等技术
  • 基于 Unit test:参照 AI coding,生成 Unit Tests,用来评估每个 candidate SQL 的得分

3.4.2 SQL 语法微调

采用 SFT 方法,通过微调小参数量模型来生成可控的 SQL 查询。然而,参数限制使得复杂的推理和领域的迁移变得困难。此时可以聚焦于生成高精度、多样化的 SQL 候选语句。

基础语法训练:这一阶段专注于使用简单且通用的 SQL 模式和语法对预训练模型进行微调,不涉及具体 SQL 方言。其目标是开发一个能够激活 SQL 生成能力的基础模型。

生成增强训练:在基础训练后,通过多任务和句法偏好数据增强模型能力。除了标准的查询生成,还可以额外设计 SQL 转换任务以深化 SQL 与问题间的关系。这包括从 SQL 推断问题、从 SQL 选择证据及其优化任务。这些任务加强了 SQL 与上下文信息的关联性,提高了 SQL 生成的广泛性和多样性。通过不同风格的句法特征,扩展训练样本,使模型从多样化数据中学习,从而生成更丰富的 SQL 查询。

3.4.3 SQL 查询优化

生成的候选 SQL 查询不可避免地包含逻辑或语法错误。通过利用这些 SQL 查询缺陷中的线索,进行一定程度的修正。为此,可以引入一个 SQL 优化器来优化生成的 SQL。在实际应用中,基于与架构相关的上下文、生成的 SQL 查询以及执行结果(包括潜在的错误信息),可以使模型能够进行第二轮的修正。原始 SQL 和重新生成的 SQL 还可以进一步通过选择模型进行最优选择,这一过程可以迭代执行。

3.5 检索增强生成(RAG)

简单来讲,RAG 技术就是通过检索获取相关的知识并将其融入 Prompt,让大模型能够参考相应的知识从而给出合理回答。因此,可以将 RAG 的核心理解为「检索 + 生成」。而在上文的「提示词工程」章节我们可以看到,为了提高 NL2SQL 生成的 SQL 质量,需要在提示词中加入业务领域知识、表知识(Schema)和列知识(Indicator),甚至是一些样例(Examples)问题便于 query 改写。而这往往又会造成提示词过多,带来上下文 token 不够的问题。因此,如果能将这些知识都转换成即时查询的方式,可以有效解决上下文 token 过大的问题。

在 NL2SQL 场景中,以下关键步骤可以借助 RAG 提高效率:

  • 领域知识查询:
    • RAG 可以利用预训练模型和检索技术相结合,帮助理解用户的查询所涉及的领域或上下文。通过从相关文档或数据库检索信息,RAG 可以为生成更精确的 SQL 语句提供背景知识。
    • 具体应用包括根据领域特定的术语或概念检索相关信息,从而帮助系统更好地理解和处理复杂或专业的查询。
  • 表查询:
    • 在生成 SQL 查询时,正确选择和理解数据库中的表是至关重要的。
    • RAG 可以通过检索数据库的元数据或相关文档,帮助识别合适的表及其结构。
  • 指标查询:
    • 对于用户查询中涉及的各种指标,例如计算平均值、总和、最大值等,RAG 可以帮助检索相关的计算逻辑或历史数据。
    • RAG 能够从过去的查询实例或相关文档中提取信息,帮助提高生成查询的准确性和效率,尤其是在复杂计算的场景中。

3.6 NL2Semantic2SQL

图片

除了从数据库和 SQL 层面思考如何提高 NL2SQL 的准确性,还可以从增加语义理解层来思考解决方案。因为如何将用户模糊、多变的业务意图精准、高效地映射到企业复杂的数据资产中,这一问题本身就是数据工程问题,而非单纯的 AI 问题。

可以通过额外引入一层语义层来更好地解决 NL2SQL 问题。语义层需要有以下特征:

  • 统一的业务语义抽象层,作为 Agent 和开发人员共同理解的「数据语言」;
  • 强大的元数据管理能力,确保指标定义的唯一性、透明性和可追溯性;

NL2Semantic2SQL 技术路线通过引入语义层作为中间抽象,大幅提升了系统的灵活性和可解释性。指标平台采用「度量」和「维度」两大基础要素,并运用「基础度量」、「业务限定」、「时间限定」和「衍生方式」四大要素,灵活定义和组合具有明确业务含义的指标,打造了一个统一的语义模型。自然语言查询首先被转换为语义表示,然后由系统基于语义模型生成最优 SQL 查询。

这种语义与表结构的解耦设计,使系统能够理解指标的业务意义,而不仅仅是表结构,确保在不同场景下,同一指标的口径保持一致性。随着业务规则的变化,只需调整语义定义,无需修改所有相关表或查询,显著提高了系统的适应性。

语义层的引入是 NL2Semantic2SQL 相对于传统 NL2SQL 的核心优势。它不仅提升了查询的准确性,还增强了系统的可解释性,赋予业务人员更强的自助能力。通过构建统一的业务语义模型,指标平台有效地跨越了技术与业务之间的鸿沟,使业务人员可以直接理解和使用数据,而无需深刻掌握 SQL 语法。

3.7 半结构化的数据库表达

3.7.1 Schema LLM 专属注释

正如上文所说,在使用基于 LLM 的 NL2SQL 技术时,为了使模型能够准确理解数据表的含义和列名的表示,建议为常用的数据表及其列添加注释。

表注释有助于模型更好地理解表的基本信息,从而在生成 SQL 语句时准确定位相关表。注释应简单明了,概括表的核心内容,如订单、库存等,并建议控制在 10 字以内,以避免过多解释。

列注释通常由常用名词或短语构成,例如订单编号、日期、店铺名称等,以准确表达列名的意义。此外,可以在列注释中包含列的示例数据或映射关系。例如,对于列名「isValid」,注释可以写成「是否有效。0:否。1:是。」以清楚地表示该列的含义和数值对应关系。

但是传统的数据库表注释和列注释可能已有一定的含义和上下游对接规范,所以目前有些数据库可支持 schema 维度的 LLM 专属注释,用于为 NL2SQL 生成时获取表和列提供便利。比如阿里的 PolarDB、开源的 M-Schema 项目。

3.7.2 LLM 配置表

在解决语义不清的问题时,往往需要我们对原始的问题进行改写符合底层数据的要求。一方面我们可以通过知识库的方式解决,另一方面也有一些数据库层面提供的解决方案,比如阿里的 PolarDB 提供了「配置表」功能,通过全局生效的固定表名,存储了诸如「问题文本条件判断」、「问题处理」、「问题补充与具体业务/概念相关的信息」等前置文本转换功能,「模型生成的 SQL 条件判断」、「处理 SQL,用于对业务逻辑中的值映射进行强制处理」等后置文本转换功能信息。

4. 参考文献

5. 团队介绍

本文作者思诚,来自淘天集团 - 价格平台技术团队。本团队支撑大促(双 11、618 等)和日销业务;同时我们也直面竞对,深入参与淘宝好价、百亿补贴、聚划算等日销业务的价格心智打造。秉承「简单、开放、自驱」的技术文化,在使命与责任中互相成就,共同成长,践行让业务先赢,技术氛围浓郁。