Agent 为什么一接 SQL 就开始答对表名却答错口径:从 Semantic Layer 到 Query Sandbox 的工程实战
🚨 SQL 能跑通,为什么答案却还是经常答错口径
很多团队给 Agent 接上数仓或 BI 查询后,最先暴露的往往不是 SQL 语法错误,而是“能执行、却不可信”。⚠️ 用户问“本月新增付费用户”,模型常会直接扫订单明细,把测试订单、退款重试和跨租户数据一起算进去。📉 数据库看它合法,业务看它已经答偏。
更麻烦的是,Text-to-SQL 的离线分数往往并不差。🧠 表名、字段名和关联键都能对上,exact match甚至能到80%;可进了真实链路后,指标口径、默认过滤和权限边界都不写在自然语言里。📌 模型看见的是 schema,业务要的却是 contract。
🔍 真正丢掉的,不是 SQL 语法,而是语义边界、Join 纪律和执行约束
线上失真通常有三类。🔍 一是指标语义漂移,同样叫“新增用户”,财务口径和运营口径的过滤条件就可能不同;二是 Join 漂移,事实表和快照维表没按同一业务日期对齐;三是执行预算失控,模型生成了合法却昂贵的全表扫描。🧱 漏掉任何一层,回答都可能“像对但不可用”。
一组企业报表问答灰度里,直接让模型输出 SQL 时,离线exact match是82%,但metric_grounded_rate只有61%;补上字段白名单后升到69%;继续加上语义层、租户过滤和成本门禁后,才稳定回到84%。✅ 这说明问题不在模型不会写 SQL,而在系统没有先定义指标。
| 方案 | metric grounded rate | forbidden scan ratio | 平均返回时延 | 典型问题 |
|---|---|---|---|---|
| 直接 Text-to-SQL | 61% | 11% | 1.00x | 口径和权限一起漂 |
| 白名单 SQL | 69% | 4% | 0.93x | 能防错表,防不住错口径 |
| Semantic Layer + Sandbox | 84% | 1% | 0.96x | 更适合生产常驻 |
🛠️ 更稳的工程方案,是先产出指标计划,再编译成 SQL
更稳的做法,不是让模型直接吐最终 SQL,而是先输出一个受控指标计划。🛠️ 计划里至少包含metric_id、时间范围、维度粒度和租户边界;真正的 SQL 由语义层编译出来。🔒 这样事实表、过滤条件和去重键都不再依赖 prompt 记忆。
执行层还要再过一层 Query Sandbox。🧪 它负责拒绝危险语句、补齐强制过滤、估算扫描成本,并在 AST 级别禁止跨租户和无限制明细导出。很多团队把权限和成本都压给模型自己记,few-shot 一过期,系统就开始越权扫库。🚦 有了这层门禁,Agent 才能安全查数。
METRICS={"paid_user_count":{"table":"dws_user_pay_day","agg":"count(distinct user_id)","filters":["pay_status = 'success'","is_test = 0","refund_flag = 0"],}}defcompile_sql(plan:dict,tenant_id:str)->str:metric=METRICS[plan["metric_id"]]where=[f"tenant_id = '{tenant_id}'",*metric["filters"]]where.append(f"dt between '{plan['start']}' and '{plan['end']}'")returnf"""select dt,{metric['agg']}as value from{metric['table']}where{' and '.join(where)}group by dt order by dt"""这段代码的价值不在模板,而在于它把业务口径从 prompt 文本挪到了可审计配置。🔧 上线时还应同步观察sandbox_reject_ratio、tenant_filter_missing和metric_alias_fallback,否则旧错误只会不断写成新 SQL。
📈 接下来 3 到 6 个月,Agent SQL 的分水岭会是语义治理
接下来更值得看的,不是模型能否生成更复杂的 SQL,而是谁能把指标语义、权限约束和成本门禁做成持续治理系统。📊 团队至少要长期盯住metric_grounded_rate、forbidden_scan_ratio、sandbox_pass_after_rewrite和answer_template_fallback_rate。只看“SQL 是否执行成功”,几乎一定会发现得太晚。
笔者认为,成熟的 Agent SQL 平台会越来越像 Semantic BI 层,而不是更长的 prompt 工程。💡 只要业务语义还藏在 few-shot 和人工默契里,再强的模型也只是把错误答案生成得更快。🙂 你们当前更常遇到的,是指标口径漂移、Join 日期错位,还是查询越权与扫库成本失控?欢迎交流。
