Text2SQL-自助式数据报表开发
# 结构化和非结构化数据
非结构化数据类型
常见类型: 包括PDF、Word文档、图片(以图片形式存在的表格)等
特点: 格式不固定,难以直接进行结构化查询和分析结构化和非结构化数据的区别
核心差异: 数据格式是否固定
结构化示例: Excel表格具有固定的行列结构
价值对比: 结构化数据更便于查询和分析,价值密度更高结构化与非结构化数据库的争论与价值变化
技术阵营:
SQL代表结构化数据阵营
NoSQL代表非结构化数据阵营
发展趋势: 大模型出现前SQL数据库(如Oracle)价值更高;大模型出现后非结构化数据价值提升结构化数据的应用与优势
运算能力: 天生格式清晰,便于进行各种运算
典型应用: 生成数据看板和决策报表
工作场景: 业务人员日常需要频繁提取结构化数据大模型在结构化数据处理中的应用
传统方式: 由技术人员编写SQL语句
痛点: 业务人员提数需求频繁,打断技术人员核心工作
解决方案: 通过大模型自动生成SQL语句大模型写SQL语句的背景与需求
历史尝试: 曾培训业务人员学习SQL但效果有限
变革契机: 大模型出现后业务人员可直接用自然语言获取数据
价值: 解放技术人员,使其专注于更高价值的数据分析工作Function calling功能与思考助手搭建
关键技术: 使用function calling功能连接大模型和数据库
实现方式: 基于此功能搭建SQL查询助手
优势: 实现自助式数据提取,减少工作打断大模型开发自入型数据报表的模式
模式一: 使用LangChain封装的SQL Agent工具
模式二: 自定义提示词工程,让大模型理解表结构和需求
最佳实践: 探索不同提示词写法对结果的影响
# Text to SQL技术
Text-to-SQL (文本转SQL)
将自然语言问题自动转换为结构化的SQL查询语句,可以让用户更直观的与数据库进行交互。
Text-to-SQL的技术演变经历了3个阶段:
早期阶段:依赖于人工编写的规则模板来匹配自然语言和SQL语句之间的对应关系。机器学习阶段:采用序列到序列模型等机器学习方法来学习自然语言和SQL之间的映射关系。LLM阶段:借助LLM强大的语言理解和代码生成能力,利用提示工程、微调等方法将Text-to-SQL性能提升到新的高度。
我们目前已处于LLM阶段,基于LLM的Text-to-SQL系统会包含以下几个步骤:
自然语言理解:分析用户输入的自然语言问题,理解其意图和语义。模式链接:将问题中的实体与数据库模式中的表和列进行链接。SQL生成:根据理解的语义和模式链接结果,生成相应的SQL查询语句。SQL执行:在数据库上执行SQL查询,将结果返回给用户。
# LLM模型选择(闭源模型)
- GPT-o1/o3: o1模型开启了新的Scaling Law,更专注于推理阶段,在编程和Text to SQL中能力优于gpt-4o,同时mini模型速度更快,价格更低。
- Claude 3.7-sonnet: Anthropic公司于2025年2月发布,号称迄今为止最智能的模型,首款混合推理模型 Claude 3.7-sonnet实现了两种思考方式的结合,既能提供接近即时的响应,也能展示分步骤的详细思考过程
- Claude 3.5-sonnet:2024年推出的模型,支持20万tokens上下文,性能超过GPT-4o,在Cursor中使用非常顺滑。
- Gemini 2.0:性能强悍,支持100万token上下文。
- Qwen-Turbo:支持100万token上下文,速度快,价格非常便宜。
# LLM模型选择(开源模型)
- DeepSeek-V3:在代码生成任务中表现出色,能够快速生成高质量的代码片段。它通过从DeepSeek-R1中蒸馏推理能力,显著提升了代码生成的准确性和效率
- DeepSeek-R1: R1在代码生成和复杂逻辑推理方面表现卓越,特别是在处理复杂的编程任务和数学问题时,准确率更高。例如,在CodeforcesElo评分中,R1达到2029分,超越96.3%的人类参赛者
- Qwen:Qwen系列从0.5B,1.5B,3B,7B,14B,32B,72B等多种尺寸,性能优于Llama3.1。
# LLM模型选择(代码大模型)
- Qwen-Coder:能力强,接近闭源一线大模型,其中Qwen2.5-Coder-32B能力与GPT-4o持平
- CodeGeeX:智谱开源的代码大模型,基于GLM底座,性能卓越,在vscode等编辑器中可以找到对应的插件。
- SQLCoder:专为SQL生成而设计的开源模型,但是维护更新慢。
- DeepSeek-Coder:在多种编程语言中与开源代码模型中实现了先进的性能,但模型更新不及时
部署现状:
企业多部署通用大模型(如Qwen3-8B/32B)
个人使用推荐闭源SaaS模型(如豆包、Qwen系列)
代码大模型实际应用较少,主流仍是通用模型
# 国外模型:
- Claude系列:最新4.1版本代码生成能力最强,适合编程场景
- GPT系列:GPT-5理解能力存在争议,图表处理仍有缺陷
- Gemini:即将推出3.0版本,代码质量整体不错但有小瑕疵
# 国内模型:
- Qwen系列:当前主流,含8B/32B等版本及MOE中量级模型
- DeepSeek:年初流行但换血频繁,现多转向Qwen
- Code专用:Qwen-Coder性能接近Claude4.0,DeepSeek-Coder使用较少
部署方式:
闭源模型:通过API按token计费(如阿里云百炼)
开源模型:可本地部署(如ModelScope下载Qwen/DeepSeek系列)
企业首选开源模型以保证数据安全
# SQL Copilot
# 方法一: SQLDatabase
采用LangChain框架
提供了sqlchain,prompt,retriever,tools, agent,让用户通过自然语言,执行SQL查询
优点:使用方便,自动通过数据库连接,获取数据库的metadata
不足:执行不灵活,需要多次判断哪个表适合复杂查询很难胜任,对于复杂查询通过率低
总结
SQL + LLM使用:
- 通过SQLDatabase可以访问到数据库的Schema
- agent_executor作为SQL Agent,可以执行用户的各种SQL需求(通过自然语言=>编写SQL =>查询结果返回)
- 如果数据库中没有找到对应的表,会报OutputParseException错误
- 如果有多张表,会分别执行,然后判断哪个数据表可以得到结果
#!/usr/bin/env python
# coding: utf-8
# ## 使用DeepSeek进行数据表的查询
# In[1]:
from langchain.agents import create_sql_agent
from langchain_community.utilities import SQLDatabase
from langchain_community.agent_toolkits import SQLDatabaseToolkit
from langchain_community.llms import OpenAI
from langchain.agents import AgentExecutor
db_user = "root"
db_password = "123456"
#db_host = "localhost:3306"
db_host = "localhost:3306"
db_name = "action"
db = SQLDatabase.from_uri(f"mysql+pymysql://{db_user}:{db_password}@{db_host}/{db_name}")
# In[3]:
from langchain.chat_models import ChatOpenAI
import os
# 从环境变量获取 dashscope 的 API Key
api_key = "your api key"
# 通过LLM => 撰写SQL
llm = ChatOpenAI(
temperature=0.01,
model="deepseek-v3",
openai_api_base = "https://dashscope.aliyuncs.com/compatible-mode/v1",
openai_api_key = api_key
)
# 需要设置llm
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
# SQL智能体:给它目标,它自己会进行规划,最终把结果给你
agent_executor = create_sql_agent(
llm=llm,
toolkit=toolkit,
verbose=True
)
# Task: 描述数据表
agent_executor.run("描述与订单相关的表及其关系")
# 这个任务,实际上数据库中 没有HeroDetails表
agent_executor.run("描述HeroDetails表")
agent_executor.run("描述Hero表")
agent_executor.run("找出英雄攻击力最高的前5个英雄")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
直接使用SQL + LLM会有什么问题?
- 多个相似的数据表=>导致LangChain会尝试多次生成SQL
- 用户Prompt太宽泛=>生成的结果,不是用户想要的
# LangChain的局限性
性能瓶颈:
- 处理速度:需要遍历所有数据,耗时较长
- 扩展性问题:当数据量达10万级时效率显著下降
应用场景限制:
- 金融行业案例:银行/证券公司通常有数万至数十万张数据表
- 成本考量:大规模数据处理时时间成本和计算成本过高
# 方法2:自己编写
本质是:LLM + RAG
选择适合的LLM,比如:ChatModel: DeepSeek-V3,CodeModel: Qwen2.5-Coder, CodeGeeX2-6B
RAG,可以分成:向量数据库检索+固定文件(比如本地数据表说明等)
优点:重心在于RAG的提供上,准确性高,配置灵活
不足:需要设置的条件规则多
# SQL +向量数据库+ LLM
SQL +向量数据库+ LLM:
- 向量数据库可以提供领域知识,当用户检索某个问题的时候=>从向量数据库中找到相关的内容,放到prompt中=>提升SQL查询的相关性
RAG技术:
- 在prompt中增加few-shot examples
- 专门定制检索工具,从向量数据库中 检索到与用户query相近的知识
除了对用户query,补充领域知识外,针对专门名词(用户可以拼写错误的),也可以进行纠正
# Prompt works!
- 以下哪种prompt可以写出更好的SQL?
写法1:
prompt = f"""# language: SQL
/*
{query}你需要先判断需要哪个数据表和字段,
然后基于它们编写SQL。数据库中有以下数
据表:
=====
{table_description}
*/
# {query}"""
2
3
4
5
6
7
8
9
写法2:
prompt = f"""
--language: SQL
/*{query}
以下是数据表
=====
{table_description}
=====
编写一条SQL: {query}
*/"""
2
3
4
5
6
7
8
9
写法3:
prompt = f"""--language: SQL
### Question: {query}
### Input: {create_sql}
### Response:
Here is the SQL query I have generated to
answer the question `{query}`:
```sql
"""
2
3
4
5
6
7
8
table_description是数据表的中文描述,create_sql是数据表的建表语句,query是用户查询的问题
答案是第三个!
选择依据:
- 因其提供最完整的元数据信息
- 建表语句包含字段数据类型,避免类型错误
- 可补充字段注释和示例值提高准确性
实现要点:
- 使用标准SQL注释语法(--)
- 字段应包含数据类型定义
- 建议添加取值示例(如Gender字段可注明取值是"男/女"或"Male/Female")
# 大模型的补全能力与SQL生成
补全模型原理:
工作机制:
- 本质是代码补全而非聊天对话
- 基于大量预训练代码数据(如GitHub数十亿代码)
- 使用```SQL触发自动补全模式
优势体现:
- 更符合代码生成场景需求
- 减少不必要的解释性输出
- 直接生成可执行SQL语句
提示词模板设计
- 核心要素:
- 前置完整DDL语句
- 明确的问题描述
- 使用--标准SQL注释
- 结尾添加```SQL触发补全