随着 Text-to-SQL、ChatBI 和 Data Agent 的发展,用户开始尝试直接通过自然语言查询企业数据。但生成一条语法正确的 SQL,并不意味着得到了业务正确的答案。

同一个“销售额”,可能指订单原价、优惠后金额、实际支付金额或确认收入;两张表之间也可能存在多种看似合理的关联方式。哪些数据需要排除、指标应该基于什么粒度聚合、事实数据应该匹配哪个时间点的维度状态,这些信息通常不会完整出现在数据库 Schema 中,也无法仅凭表名和字段名可靠推断。

在传统 BI 场景中,这类问题主要表现为指标口径不一致:相同的指标被重复定义在不同报表、SQL 和数据管道中,难以形成统一的 Single Source of Truth。进入 AI 时代后,问题进一步放大——面对物理表结构与业务语言之间的 Semantic Gap,AI 可能生成语法正确、能够执行,却不符合真实业务逻辑的 SQL。

这也让语义层重新受到关注。它不再只负责统一 BI 指标,还需要为 AI 提供理解企业数据所需的上下文,包括业务指标、维度、表关系、数据粒度、过滤规则和业务词汇。

Prompt 可以临时补充部分信息,却很难长期维护和复用,也无法保证其中的规则真正进入最终执行的 SQL。更稳定的方式,是将正确查询所需的信息提前沉淀为结构化、可执行的定义。

镜舟为什么要做 Semantic View

当 AI Agent 成为新的数据查询入口,数据库不仅要正确执行 SQL,还需要为 AI 生成业务正确的 SQL 提供基础。

基于这一判断,镜舟将 Semantic View 设计为数据库中的一等对象。它是一份位于查询执行路径上的 信息契约(Information Contract):在定义阶段明确业务术语、表关系、主键、指标口径和过滤规则,在查询阶段由系统将其确定性地展开为 SQL。

与外部文档或 Prompt 不同,进入数据库执行路径的语义不再只是供模型参考的信息,而是查询必须遵循的约束。同一套定义还可以被 AI Agent、BI 工具和传统 SQL 查询复用,并通过展开后的 SQL 接受检查。

Semantic View 的四项设计原则

镜舟Semantic View 建立在四项设计原则之上。缺少其中任何一项,它所能提供的保障都会随之改变。

图片

这四项原则也对应了 Semantic View 中不同参与者的分工。

  • 人负责定义业务含义和做出判断,例如“实际支付金额应该使用哪个字段”;

  • AI 负责理解用户问题并生成查询;

  • 数据库系统负责关系解析、语义展开和确定性执行。

Semantic View 并不要求 AI 自己判断所有业务规则,而是尽可能减少查询生成阶段需要临时推断的信息。

用一个具体示例理解 Semantic View

下面通过一个有意简化的例子说明 Semantic View 的使用方式:一张事实表、两张维度表、一个 Semantic View、两种查询方式,以及一份可以审查的 SQL 展开结果。示例场景是个人购买钓鱼装备的消费分析。

图片

(数据模型:一个事实表t_item关联两个维度表)

定义一个 Semantic View

CREATE OR REPLACE SEMANTIC VIEW sv_fishing_item_spend
  TABLES (
    items      AS t_item       PRIMARY KEY (id)
      WITH SYNONYMS = ('fishing gear spend', 'purchase record')
      COMMENT = 'one row = one purchase',
    item_types AS t_item_type  PRIMARY KEY (id),
    brands     AS t_item_brand PRIMARY KEY (id)
  )
  RELATIONSHIPS (
    item_to_type  AS items (item_type) REFERENCES item_types (id),
    item_to_brand AS items (brand)     REFERENCES brands (id)
  )
  DIMENSIONS (
    items.buy_year AS YEAR(items.buy_date)
      WITH SYNONYMS = ('purchase year', 'year'),
    item_types.item_type_name AS item_types.item_type
      WITH SYNONYMS = ('gear category', 'category')
      SAMPLE_VALUES = ['rod','line','hook','accessory','bait','float'],
    brands.item_brand_name AS brands.item_brand
      WITH SYNONYMS = ('gear brand', 'brand', 'make')
      SAMPLE_VALUES = ['Woding','Handing','Liuzhiqiang','Other','Lianqiu','Chuanze']
  )
  METRICS (
    items.purchase_count   AS COUNT(items.id)         WITH SYNONYMS = ('purchase count'),
    items.total_real_spend AS SUM(items.real_amount)   WITH SYNONYMS = ('total amount paid'),
    brands.brand_count     AS COUNT(DISTINCT brands.id),
    items.avg_brand_cost   AS items.total_real_spend / brands.brand_count   -- derived metric
  )
  AI_SQL_GENERATION 'For spend use total_real_spend; for counts use purchase_count.'
  AI_QUESTION_CATEGORIZATION 'Route questions about gear spending, amounts and brand breakdowns to this view.';

这一定义中有三点值得注意。

1. 一旦通过 RELATIONSHIPS 声明表之间的关系,后续查询便不再需要手动编写 Join。

2. SYNONYMS 和 SAMPLE_VALUES 主要提供给语言模型使用,而不是提供给数据库引擎计算。

  • 用户说“purchase year”或“year”时,对应 buy_year

  • 用户说“gear brand”“brand”或“make”时,对应品牌维度;

  • 用户提到“float”或“Handing”时,模型可以参考样例值,将其识别为具体的数据取值。

3. avg_brand_cost 是一个派生指标,即基于其他指标定义的指标。

使用两种查询方式

对于“2024 年,我在每个品牌上实际花费了多少钱,分别购买了多少次?”这个问题,可以直接基于语义进行查询:

SELECT * FROM SEMANTIC_VIEW(
  sv_fishing_item_spend
  DIMENSIONS brands.item_brand_name
  METRICS    items.total_real_spend, items.purchase_count
  WHERE      items.buy_year = 2024
  ORDER BY   items.total_real_spend DESC
) AS sv;

在这种查询方式下,不需要编写 Join,不需要使用聚合函数,也不需要猜测底层物理字段的名称。这种形式更接近对分析意图的描述,也更容易由语言模型生成。

Semantic View 也可以作为一张扁平化的宽表直接读取,这样,BI 工具即使不了解 Semantic View 特有的查询语法,也可以直接连接并复用相同的维度和指标定义。无需理解语义语法即可复用相同定义:

SELECT items__buy_month, items__total_real_spend
FROM sv_fishing_item_spend
WHERE items__buy_year = 2024;

一个清晰可读的 SQL 结果​​​​​​​

EXPLAIN INLINE
SELECT * FROM SEMANTIC_VIEW(
  sv_fishing_item_spend
  DIMENSIONS brands.item_brand_name
  METRICS    items.total_real_spend
  WHERE      items.buy_year = 2024
) AS sv;

返回:​​​​​​​

SELECT `brands`.`item_brand`      AS `item_brand_name`,
       SUM(`items`.`real_amount`) AS `total_real_spend`
FROM `test`.`t_item` AS `items`
LEFT JOIN `test`.`t_item_type`  AS `item_types` ON `items`.`item_type` = `item_types`.`id`
LEFT JOIN `test`.`t_item_brand` AS `brands`     ON `items`.`brand` = `brands`.`id`
WHERE YEAR(`items`.`buy_date`) = 2024
GROUP BY 1;

审核人员可以逐行查看实际执行的计算过程。这正是“SQL 输入、SQL 输出”原则背后的机制:系统的可信度建立在透明、可检查的执行过程上,而不是依靠无法验证的保证。

语义信息如何帮助模型生成查询?

对于“2024 年,我在 Handing 品牌的浮漂上花了多少钱?”这个问题,模型完成每一步解析时,都有 Semantic View 中定义的元数据作为依据。

图片

(问题中的每个短语都会映射到语义视图中的一个同义词或示例值)

如果没有 Semantic View,其中每一步都可能成为模型出错的地方。

名为 brand 的字段实际保存的可能是品牌 ID,而不是品牌名称;数据中的取值可能与用户的表达方式不同;amount 和 real_amount 看起来十分相似,却可能分别代表商品标价和实际支付金额。

模型越强,越能根据有限信息生成一条看起来合理的 SQL。但如果缺少必要的业务语义,这种合理仍然只是推断,而不是确定性。

Semantic View 系列预告

作为 Semantic View 系列的第一篇,本文主要讨论了一个基础问题:AI 生成查询时缺少哪些信息,以及为什么需要将这些信息从查询阶段前移至定义阶段。

接下来,我们还将通过两篇内容,进一步介绍 镜舟Semantic View 的设计与能力边界:

  • Semantic Views, Part 2: 什么是 Semantic View

    完整拆解这份“信息契约”:哪些信息需要在定义阶段提供、由谁提供,以及为什么将语义置于数据库执行路径上,能够使其从外部参考转变为查询必须遵守的约束。同时介绍 Semantic View 在 Agent 架构中的位置,以及它如何同时服务 AI Agent 和 BI 工具。

  • Semantic Views, Part 3: 准确性从何而来,以及 Semantic View 不做什么

    说明查询准确性为何不是模型的单一能力,而是建立在业务规则、表关系、主键与粒度等信息之上的依赖链;同时厘清 Semantic View 的职责边界,以及它与业务上下文、数据建模、查询优化和物理加速之间的分工。

从补齐查询时缺失的信息,到建立一份可执行的信息契约,再到明确准确性的来源与边界,后续两篇将继续展开 Semantic View 如何为 AI 查询提供更稳定、可控的语义基础。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐