惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
博客园 - 叶小钗
Blog — PlanetScale
Blog — PlanetScale
Microsoft Azure Blog
Microsoft Azure Blog
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
A
About on SuperTechFans
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
D
Docker
Jina AI
Jina AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Register - Security
The Register - Security
J
Java Code Geeks
S
SegmentFault 最新的问题
月光博客
月光博客
G
Google Developers Blog
美团技术团队
Last Week in AI
Last Week in AI
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
T
The Blog of Author Tim Ferriss
腾讯CDC
Recent Announcements
Recent Announcements
Recorded Future
Recorded Future
The Cloudflare Blog
有赞技术团队
有赞技术团队
博客园_首页
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
B
Blog
I
InfoQ
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Fortinet All Blogs
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
爱范儿
爱范儿
D
DataBreaches.Net
F
Full Disclosure
M
MIT News - Artificial intelligence
博客园 - 司徒正美
H
Help Net Security

博客园 - China Soft

.NET 程序保护实战系列01-流水线架构与保护引擎总览 试官问:你用 AI 编程半年了,那怎么保证 Claude Code 写出来的代码是对的? C#实现控制台多区域输出 园友特惠| 1Panel 企业版 & AI 一体机限量放售,最高直降 5100! 上位机程序发布打包成安装包---Inno Setup 这是一篇学习笔记,分享给大家,如果大家喜欢,也会开启USB的专辑 我问了 AI 一个问题:编码能力贬值后,什么能力值钱? Visual Studio 2026(VS2026) 密钥/激活码 Dddify:给 ASP.NET Core 项目一套轻量、清晰、可落地的 DDD 基础设施 C# ESP32/STM32 轻量 Web 能力库:PicoServer.Nano 高性能百度OCR ONNX Runtime C#实现 别再说 AI 开发就是调接口了!5 种主流模式一次讲清 使用Cursor实现管理系统登录界面的快速开发 在 Avalonia 中编写高性能动画 傻子可懂的 Harness Engineering 入门教程 + 项目实战,一次搞懂 AI 编程工程化! AI/Vibe Coding,本质是软件人工时代向软件工业时代发展 体验优先:十分钟使用 Python+LangChain 玩转阿里通义千问 大模型基础(二):必懂5大基础概念《Token、上下文窗口、Embedding、预训练、微调》 大模型基础(一):什么是LLM? Prompt、Agent、Function Call、Skill、MCP,傻傻分不清楚? 那些喊着AI 要淘汰你的人,正在靠你的焦虑赚大钱! 作为一线研发,我快被全网的 AI 焦虑逼疯了。 Qt QtWebEngine 白屏的解决方案 都是微软亲儿子,WPF凭啥干不掉WinForm?这3个场景说明白了 .NET 高级开发 | C# 中的动态代码:反射、EMIT、表达式树、Roslyn、Source Generators 大模型看大模型:推理Token的能耗用电量比对 WorkBuddy:从“我是谁”到“帮我干活” .NET 高级开发 | 开发 .NET 诊断工具、链路追踪原理 Prompt 焚诀——一个模板,终结你和 AI 的所有沟通问题 [项目]涉案资产信息化管理平台(山东某执法单位定制开发) 大模型RAG实战,从被骂不靠谱到成为部门MVP,这是我的踩坑全记录 白帽子为什么几乎都绕不开 httpx:一款 HTTP 资产探测工具的技术价值 从Prompt工程到Skill工程:Agent Skills开放标准彻底改变了AI协作方式 MAUI项目在Android平台通过U盘实现软件更新 微软竟然出了免费的 AI 应用开发课?!我已经学上了 一文彻底搞懂 OpenClaw 的架构设计与运行原理(万字图文) AI到底聪明在哪——从手机人脸识别说起 硬核科普:为何小米任天堂封杀 Root?揭秘操作系统从启动到“夺权”的底层游戏
提升 Text2SQL 准确率
China Soft · 2026-05-09 · via 博客园 - China Soft

https://www.cnblogs.com/aspnetx/p/19990591

摘要

随着大语言模型的爆发,Text2SQL(自然语言转SQL)技术正在重塑我们与数据库的交互方式。本文将系统性地梳理提升 Text2SQL 准确率的核心方法,涵盖提示工程、模型微调、推理增强三大维度。所有示例基于微软 AdventureWorksDW2016 数据仓库。

引言:为什么 Text2SQL 准确率如此重要?

在数据驱动的时代,让非技术用户能够通过自然语言查询数据库,是一个极具价值但也极具挑战的任务。传统的 Text2SQL 系统准确率有限,难以投入实际应用。但随着 GPT-4、Llama、Qwen 等大模型的出现,这一领域迎来了革命性的突破。

目前业界领先的系统在 Spider 数据集上已能达到 82.5% 的执行准确率,但如何在实际业务场景中达到甚至超越这个水平?本文将从五个核心维度展开:

  1. Schema 设计与呈现 - 让模型更好地理解数据库结构
  2. 提示工程优化 - 设计高效的提示词策略
  3. 业务上下文配置 - 消除业务语言与技术语言的鸿沟
  4. 模型微调方法 - 针对特定任务优化模型能力
  5. 推理时增强策略 - 在推理阶段提升准确率

本文使用的是微软SQLServer官方的示例库,使用的是数据仓库的示例库AdventureWorksDW,我学习数据仓库的时候一直都参考这个库,大家可以很容易在微软的SQLServer官方网站上下载到这个库。


一、Schema 设计与呈现:打好地基

1.1 J-Schema:更友好的数据库结构呈现

传统 Schema 往往只提供表名和字段名,这对于模型理解业务语义是不够的。J-Schema 方法提出了一种更优秀的呈现方式:

示例:DimCustomer 表(客户维度表)

表名: DimCustomer (客户维度表)
字段:
  - CustomerKey (客户代理键, 主键, 自增)
  - GeographyKey (地理代理键, 外键 → DimGeography.GeographyKey)
  - CustomerAlternateKey (客户业务标识, 如会员编号)
  - FirstName (名)
  - LastName (姓)
  - BirthDate (出生日期, 格式: YYYY-MM-DD)
  - MaritalStatus (婚姻状态, 可选值: S-单身/M-已婚)
  - Gender (性别, 可选值: M-男/F-女)
  - EmailAddress (电子邮箱)
  - YearlyIncome (年收入, 单位: 美元)
  - TotalChildren (子女总数)
  - EnglishEducation (教育程度, 可选值: Bachelors/Graduate/High School/Partial College/Partial High School)
  - EnglishOccupation (职业, 如: Professional/Management/Clerical 等)
  - AddressLine1 (地址第一行)
  - Phone (电话号码)
  - DateFirstPurchase (首次购买日期)
  - CommuteDistance (通勤距离, 如: 0-1 Miles/1-2 Miles/5-10 Miles)
  
示例值:
  - CustomerKey: 11000, 11001
  - FirstName: Jon, Yang
  - LastName: Yang, Zhu
  - BirthDate: 1972-01-12
  - MaritalStatus: S
  - Gender: M
  - YearlyIncome: 90000.00
  - EnglishEducation: Bachelors
  - EnglishOccupation: Professional

Key points:

  • ✅ 提供字段语义描述
  • ✅ 说明主外键关系
  • ✅ 给出字段格式和可选值
  • ✅ 提供示例数据(帮助模型理解数据特征)

1.2 表关联关系管理

多表查询是 Text2SQL 的难点之一。清晰定义表关联关系,能让模型生成更准确的 JOIN 语句:

AdventureWorksDW2016 核心表关联关系:

{
  "relationships": [
    {
      "from_table": "FactInternetSales",
      "from_column": "CustomerKey",
      "to_table": "DimCustomer",
      "to_column": "CustomerKey",
      "relation_type": "many_to_one",
      "description": "一个客户可以有多个互联网销售订单"
    },
    {
      "from_table": "FactInternetSales",
      "from_column": "ProductKey",
      "to_table": "DimProduct",
      "to_column": "ProductKey",
      "relation_type": "many_to_one",
      "description": "一个产品可以被多次销售"
    },
    {
      "from_table": "FactInternetSales",
      "from_column": "OrderDateKey",
      "to_table": "DimDate",
      "to_column": "DateKey",
      "relation_type": "many_to_one",
      "description": "订单日期关联到日期维度"
    },
    {
      "from_table": "DimCustomer",
      "from_column": "GeographyKey",
      "to_table": "DimGeography",
      "to_column": "GeographyKey",
      "relation_type": "many_to_one",
      "description": "客户关联到地理位置"
    },
    {
      "from_table": "DimProduct",
      "from_column": "ProductSubcategoryKey",
      "to_table": "DimProductSubcategory",
      "to_column": "ProductSubcategoryKey",
      "relation_type": "many_to_one",
      "description": "产品属于某个子类别"
    },
    {
      "from_table": "DimProductSubcategory",
      "from_column": "ProductCategoryKey",
      "to_table": "DimProductCategory",
      "to_column": "ProductCategoryKey",
      "relation_type": "many_to_one",
      "description": "子类别属于某个大类"
    },
    {
      "from_table": "FactResellerSales",
      "from_column": "ResellerKey",
      "to_table": "DimReseller",
      "to_column": "ResellerKey",
      "relation_type": "many_to_one",
      "description": "经销商销售关联到经销商维度"
    },
    {
      "from_table": "FactResellerSales",
      "from_column": "EmployeeKey",
      "to_table": "DimEmployee",
      "to_column": "EmployeeKey",
      "relation_type": "many_to_one",
      "description": "经销商销售关联到员工(销售代表)"
    }
  ]
}

如果建表脚本已经包含了这些信息,可以让大模型帮助生成这些关联信息。


二、提示工程优化:引导模型思考

2.1 思维链(Chain-of-Thought)引导

复杂查询需要多步推理。通过思维链提示,引导模型逐步分析,以下是一个具体的示例:

示例:查询 2014 年每个产品类别的销售额

问题: 查询2014年每个产品类别的总销售额,按销售额降序排列

思考过程:
1. 确定时间范围: 2014年 → DimDate.CalendarYear = 2014
2. 需要的字段: 产品类别名、销售额总计
3. 涉及的表: 
   - FactInternetSales (销售事实表)
   - DimProduct (产品维度)
   - DimProductSubcategory (产品子类别)
   - DimProductCategory (产品类别)
   - DimDate (日期维度)
4. 关联条件:
   - FactInternetSales.ProductKey = DimProduct.ProductKey
   - DimProduct.ProductSubcategoryKey = DimProductSubcategory.ProductSubcategoryKey
   - DimProductSubcategory.ProductCategoryKey = DimProductCategory.ProductCategoryKey
   - FactInternetSales.OrderDateKey = DimDate.DateKey
5. 聚合逻辑: 按 EnglishProductCategoryName 分组, SUM(SalesAmount) 计算总额
6. 排序: ORDER BY 总销售额 DESC

SQL:
SELECT 
    dc.EnglishProductCategoryName AS ProductCategory,
    SUM(fis.SalesAmount) AS TotalSalesAmount
FROM FactInternetSales fis
    INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    INNER JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    INNER JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
    INNER JOIN DimDate dd ON fis.OrderDateKey = dd.DateKey
WHERE dd.CalendarYear = 2014
GROUP BY dc.EnglishProductCategoryName
ORDER BY TotalSalesAmount DESC;

2.2 Few-Shot 示例库

针对复杂、高频的查询场景,提供示例 SQL:

examples = [
    {
        "question": "查询每个产品类别的销售数量",
        "sql": """
SELECT 
    dc.EnglishProductCategoryName,
    COUNT(*) AS SalesCount
FROM FactInternetSales fis
    INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    INNER JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    INNER JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
GROUP BY dc.EnglishProductCategoryName
ORDER BY SalesCount DESC;
        """
    },
    {
        "question": "查找最近30天未下单的客户",
        "sql": """
SELECT 
    dc.FirstName,
    dc.LastName,
    dc.EmailAddress
FROM DimCustomer dc
WHERE dc.CustomerKey NOT IN (
    SELECT DISTINCT CustomerKey 
    FROM FactInternetSales 
    WHERE OrderDate >= DATEADD(DAY, -30, GETDATE())
);
        """
    },
    {
        "question": "查询每个地区的销售额和订单数",
        "sql": """
SELECT 
    dst.SalesTerritoryRegion,
    dst.SalesTerritoryCountry,
    COUNT(DISTINCT fis.SalesOrderNumber) AS OrderCount,
    SUM(fis.SalesAmount) AS TotalSales
FROM FactInternetSales fis
    INNER JOIN DimSalesTerritory dst ON fis.SalesTerritoryKey = dst.SalesTerritoryKey
GROUP BY dst.SalesTerritoryRegion, dst.SalesTerritoryCountry
ORDER BY TotalSales DESC;
        """
    },
    {
        "question": "查询年收入前10的客户及其购买总额",
        "sql": """
SELECT TOP 10
    dc.FirstName,
    dc.LastName,
    dc.YearlyIncome,
    SUM(fis.SalesAmount) AS TotalPurchases
FROM DimCustomer dc
    INNER JOIN FactInternetSales fis ON dc.CustomerKey = fis.CustomerKey
GROUP BY dc.CustomerKey, dc.FirstName, dc.LastName, dc.YearlyIncome
ORDER BY dc.YearlyIncome DESC;
        """
    }
]

示例 SQL 的价值:

  • 帮助模型"举一反三",将示例应用到类似场景
  • 规范 SQL 风格和最佳实践
  • 提升复杂查询的生成质量

2.3 自定义提示词规则

定义全局适用的业务规则:

全局规则:
1. 所有金额字段统一使用 money 类型,注意精度问题
2. 时间范围查询优先使用 DateKey 关联 DimDate 表
3. 产品相关查询需要考虑产品层次结构: Product → Subcategory → Category
4. 客户相关查询注意 GeographyKey 关联地理位置信息
5. 销售数据有两个来源: FactInternetSales (互联网销售) 和 FactResellerSales (经销商销售)
6. 日期字段有三种: OrderDate (下单日期), DueDate (到期日期), ShipDate (发货日期)
7. 金额计算注意货币类型: CurrencyKey 关联 DimCurrency
8. 促销活动: PromotionKey 关联 DimPromotion

三、业务上下文配置:让模型"懂业务"

3.1 术语配置:业务语言 → 技术语言

业务人员说的"大客户",数据库里可能是 YearlyIncome > 100000。术语配置是关键桥梁:

{
  "terminology": [
    {
      "business_term": "大客户",
      "technical_mapping": "YearlyIncome > 100000",
      "description": "年收入超过10万美元的客户"
    },
    {
      "business_term": "互联网销售",
      "technical_mapping": "FROM FactInternetSales",
      "description": "通过网站直接销售给客户的订单"
    },
    {
      "business_term": "经销商销售",
      "technical_mapping": "FROM FactResellerSales",
      "description": "通过经销商渠道的销售"
    },
    {
      "business_term": "北美地区",
      "technical_mapping": "SalesTerritoryGroup = 'North America'",
      "description": "北美销售区域(美国、加拿大)"
    },
    {
      "business_term": "欧洲地区",
      "technical_mapping": "SalesTerritoryGroup = 'Europe'",
      "description": "欧洲销售区域"
    },
    {
      "business_term": "太平洋地区",
      "technical_mapping": "SalesTerritoryGroup = 'Pacific'",
      "description": "太平洋销售区域(澳大利亚等)"
    },
    {
      "business_term": "自行车类产品",
      "technical_mapping": "EnglishProductCategoryName = 'Bikes'",
      "description": "自行车类别产品"
    },
    {
      "business_term": "配件类产品",
      "technical_mapping": "EnglishProductCategoryName = 'Accessories'",
      "description": "配件类别产品"
    },
    {
      "business_term": "服装类产品",
      "technical_mapping": "EnglishProductCategoryName = 'Clothing'",
      "description": "服装类别产品"
    },
    {
      "business_term": "促销订单",
      "technical_mapping": "PromotionKey <> 1",
      "description": "参与了促销活动的订单(PromotionKey=1 表示无促销)"
    }
  ]
}

3.2 字段描述增强

清晰的字段描述比字段名更重要:

示例:FactInternetSales 表字段描述

-- ❌ 不好的做法(仅有字段名)
CREATE TABLE FactInternetSales(
    ProductKey int,
    OrderDateKey int,
    CustomerKey int,
    SalesAmount money,
    ...
);


四、模型微调方法:从通用到专用

4.1 为什么需要微调?

通用大模型虽然能力强大,但在特定领域的 Text2SQL 任务上,仍可能存在:

  • 不理解特定业务术语(如"太平洋地区"对应哪个 SalesTerritoryGroup)
  • 生成的 SQL 不符合数据仓库规范(如忘记关联 DimDate)
  • 复杂查询准确率不足(如多表关联、层次结构查询)

微调可以让模型更好地适应特定场景。

4.2 DB-GPT-Hub 微调实战

DB-GPT-Hub 是一个专注于 Text-to-SQL 微调的开源项目,在 Spider 数据集上达到了 78.9% 的执行准确率(超过 GPT-4 的 76.2%)。

微调流程(以 AdventureWorksDW2016 为例):

1. 数据准备
   - 收集 (问题, SQL) 对,例如:
     Q: "查询2014年每个产品类别的销售额"
     A: "SELECT dc.EnglishProductCategoryName, SUM(fis.SalesAmount)..."
   
   - 数据清洗和增强
     * 添加同义问题("查询各产品类别的销售总额")
     * 变换时间条件(2014 → 2013, 2015)
     * 变换聚合维度(按类别 → 按地区、按客户)
   
   - 划分训练集/验证集(80%/20%)

2. 模型选择
   - 推荐: CodeLlama-13B 或 Qwen2.5-Coder-32B
   - 量化: 4bit + LoRA 降低显存需求(可在单张 A100 上训练)

3. 训练配置
   - 学习率: 2e-4
   - Batch Size: 16
   - Epochs: 3-5
   - 最大序列长度: 2048(AdventureWorks 表名较长)

4. 评估优化
   - 使用执行准确率评估(在真实数据库上执行)
   - 对比语法准确率 vs 执行准确率
   - 分析错误类型:表关联错误、字段错误、聚合错误等

AdventureWorksDW2016 微调数据示例:

[
  {
    "question": "查询销售额最高的前10个产品",
    "sql": "SELECT TOP 10 dp.EnglishProductName, SUM(fis.SalesAmount) AS TotalSales FROM FactInternetSales fis INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey GROUP BY dp.EnglishProductName ORDER BY TotalSales DESC"
  },
  {
    "question": "查询每个国家的客户数量",
    "sql": "SELECT dg.EnglishCountryRegionName, COUNT(DISTINCT dc.CustomerKey) AS CustomerCount FROM DimCustomer dc INNER JOIN DimGeography dg ON dc.GeographyKey = dg.GeographyKey GROUP BY dg.EnglishCountryRegionName ORDER BY CustomerCount DESC"
  },
  {
    "question": "查询2014年每月的销售趋势",
    "sql": "SELECT dd.EnglishMonthName, dd.MonthNumberOfYear, SUM(fis.SalesAmount) AS MonthlySales FROM FactInternetSales fis INNER JOIN DimDate dd ON fis.OrderDateKey = dd.DateKey WHERE dd.CalendarYear = 2014 GROUP BY dd.EnglishMonthName, dd.MonthNumberOfYear ORDER BY dd.MonthNumberOfYear"
  }
]

微调的方法门槛高,成本高,周期长,中小短期项目不是很推荐。


五、推理时增强策略:多选最优

5.1 自洽性(Self-Consistency)

生成多个候选 SQL,通过投票选择最优解:

示例:查询每个产品类别的平均销售额

问题: 查询每个产品类别的平均订单金额

候选SQL:
1. 
SELECT dc.EnglishProductCategoryName, AVG(fis.SalesAmount) AS AvgAmount
FROM FactInternetSales fis
    INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    INNER JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    INNER JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
GROUP BY dc.EnglishProductCategoryName;

2.
SELECT dc.EnglishProductCategoryName, AVG(fis.ExtendedAmount) AS AvgAmount
FROM FactInternetSales fis
    INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    INNER JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    INNER JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
GROUP BY dc.EnglishProductCategoryName;

3.
SELECT dc.EnglishProductCategoryName, SUM(fis.SalesAmount)/COUNT(*) AS AvgAmount
FROM FactInternetSales fis
    INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    INNER JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    INNER JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
GROUP BY dc.EnglishProductCategoryName;

分析:
- SQL 1 使用 SalesAmount(实际销售金额,包含折扣)
- SQL 2 使用 ExtendedAmount(扩展金额,未含折扣)
- SQL 3 手动计算平均值

投票结果:
SQL 1 和 SQL 3 语义等价 → 选择最常见的逻辑
最终选择: SQL 1(语义最清晰)

硬投票 vs. 软投票:

  • 硬投票:选择出现次数最多的 SQL
  • 软投票:根据执行结果相似度加权投票(更优)

5.2 MCS-SQL:多提示架构

MCS-SQL 方法在 BIRD 数据集上达到 65.5% 准确率,Spider 上达到 89.6%:

核心流程:

  1. 多提示生成:使用不同风格的提示词生成多个候选 SQL
  2. Schema 精炼:从完整 Schema 中筛选相关表和字段
  3. 置信度评分:评估每个候选 SQL 的可靠性
  4. 多选机制:综合选择最优解

AdventureWorksDW2016 应用示例:

问题: "查询2014年北美地区自行车类产品的销售额"

提示1(结构化):
表: FactInternetSales, DimProduct, DimProductCategory, DimSalesTerritory, DimDate
条件: CalendarYear=2014, SalesTerritoryGroup='North America', EnglishProductCategoryName='Bikes'
目标: SUM(SalesAmount)

提示2(自然语言):
从销售事实表中查询2014年的销售数据,筛选北美地区和自行车产品,计算总销售额

提示3(SQL模板):
SELECT SUM(fis.SalesAmount)
FROM FactInternetSales fis
    JOIN DimDate dd ON fis.OrderDateKey = dd.DateKey
    JOIN DimSalesTerritory dst ON fis.SalesTerritoryKey = dst.SalesTerritoryKey
    JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
WHERE dd.CalendarYear = ?
    AND dst.SalesTerritoryGroup = ?
    AND dc.EnglishProductCategoryName = ?

多提示生成的候选SQL经过置信度评分和投票,选择最优解。

六、RAG 增强:注入领域知识

6.1 为什么需要 RAG?

大模型的知识来自训练数据,对于:

  • 企业内部业务规则(如"促销订单的 PromotionKey <> 1")
  • 实时数据变化(如新增产品类别)
  • 非公开的领域知识(如 AdventureWorks 的业务逻辑)

模型无法直接获取。RAG(检索增强生成)通过外挂知识库解决这一问题。

6.2 RAG 在 Text2SQL 中的应用

AdventureWorksDW2016 知识库示例:

用户问题: "查询参与了促销活动的订单数量"
  ↓
检索相关文档
  ↓ (找到: "促销订单的 PromotionKey <> 1,PromotionKey=1 表示无促销")
注入到 Prompt
  ↓
模型生成 SQL:
SELECT COUNT(DISTINCT SalesOrderNumber) AS PromotionOrderCount
FROM FactInternetSales
WHERE PromotionKey <> 1;

典型流程:

  1. 知识库构建:整理业务规则、术语定义、常见查询模式

    知识条目示例:
    - "互联网销售存储在 FactInternetSales 表"
    - "经销商销售存储在 FactResellerSales 表"
    - "产品层次: Product → Subcategory → Category"
    - "日期维度包含日历年度和财年两种时间维度"
    - "销售区域分为三大组: North America, Europe, Pacific"
    
  2. 向量化存储:使用 Embedding 模型向量化

  3. 相似度检索:根据用户问题检索相关文档

  4. Prompt 增强:将检索结果注入提示词


七、完整实践案例:SQLBot 五大配置项

SQLBot是我目前见过国内比较优秀的一个Text2SQL的开源项目。这里以 SQLBot 开源项目为例,简单汇总了下企业级 Text2SQL 系统需要五大配置项:

7.1 配置项详解(AdventureWorksDW2016 实战)

配置项作用AdventureWorks 示例
表管理 字段描述、示例值 SalesAmount: 实际销售金额(含税、含运费)
表关联关系 多表 JOIN 逻辑 FactInternetSales.CustomerKey → DimCustomer.CustomerKey
术语配置 业务→技术映射 "自行车产品" = EnglishProductCategoryName = 'Bikes'
示例 SQL 复杂查询模板 提供 10-50 个高频查询示例(见下文)
自定义提示词 全局规则 "日期查询优先使用 DateKey 关联 DimDate"

7.2 AdventureWorksDW2016 示例 SQL 库

-- 示例1: 按产品类别统计销售额
SELECT 
    dc.EnglishProductCategoryName,
    COUNT(DISTINCT fis.SalesOrderNumber) AS OrderCount,
    SUM(fis.SalesAmount) AS TotalSales,
    AVG(fis.SalesAmount) AS AvgOrderAmount
FROM FactInternetSales fis
    INNER JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey
    INNER JOIN DimProductSubcategory dps ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
    INNER JOIN DimProductCategory dc ON dps.ProductCategoryKey = dc.ProductCategoryKey
GROUP BY dc.EnglishProductCategoryName
ORDER BY TotalSales DESC;

配置优先级:

  1. 基础能力:表管理 + 表关联关系(必须配置)
  2. 沟通桥梁:术语配置(高频使用)
  3. 标准答案:示例 SQL(针对性强)
  4. 全局规则:自定义提示词(补充约束)

八、实战建议:如何选择优化路径?

8.1 按场景选择

场景推荐方法准确率预期AdventureWorks 示例
简单单表查询 Few-Shot 示例 85%+ SELECT * FROM DimCustomer WHERE YearlyIncome > 100000
多表关联查询 Schema 增强 + 表关联配置 80%+ 产品销售分析(需关联 3-5 张表)
复杂业务查询 术语配置 + 示例 SQL + RAG 75%+ 客户 RFM 分析、促销效果分析
特定领域 模型微调 85%+ 针对 AdventureWorks 微调
高准确率要求 微调 + 推理时增强 90%+ 企业级报表系统

8.2 成本效益分析

方法开发成本标注成本硬件需求效果提升
提示工程 10-20%
Schema 增强 5-10%
RAG 5-15%
模型微调 15-25%
推理增强 5-10%

总结:准确率提升路线图

第一阶段(快速见效)
  ├─ 优化 Schema 呈现(J-Schema)
  ├─ 添加字段描述和示例值
  └─ 配置 10-20 个 Few-Shot 示例(基于 AdventureWorks)

第二阶段(深度优化)
  ├─ 术语配置(业务语言映射)
  │   - "大客户" → YearlyIncome > 100000
  │   - "北美地区" → SalesTerritoryGroup = 'North America'
  ├─ 表关联关系管理
  │   - FactInternetSales 的所有外键关系
  │   - 产品层次结构(Product → Subcategory → Category)
  └─ 自定义提示词规则
      - 日期查询使用 DateKey 关联 DimDate
      - 产品查询考虑层次结构

第三阶段(持续改进)
  ├─ 构建 RAG 知识库
  │   - AdventureWorks 业务规则
  │   - 常见查询模式
  ├─ 收集反馈数据
  │   - 记录用户修正的 SQL
  │   - 分析错误模式
  └─ 模型微调(可选)
      - 使用 AdventureWorks 数据生成训练集
      - 针对特定查询类型优化

第四阶段(企业级)
  ├─ 推理时增强(多候选投票)
  ├─ 权限控制
  │   - 按销售区域限制数据访问
  │   - 敏感字段脱敏
  └─ 监控与优化
      - 查询性能监控
      - 准确率持续跟踪

参考资料

  1. SQLBot 最佳实践指南
  2. MCS-SQL: 多提示多选架构
  3. Text2SQL 准确率暴涨 22.6%
  4. DB-GPT-Hub 微调教程
  5. Alpha-SQL: 零样本 Text2SQL
  6. AdventureWorks 示例数据库官方文档