# FDE W5D5 评测题 · Text2SQL 最小 Demo

> 配套《FDE-W5D5-Text2SQL最小Demo-学习手册.html》。场景统一为「特药理赔 Agent」。
> 每个题目含：**考察点**（考什么）、**评分维度**（按 1~5 分档，总分 5 分）、**参考答案**（折叠，点击展开）。
> 评分维度通用说明：① 正确性（概念/结论对不对）② 完整性（关键要点是否齐全）③ 工程与风险意识（是否想到安全/兜底/成本）。

---

## L1 基础（概念识别，能说清"是什么"）

### Q1. 什么是 Text2SQL？它适合特药理赔 Agent 里的哪类问题？
- **考察点**：Text2SQL 的定义与适用边界。
- **评分维度**：
  - 正确性（2 分）：能定义"自然语言转 SQL"。
  - 完整性（2 分）：能区分适合/不适合的场景。
  - 工程意识（1 分）：提到"前提是安全"。
<details><summary>参考答案（点击展开）</summary>

Text2SQL（NL2SQL）是把自然语言问题转换成可在数据库执行的 SQL 的任务。

在特药理赔 Agent 里，它适合**结构化、可聚合**的问题，例如："3 月我报的奥希替尼花了多少""哪些保单的特药额度还没用完""上个月理赔金额 Top10 的药品"。

不适合：知识条款类（"特药目录怎么规定"→应走 RAG）、实时写操作（"帮我提交一笔理赔"→应走业务 API）。核心是：数据在结构化库、需要筛选/聚合/关联时优先 SQL。

</details>

### Q2. Text2SQL 端到端流程有哪些步骤？
- **考察点**：流程记忆与顺序。
- **评分维度**：
  - 正确性（2 分）：顺序基本正确。
  - 完整性（3 分）：8 步齐全（路由判断→Schema Linking→生成→安全校验→执行计划/超时→执行→结果解释→自然语言）。
<details><summary>参考答案（点击展开）</summary>

用户问题 → 数据路由判断（确认走 SQL）→ Schema Linking（话术映射表/字段）→ 生成只读 SQL（低 T + schema 上下文）→ SQL 安全校验（只读/白名单/参数化/行数/EXPLAIN）→ 执行计划 & 超时 → 执行（受限连接）→ 结果解释（SQL→自然语言）→ 自然语言回答。

关键：安全校验是独立于"生成"的一道关卡，不能合并。

</details>

### Q3. 什么是 Schema Linking？
- **考察点**：核心概念理解。
- **评分维度**：
  - 正确性（3 分）：能把"自然语言实体 → 表/字段/枚举"说清。
  - 完整性（2 分）：提到它是"准确率命门"，错则 SQL 形对义错。
<details><summary>参考答案（点击展开）</summary>

Schema Linking 是把用户话术里的实体/概念，对齐到数据库真实的表名、字段名、枚举值。例如"报销金额"→`claim.clm_amt`，"奥希替尼"→`drug.name='奥希替尼'`，"上个月"→`clm_date BETWEEN 上月首日 AND 上月末`。

它是 Text2SQL 的**准确率命门**：Linking 错，后面 SQL 再语法正确也是错答案（形对义错）。

</details>

### Q4. SQL 安全校验里的"只读"指什么？
- **考察点**：安全基础概念。
- **评分维度**：
  - 正确性（3 分）：只允许 SELECT（及 CTE 的 WITH...SELECT），禁止 DML/DDL。
  - 工程意识（2 分）：提到用 AST 解析而非正则，且数据库账号也应只读。
<details><summary>参考答案（点击展开）</summary>

"只读"指解析 SQL 的 AST，只允许 SELECT（含 WITH...SELECT 形式的只读查询），拒绝一切 INSERT/UPDATE/DELETE/DROP/ALTER 等写操作与 DDL。

工程上：① 用 SQL 解析器（JSqlParser/Apache Calcite）做 AST 校验，别只靠正则（可被注释/换行绕过）；② 数据库账号本身也要 GRANT SELECT only，应用层+数据库层纵深防御。

</details>

---

## L2 进阶（机制与做法，能说清"怎么做/为什么"）

### Q5. Schema Linking 不准会导致什么问题？怎么做才准？
- **考察点**：错误后果 + 工程做法。
- **评分维度**：
  - 正确性（2 分）：指出"形对义错"。
  - 完整性（2 分）：列出 3 个数据源（元数据/注释/召回裁剪）。
  - 工程意识（1 分）：提到枚举/时间归一化、先映射后生成。
<details><summary>参考答案（点击展开）</summary>

**后果**：Linking 错 → SQL 查错表/错字段/错值 → 形对义错，给用户错误理赔数据。

**怎么做准**：
1. 建数据字典 + 中文注释（建表 comment，让 `clm_amt=理赔金额`）。
2. 用问题召回 Top-K 相关表（向量/关键词），避免全库 schema 噪声。
3. 让模型先输出 (表,字段) 映射，再生成 SQL。
4. 枚举值归一化（"奥希替尼"→精确匹配 drug_name）。
5. 时间表达式归一化（"上个月"→具体日期区间）。
本质是检索增强：多数失败在 Linking 而非生成。

</details>

### Q6. 为什么只读校验要用 AST 解析而不是正则？
- **考察点**：防护绕过意识。
- **评分维度**：
  - 正确性（3 分）：列举正则绕过方式（注释/换行/大小写/编码）。
  - 工程意识（2 分）：AST 看语法树结构，只看"语句类型"，更稳。
<details><summary>参考答案（点击展开）</summary>

正则匹配字符串极易被绕过：攻击者/模型可在语句中插入注释（`SEL/* */ECT`）、换行、大小写混合（`sElEcT`）、特殊编码来绕过关键词黑名单；而 AST 解析把 SQL 变成语法树，只判断"根节点是不是 SELECT 语句"，结构层面的判断无法被文本变形绕过。所以生产用 JSqlParser/Calcite 等解析器做 AST 校验。

</details>

### Q7. 白名单表为什么要覆盖 JOIN / 子查询里的表？
- **考察点**：越权防护的细粒度。
- **评分维度**：
  - 正确性（3 分）：指出越权表可藏在 JOIN/子查询。
  - 工程意识（2 分）：所有被引用表都要 ∈ 允许集；结合数据库只读账号。
<details><summary>参考答案（点击展开）</summary>

越权访问不一定在主查询的 FROM 里，也可能藏在 `JOIN`、`子查询`、`CTE`、甚至 `IN (SELECT ...)` 里。若只校验顶层表，会漏掉这些隐式引用的敏感表（如 `user_credential`、`payment_account`）。

正确做法：从 AST 提取**所有**被引用的表名（含 JOIN/子查询/CTE），逐一校验是否在允许集内；同时数据库账号只 GRANT SELECT 给白名单表，双重保险。

</details>

### Q8. 参数化、行数 LIMIT、EXPLAIN 各防什么？
- **考察点**：三关各自职责。
- **评分维度**：
  - 正确性（3 分）：参数化防注入、LIMIT 防拖库、EXPLAIN 防慢查询。
  - 工程意识（2 分）：LIMIT 太低会静默截断要提示；EXPLAIN 高并发可免检。
<details><summary>参考答案（点击展开）</summary>

- **参数化（防注入）**：用户输入走绑定变量 `?`，防 `' OR '1'='1` 注入和语法错（Java 的 PreparedStatement 同理）。
- **行数 LIMIT（防拖库）**：自动追加 LIMIT 或校验用户 LIMIT 不超阈值，防 `SELECT *` 返回百万行拖垮连接。
- **EXPLAIN（防慢查询）**：执行前看是否全表扫/笛卡尔积/超成本，超标则拒绝或改写，避免占满连接池。

注意：LIMIT 太低会"静默截断"导致统计错，结果解释要提示"已截断"；EXPLAIN 本身有成本，高并发可对简单查询免检或缓存计划。

</details>

---

## L3 深度（设计与权衡，能讲清"为什么这样设计"）

### Q9. 为什么"生成 SQL"和"安全校验"必须解耦？请深入谈纵深防御。
- **考察点**：不可信生成 vs 可信守门 的架构思想。
- **评分维度**：
  - 正确性（2 分）：生成不可信（LLM 会错/越狱），校验必须确定性。
  - 完整性（2 分）：列全纵深防御层次（prompt 软防线→AST→白名单→库账号只读）。
  - 工程意识（1 分）：守门员不能和生成合并，否则不安全。
<details><summary>参考答案（点击展开）</summary>

生成由 LLM 完成，**不可信**：它可能产出错误 SQL，也可能被越狱/上下文注入诱导吐出 `DROP`/`UPDATE`。若把"安全"寄托在 prompt 的"请只输出 SELECT"上，等于把守门员和不可信来源合并，必然失守。

因此安全校验必须是**独立的确定性规则层**。纵深防御层次：
1. prompt 软防线（先声明只读，挡掉大部分明显违规）；
2. AST 校验（应用层，只允许 SELECT）；
3. 白名单表（含 JOIN/子查询）；
4. 数据库账号本身 GRANT SELECT only（即使应用层漏了，库层也挡住写/越权）。

这是整个 Agent Harness"不可信生成 + 可信守门"思想的缩影。

</details>

### Q10. 结果解释时如何保证数字准确？空结果怎么处理？
- **考察点**：闭环准确性 + 边界处理。
- **评分维度**：
  - 正确性（2 分）：数字必须来自真实 SQL 结果，不让模型重算/编。
  - 完整性（2 分）：空结果 ≠ 0 元，要如实说"未查到"。
  - 工程意识（1 分）：异常不暴露 SQL/表名，友好提示+日志+可转人工。
<details><summary>参考答案（点击展开）</summary>

**数字准确**：结果解释把行集转自然语言，但金额/计数必须直接来自真实 SQL 结果，不能让模型"重新算"或编造。分工是"SQL 负责准，语言模型负责顺"。若结果被 LIMIT 截断，解释里必须明示"仅统计前 N 条"。

**空结果**：SQL 正常但 0 行（如查不存在的保单），要如实说"未查到相关记录"，**不能编"您报销 0 元"**——0 元和没有是两回事，保险场景会误导用户引发投诉。

**异常**：超时/权限/语法漏网时，别把原始报错（含表名/SQL）抛给用户（信息泄露），给友好提示并记日志，可降级（返回近 30 天概览）或转人工。

</details>

### Q11. 如果 Text2SQL 生成的 SQL 执行超时，你怎么设计兜底？
- **考察点**：容错与降级设计。
- **评分维度**：
  - 正确性（2 分）：语句级超时 + 杀查询。
  - 完整性（2 分）：友好提示 + 缩小范围建议 / 降级 / 转人工。
  - 工程意识（1 分）：记 Trace、不拖垮连接池（连接池隔离）。
<details><summary>参考答案（点击展开）</summary>

1. **执行层**：受限独立连接池 + 语句级超时（如 3s），超时即 `KILL QUERY`，保证一个烂查询拖不垮整个理赔服务（连接池隔离）。
2. **用户层**：返回友好提示"查询过慢，请缩小时间范围或指定具体保单"，不暴露 SQL/表名。
3. **降级**：可返回近 30 天概览等轻量结果，或转人工。
4. **可观测**：把超时、原 SQL、耗时记到 Trace，便于后续优化索引或改写查询。
即便 EXPLAIN 放行，线上数据分布变化也可能让查询变慢，超时是最后兜底。

</details>

---

## L4 场景（特药理赔 Agent 实战推演）

### Q12. 用户问"我上个月特药报销了多少钱"，请完整描述从问题到回答的处理链路（含安全校验）。
- **考察点**：端到端串讲 + 安全校验落地。
- **评分维度**：
  - 正确性（2 分）：链路顺序正确。
  - 完整性（2 分）：Schema Linking 把"特药报销/上个月"映射到具体表字段；安全校验五关逐一道出。
  - 工程意识（1 分）：结果解释数字来自真实结果，空结果处理。
<details><summary>参考答案（点击展开）</summary>

1. **路由判断**：问题含"多少钱/上个月"，属聚合统计 → 走 SQL（非 RAG/API）。
2. **Schema Linking**：召回理赔相关表（`claim`/`policy`/`drug`），把"特药报销金额"→`claim.clm_amt`，"上个月"→`claim.clm_date BETWEEN 上月首日 AND 上月末`，"我"→按当前用户 member_id 过滤。
3. **生成**：低 T=0，prompt 含 schema 与"仅 SELECT"，生成如 `SELECT SUM(clm_amt) FROM claim WHERE member_id=? AND clm_date BETWEEN ? AND ? AND drug_type='特药'`。
4. **安全校验五关**：
   - 只读：AST 确认是 SELECT；
   - 白名单：引用的 `claim` 在允许集；
   - 参数化：`member_id`/`日期` 走绑定变量；
   - 行数：聚合查询自动 LIMIT（或无需）；
   - EXPLAIN：无全表扫则放行。
5. **执行**：受限连接 + 超时。
6. **结果解释**：把 SUM 值组织成"您上个月特药报销合计 ¥X"，数字来自真实结果；若为空则说"未查到相关记录"，不编 0 元。

</details>

### Q13. 用户问"把所有客户的身份证号和银行卡号导出来"，作为特药理赔 Agent 你如何处理（路由+安全+拒答）？
- **考察点**：安全红线 + 越权/敏感数据防护 + 拒答。
- **评分维度**：
  - 正确性（2 分）：识别为越权+敏感数据，必须拒绝。
  - 完整性（2 分）：白名单挡 `user_credential`/`payment_account`；即使绕过也有库账号/权限挡；
  - 工程意识（1 分）：友好拒答而非执行，记审计日志，不暴露内部结构。
<details><summary>参考答案（点击展开）</summary>

这是安全红线场景，绝不能执行：

1. **路由层**：虽像 SQL 查询，但目标是敏感表（`user_credential`/`payment_account`），且超出该 Agent 职责——应在路由阶段就识别为"越权/敏感"并拦截，不进入生成。
2. **安全校验层**：即使生成了 SQL，白名单表校验会拒绝引用敏感表；即便绕过，数据库账号对这些表无 SELECT 权限，库层再挡一道。
3. **拒答**：返回友好提示"抱歉，我无法导出客户身份证号与银行卡号等敏感信息"，**不执行、不暴露**内部表结构或报错细节。
4. **审计**：把该次越权请求记审计日志（谁、何时、问了什么），便于安全复盘。
体现原则：最小权限 + 纵深防御 + 该拒答时拒答（而非硬编或硬查）。

</details>

---

## 评分汇总表

| 编号 | 层级 | 主题 | 满分 | 你预估得分 |
|------|------|------|------|-----------|
| Q1 | L1 | Text2SQL 定义与适用 | 5 | |
| Q2 | L1 | 端到端流程 | 5 | |
| Q3 | L1 | Schema Linking 概念 | 5 | |
| Q4 | L1 | 只读含义 | 5 | |
| Q5 | L2 | Schema Linking 做法 | 5 | |
| Q6 | L2 | AST vs 正则 | 5 | |
| Q7 | L2 | 白名单覆盖 JOIN | 5 | |
| Q8 | L2 | 参数化/LIMIT/EXPLAIN | 5 | |
| Q9 | L3 | 生成与校验解耦 | 5 | |
| Q10 | L3 | 结果解释与空结果 | 5 | |
| Q11 | L3 | 超时兜底 | 5 | |
| Q12 | L4 | 端到端场景串讲 | 5 | |
| Q13 | L4 | 越权敏感数据拒答 | 5 | |
| **合计** | | | **65** | |

### 达标线
- **及格（≥ 39 / 65，且 L1 全对）**：能讲清 Text2SQL 基本流程与核心概念，理解安全校验的存在意义。
- **达标线①（核心，必须达到）**：能**完整讲清 Text2SQL 流程，并把安全校验每一环（只读/白名单/参数化/行数/EXPLAIN）逐一道出**，说清每环挡什么。
- **达标线②（核心，必须达到）**：能讲清**为什么必须只读+白名单（资损/合规/纵深防御）**，以及 **Schema Linking 怎么做才能准**（数据字典+中文注释+表召回+先映射后生成+枚举/时间归一化）。
- **优秀（≥ 55 且 L4 两题均 ≥4）**：能在特药理赔场景里流畅推演端到端链路，并正确处理越权/敏感数据的拒答红线。

> 判定：达标线①和②任一项缺失，视为本次未达标，需重读手册 s7~s14 并重做对应评测题。
