1.Text-to-SQL应用概述
什么是Text-to-SQL?Text-to-SQL也称为NL2SQL,是将自然语言查询转换为可在关系数据库上执行的SQL查询的技术。其核心目标是准确捕捉并反映用户意图,生成相应的SQL查询,确保执行后返回符合预期的结果。早在生成式人工智能LLM技术出现之前,已有很多专注于Text-to-SQL任务的机器学习项目。随着大模型技术的快速发展,凭借其强大的自然语言理解能力和推理能力,Text-to-SQL的性能得到了显著提升的同时,也大大降低了访问关系数据库和进行数据分析的门槛,并能够支持各种企业级应用。
Text-to-SQL技术的实际应用所面临的挑战主要在于自然语言的不确定性、数据库的复杂性和数据质量差异、自然语言到SQL语言的转换3个方面。这不仅需要模型具备强大的语言理解能力,还必须深入了解SQL语法,并在面对多样化的数据库结构和环境时表现良好的泛化能力。
大语言模型LLMs凭借其强大的语言理解和生成能力,为Text-to-SQL技术应用发展提供了新思路,LLMs能够通过理解自然语言问题的语义,建立问题与数据库模式之间的关联,并根据上下文生成正确的SQL查询。此外,LLMs还具备领域适应能力和错误修正能力,使其在Text-to-SQL任务中展现出显著优势。Text-to-SQL正在成为连接自然语言与结构化数据的重要桥梁,为企业数据分析和决策支持开辟了新的可能性。
2.Text-to-SQL的技术发展
Text-to-SQL技术的核心在于将用户输入的自然语言查询精准地转化为等价的SQL查询语句,从而使非技术人员也能借助日常语言与数据库进行交互。这一转换过程通常涵盖自然语言处理(NLP)、语义解析以及SQL生成等关键环节。当用户输入自然语言问题后,系统会首先运用NLP技术来理解用户的意图,然后通过语义解析把提取到的信息映射到数据库模式上,最后生成相应的SQL查询语句。
文本到SQL系统的发展历程宛如一部技术进化史,经历了从简单到复杂、从规则驱动到数据驱动、从特定领域到跨领域通用的漫长演进。早期的文本到SQL系统主要依赖严格的规则,通过人工精心编写语法规则和启发式方法,试图将自然语言查询转换为SQL命令。在简单且特定的数据库应用场景中,这些系统能够发挥一定的作用,而随着数据复杂性的不断增加以及查询需求的日益多样,其局限性也逐渐凸显出来。面对复杂的查询结构和多样的数据库模式,基于规则的系统显得力不从心,难以实现有效的泛化,这促使了技术的进一步革新。深度学习的浪潮为文本到SQL技术应用带来了新的曙光。
2017年,基于序列到序列模型(如LSTM和Transformer)的方法开始崭露头角,Seq2SQL和SQLNet等模型应运而生。这些模型采用了端到端的可微分架构,直接对自然语言进行解释并生成SQL查询。相较于传统方法,它们在性能、灵活性和可扩展性方面都有了显著提升,能够学习自然语言与SQL之间的映射关系,初步解决了一些复杂查询的生成问题。
预训练语言模型PLMs的出现,进一步推动了文本到SQL技术的发展。PLMs基于大规模无监督文本数据进行预训练,能够学习到丰富的语言表示,然后通过微调适应特定任务。在文本到SQL领域,PLMs通过将自然语言查询和数据库模式整合为统一表示,提升了SQL生成的准确性,尤其在处理多表连接、嵌套查询等复杂任务上表现出色。不过,PLMs也并非尽善尽美,其在跨领域应用时仍需大量针对特定任务的微调,且在理解复杂数据库模式方面存在一定的局限性。大语言模型的问世,标志着文本到SQL系统进入了一个全新的阶段。这些模型凭借其海量的参数和大规模的训练数据,展现出了强大的语言理解和生成能力。在文本到SQL任务中,LLMs能够更有效地捕捉自然语言查询与数据库模式之间的复杂关系,在零样本和少样本学习场景下表现优异,显著减少了对特定任务微调的依赖,提高了系统的灵活性和适应性。
3.Text-to-SQL应用存在的不足
当前,在Text-to-SQL的实际应用中,模型输出SQL的准确性尚未达到生产系统的精度要求,生成和执行效果仍存在优化空间。尽管借助大语言模型(LLMs)的能力,Text-to-SQL技术已取得了显著进展,但在实际应用中仍存在一些不足之处:
(1)查询意图理解偏差
由LLMs直接生成的SQL有时无法准确反映用户的查询意图,导致生成的SQL逻辑不正确,从而无法得到所需的查询结果。尤其在涉及多表关联和复杂筛选查询需求时,这种偏差更为明显。
(2)捏造错误数据信息
在生成SQL语句时,LLMs可能会产生一些看似合理但实际上并不存在的结构定义信息。这是由于大模型的幻觉问题所致,模型尚未充分学习数据库信息,并且对当前上下文的理解不足,从而导致误导性输出。
(3)多次生成答案不同
LLMs生成的SQL信息存在不稳定性。对于同一问题的多次提问,生成的内容可能不完全一致。这就需要人为干预,通过择优筛选和修正优化,才能确保其达到正确且可用的状态。
以上情况都在一定程度上影响了实际应用的用户体验。
4.利用提示工程、模型微调、RAG和Agent的优化思路
为解决这些问题,可考虑采用提示工程(Prompt Engineering)、模型微调(Fine-tuning)、联合检索增强生成和智能代理(RAG & Agent)等方法,以优化模型及应用的Text-to-SQL任务设计。
4.1.提示工程优化
通过设计特定的提示词或语句,引导模型生成更贴合用户意图的输出内容。在处理SQL查询时,向模型注入特定领域的知识,如SQL规范、数据库架构以及数据字段注释等额外信息,能够显著提升模型对于SQL语句结构和逻辑的理解能力。
提示工程的关键在于将自然语言问题与必要的数据库信息转化为适用于大语言模型(LLM)的自然语言序列输入,即问题表示。同时,当允许输入一些样例以利用LLM的上下文学习能力时,还需要考虑如何选择样例以及如何将这些样例有机地组织到输入序列中。
通过构建包含基本提示、文本表示提示、OpenAI范式提示、代码表示提示、指令微调提示以及上下文学习等综合Prompt策略的方法,在Text-to-SQL的Prompt设计中融入说明、数据结构、示例、提示或约束、领域知识及用户问题等要素,能够取得较好的效果,具体如下:
(1)说明:如,“你是一个SQL生成专家。请参考如下的数据表结构,输出SQL语句。”
(2)数据结构:相当于语言翻译中的字典。即需要使用的数据库表结构,把数据结构组装进Prompt,包括表名、列名、列的类型、列的含义、主外键信息。
(3)示例:作为可选项,也是提示工程的常见方式。即指导大模型生成SQL的参考范本。
(4)提示或约束:其他必要的指示。
(5)领域知识:可选项,某些特定问题中,对常识描述的解释。
(6)用户问题:用户提出的问题。
融合上述元素,可以得到TEXT-TO-SQL通用Prompt模板框架如下:
4.2.模型微调优化
针对预训练模型进行定制化调整,以更好地契合特定应用场景的需求。尤其在Text-to-SQL这类复杂任务中,通过利用包括SQL语句的专门数据集对模型进行微调,可以强化模型对SQL语言特性的理解和生成能力。这一过程不仅保留了大模型的语言理解广度,还提升了处理SQL转换的精确性和效率,有效避免生成SQL查询时的常见错误,从而提高了整体执行效果。能够支持微调的开源框架有很多,包括:
(1)DB-GPT-Hub
DB-GPT-Hub是一个利用大型语言模型(LLMs)实现Text-to-SQL解析的实验项目,主要包含数据集收集、数据预处理、模型选择与构建以及微调权重等步骤。通过这一系列处理,可以在提高Text-to-SQL能力的同时降低模型训练成本,最终实现基于数据库的自动问答。
DB-GPT-Hub采用了最新版本的预训练语言模型,如GPT-3或其开源变体,对大量的代码库进行训练,以学习编码模式和最佳实践。这种基于Transformer架构的模型具有以下特性:
上下文感知:模型能够理解代码块的整体结构,生成的代码与其上下文紧密相关。
多样性:能够根据不同的编程风格生成多种可能的代码实现。
可扩展性:通过持续训练和整合新的代码数据,可以不断提高代码生成的准确性和适用性。
(2)LLaMA-Factory
LLaMA-Factory的目标是整合主流的高效训练微调技术,适配开源模型,形成一个功能丰富、适配性好的训练框架。它提供了多个高层抽象调用接口,包含多阶段训练、推理测试、benchmark评测以及API Server等。
使用LLaMA-Factory进行模型微调是一个涵盖从选择模型、数据加载、参数配置到训练、评估优化直至部署应用的全面且高效的流程。
4.3.RAG/Agent增强
(1)RAG增强
RAG作为一种融合了检索和生成任务的人工智能技术,正在引领数据库查询领域的革新。它通过增强语言模型的能力,使其能够更精确地理解查询意图并生成相应的SQL语句,从而实现对数据库的高效且直观的访问。
Vanna是一个开源的、基于大模型和RAG框架的Text-to-SQL工具。它结合了RAG框架、大型语言模型、高质量的训练数据、持续优化、广泛的数据库支持以及开源定制特性,实现了在复杂数据集上的高精度表现。
RAG技术结合了检索(Retrieval)和生成(Generation)两方面的能力。在数据库查询的背景下,它不仅能够检索数据库中的信息,还能够根据检索到的信息生成相应的SQL查询语句。其中,检索组件负责从数据库中提取与用户查询相关的数据,使用索引和搜索算法快速定位信息,确保查询的准确性和效率;生成组件则在检索到相关信息后,根据这些数据构建SQL语句。
Vanna框架的工作原理可以概括为以下几个步骤:
-
用户输入:用户以自然语言的形式提出查询请求。
-
意图识别:通过自然语言处理(NLP)引擎分析用户的查询,识别其意图和关键信息。
-
信息检索:根据识别的意图,检索数据库中相关的数据。
-
SQL生成:结合检索到的数据,生成相应的SQL语句。
-
执行与反馈:生成的SQL语句在数据库上执行,并将结果反馈给用户。
(2)Agent增强
AI Agent(智能体)是一种模拟人类或其他智能体行为和决策过程的系统。通过引入行动能力、长期记忆机制和工具整合能力,能够感知环境、处理信息、制定策略并执行行动来完成任务。AI Agent通过一个框架规划多个方法,这个框架具有一些具体模块,支持整个结构的运行。在Text-to-SQL任务中,这通常涉及多个步骤,Agent需要了解这些步骤并提前规划,具体的类型包括:
-
目标和任务分解:Agent将大型任务分解为更小、更易管理的子目标,以便有效地处理复杂任务。
-
反思与改进:Agent可以对过去的行为进行自我校准和自我反思,从错误中学习并改进未来步骤,从而提高最终结果的质量。
-
外部工具与资源利用:Agent可以调用各种外部工具集,如搜索引擎、数据库接口等,以扩展其功能并增强解决问题的能力。
-
对话管理与上下文保持:通过维护对话历史和关键信息,Agent能够在连续提问或修正查询时保持上下文的连贯性,提升用户体验。
5.基于Agent的Text-to-SQL应用实践
DB-GPT通过多模型管理、RAG框架、API调用、可视化、Text-to-SQL效果优化、Multi-Agents框架协作、AWEL智能体工作流编排、意图识别等多种技术支持,围绕Agengt数据应用构建大模型应用基础服务能力。其中,Agent的核心模块主要包括:Memory、Profile、Planing、Action等,围绕Agent构建多Agent之间的协作能力,包括:
(1)单一Agent:单个Agent有具体任务与目标,不涉及多模型协作。
(2)Auto-Plan:Agent自己制定计划,在多Agent协作时负责路径规划、分工协作等。
(3)AWEL编排:通过程序编排来实现多智能体的协作。
本文实践内容通过本地搭建DB-GPT及大模型服务环境,使用Text-to-SQL数据对话功能和创建Agent智能体Text-to-SQL应用对结构化数据集进行SQL生成分析验证。
5.1.应用架构
DB-GPT的Agent应用架构包括Resources、Agent、AWEL、Apps四个部分,如图所示:
Resources:是DB-GPT中智能体与外界交互的桥梁,包括工具、数据库、知识库等。
Agent:由Profile、Memory、Planing、Action模块组成,Profile模块的目的是做Agent角色认定,回答的核心问题,Memory即记忆模块用来存储、获取、检索信息,Planning模块制定计划,Action模块执行智能体的具体决策。
AWEL:是Agent智能体工作流表达语言,通过AWEL API可以专注于大模型应用业务逻辑开发,其采用分层 API 的设计,包括算子层、AgentFrame层以及DSL层。
Apps:能够支持Text-to-SQL应用、数据应用和问答应用等。
5.2.环境部署
(1)下载DB-GPT源码
(2)安装Miniconda环境
根据系统架构类型下载对应的安装文件
根据提示信息执行.sh安装文件
(3)创建Python虚拟环境
(4)修改.env配置文件
使用代理模型OpenAI并下载Embedding模型
在.env文件中配置Embedding模型
在.env文件中配置代理模型
(4)启动服务
(4)访问服务
访问浏览器地址http://localhost:5670
5.3.数据准备
数据准备使用MySQL数据库和CSpider的car-dataset数据集,car-dataset表示一个汽车相关的信息库,包含了continents、countries、car_maker、model_list、car_names、cars_data数据表及相关数据,实体关系及表结构字段信息如下:
continents数据表
countries数据表
car_makers数据表
model_list数据表
car_names数据表
cars_data数据表
预设问题包括单表查询、关联表查询和多表查询共9个查询问题。
(1)单表查询
问题1:统计数据集中的汽车数量?
问题2:统计数据集car_names表中不同model的汽车数量占比?
问题3:统计数据集中各制造商的车型数量占比?
(2)关联表查询
问题4:查询数据集中加速用时最少的车型?
问题5:统计数据集中不同年份生产的车型数量?
问题6:按照质量大小进行排序,查询最重的50辆汽车及其所属车型?
(3)多表查询
问题7:统计数据集中各国家生产的车型model数量占比?
问题8:统计数据集中的德国汽车制造商数量是多少?
问题9:统计数据集中所有欧洲生产汽车的平均马力是多少?
5.4.设定Prompt提示
按照通用Prompt模板设计提示如下:
(1)说明
你是1名数据库专家,擅长使用SQL语言帮助用户进行数据分析,能够根据用户提出的分析需求进行数据信息查询和处理SQL并生成计算结果,请根据以下用户问题生成意图理解清晰、解答准确的SQL语句。
以下cars-dataset数据集描述了1970年至1983年各国家制造商生产的406种汽车模型数据,其中包括:
car_makers数据表,生产汽车的公司信息;
car_names数据表,具体的汽车名称信息;
cars_data数据表,具体的汽车运行参数;
continents数据表,大洲列表;
countries数据表,国家列表;
model_list数据表,制造商生产的车型信息;
(2)数据库表结构
这里是数据库表的结构信息:
CREATE TABLE car_makers (
Id INT NOT NULL AUTO_INCREMENT COMMENT '制造商ID',
Maker VARCHAR(255) COMMENT '制造商简称',
FullName VARCHAR(255) COMMENT '制造商全称',
Country INT COMMENT '国家ID',
PRIMARY KEY (Id),
FOREIGN KEY (Country) REFERENCES countries(CountryId)
);
CREATE TABLE car_names (
MakeId INT AUTO_INCREMENT PRIMARY KEY COMMENT '汽车ID',
Model VARCHAR(255) COMMENT '车型名称',
Make VARCHAR(255) COMMENT '汽车名称',
FOREIGN KEY (Model) REFERENCES model_list(Model)
);
CREATE TABLE cars_data (
Id INT AUTO_INCREMENT PRIMARY KEY COMMENT '汽车ID',
MPG VARCHAR(255) COMMENT '每加仑英里数',
Cylinders INT COMMENT '气缸数',
Edispl FLOAT COMMENT '发动机排量',
Horsepower VARCHAR(255) COMMENT '马力',
Weight INT COMMENT '重量',
Accelerate FLOAT COMMENT '加速时间',
Year INT COMMENT '发布年份',
FOREIGN KEY (Id) REFERENCES car_names(MakeId)
);
CREATE TABLE continents (
ContId INT NOT NULL AUTO_INCREMENT COMMENT '洲ID',
Continent VARCHAR(255) COMMENT '洲名称',
PRIMARY KEY (ContId)
);
CREATE TABLE countries (
CountryId INT NOT NULL AUTO_INCREMENT COMMENT '国家ID',
CountryName VARCHAR(255) COMMENT '国家名称',
Continent INTEGER COMMENT '洲ID',
PRIMARY KEY (CountryId),
FOREIGN KEY (Continent) REFERENCES continents(ContId)
);
CREATE TABLE model_list (
ModelId INT NOT NULL AUTO_INCREMENT COMMENT '车型ID',
Maker INTEGER COMMENT '制造商ID',
Model VARCHAR(255) UNIQUE COMMENT '车型名称',
PRIMARY KEY (ModelId),
FOREIGN KEY (Maker) REFERENCES car_makers(Id)
);
(3)用户问题及对应SQL语句示例
这里是部分用户问题及对应SQL语句示例:
问题:统计数据集中所有在美国制造的汽车的平均马力是多少?
回答:
SELECT AVG(cars_data.Horsepower) FROM cars_data JOIN car_names ON cars_data.Id = car_names.MakeId JOIN car_makers ON car_names.MakeId = car_makers.Id JOIN countries ON car_makers.Country = countries.CountryId WHERE countries.CountryName = "USA"
问题:统计数据集中在1970年,各个国家生产的汽车数量占比?
回答:
SELECT CountryName, COUNT(*) AS Count, (COUNT(*)/(SELECT COUNT(*) FROM cars_data WHERE Year = 1970)) * 100 AS Percentage
FROM cars_data a JOIN car_names b ON a.Id = b.MakeId
JOIN model_list c ON b.Model = c.Model
JOIN car_makers d ON d.Id = c.Maker
JOIN countries e ON e.CountryId = d.Country
WHERE a.Year = 1970
GROUP BY CountryName
(4)领域知识
略
(5)约束条件
略
(6)用户问题
参见数据准备预设问题内容。
在交互界面中,将Prompt提示内容按照格式要求维护到系统中。选择[应用管理]->[提示词]->[新增Prompts],依次填写信息后保存。
5.5.创建Agent应用
开发自定义Agent可以通过角色定义、重载推理、构建记忆对象、定义模型输出、输出执行、执行展示等方法进行实现。这里我们使用DB-GPT提供的默认数据分析智能体(DataScientist)创建Agent应用。
(1)添加数据源
在交互界面中,将数据库添加到数据源中。选择[应用管理]->[数据库]->[添加数据源],依次填写本地数据库信息后保存。
(2)创建数据应用
在交互界面中,创建应用,选择[应用管理] ->[应用程序] ->[创建应用],选择[多智能体自动规划模式],填写应用名称和描述,点击确定。
依次选择对应的参数:
智能体:选择[DataScientist]智能体、[Reporter] 智能体
提示词:选择提前设定的Prompt提示
模型策略:选择优先级策略,可以按照优先级使用不同的模型。
可用资源:资源类型选择数据库类型,参数选择之前添加的数据源
推荐问题: 可以根据情况来设定默认问题。
(3)开始对话
点击开始对话,输入预设问题进行问答。
5.6.使用预设问题生成SQL并执行查询
(1)单表查询
问题1:统计数据集中的汽车数量?
问题2:统计数据集car_names表中不同model的汽车数量占比?
问题3:统计数据集中各制造商的车型数量占比?
(2)关联表查询
问题4:查询数据集中加速用时最少的车型?
问题5:统计数据集中不同年份生产的车型数量?
问题6:按照质量大小进行排序,查询最重的50辆汽车及其所属车型?
(3)多表查询
问题7:统计数据集中各国家生产的车型model数量占比?
问题8:统计数据集中的德国汽车制造商数量是多少?
问题9:统计数据集中所有欧洲生产汽车的平均马力是多少?
5.7.与Chat Data应用比较
简要生成结果比较如下:
注:Chat Data为DB-GPT默认数据对话应用(无提示优化及Agent增强)
5.8.结果分析
将生成的结果与Chat Data原生数据对话应用的输出进行对比后发现,在结果准确性方面,Agent应用的表现略有提升,在问题理解和SQL生成方面,Agent应用依赖于其规划能力和行动策略,执行过程的优化更为突出。
6.因此
随着生成式大语言模型的规模和训练数据的不断增长,LLMs的语言理解和逻辑推理能力不断提升,准确理解丰富语义并处理复杂数据关系的通用性和专业性能力也将增加。同时,利用AI Agent实现Text-to-SQL应用还可以进一步优化Agent策略以及与知识图谱、RAG等技术深入结合,拓展更多应用场景,以提升其应用能力和商业价值。