系列目录(共 15 篇):
- 开篇:为什么这个时代我们需要 Text2SQL
- 技术原理深度剖析(本文)
- 企业语义治理:ChatBI 落地的核心难题
4-15(略)关键词:Text2SQL 技术原理、NL2SQL 链路、Schema Linking、SQL 生成、SQL 校验、意图识别、实体抽取、向量检索
目录
- 一、写在前面:为什么要懂技术原理
- 二、Text2SQL 的完整技术链路
- 三、第 1 步:意图识别
- 四、第 2 步:实体抽取与归一化
- 五、第 3 步:Schema Linking(最关键的一步)
- 六、第 4 步:SQL 生成
- 七、第 5 步:SQL 校验与修正
- 八、第 6 步:执行与返回
- 九、关键技术挑战与解决方案
- 十、技术方案对比:Prompt Engineering vs Fine-tuning vs Agent
- 十一、一个完整的真实案例
- 十二、未来趋势:从单步到 Agent
- 十三、总结
一、写在前面:为什么要懂技术原理
你可能会问:作为 Text2SQL 的使用者,我为什么要懂技术原理?
答案是:只有理解技术原理,你才能:
- ✅ 准确判断一个 Text2SQL 项目的技术深度
- ✅ 在选型时不被营销话术忽悠
- ✅ 在落地时知道哪些坑可以避开
- ✅ 在出问题时知道排查方向
这篇博客,我会从最底层的技术原理讲起,把 Text2SQL 的完整链路拆解给你看。
二、Text2SQL 的完整技术链路
Text2SQL 的完整链路可以分为6 大步骤:
┌─────────────────────────────────────────────────────────┐ │ │ │ 用户问题:"上个月华东地区新客的复购率是多少?" │ │ │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 第 1 步:意图识别 │ │ 判断用户想做什么:查询?对比?归因?预测? │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 第 2 步:实体抽取与归一化 │ │ 提取时间、维度、指标:上个月、华东、新客、复购率 │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 第 3 步:Schema Linking │ │ 把业务术语映射到数据库表和字段 │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 第 4 步:SQL 生成 │ │ 大模型根据 Schema 和问题生成 SQL │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 第 5 步:SQL 校验与修正 │ │ 语法、Schema、权限、时间四层校验 │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 第 6 步:执行与返回 │ │ 执行 SQL,返回数据 + 可视化 + 洞察 │ └───────────────────────┬─────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 最终结果:复购率 18.5%,样本用户数 12,485 │ │ │ └─────────────────────────────────────────────────────────┘[截图位置 1:6 大步骤的完整流程图,建议用流程图清晰展示]
三、第 1 步:意图识别
3.1 什么是意图识别?
意图识别是判断用户想要做什么的第一步。
3.2 常见的用户意图类型
| 意图类型 | 示例问题 | 系统响应 |
|---|---|---|
| 查询 | “上个月 GMV 多少?” | 返回具体数字 |
| 对比 | “Q1 vs Q2 的 GMV 对比” | 返回对比图表 |
| 归因 | “为什么 Q2 GMV 下降了?” | 分析原因 |
| 预测 | “下个月 GMV 预计多少?” | 给出预测 |
| 排名 | “GMV Top 10 的商品” | 返回排名表 |
| 明细 | “列出所有退款订单” | 返回明细数据 |
| 趋势 | “GMV 过去 6 个月趋势” | 返回趋势图 |
3.3 意图识别的实现方式
方式 1:分类器(传统 ML)
# 用 BERT 等模型做意图分类fromtransformersimportBertForSequenceClassification model=BertForSequenceClassification.from_pretrained('bert-base-chinese')intent=model.predict(user_query)# 输出:query/comparison/...方式 2:大模型(推荐)
prompt=""" 判断用户问题的意图类型,从以下类别中选择: - query(简单查询) - comparison(对比分析) - attribution(归因分析) - prediction(预测) - ranking(排名) - detail(明细查询) - trend(趋势分析) 用户问题:{user_query} 意图类型: """3.4 真实案例
用户问:「为什么 Q2 GMV 下降了?」
- ❌ 错误理解:执行 SQL 查询 Q2 GMV
- ✅ 正确理解:识别为归因意图,调用归因分析 Agent
意图识别看似简单,但它决定了后续所有步骤的方向,错了就全错。
四、第 2 步:实体抽取与归一化
4.1 什么是实体抽取?
从用户问题中提取出结构化的查询条件。
4.2 实体类型
| 实体类型 | 示例 |
|---|---|
| 时间 | “上个月”、“最近 7 天”、“Q1 2026” |
| 地理 | “华东”、“北京”、“一线城市” |
| 人群 | “新用户”、“VIP 用户”、“女性用户” |
| 指标 | “GMV”、“复购率”、“转化率” |
| 维度 | “按渠道”、“按品类”、“按设备” |
| 数值条件 | “大于 1000”、“Top 10” |
| 排序方式 | “升序”、“降序”、“最高” |
4.3 实体抽取的真实挑战
挑战 1:歧义性
用户问:「最近一周的销售情况」
- "最近一周"是自然周(周一到周日)还是最近 7 天?
- "销售情况"是指 GMV、订单数还是用户数?
挑战 2:省略
用户问:「华东的复购率」
- 时间范围省略了(默认?近 30 天?)
- 用户分群省略了(默认全部用户?新用户?)
挑战 3:业务术语
用户问:「一路生花的播放量」
- "一路生花"是歌曲名还是维度值?
- 字段名是
song_name还是track_title?
4.4 实体归一化
提取出的实体要归一化为标准形式:
| 原始表述 | 归一化后 |
|---|---|
| “上个月” | time_range: 'last_month' |
| “最近 7 天” | time_range: 'last_7_days' |
| “华东” | region: 'east_china' |
| “新用户” | user_type: 'new' |
| “复购率” | metric: 'repurchase_rate' |
4.5 实现方式
prompt=""" 从用户问题中提取关键实体,返回 JSON 格式: { "time_range": "...", "region": "...", "user_type": "...", "metrics": ["..."], "dimensions": ["..."] } 用户问题:{user_query} """五、第 3 步:Schema Linking(最关键的一步)
5.1 什么是 Schema Linking?
Schema Linking 是把业务术语映射到数据库表和字段的过程。
5.2 为什么这是最关键的一步?
某研究统计了 Text2SQL 错误的原因:
Schema linking 错误:37% Join 错误:21% Group by 错误:23% 其他错误:19%Schema linking 占了 37% 的错误!它是 Text2SQL 最大的瓶颈。
5.3 Schema Linking 的挑战
挑战 1:表和字段数量巨大
一家中大型企业的数仓: - 表数量:500-2000 张 - 字段总数:5000-20000 个直接把这么多表和字段塞给大模型,会超出 token 限制,也会让模型抓不住重点。
挑战 2:命名不一致
业务说:“订单金额”
数据库里可能的字段:
order_amount(订单表)paid_amount(支付表)revenue(收入表)gmv(GMV 指标表)
AI 不知道哪个对。
挑战 3:跨表关联复杂
电商业务的核心数据模型: - 用户表(dim_user) - 订单表(dwd_order) - 商品表(dim_product) - 支付表(dwd_payment) - 物流表(dwd_logistics) - 售后表(dwd_refund) "上个月华东新客的复购率"涉及: - 时间维度(订单表 + 支付表) - 地理维度(用户表) - 用户类型(用户表) - 复购计算(订单表 + 支付表 + 售后表)5.4 Schema Linking 的解决方案
方案 1:全量 Schema + 大模型
# 把所有表结构给大模型prompt=f""" 数据库 Schema:{all_tables_schema}用户问题:{user_query}请找出需要的表和字段。 """问题:表太多,超过 token 限制。
方案 2:向量检索(主流方案)
1. 把每个表、每个字段的描述向量化 2. 把用户问题向量化 3. 用向量相似度检索最相关的 Top-K 个表/字段 4. 把 Top-K 个表/字段给大模型方案 3:关键词匹配 + 编辑距离
1. 用关键词匹配("GMV" → "gmv" 字段) 2. 用编辑距离("GVM" → "GMV" 字段) 3. 结合业务词典(同义词映射)方案 4:知识图谱(高级)
1. 构建业务术语 → 数据库字段的知识图谱 2. 通过图查询找到相关字段 3. 包含字段之间的关联关系5.5 真实案例
用户问:“上个月华东新客的复购率”
Schema Linking 步骤:
1. 向量化用户问题 embedding = vectorize("上个月华东新客的复购率") 2. 检索相关表 Top-5 相关表: - dwd_order(相似度 0.92) - dim_user(相似度 0.88) - dwd_payment(相似度 0.85) - dwd_refund(相似度 0.78) - dim_region(相似度 0.75) 3. 检索相关字段 从 Top-5 表中检索相关字段: - dwd_order.user_id, order_id, created_at, amount - dim_user.user_id, region, register_time, user_type - dwd_payment.order_id, paid_at, paid_amount - dwd_refund.order_id, refund_at, refund_amount 4. 组装 Schema 上下文 把相关表和字段组织成结构化文本[截图位置 2:Schema Linking 的流程示意图,建议展示从问题到表/字段的映射过程]
六、第 4 步:SQL 生成
6.1 SQL 生成的本质
有了 Schema 上下文,大模型就可以生成 SQL 了。
6.2 SQL 生成的 Prompt 设计
prompt=f""" 你是 SQL 专家。根据以下信息生成 SQL: 数据库类型:MySQL 数据库 Schema(已筛选相关表):{relevant_schema}用户问题:{user_query}提取的实体: - 时间范围:{time_range}- 维度:{dimensions}- 指标:{metrics}要求: 1. 只生成 SQL,不要解释 2. 使用标准 SQL 语法 3. 考虑性能优化 4. 添加必要的注释 SQL: """6.3 关键技术点
关键技术点 1:Few-shot Learning
提供几个示例让大模型学习:
示例 1: 问题:上个月 GMV SQL:SELECT SUM(order_amount) FROM dwd_order WHERE dt BETWEEN ... AND ... 示例 2: 问题:各渠道转化率 SQL:SELECT channel, SUM(paid_orders) / SUM(click_uv) AS cvr FROM ...关键技术点 2:Chain-of-Thought(思维链)
prompt=""" 让我们一步步思考: 1. 需要哪些表?dwd_order, dim_user 2. 需要哪些字段?user_id, region, order_id, created_at 3. 关联关系?dwd_order.user_id = dim_user.user_id 4. 过滤条件?region='华东' AND user_type='new' AND created_at 上个月 5. 聚合逻辑?每个用户订单数 ≥ 2 算复购,复购用户数 / 总用户数 6. 最终 SQL:SELECT ... """关键技术点 3:Self-Correction(自校正)
让大模型先生成 SQL,再让大模型自己检查:
# 第一轮:生成 SQLsql_1=llm.generate(prompt_1)# 第二轮:检查 SQLprompt_2=f""" 检查以下 SQL 是否正确: SQL:{sql_1}用户问题:{user_query}如果有错误,请修正。 """sql_2=llm.generate(prompt_2)6.4 SQL 生成的主要错误
| 错误类型 | 占比 | 示例 |
|---|---|---|
| Schema 错误 | 37% | 表名/字段名错误 |
| Join 错误 | 21% | Join 条件错误,笛卡尔积 |
| Group by 错误 | 23% | Group by 字段遗漏 |
| 语法错误 | 10% | SQL 语法不规范 |
| 时间错误 | 5% | 时间范围理解错误 |
| 其他 | 4% | 业务逻辑错误 |
七、第 5 步:SQL 校验与修正
7.1 为什么需要校验?
即使是最强的大模型,SQL 生成准确率也只能做到85-90%。剩下的 10-15% 必须靠校验机制来兜底。
7.2 四层校验机制
┌─────────────────────────────────────┐ │ 校验层 1:语法校验 │ │ - SQL 语法是否合法 │ │ - 数据库是否能解析 │ └─────────────────┬───────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 校验层 2:Schema 校验 │ │ - 表名、字段名是否在 Schema 中 │ │ - 数据类型是否匹配 │ └─────────────────┬───────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 校验层 3:权限校验 │ │ - 用户是否有权限访问这些表 │ │ - 是否访问了敏感字段 │ └─────────────────┬───────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 校验层 4:业务校验 │ │ - 时间范围是否合理 │ │ - 指标口径是否符合定义 │ │ - 是否违反业务规则 │ └─────────────────────────────────────┘7.3 校验的具体实现
语法校验:
# 用 sqlparse 库importsqlparse parsed=sqlparse.parse(sql)ifnotparsed:raiseSyntaxError("SQL 无法解析")# 或者在 EXPLAIN 前用数据库 EXPLAINcursor.execute(f"EXPLAIN{sql}")Schema 校验:
# 检查表名和字段名是否在允许的 Schema 中allowed_tables=get_allowed_tables(user)allowed_columns=get_allowed_columns(user,table)ifnottableinallowed_tables:raiseSchemaError(f"无权访问表{table}")forcolumnincolumns:ifnotcolumninallowed_columns[table]:raiseSchemaError(f"无权访问字段{column}")权限校验:
# 行级权限if"user_id = 'self'"notinsqlandnotis_admin(user):raisePermissionError("只能查询自己的数据")# 列级权限sensitive_columns=["id_card","phone","password"]forcolinsensitive_columns:ifcolincolumnsandnothas_permission(user,col):raisePermissionError(f"无权访问敏感字段{col}")业务校验:
# 时间范围校验if"BETWEEN '1900-01-01'"insql:raiseBusinessError("时间范围异常")# 指标口径校验ifmetric_defandnotsql_matches_definition(sql,metric_def):raiseBusinessError("SQL 不符合指标定义")7.4 修正机制
当校验失败时,系统需要自动修正:
defcorrect_sql(sql,error):ifisinstance(error,SyntaxError):# 用大模型修正语法错误returnllm.correct_syntax(sql,error.message)elifisinstance(error,SchemaError):# 修正表名/字段名returnsql_corrector.correct_schema(sql,error)elifisinstance(error,PermissionError):# 移除敏感字段returnsql_corrector.remove_sensitive(sql,sensitive_columns)elifisinstance(error,BusinessError):# 用规则或大模型修正业务错误returnsql_corrector.correct_business(sql,error)八、第 6 步:执行与返回
8.1 执行 SQL
# 通过数据库连接执行result=database.execute(sql)# 返回结构{"columns":["repurchase_rate","user_count"],"rows":[[0.185,12485]],"execution_time":1.2,# 秒"row_count":1}8.2 数据可视化
根据结果自动选择可视化方式:
| 数据特征 | 推荐可视化 |
|---|---|
| 单个数字 | 大字 + 同比环比 |
| 2 个数字对比 | 对比卡片 |
| 时间序列 | 折线图 |
| 分类对比 | 柱状图 |
| 占比 | 饼图 |
| 地理分布 | 地图 |
| 多维度 | 透视表 |
8.3 数据洞察
更进一步,系统可以给出数据洞察:
📊 数据结果 复购率:18.5% 对比上月:+2.3% 样本用户数:12,485 💡 数据洞察 - 复购率上升主要来自 25-30 岁年龄段 - 该群体贡献了 67% 的复购订单 - 相比之下,35+ 用户复购率反而下降 1.2% 🔍 指标口径 复购率 = 30 天内重复下单用户数 / 总下单用户数 数据更新时间:每日凌晨 3:00[截图位置 3:执行与返回的完整结果展示,建议截一张真实的效果图]
九、关键技术挑战与解决方案
9.1 挑战 1:复杂查询的 SQL 生成
问题:多表关联、嵌套子查询、窗口函数等复杂 SQL
解决方案:
- 分步生成:先生成简单查询,再嵌套
- 提供参考示例:让大模型学习历史正确 SQL
- Text-to-SQL 微调:在特定领域微调大模型
9.2 挑战 2:大模型幻觉
问题:大模型会"编造"不存在的表或字段
解决方案:
- 严格限制 Schema:只提供相关表和字段
- 强制 Schema 校验:发现幻觉立即修正
- 多次生成取最优:生成 N 个 SQL,选最好的
9.3 挑战 3:性能问题
问题:大模型推理慢,每次查询需要 2-10 秒
解决方案:
- 查询缓存:相同问题直接返回缓存
- 预计算:常见指标预计算好
- 小模型 + 大模型混合:简单查询用小模型
9.4 挑战 4:成本问题
问题:每次查询都要调大模型,成本高
解决方案:
- 问题分类:简单问题用小模型
- 缓存复用:相同/相似问题用缓存
- 本地部署:用开源模型本地推理
十、技术方案对比:Prompt Engineering vs Fine-tuning vs Agent
10.1 三种技术方案
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| Prompt Engineering | 通过 prompt 设计引导大模型 | 实施快、成本低 | 复杂场景效果差 |
| Fine-tuning | 在特定数据上微调大模型 | 效果好、可控性高 | 数据准备难、成本高 |
| Agent | 多个 Agent 协作完成 | 灵活、可扩展 | 复杂度高、调试难 |
10.2 选型建议
| 场景 | 推荐方案 |
|---|---|
| 简单查询、PoC 验证 | Prompt Engineering |
| 特定领域、高准确率要求 | Fine-tuning |
| 复杂任务、多步推理 | Agent |
10.3 主流项目采用的技术方案
| 项目 | 技术方案 |
|---|---|
| Vanna | Fine-tuning + RAG |
| SuperSonic | Agent + 语义层 |
| DB-GPT | Agent + AWEL 编排 |
| WrenAI | Prompt Engineering + GenBI |
| SQLBOT | Prompt Engineering + 语义层 |
十一、一个完整的真实案例
为了让你更直观地理解,我们走一遍真实案例。
11.1 用户问题
"上个月华东地区新客的复购率"11.2 第 1 步:意图识别
{"intent":"query","confidence":0.95,"description":"用户想查询复购率"}11.3 第 2 步:实体抽取
{"time_range":{"type":"relative","value":"last_month","standardize":"2025-06-01 to 2025-06-30"},"region":{"type":"enum","value":"east_china","standardize":"华东"},"user_type":{"type":"enum","value":"new","standardize":"新用户"},"metrics":[{"name":"repurchase_rate","definition":"30天内重复下单用户数 / 总下单用户数"}],"dimensions":[]}11.4 第 3 步:Schema Linking
{"tables":[{"name":"dwd_order","alias":"o","reason":"订单主表,包含订单信息"},{"name":"dim_user","alias":"u","reason":"用户维度表,包含地域和用户类型"}],"columns":[{"table":"dwd_order","column":"user_id","alias":"o.user_id"},{"table":"dwd_order","column":"order_id","alias":"o.order_id"},{"table":"dwd_order","column":"created_at","alias":"o.created_at"},{"table":"dim_user","column":"region","alias":"u.region"},{"table":"dim_user","column":"user_type","alias":"u.user_type"},{"table":"dim_user","column":"register_time","alias":"u.register_time"}],"joins":[{"type":"INNER JOIN","condition":"o.user_id = u.user_id"}]}11.5 第 4 步:SQL 生成
SELECTCOUNT(DISTINCTCASEWHENorder_cnt>=2THENuser_idEND)*1.0/COUNT(DISTINCTuser_id)ASrepurchase_rateFROM(SELECTo.user_id,COUNT(o.order_id)ASorder_cntFROMdwd_order oINNERJOINdim_user uONo.user_id=u.user_idWHEREo.created_atBETWEEN'2025-06-01'AND'2025-06-30'ANDu.region='east_china'ANDu.user_type='new'GROUPBYo.user_id)t;11.6 第 5 步:SQL 校验
✅ 语法校验:通过 ✅ Schema 校验:表和字段都在允许范围 ✅ 权限校验:用户有权限访问这些数据 ✅ 业务校验:时间范围合理,指标口径正确11.7 第 6 步:执行与返回
{"data":{"repurchase_rate":0.185,"user_count":12485},"execution_time":1.2,"visualization":"number_with_comparison","insights":["复购率 18.5%,环比上升 2.3%","主要增长来自 25-30 岁年龄段","该群体贡献了 67% 的复购订单"]}[截图位置 4:完整真实案例的执行结果截图,建议展示从问题到结果的完整流程]
十二、未来趋势:从单步到 Agent
12.1 当前主流:单步 Text2SQL
用户问题 → 单一流程 → SQL → 结果12.2 未来趋势:Agent 化
用户问题 → Planner Agent ↓ 拆解为多个子任务 ↓ ┌─────────┼─────────┐ ↓ ↓ ↓ Text2SQL Data Agent Knowledge Agent ↓ ↓ ↓ └─────────┼─────────┘ ↓ 综合 Agent 汇总 ↓ 返回用户Agent 化的优势:
- ✅ 支持复杂任务(多步推理、跨数据源)
- ✅ 自动调用工具(数据解读、报告生成)
- ✅ 可扩展性强
十三、总结
Text2SQL 的完整技术链路分为6 大步骤:意图识别 → 实体抽取 → Schema Linking → SQL 生成 → SQL 校验 → 执行返回。
每一步都有关键技术挑战,其中:
- Schema Linking 是最大的瓶颈(37% 错误)
- SQL 生成依赖大模型能力(85-90% 准确率)
- SQL 校验是质量兜底(4 层校验)
- 执行返回需要可解释(数据 + 洞察)
理解了这个链路,你再看任何 Text2SQL 项目,都能快速判断它的技术深度和能力边界。
下一篇预告:企业语义治理:ChatBI 落地的核心难题——我会从 4 大核心机制(Domain Scoping、Metric Registry、Entity Modeling、强制消歧)的角度,把 ChatBI 落地的核心难题讲透。
本系列博客基于 2026 年 6-7 月调研撰写,参考资料包括 Vanna、SuperSonic、DB-GPT 等开源项目 GitHub 仓库、BIRD 基准测试、Spider 基准测试等技术资料。
如果觉得有用,欢迎点赞、收藏、关注三连!你的支持是我更新这个系列的最好动力。