Text-to-SQL 如何区分表结构与业务规则知识,并适应表结构变更?

考查重点:Schema 结构与业务语义。Schema 描述字段、类型和关联,业务知识描述指标、过滤与计算口径;检索两类信息生成 SQL,结构变更使相关缓存失效,再校当前库的执行结果

本题目录

参考答案

核心回答

把知识分成结构事实和业务语义,再通过稳定标识与版本关联。表结构说明“数据怎样存”,业务规则说明“这次应该怎样算”。 生成时需要两者共同约束;数据库变更后更新受影响的元数据、索引、示例和缓存,并重新验证查询。

两类知识分别保存什么

结构知识包括数据源、表列名称、类型、主外键、关联关系和可用字段。业务知识包括指标公式、计算粒度、过滤条件、单位、时区、时间口径、同义词及生效时间。

例如 amount 是数值类型,只是结构事实;“净销售额等于已支付金额扣除符合条件的退款,并按支付日统计”属于业务规则。字段注释可以帮助理解,但不足以自动推导全部规则。相同字段也可能服务于多个指标,不能只按字段名相似就认定同一口径。

检索时先锁定用户有权访问的数据源,召回相关结构与指标定义,再补齐连接键、计算依赖和必要的取值说明。给模型的规则应标明适用范围和版本;出现相互矛盾的有效规则,应澄清或交给维护者确认。

结构变化怎样处理

从变更流程或周期同步中检测表列新增、删除、重命名、类型和关联变化,对比旧版本生成影响列表。利用字段与指标、示例、索引的依赖关系更新受影响内容,并使相关查询缓存和生成缓存失效。

重命名不能简单做字符串替换:要确认它确为同一业务含义;类型变化可能影响比较、聚合和精度,关联变化可能引起重复统计。没有可靠映射时暂停受影响能力,比让模型猜一个近似字段更稳妥。

业务口径变化也应版本化。历史时间段是否沿用旧口径,需由业务定义,不应因为今天规则更新就悄悄改变历史统计解释。

如何验证更新完成

生成和执行校验要使用相容的结构版本;发现执行时结构已经变化,应刷新必要上下文并有限重试,不能把未知列错误原样无限回喂模型。新 SQL 重新检查权限与资源约束。

回归受影响的指标、连接、示例和权限用例,比较预期结果;保留知识来源、变更时间和对应版本,便于说明同一个问题为何在不同日期得到不同结果。EXPLAIN 通过只能说明数据库可以处理相应结构,无法证明业务口径同步正确。

对应教程

参考资料

SQLBotPython

基于 SQLBot

核心回答

SQLBot 将表字段元数据、人工维护的表关系、业务术语和 SQL 示例分开管理,生成时再组合成上下文。表字段说明有哪些可用对象、类型和注释,表关系提供连接依据;术语解释业务含义与同义表达,示例则提供“问题—查询写法”的参考。字段类型本身不能说明库存余额采用哪个快照时点、滞销天数按哪类出库计算,这类口径需要补进业务说明或示例。

适应结构变化时,先同步真实表字段,再检查人工关系、业务说明和示例是否仍引用正确对象。该版本的结构同步会更新元数据并触发表与数据源的向量更新,但这条同步链没有自动迁移业务术语、改写示例 SQL 或清理全部生成依赖的过程。

不同知识怎样进入 SQL 上下文

以平台管理的普通数据源问数为例,get_table_schema() 从启用的表与字段构造结构信息,列权限过滤也在构造前处理。选表后,表名、字段名、类型与注释被组织成 Schema 文本;已有人工配置的 table_relation 会补充相关表及连接字段。这里的表关系来自维护的关系图,不等于系统自动读取并验证了数据库中的外键约束。表字段范围、结构与表关系组装。

业务语义走独立匹配:filter_terminology_template() 根据未扩展的关键词或原问题匹配术语,带上当前数据源等适用范围,返回主词、同义词与解释;filter_training_template() 按问题匹配该数据源范围内的 SQL 示例。开启向量匹配时可补充语义候选,结果随后被格式化为上下文,并非修改数据库结构或训练模型。术语匹配入口、示例匹配入口、术语模板、示例模板。

sql_sys_question() 分别构造结构、术语和示例模板,init_messages() 将这些内容逐项加入生成 SQL 的消息。结构信息与业务解释因此可以同时约束查询,但前提是对应内容确实被匹配并加入;只维护一条术语,并不代表每次生成都会使用它。模板构造、消息注入。

结构同步更新了什么

同步逻辑按表名、字段名匹配记录:已有表更新数据库注释,已有字段更新类型、原始注释和顺序,新表新字段创建记录。已有的 custom_comment 不会因此被数据库注释覆盖,所以人工维护的业务说明可以保留,也需要在含义变化时另行检查。表与字段同步。

同步结束会提交表和数据源的向量更新任务,这些任务在线程池中运行。触发更新与更新完成需要区分;重新生成时应检查实际选表结果及注入的结构,确认使用的是更新后的内容。单表字段更新、后台向量更新。

字段重命名也不会自动识别为同一业务字段的迁移。旧名称可能仍出现在术语解释、示例查询和人工关系配置中,相关内容需要单独确认和修改。若要实现“字段变化后自动定位并停用受影响的规则、示例与缓存”,还需要额外维护依赖关系与失效机制,不能仅靠同步表结构完成。

怎样验证一次变更

例如业务库把库存数量字段从 stock_qty 改成 on_hand_qty,且业务含义不变:先同步字段,检查注入结构是否已使用新名称;再检查相关术语、示例及连接配置中是否残留旧引用。用同一批问数问题重新生成查询,对照参考 SQL 检查库存快照、出入库和日期口径,并核对查询结果与可访问范围。

这能分别确认结构刷新、知识匹配与业务结果。查询成功执行只说明表字段和语法可用,不能证明新字段承接了原来的业务含义,也不能证明示例中的统计口径仍然正确。

WrenAIPython / Rust

基于 WrenAI

核心回答

WrenAI 把物理结构与业务语义通过逻辑模型连接起来:数据库表列说明数据存在哪里,MDL 语义模型说明对外使用什么名称、怎样关联和计算。 当前架构由 Python SDK/CLI 加载模型、组织查询并连接数据源,Rust 语义引擎基于 Apache DataFusion 参与规划,将模型引用展开为目标数据库可执行的 SQL。

表结构改变后,更新物理映射和受影响的字段、关系或度量定义,重新构建 manifest,再让查询调用方使用新版本。仅改数据库,或者只改一段业务说明,都不会自动完成这条更新链;编译和查询可执行也不等于业务口径正确。

YAML 中哪些是结构,哪些是业务规则

项目把模型、关系、视图和聚合定义保存为可审阅的 YAML 与 SQL 文件:

  • 模型与字段: metadata.yml 声明逻辑字段、类型和主键等信息,ref_sql.sql 将逻辑模型映射到物理表或查询。类型是结构事实,对外名称、描述和计算表达式则带有语义选择。
  • 度量与维度: cube 的 measures 定义聚合或计算,dimensions 定义按什么字段分组。它们明确“怎样算、按什么粒度看”,并非从字段类型自动推导。
  • 关系: relationships.yml 保存模型间的连接条件及 join_type,让可复用关系进入规划,而不是每次让模型仅凭同名字段猜连接。

原仓库的示例很具体:逻辑模型 orders 通过 ref_sql.sql 读取 public.raw_orders,声明每行是一笔订单;order_metrics 以 orders 为 base_object,定义 SUM(amount) 和 COUNT(*),以 customer_id 为维度。orders_customer 则声明订单到客户的 MANY_TO_ONE 关系。这里金额如何聚合、按谁分组、使用哪个连接条件,都是明确维护的定义。见示例度量与维度。

cube 在这条链中是逻辑聚合定义:查询先转换为普通 SQL,再交给引擎执行,不意味着已经自动生成物化聚合表。类似地,声明 MANY_TO_ONE 也不证明客户键在实际数据中唯一。关系粒度或数据质量不符合声明时,仍可能重复加总。

定义怎样进入查询规划

加载器读取模型目录的 metadata.yml,合并同目录的 ref_sql.sql,并加载关系、视图与 cube。wren context build 默认先检查项目结构,再调用 build_json(),将定义转成引擎使用的命名形式并写入 target/mdl.json。它不是把原始 YAML 直接塞进提示词。见模型加载与构建入口。

查询时,WrenEngine.dry_plan() 解析对逻辑模型的引用,提取相关 manifest,借助语义引擎与改写器展开模型和视图,生成目标方言的 SQL;query() 再通过对应连接器执行。cube 查询也先由 cube_query_to_sql() 生成基于其 base_object 的查询,再走相同引擎链。

因此,业务定义不只作为自然语言提醒,还会参与实际计算与连接的规划。Rust 侧能够检查部分模型依赖,例如 cube 基对象是否存在、派生度量是否成环、层级是否引用已声明维度;但“退款是否应该扣除”“金额单位是否一致”仍需先由业务定义并用数据核对。

结构变化后怎样更新

如果物理字段从 amount 改为 gross_amount,而含义和单位不变,可以修改模型映射,例如用 gross_amount AS amount 继续暴露逻辑字段 amount。这样,下游已确认的度量可以继续引用逻辑字段。若新字段已经变成含税金额或统计范围改变,就不能只加别名维持表面兼容,还要修改度量、说明及相关查询。

更新过程需要区分三件事:

  1. 修改源定义。 检查物理映射、列类型、连接条件、指标公式和业务说明的影响范围。
  2. 重新构建与索引。 构建新的 target/mdl.json;使用语义检索时,按项目工作流更新相应 memory 索引,使 Agent 读取的模型说明与执行定义一致。
  3. 让调用方加载新定义。 直接创建的 WrenEngine 保存传入的 manifest_str,不会因为 YAML 改动自动热更新。当前 LangChain SDK 的 ProjectMDLSource 则在加载时重读 target/mdl.json,工具调用据此创建引擎,因此外部构建的新文件可在后续调用中被拾取。不能把“改文件”“构建完成”“调用已使用新版本”视为同一时刻。见SDK 的 manifest 读取。

验证时先看规划后的物理 SQL 是否使用新字段与预期关系,再用固定数据检查总额、分组、空值和多表连接结果。还应保留一个会发生一对多放大的样例,核对聚合粒度。物理映射保持兼容,可以降低结构变化对上层查询的影响;业务口径本身改变时,则需要明确版本和生效范围,不能由兼容映射替业务做决定。

参考资料

相关面经

1 篇

字节跳动

AI 应用工程师
一面
查看原面经 →
如果业务表结构变了、加了新表,怎么处理?

收录题集

1 个来源,共1 份题集

相关题目

4 题