用 AI Agent 生成和维护语义视图

语义视图的设计涉及业务理解、表结构分析和语义建模,这类工作非常适合交给 AI Agent 完成。本文从实践角度说明:在动手之前需要完成哪些业务对齐工作,Agent 需要收集哪些信息、如何判断设计质量、以及哪些常见错误会让视图"创建成功但结果错误"。

为什么语义视图适合 Agent 生成

语义视图的创建有两个难点:

  1. 业务理解:维度和指标的命名、同义词、注释需要贴近业务语言,而不是照搬物理列名
  2. 表结构分析:外键关系、类型匹配、主键选择需要先读懂数据,再做设计决策

这两件事 Agent 都擅长——它可以同时查询表结构、采样数据、理解业务描述,然后生成一个完整的语义视图定义。但有一件事 Agent 做不到:主动发现业务口径分歧。跳过业务对齐直接让 Agent 建模,等到视图上线后才发现"员工数"在不同报表里定义不一样——这是最难排查的问题类型,也是最容易被忽略的步骤。

业务对齐:在动手之前

技术实现是最简单的部分。 生成一个能运行的语义视图只需要十分钟;生成一个业务上真正有用的语义视图,需要先做好业务对齐。

两类失败模式

失败类型症状发现时机
技术失败创建报错(类型不匹配、外键引用错误)立即发现
业务失败创建成功,但查询结果不符合业务预期上线后才发现

业务失败更危险:查询不报错,数字看起来合理,但计算口径与业务理解不一致,可能影响决策。

需要收集的五类业务知识

在让 Agent 开始工作之前,先收集以下五类信息:

1. 分析域定义

这个视图要回答哪些核心业务问题?不是"帮我建一个员工视图",而是:

  • 场景:按部门、入职年份分析薪资分布
  • 使用者:HR 数据分析师、部门经理
  • 常用维度:部门、入职时间、在职状态
  • 不包含:绩效数据、晋升记录(属于另一个分析域)

明确边界很重要。一个视图覆盖太多主题,不如拆成多个聚焦的视图。

2. 指标口径

同一个指标名称,不同部门可能有完全不同的计算方式:

指标名HR 口径财务口径管理层口径
员工人数在册人数(含试用期)在岗人数(已转正)全时当量(FTE)
平均薪资全员含离职仅在职员工仅正式员工(排除实习生)
订单金额下单金额实收金额(扣退款)确认收入(按财务准则)

必须在建模前确认每个指标的口径,包括:

  • 分子和分母分别是什么
  • 包含还是排除哪些数据(离职员工、测试账户、退款订单)
  • 按什么时间点统计(下单时间、支付时间、确认时间)

3. 维度粒度

同一个业务概念,可以有不同的粒度级别:

维度可选粒度需要确认
时间自然月 / 财季 / 入职年份是否需要多个时间维度?
地理城市 / 省份 / 大区最细粒度是什么?是否需要上卷?
组织自然部门 / 业务线 / 成本中心上卷逻辑在数据库里还是需要表达式实现?

4. 业务规则和过滤条件

哪些数据在正常分析中应该被排除?这些规则往往是隐性的,需要主动问:

  • 测试账户(
    is_test = true
    is_test = true
  • 已删除的记录(
    is_deleted = false
    is_deleted = false
  • 特殊时间段的异常数据(如系统迁移期间的脏数据)
  • 法务和合规要求(某些数据不能出现在报表中)

这些规则可以设计成 FILTERS 子句,也可以直接写入指标的条件聚合里。

5. 术语表

物理列名往往是缩写或技术命名,需要建立业务术语映射:

物理列名业务含义常用同义词
dept
dept
所在部门部门、department、team
hire_date
hire_date
入职日期入职时间、onboard date、加入日期
is_active
is_active
是否在职在职状态、active status、在岗
salary
salary
月薪(税前)薪资、工资、月薪、base salary

术语表直接影响 Analytics Agent 能否通过自然语言找到正确的维度和指标。

口径文档模板

将以下模板填写完整后交给 Agent,可以显著提升生成质量:

## 语义视图口径文档 ### 分析域 - 视图名称: - 核心业务问题:(例:按部门分析员工薪资分布和人员结构) - 主要使用者:(例:HR 数据分析师、部门经理) - 常用查询维度:(例:部门、入职年份、在职状态) - 不包含的内容:(例:绩效数据、晋升记录) ### 涉及的物理表 - 主表:schema.table_name(说明:...) - 维度表:schema.table_name(说明:...) - 关联关系:主表.列名 → 维度表.列名(类型:...) ### 指标口径 | 指标名 | 计算公式 | 包含条件 | 排除条件 | 统计时间点 | |-------|---------|---------|---------|----------| | 员工总数 | COUNT(id) | 全部员工 | 无 | 当前时点 | | 在职员工数 | COUNT(id) | is_active=true | 离职员工 | 当前时点 | | 平均薪资 | AVG(salary) | 全部员工 | 无 | 当前时点 | ### 维度粒度 | 维度 | 粒度 | 来源列 | 是否需要计算 | |-----|-----|-------|------------| | 部门 | 自然部门 | employees.dept | 否 | | 入职年份 | 年 | YEAR(employees.hire_date) | 是 | | 部门经理 | 个人 | departments.manager | 否(跨表) | ### 业务规则 - 排除条件:(例:排除 is_test=true 的测试账户) - 数据范围:(例:仅统计 2019 年以后的数据) - 特殊处理:(例:兼职员工按 0.5 FTE 计算) ### 术语表 | 物理列名 | 业务术语 | 同义词 | |---------|---------|-------| | dept | 部门 | department, team | | hire_date | 入职日期 | 入职时间, onboard date |

向谁收集、如何收集

信息类型找谁有效提问方式
指标口径数据分析师、业务负责人"这个数字是怎么算出来的?包含哪些人/订单?"
维度粒度报表使用者"你通常按什么维度看这个数据?最细到什么级别?"
业务规则数据工程师、DBA"这张表里有哪些数据是正常分析不应该包含的?"
术语映射业务用户"你们平时说的'在职员工'对应数据库里哪个字段?"

最实用的方法:拿一份现有报表,逐个数字追问其计算逻辑。这样既能快速发现口径分歧,也能让现有报表成为最好的业务文档参考。

典型口径冲突案例

以下是实际项目中常见的口径分歧,说明为什么业务对齐不能跳过:

案例 1:员工人数

HR 说"我们有 500 人",财务说"在岗 480 人",管理层说"FTE 是 460"——同一时点,三个数字都对,但口径不同。如果语义视图只定义一个"员工总数",三个部门都会觉得数字不对。

解决方案:定义三个独立指标,分别对应三种口径,并在注释中说明差异。

案例 2:订单金额

销售看"下单金额"(GMV),财务看"实收金额"(扣退款),运营看"有效订单金额"(排除测试订单和异常订单)。同一张订单表,三种 WHERE 条件,三个完全不同的数字。

解决方案:建立三个指标,分别命名为

gmv
gmv
net_revenue
net_revenue
valid_order_amount
valid_order_amount
,并在同义词中加入各部门的常用叫法。

案例 3:时间维度

"按月分析"可能是自然月(1月1日-1月31日),也可能是财务月(财年第一个月从4月开始),还可能是滚动30天。如果不确认,Agent 会默认用自然月,财务部门的数据就对不上。

解决方案:明确时间维度的定义,如果需要多种时间口径,定义多个时间维度。

识别口径冲突的方法:对同一指标反复追问——"是否包含离职员工?""是否包含实习生?""是否包含未完成状态?"通常在第二或第三个问题时就能暴露分歧。


第一步:收集必要信息

完成业务对齐后,进入技术信息收集阶段。

这是最关键的一步。 信息不足时,Agent 会生成一个"能跑通"但业务上没用的视图。

必须收集的信息

1. 分析目标

不是"帮我建一个语义视图",而是:

  • 这个视图要回答什么业务问题?("分析各部门薪资分布" vs "分析员工离职率趋势")
  • 主要使用者是谁?(数据分析师、业务经理、还是 AI Agent 自动查询)
  • 最常用的查询维度是什么?(按部门、按时间、按地区)

2. 涉及的物理表

让 Agent 先读表结构,不要靠猜:

cz-cli agent run "描述 doc_test schema 下 employees 和 departments 表的结构,包括列名、类型、样例数据" \ --profile aliyun_shanghai_prod

Agent 需要知道:

  • 每张表的主键是什么
  • 表之间如何关联(关联列的名称和类型是否一致)
  • 哪些列适合做维度,哪些适合做指标
  • 数据量级(影响是否需要分区或过滤)

3. 业务术语映射

物理列名往往是缩写或技术命名,需要明确业务含义:

物理列名业务含义常用别名
dept
dept
所在部门部门、department
hire_date
hire_date
入职日期入职时间、onboard date
is_active
is_active
是否在职在职状态、active status

4. 指标定义的口径

同一个"平均薪资"可能有不同口径:

  • 是否包含离职员工?
  • 是否包含实习生?
  • 按自然月还是按财年统计?

这些口径决定了指标的过滤条件和维度设计,必须在建模前确认。

可选但有价值的信息

  • 现有的报表或 SQL 查询(帮助 Agent 理解实际使用模式)
  • 已知的数据质量问题(某列有大量 NULL、某表有重复数据)
  • 下游工具(Analytics Agent、BI 工具、还是直接 SQL 查询)

第二步:让 Agent 分析表结构

在生成语义视图之前,Agent 应该先做一轮表结构分析,而不是直接开始写 CREATE 语句。

cz-cli agent run " 分析 doc_test.employees 和 doc_test.departments 两张表: 1. 描述每张表的列名、类型和含义 2. 找出两张表之间的关联关系(关联列名称和类型) 3. 判断哪些列适合作为维度,哪些适合作为指标 4. 检查关联列的类型是否一致,是否可以直接用作外键 5. 采样几行数据,确认数据质量 " --profile aliyun_shanghai_prod

Agent 在这一步需要特别检查:

外键类型匹配:这是最常见的创建失败原因。如果

employees.dept
employees.dept
(string)要关联
departments.dept_id
departments.dept_id
(int),类型不匹配,创建时会报错:

CZLH-42000: type string of foreign key column dept does not match type int of referenced column dept_id

正确做法是找到类型一致的关联列,或者在设计时明确指定引用列:

FOREIGN KEY (dept) REFERENCES depts (dept_name) -- 显式指定引用 dept_name 而非主键 dept_id

主键选择:语义视图的主键不必是物理表的主键,选择能唯一标识业务实体的列即可。如果用

dept_name
dept_name
作为部门表的主键(而非
dept_id
dept_id
),可以让外键关联更自然。

第三步:生成语义视图

信息收集完毕后,给 Agent 一个结构化的指令。把口径文档直接附在指令里,这是提升生成质量最有效的方式:

cz-cli agent run " 基于以下信息,为 doc_test schema 创建一个员工薪资分析语义视图: 分析目标:按部门、入职年份分析员工薪资分布,支持部门经理维度 涉及表:doc_test.employees(主表)、doc_test.departments(维度表) 关联关系:employees.dept(string)关联 departments.dept_name(string) 需要的维度: - 员工姓名(唯一标识) - 所在部门 - 入职年份(从 hire_date 提取) - 部门经理(来自 departments 表) - 是否在职 需要的指标: - 员工总数(COUNT 全部员工) - 在职员工数(COUNT is_active=true 的员工) - 平均薪资(AVG 全部员工,含离职) - 最高薪资 要求: - 使用中英文双语同义词 - 为每个维度和指标添加中文注释 - 视图名称:emp_salary_analysis " --profile aliyun_shanghai_prod

第四步:验证生成结果

创建成功不等于可用。 这是最容易被忽略的一步。

必须验证的查询

-- 1. 验证基础查询是否返回预期结果 SELECT * FROM semantic_view( doc_test.emp_salary_analysis, DIMENSIONS department, METRICS total_employees, METRICS avg_salary ); -- 检查:行数是否合理?数值是否在预期范围内? -- 2. 验证跨表维度(外键关联是否生效) SELECT * FROM semantic_view( doc_test.emp_salary_analysis, DIMENSIONS manager_name, METRICS total_employees ); -- 检查:是否返回了部门经理维度?结果是否正确? -- 3. 验证计算维度 SELECT * FROM semantic_view( doc_test.emp_salary_analysis, DIMENSIONS hire_year, METRICS total_employees ) ORDER BY hire_year; -- 检查:年份是否正确提取?是否有意外的 NULL 值? -- 4. 验证条件指标 SELECT * FROM semantic_view( doc_test.emp_salary_analysis, DIMENSIONS department, METRICS total_employees, METRICS active_count ); -- 检查:active_count 是否小于等于 total_employees?

常见的"静默错误"

以下情况创建时不报错,但查询结果是错的,必须通过验证发现:

算术表达式指标结果错误

MAX(salary) - MIN(salary)
MAX(salary) - MIN(salary)
这类指标定义在查询时只返回第一个操作数(MAX 的值),减法不执行。如果 Agent 生成了这类指标,需要改为在外层 SQL 计算:

-- 不要在 METRICS 里定义:salary_range AS MAX(salary) - MIN(salary) -- 改为在查询时计算: SELECT department, max_salary - min_salary AS salary_range FROM semantic_view(my_view, DIMENSIONS department, METRICS max_salary, METRICS min_salary);

外键关联未生效:如果跨表维度查询返回 NULL 或行数异常,说明外键关联没有正确建立。检查

DESC EXTENDED
DESC EXTENDED
的输出,确认外键定义是否正确。

维度去重行为:只传 DIMENSIONS 不传 METRICS 时,返回的是去重后的维度值列表,不是原始行数。如果期望看到所有行,需要加上 COUNT 指标。

第五步:迭代优化

语义视图的第一版通常不是最终版。常见的迭代需求:

添加遗漏的维度:发现需要按"薪资等级"分析,但视图里没有这个维度。由于 ALTER 不支持增删维度,需要重建:

cz-cli agent run " 在 doc_test.emp_salary_analysis 语义视图中增加一个薪资等级维度: - 维度名:salary_level - 定义:CASE WHEN salary >= 10000 THEN '高' WHEN salary >= 7000 THEN '中' ELSE '低' END - 注释:薪资等级(高/中/低) 请先导出当前视图定义,添加新维度后重建。 " --profile aliyun_shanghai_prod

修正指标口径:发现"平均薪资"应该只统计在职员工。需要把

AVG(salary)
AVG(salary)
改为
AVG(CASE WHEN is_active = true THEN salary END)
AVG(CASE WHEN is_active = true THEN salary END)

cz-cli agent run " 修改 doc_test.emp_salary_analysis 的 avg_salary 指标: 当前定义:AVG(salary) 修改为:AVG(CASE WHEN is_active = true THEN salary END) 含义:仅统计在职员工的平均薪资 请重建视图。 " --profile aliyun_shanghai_prod

优化同义词:Analytics Agent 或用户反馈某个维度用自然语言查不到,需要补充同义词。

设计质量检查清单

Agent 生成语义视图后,可以用这个清单做最终检查:

业务对齐

  • 每个指标的口径已与业务方确认(包含/排除条件)
  • 时间维度的粒度和起止范围已确认
  • 已知的口径分歧已通过多个指标分别定义
  • 术语表已建立,同义词覆盖主要业务叫法

结构完整性

  • 每个逻辑表都有明确的主键
  • 外键关联的两端列类型一致
  • 被引用的逻辑表在 TABLES 子句中先于引用方定义

语义质量

  • 维度和指标名称使用业务术语,而非物理列名缩写
  • 关键维度和指标都有中文注释
  • 时间类维度设置了
    is_time = true
    is_time = true
  • 唯一标识类维度设置了
    is_unique = true
    is_unique = true
  • 面向 AI Agent 使用时,重要维度添加了同义词

指标正确性

  • 没有使用算术表达式指标(
    A - B
    A - B
    A / B
    A / B
  • 没有使用窗口函数指标(
    RANK() OVER
    RANK() OVER
  • 没有使用派生指标(指标引用指标)
  • 条件聚合指标(
    COUNT(CASE WHEN ...)
    COUNT(CASE WHEN ...)
    )已验证结果正确

查询验证

  • 基础维度+指标查询结果符合预期
  • 跨表维度查询(外键关联)结果正确
  • 计算维度(表达式)结果正确
  • 数值量级合理(没有异常的 NULL 或 0)

完整示例:从零生成一个可用的语义视图

以下是一个完整的 Agent 对话流程,展示从需求到可用视图的全过程。

对话 1:业务对齐

用户:帮我为员工数据创建一个语义视图,用于分析各部门薪资情况 Agent:好的,在开始之前先确认几个业务口径: 1. "平均薪资"是否包含离职员工(is_active = false)? 2. 是否需要区分"全员平均薪资"和"在职员工平均薪资"两个指标? 3. 时间维度按自然年还是财年? 4. 这个视图主要给谁用——BI 报表、Analytics Agent,还是直接 SQL 查询?

对话 2:确认口径

用户:平均薪资统计所有员工,但也需要一个只统计在职员工的指标。 时间按自然年,主要给 Analytics Agent 用。 Agent:明白了。我会定义两个薪资指标: - avg_salary:AVG(salary),全员平均 - active_avg_salary:AVG(CASE WHEN is_active = true THEN salary END),在职员工平均 因为主要给 Analytics Agent 用,我会为每个维度和指标添加中英文同义词。 [查询表结构] doc_test.employees: id(int), name(string), dept(string), salary(decimal), hire_date(date), is_active(boolean) doc_test.departments: dept_id(int), dept_name(string), manager(string) 关联关系:employees.dept(string) → departments.dept_name(string),类型一致,可以直接关联。 开始创建...

对话 3:验证结果

Agent:视图已创建。我来验证一下关键查询: [执行验证查询] 按部门统计:Engineering(2人, avg 11500, active_avg 11500), Marketing(2人, avg 8750, active_avg 9000), HR(1人, avg 7500, active_avg NULL) ✓ 注:HR 部门 Diana 已离职,active_avg 为 NULL 符合预期(无在职员工薪资数据) 跨表维度(部门经理):Frank/Grace/Henry 各对应正确部门 ✓ 入职年份维度:2019-2023 各1人 ✓ 验证通过,视图可以正常使用。 建议:如果后续需要"薪资范围"(最高-最低)这类指标,需要在查询时计算, 不能定义在视图里(当前版本限制): SELECT dept, max_salary - min_salary AS range FROM semantic_view(...)

相关文档

联系我们
预约咨询
微信咨询
电话咨询