一、引言
Text-to-SQL任务旨在将自然语言查询转换为结构化查询语言(SQL),从而使非专业用户能够便捷地访问和操作数据库。近期,阿里云的OpenSearch引擎凭借其一致性对齐技术,在当前极具影响力的Text-to-SQL任务榜单BIRD数据集上荣获第一名,超越了包括IBM、Google、字节跳动、斯坦福大学等知名科技公司和高校。本文将介绍Text-to-SQL的技术演进,并对OpenSearch-SQL方法进行剖析。
同时,阿里云OpenSearch中该功能已经上线,欢迎大家使用。
开放搜索平台:https://help.aliyun.com/zh/open-search/search-platform/
二、背景
Text-to-SQL领域的研究历史悠久,其核心在于如何使人们能够通过自然语言提问并获得精准的SQL查询结果。过去,由于复杂的语法和逻辑要求,这一领域的价值主要集中在学术界。然而,随着大模型技术的发展,工业级的Text-to-SQL解决方案开始逐渐涌现。
Text-to-SQL技术面临的主要挑战在于准确解析用户意图,识别问题中的实体和关系,并将其映射到数据库的表、列及对应的SQL操作。这一过程不仅需要模型具备强大的语言理解能力,还必须深入了解SQL语法,并在面对多样化的数据库结构时展现良好的泛化能力。
为推动该领域的发展,一系列公开数据集和基准测试相继出现,如WikiSQL、Spider和BIRD等。它们为模型的训练和评估提供了标准,促进了技术的交流与竞争。这些丰富的资源使得Text-to-SQL系统从最初的简单查询,逐步发展到能够处理多条推理、比较运算和聚合函数等复杂SQL查询,极大地拓宽了其应用场景。
下图是一个Text-to-SQL极简的例子:
三、技术演进
3.1 传统方法
3.1.1 基于Sketch
这些方法基于SQL的结构,将SQL生成过程拆分为多个子模块,例如SELECT、AGG函数和WHERE条件等。在后续的生成过程中,根据这些模块的槽位选择相应的具体方法,从而提高生成的灵活性和准确性。
最初的方法以Seq2SQL为代表,它利用神经网络的分类任务对分解后的架构进行槽位内容的预测和填写。尽管这种基于架构分解的方法显著简化了Text-to-SQL任务的复杂度,但也因此限制了其处理SQL复杂性上限。例如,对于WikiSQL这样相对简单的数据集,这种方法能够取得不错的效果;然而,对于Spider等涉及复杂语法的问题,这种方法往往无法达到预期的结果。
类似思路的方法还有Coarse2Fine和RYANSQL等。这些方法不仅通过模型生成具体架构中的槽位内容,还尝试让模型先生成自然语言查询(NLQ)的具体架构。这一改进使得这些方法在处理复杂语法和多样化数据库环境时具有更好的扩展性。
3.1.2 基于中间语言
还有一些研究人员发现,与直接生成SQL相比,在解码过程中生成其他内容更容易与自然语言保持一致。这种先生成中间语言(可以是预先存在的语言或专门为特定任务构建的语言),再生成SQL的方法被称为基于中间语言的方法。
比如上图的IRNet,专门为SemQL构建了中间语言,于是让模型通过构建中间语言的方式来简化生成SQL的难度,等到生成中间语言后继续生成SQL。
3.1.3 小结
基于传统模型的方法还包括一些采用预训练模型替代传统编码器、利用图结构分析语法树,以及将重点放在数据库信息过滤等方面的算法。总体来看,基于Sketch、中间语言等形式的方法是对模型能力不足的一种补充。然而,最终生成SQL的效果在很大程度上依赖于研究人员手工设置的架构的表示能力,这限制了这些方法的迁移能力。
3.2 LLM方法
随着LLM能力的不断提高,LLM驱动的方法相较于传统方法展现出更强的迁移能力和推理能力,使得Text-to-SQL任务逐步进入一个新的阶段。在这个阶段中,更复杂的SQL任务得以有效处理,而无需局限于人为设计的具体框架。从数据集的角度来看,LLM驱动的方法所面临的任务难度也逐渐从Spider过渡到了BIRD,标志着对更复杂查询的挑战能力显著提升。
举例来说,传统方法中使用的经典模型T5-Base在Spider上可以达到71.1%的准确率,但在BIRD上仅实现了7.06%的准确率。而GPT-4在Spider上达到83.9%的准确率,而在BIRD上则为54.89%的准确率。这一对比反映了大模型驱动的方法在迁移性和应对更复杂问题上的显著优势。
3.2.1 标准框架
虽然LLM驱动的Text-to-SQL任务尚未形成一个明确的统一框架,但目前能够取得良好效果的框架大致可以归纳为以下四个部分:
- 准备阶段:准备数据库所必须的信息。
- 清洗各环节所用的数据库DDL。
- 处理数据库存储值,维护向量数据库。
- 准备Few-shot。
- 提取阶段:根据具体的问题提取必须信息,帮助模型降低任务难度。
- 面对大型数据库和复杂的任务,通过提取任务过滤字段和值来降低生成任务的难度。
- 生成阶段:根据所有的准备信息用大模型生成SQL,同时设计一些生成SQL的思路
- 使用COT、任务分解等方式。
- 用Few-shot驱动LLM理解任务。
- 优化阶段:根据一些规则或者SQL的执行结果对SQL进行二次自动修正。
- 根据执行结果对不可执行的SQL进行改正。
- 通过大模型进行SQL的选择。
3.2.2 代表方法
在LLM驱动的方法中,一些具有代表性的模型包括:
- DIN-SQL:利用链式推理(COT)进行SQL生成,增强了生成的逻辑性和可追溯性。
- ExSL + Granite-34B-Code:使用微调(SFT)模型来完成SQL生成任务,体现了预训练模型在特定任务上的适应能力。
- MAC-SQL:通过任务分解的方式来完成SQL生成,降低了复杂任务的难度,使模型能更好地处理多步骤的问题。
- DAIL-SQL:采用动态Few-shot策略,进一步提升模型在不同场景下的适应性。
- CHESS:使用更复杂的抽取模式以选择关键字段,在处理复杂SQL时表现出色。
这些方法在实际应用中均取得了不错的效果,展示了大模型技术在Text-to-SQL任务中的潜力。
四、OpenSearch-SQL方法剖析
在对基于LLM的Text-to-SQL方法进行分析后,我们提出了OpenSearch-SQL,旨在为Text-to-SQL方法提供一个标准的流程并解决当前方法中一些共性的问题。OpenSearch-SQL分为两个版本,均遵循如下的多Agent框架形式:
4.1 OpenSearch-SQL, v1
在OpenSearch-SQL, v2(以下简称v1)版本中,我们首次定义了上述Text-to-SQL框架。目前,v1在BIRD榜单上排名第十一(提交时为第二)。
- 预处理Agent:构建了Few-shot示例、数据库中值的向量库以及数据库结构信息。
- 生成Agent:利用动态Few-shot驱动LLM生成SQL。
- 优化Agent:根据SQL的执行结果对生成的SQL进行纠错和修正,最终得到优化后的SQL查询。
尽管v1版本已经取得了不错的效果,但经过深入分析,我们发现多Agent协作过程中,生成阶段的任务复杂性以及指令遵循失败是导致大模型生成不准确SQL的主要原因。具体问题如下:
- 生成阶段任务难度过高:
从SQL组件(如表、列和值)到生成SQL之间,存在复杂的思考过程。目前的方法往往要求模型直接完成这一转换,这无疑增加了生成任务的难度。
- 指令遵循失败:
- 提取字段和值:出现提取内容不完整或不一致的情况。
- 生成阶段:模型在生成阶段未充分利用提取出的信息。
- SQL风格不匹配:生成的SQL虽然合理,但与数据库的风格不符。
- 忽视需求:即使在提示中清楚表述了需求,LLM仍可能无视这些要求。
4.2 OpenSearch-SQL, v2
为了解决v1版本中存在的问题,在OpenSearch-SQL, v2中,我们一开始就定义了两个问题:
- 如何降低SQL生成的难度:渐进式生成
- 如何提高LLM指令遵循的成功率:一致性对齐
4.2.1 渐进式生成
为了降低SQL生成过程中的难度,我们提出了一种全新的方法来分解生成任务。虽然已有一些方法将生成SQL的过程划分为子任务进行处理再进行归并,但在实际场景中,这种分解可能会延长生成链条,并且在分解和组合的过程中容易引入误差,导致无法简单地将各个子SQL有效组合。因此,我们的目标是设计一种更为高效的分解方法,使得生成过程更简洁,同时减少误差的累积,从而提升整体SQL的生成准确性和效率。
我们认为可以逐步的完成SQL中的各个部分:SELECT、WHERE、GROUP BY等。于是,我们用一种COT的思路,逐步生成分析,SQL中的SELECT、Column、Value以及SQL本体。
What is the phone number of the school that has the highest average score in Math?
#reason: The question want to know the phone number of the school, so the SQL SELECT schools.Phone and the condition is the school that has the highest average score in Math. #columns: schools.Phone, schools.CDSCode, satscores.AvgScrMath #values: highest average score in Math refers to ORDER BY satscores.AvgScrMath DESC LIMIT 1 #SELECT: phone number of the school refers to schools.Phone #SQL-like: SELECT schools.Phone FROM schools ORDER BY satscores.AvgScrMath DESC LIMIT 1 #SQL: SELECT T1.Phone FROM schools AS T1 INNER JOIN satscores AS T2 ON T1.CDSCode = T2.cds ORDER BY T2.AvgScrMath DESC LIMIT 1
这样的做法相对于分解任务再合并的好处是:
- 由于环节之间的Gap很小,检查时可以清晰看出SQL生成过程中是哪一个环节出了问题。
- 渐近生成可以先忽略语法上不重要的信息对SQL生成的影响(如JOIN)。
- COT中一次性完成任务可以避免多agent合作引入的不一致性。
4.2.2 一致性对齐
对于第二个问题,我们首先分析了比较经典的提升模型在子任务上表现的方法:Post-training
虽然SFT、RLHF、DPO等后期训练方法存在通用能力下降的问题,但对于子任务而言,这些方法能够快速对齐子任务的风格。然而,这种对齐通常伴随着一些挑战:
- 数据准备与不确定性:对齐子任务的过程中需要准备大量的数据以及处理不确定的训练结果。目前较为常见的做法是仅对Text-to-SQL任务中生成SQL步骤的模型进行SFT,而其他部分仍然依赖于大基座模型(如GPT-4)来完成。这种策略虽然减少了数据需求,但可能无法充分发挥模型的潜力。
- 通用能力损失:这种训练方式往往会导致模型的通用能力下降。以一些参数量较小的大模型为例,SFT可能会使模型在简单问题上的表现显著提升,但在面对更复杂或困难的问题时,其表现反而可能下降。这表明,仅依赖于特定任务的训练可能会损害模型在广泛应用场景中的适应能力。
因此,在进行子任务对齐时,需要谨慎权衡其带来的优势与潜在的风险,寻找一种既能实现对齐又不损害通用能力的平衡方法。
在实践中我们发现了基座大模型对于复杂任务常常会出现指令遵循失败的问题,这是导致基座模型不如SFT模型效果的重要原因。那么是否可以在Agent中保证大模型的指令遵循效果呢?
出于这个设想,我们做了一系列实验,最后发现两个现象:
- 难度相关性:对于一个复杂任务如果将其分解为更简单的子任务,那么子任务的指令遵循程度更高。
- 生成波动性:对于模型能做对的SQL,它仍然会有一定的概率出错,这个概率和问题的难度正相关(实验上来说,相同的prompt在两次实验中badcase大约有10%左右的差集)。
根据这个现象,我们在OpenSearch-SQL中使用了Double Check + Vote 机制,这个机制通过:
- 任务分解:对子任务的分解,来降低LLM解决的子任务的难度,同时便于检查LLM对Agent中指令遵循的质量并进行重新生成。这个任务的工作有:
- 通过分解降低指令的复杂度。
- 因为分解后的子任务更简单,因此可以简单的对LLMs指令遵循的结果进行验证。具体实践上来说,这一步甚至可以直接通过检查完成对齐,而不必在Agent中指令模型的工作。
- SQL纠错:通过对SQL执行结果的分析,更进一步的根据执行结果的不同类型进行进一步的纠错。
- 不同的错误类型对应不同的纠错prompt。
- 通过执行多个生成SQL的结果进行Vote减少模型波动性的影响。
- Vote:通过Self-consistency和Vote机制,选择一致性最高的SQL结果作为答案,同时选择相同结果中执行时长最短的SQL。这一步使得SQL的准确率和效率都得到了提升。
4.3 展望
在一致性对齐方面,仍有许多优化的空间。通过原子化模型输出,Text-to-SQL任务的上限还有很大的提升潜力。利用原子化Agent任务,大模型可以快速构建各种任务的链路,并具备热插拔的能力,以便灵活接入不同的任务。这种机制不仅提高了模型的适应性,还能帮助开发者根据特定需求快速实现特定功能,进而提升整体效率和效果。
五、快速体验OpenSearch-SQL
在了解OpenSearch-SQL的具体方法和性能表现后,企业和开发者现在可以迅速体验OpenSearch-SQL的强大功能。目前,OpenSearch-SQL已正式上线,用户可以在OpenSearch-SQL搜索开发平台中进行体验,感受其卓越的性能与应用效果。
来源 | 阿里云开发者公众号
作者 | 问云