自然语言生成 SQL 的演示通常以“查询成功返回结果”结束,企业使用却从这里才开始追问:净销售额如何定义,用户能看到哪些区域,上月按哪个时区计算,金额是否被关联放大,查询是否消耗了过量资源。可靠性来自一组可检查的约束与证据。本文用一个零售分析场景,说明这些约束如何贯穿从提问到结果交付的完整流程。
一、先把问题拆成可以检验的业务意图
用户问“上月华东净销售额同比是多少”,至少包含指标、地区、月份、比较周期和权限范围五项条件。净销售额可能按支付金额减退款计算,也可能按履约确认收入计算;华东可能按收货地、门店所在地或销售组织划分。系统若未经定义就选择一列 revenue,生成的语句即使完全合法,也可能回答另一个问题。
应先形成结构化的查询意图:指标标识及版本、允许的维度、筛选条件、时间区间、归属时间字段和用户身份。存在经过业务确认的默认值时,可以展示后继续执行;缺少关键口径时,应提出能消除歧义的具体问题。不要让用户在整套数据库术语中重新描述需求,也不要把模型对常用词的猜测当成组织的正式定义。
例如订单 O101 支付 100 元,有金额分别为 60 元和 40 元的两条商品明细,另有一笔 20 元已完成退款。在约定的净收款口径下应为 80 元;直接连接明细后求和支付金额却可能得到 200 元,再错误扣减退款。这个小例子说明,语法正确、执行成功、业务正确是三件需要分别验收的事。
二、语义指标层要管住粒度与计算路径
指标层的价值是把共同认可的含义变成可复用的计算约束。dbt 的语义模型文档描述了实体、维度、时间维度和指标的组织方式。无论采用何种工具,都应把净销售额的金额来源、退款状态、订单排除条件、币种处理、可用维度与时间归属写入受版本控制的定义,并为每次修改记录生效范围。
在示例中,可先把支付与退款分别聚合到订单粒度,再组合得到净收款;若查询要求按商品拆分,还需要明确退款如何分摊。没有可靠分摊规则时,指标就不应宣称支持商品维度。允许模型自由选择任意可连接的表,会把结构上的连通误认为业务上的可比较,最终产生看似精细却无法解释的结果。
推荐让模型负责匹配意图、选择已批准的指标和解释限制,由确定性的编译或查询构建环节落实成熟指标。探索性问题可以走受控的临时查询路径,但应标明口径尚未认证。语义层也不是正确性的证明:主键是否唯一、维度是否有历史版本、关联基数是否符合声明,仍需在数据上持续验证。
三、模式检索要找出业务关系,而非堆满表名
企业数据库中的 orders、orders_v2、order_archive 和 order_test 往往都与“订单”相似。只做名称相似度检索,容易召回已废弃或测试表。检索对象应包含表的业务用途、所属领域、维护责任人、认证状态、字段说明、枚举含义、主外键关系以及更新时间,并优先限制在用户有权访问的目录范围内。
检索可以先定位业务域与指标,再扩展必要的表关系,最后选出计算必需的列。给模型的上下文需要包含粒度和合法关联路径,而不只是若干列名。示例中的支付表、退款表和订单地区维度可能已经足够;把商品明细一并加入,反而增加错误连接的机会。采样值用于理解编码时,应采用获准且必要的值,避免把敏感明细装进提示上下文。
Spider 2.0 原始论文把企业 Text-to-SQL 描述为需要检索元数据、方言文档和项目知识的工作流问题。这支持把检索视为独立的工程环节,而不是无限扩大提示长度。评估时可以单独检查正确表、关联边和口径说明是否被找回;若上下文已经缺失退款定义,继续微调 SQL 生成提示通常无法补回事实。
四、时间口径必须进入答案,也必须进入查询
假设提问时间为 2026 年 9 月 27 日,业务时区为 Asia/Shanghai,“上月”应明确为当地时间 8 月 1 日零点至 9 月 1 日零点之前。使用包含起点、不包含终点的区间,能避免月底最后一秒精度不同带来的遗漏。若数据库存储 UTC,应由受控逻辑转换边界,而不是让模型随意使用服务器当前日期。
同比还需要明确比较 2025 年同一自然月,而不是简单减去固定天数。净销售额若按支付发生月统计、退款按退款完成月扣除,与将退款追溯回原订单月份相比,会给出不同但各自可能合理的答案。必须由指标定义选定政策,并在答案旁简要展示。历史区域归属也应说明采用交易时的归属,还是当前客户或门店归属。
数据截止时间与业务区间是两个字段。查询覆盖完整 8 月,但退款源只同步到 9 月 26 日,说明答案对后续补录仍可能修订。系统应带出数据版本或截止标识,区分暂定与已结算状态;同比基期为零时,应按约定返回不可计算或业务指定表示,不能为了凑出百分比而随意替换分母。
五、执行权限要由数据库和网关共同落实
提示词要求“只生成 SELECT”不足以构成只读边界。执行前需要用对应方言的解析器检查完整语句结构,限制为允许的查询形态,拒绝多语句、写入结构和未批准函数,并参数化外部输入。执行身份只授予必要对象的读取权限,同时开启合适的只读事务或使用受控只读数据源;解析失败时不能退回字符串关键词判断。
PostgreSQL 的 SET TRANSACTION 文档规定了只读事务所限制的命令,也说明这是一种高层只读语义。它应与最小权限组合使用,不能被理解为对任意函数、外部访问或资源消耗的全面隔离。模型不得自行切换执行角色、修改会话保护设置,或通过错误重试改用权限更高的账户;这些动作应由执行服务控制。
行级权限同样需要真实角色验证。PostgreSQL 文档明确超级用户、具有 BYPASSRLS 属性的角色以及通常情况下的表所有者会绕过行安全策略。以管理员身份测试成功并不能证明华东经理只能看到华东。结果缓存也必须包含有效授权范围和策略版本,权限变化后失效;只按问题文本复用答案,可能把一个人的查询结果交给另一个人。
六、成本与重试应成为查询计划的一部分
返回十行不意味着只扫描十行。BigQuery 的成本文档说明,在非聚簇表上增加 LIMIT 不能作为降低扫描计费的办法,并提供 dry run 与按需计费下的最大计费字节限制。实际网关应使用目标引擎支持的估算和硬限制,同时要求必要的分区过滤、控制执行时长与并发,并限制传回模型的结果规模。
估算结果也有边界。某些权限策略或查询形态可能让预执行估算不完整,不能把缺失或零估算自动当成免费执行。可以为已认证指标设定日常预算,为复杂探索查询采用更严格的运行配额,并记录实际消耗。预算阈值必须根据数据规模和用户需求验证;它是服务策略,不是模型自行决定的货币授权。
自动修复循环要有总预算。语法错误可以在限定次数内根据经过处理的错误信息修正,权限错误和预算拒绝则不应触发绕过限制的重写。连续尝试多个查询时,记录每次版本、错误类别、扫描消耗与最终选择。否则,一个前端看来只有一次的自然语言请求,可能在后台生成多次昂贵试探,而用户仍不知道失败原因。
七、用反例验证业务正确,而非只比对 SQL 文本
评估至少应分开报告语法通过率、执行成功率、权限合规率和业务结果正确率。SQL 文本不同可能得到等价结果,文本相似也可能在边界条件下算错。建立由业务负责人确认的题目、指标定义和预期结果,固定数据快照与授权角色,再比较聚合值、分组集合、空值行为、排序要求及允许的数值误差。
只在一份普通样本上得到正确答案仍可能是巧合。应加入跨月退款、一单多明细、无成交地区、重复维度键、已取消订单、多币种和同比基期为零等反例。对于 O101,增加一条不改变订单总额的明细后,订单净收款仍应为 80 元;这类不变量测试比只检查生成的查询包含 SUM 更接近业务目标。
还要测试系统是否知道何时不能回答。问题缺少关键口径、请求越权区域或数据不完整时,合格行为可能是提出一个澄清问题、拒绝越权部分,或返回带边界的部分结果。分别记录正确回答、错误回答、合理弃答与过度弃答,避免为了提高表面成功率而鼓励模型在所有情形下给出确定数字。
八、把可核查的证据随答案一起交付
一个可用答案可以写成:2026 年 8 月华东净收款为某金额,同比增长某比例;按支付发生日计入、按退款完成日扣除,使用交易时门店地区,数据截至某时点。具体数值由实际执行结果填入。将口径、区间和截止时间用业务语言展示,比直接贴一大段 SQL 更有助于使用者判断答案能否进入经营分析。
需要追查时,再提供查询标识、指标版本、授权范围、使用的数据对象、实际执行语句和运行消耗。解释必须由已解析的查询计划与结果元数据生成,不能让模型凭记忆补写自己并未使用的筛选条件。审计记录应能区分用户意图、模型候选、网关改写与最终执行,避免事后无法判断错误发生在哪一层。
上线可从定义稳定、权限清晰、能与既有报表对账的少量指标开始,随后根据失败样本扩展领域。先验证检索、口径、执行和评估链路,再增加问题覆盖范围。可靠的 Text-to-SQL 服务既能给出正确答案,也能让人理解答案依据,并在证据不足时停在明确边界内;这比单纯提高生成 SQL 的数量更接近企业需要的能力。
