Skip to content

第33章 语义层工程


场景引入

第32章已经说明,DataAgent 长期直连 ODS 物理表会把业务口径暴露给模型猜测。用户问“上周华东销售下滑的主要 SKU 是什么”,系统需要先处理“销售”“华东”“上周”这三个词。销售可能是运营 GMV,也可能是财务不含税 GMV;华东可能来自组织主数据,也可能来自历史区域划分;上周可能按自然周,也可能按企业财务周。语义层的作用,是把这些容易漂移的业务含义固定下来。数据平台团队在语义层中维护指标、维度、Join、默认过滤、权限和版本;DataAgent 在运行时调用语义层,把 Question Frame 中的口语槽位绑定到可执行对象。这样模型负责规划和表达,语义层负责事实口径。

经营会议里最常见的数据争议,常常落在“你说的这个数到底怎么算”。同一句“销售额”,运营团队可能指含促销调整的 GMV,财务团队可能指不含税收入,区域团队可能把退货算到下周,电商团队又按支付时间统计。每个口径在自己的场景里都可能成立,但如果 DataAgent 只凭表名和列注释生成 SQL,就会把这些差异压扁成一个看似确定的字段。一次真实问数链路通常会经过多个含义转换。用户说“上周华东销售下滑”,系统要先把“销售”识别为候选指标,把“华东”映射到组织主数据,把“上周”展开为企业认可的业务周,再判断当前用户能看到哪些明细。任何一步出错,SQL 都可能正常执行,结果却不被业务承认。更麻烦的是,这类错误不一定在数据库层报错。查询返回了数字,图表也画出来了,直到会议上有人对账,问题才暴露出来。

语义层要解决的正是这种“SQL 正确但业务错误”的风险。它把物理表之上的指标、维度、Join 路径、权限、版本和默认过滤整理成机器可执行的业务模型。DataAgent 维护独立指标定义,或者在 Prompt 里临时解释 GMV 公式,都会让同一指标在系统间分裂。模型可以帮助理解用户语言、选择候选对象和生成说明,但最终口径必须来自语义层的 Metric、Dimension、View 和 Glossary。

语义层远不止给数据库加中文注释。中文注释能帮助模型猜字段含义,却无法表达生效时间、适用角色、默认过滤、数据新鲜度、血缘和质量状态。DataAgent 需要这些信号来决定是否回答、是否追问、是否拒答,以及回答里应该如何写口径和限制条件。一个成熟系统在给出数字时,至少要能说清楚用了哪个 metric_id@version,数据同步到什么时候,当前用户是通过哪个 View 获得访问权限的。这里采用 DataAgent 消费侧视角。第15章已经从数据平台视角讨论元数据和指标建设,下面不再重复建设流程,而关注 DataAgent 在一次 Run 中如何读取语义层、如何消歧,以及如何把可信上下文带入回答和 Trace。

33.1 语义层作为可信问数地基

语义层是在物理表之上的业务抽象。它集中定义 Measure、Dimension、Hierarchy、View、Join 路径和访问策略,并通过 SQL、REST、GraphQL 或产品 API 暴露给上层应用。Cube、MetricFlow 和 dbt Semantic Layer 都属于这一类实践。如果没有语义层,DataAgent 生成 SQL 时会同时面对口径、Join 和权限三类不稳定因素。销售额是否含税、是否扣退货、是否包含促销调整,决定了指标口径;事实表和维表关系是否被正确约束,决定了结果是否重复或漏算;同一张物理表中可能同时包含可公开指标和敏感字段,模型直接选表很容易越权。

表33-1:无语义层时的风险与语义层提供的约束。来源:本书整理。

问题 无语义层时的风险 语义层约束
指标口径 模型自行猜 GMV 定义 Metric 定义和版本
Join 路径 物理表随意 Join 预建模关系和 View
权限 直接暴露敏感列 行列权限和角色视图
新鲜度 不知道数据同步时间 元数据和质量信号

给表写中文注释只是语义层的起点。注释能解释列名,但表达不了聚合公式、默认过滤、版本、权限和 Join 图。DataAgent 需要可执行 Metric,也不能只看一段描述性文本。Memory 适合记录用户上次确认了“用同比展示”或“默认看华东区”,指标数学定义仍要回到语义层版本。如果把 GMV 公式写进长期 Memory,组织调整或会计政策变化后,DataAgent 很容易继续使用旧口径。

语义层的价值还体现在跨产品一致性上。BI 看板、DataAgent 问数、定时报告和告警系统如果分别维护指标定义,短期开发会更快,长期对账会非常痛苦。平台化 DataAgent 应尽量消费同一套语义层。为了让模型“更好理解”而复制一份 Agent 专用 YAML,会让 GMV、毛利和收入这类核心指标在多个系统中分叉。Agent 可以有自己的提示词和问法策略,指标数学定义则应保持统一。

建设侧和消费侧要分工明确。数据平台团队负责模型发布、指标审批、血缘和质量;DataAgent 团队负责把用户语言映射到这些模型,并把结果解释给业务用户。DataAgent 可以向数据平台反馈“哪个术语经常歧义”“哪个指标缺少 title”“哪个 View 太大导致 Linking 噪声”。修表和改口径仍要经过数据平台流程,否则线上问数会绕过已有的数据治理责任。


33.2 Metric、Dimension、View 与 Glossary

DataAgent 消费语义层时,最常接触四类对象。Metric 定义可聚合指标,例如运营 GMV、订单量、毛利率。Dimension 定义切片属性,例如区域、品类、渠道、SKU。View 定义某类用户可见的指标和维度集合。Glossary 定义业务术语到语义对象的映射,例如“营业额”“销售额”“GMV”可能对应多个 Metric。

表33-2:语义层对象与 DataAgent 用法。来源:本书整理。

对象 作用 DataAgent 用法
Metric 指标公式、默认过滤、版本 绑定 Question Frame 中的指标槽位
Dimension 过滤、分组、下钻字段 绑定时间、区域、SKU 等维度
View 角色或场景可见范围 限制 Planner 可见对象
Glossary 业务术语映射 把用户口语转成候选 Metric

每个 Metric 至少应有程序 ID、展示标题、定义、owner、版本和默认过滤。展示标题很重要,因为它会进入用户回答。只写“GMV 下降 12.3%”会留下口径疑问;写成“运营 GMV gmv_ops@2025Q1 下降 12.3%”,用户才能知道系统采用的是哪套口径。把整个仓库 DDL 交给 Planner,会让上下文变长,也会增加错误联想。更可靠的做法是分层裁剪:用户登录后按角色注入 View 摘要;Linker 根据问题召回少量候选 Metric 和 Dimension;Join、默认过滤和 SQL 编译交给语义层 API 完成。这样能控制上下文长度,也能减少模型把无关表拉进查询的机会。

view: sales_ops
metrics:
  - gmv_ops
  - gmv_tax_excluded
  - order_count
dimensions:
  - region_code
  - category
  - sku
  - week

上面这段摘要只告诉 Planner “当前角色可以围绕哪些对象规划”。它不是完整语义层模型,也不包含所有物理 Join 细节。完整定义仍由 infra/semantic_layer/ 的 API 持有。View 的粒度要适合角色,而非只适配数据库结构。运营总监需要看到区域、品类、SKU、渠道和经营 GMV;财务 Controller 需要看到毛利、成本和不含税收入;门店经理可能只能看到自己负责的门店。一个过大的 View 会让 Linker 候选过多,一个过小的 View 又会导致用户频繁被拒答。View 的设计应根据业务角色和常见问题持续调整。

Glossary 是持续维护的业务词表。业务术语会变化,用户会使用简称、别名和口语表达。例如“营收”“销售额”“流水”“GMV”在不同企业中可能不同。Glossary 应记录同义词、适用范围、候选 Metric 和默认策略,并把高频澄清问题反馈给数据治理流程。缺少 Glossary 时,模型只能依赖表名和列名猜测业务含义,稳定性很差。Metric 的 titledescription 会进入 DataAgent 的回答、追问和 Trace,不能按普通文档字段随手填写。标题过于工程化,例如 gmv_ops_v2,业务用户无法理解;描述过于营销化,又无法支撑审计。比较好的写法是短标题加精确定义,例如“运营 GMV:含促销调整,按订单创建时间统计,扣除部分退单”。这类文本既能给模型消歧,也能给用户解释。


33.3 Schema Linking 与字段消歧

Schema Linking 是把 Question Frame 中的口语槽位绑定到语义层对象和必要物理 schema 的过程。用户说“销售下滑”,Frame 里可能只有 metrics: [gmv]task_type: diagnose;Linker 要进一步判断这个 gmv 对应哪个 Metric、哪个版本、哪些维度和过滤条件。

图33-1:Schema Linking 模式链接流程

图33-1:Schema Linking 模式链接流程。来源:本书自绘。Alt text:流程从用户问题出发,经术语识别、候选字段召回、按信号打分、消歧确认,输出绑定到具体 Metric 与字段的 Linked Schema。

Linking 通常按三步完成。第一步用 Glossary 找候选对象,例如“销售额”“GMV”命中运营 GMV 和财务 GMV。第二步用 View 过滤,把当前用户无权使用或当前场景不适用的对象排除。第三步在允许范围内用向量检索、历史成功 Run 和列注释召回候选字段,再按规则或模型 rerank。

表33-3:Linking 信号来源。来源:本书整理。

信号 优先级 说明
Glossary 业务术语到候选 Metric
View 当前角色和租户可见范围
向量检索 在允许范围内召回字段
历史成功 Run 需校验 Metric 版本
模型自由推断 必须经过 schema 校验

沿用第32章的华东下滑问题,Linker 会先把“销售”识别为 GMV 候选,再用 sales_ops View 和用户角色收窄范围。如果仍存在两个合法口径,就要追问或采用角色默认,并在回答中明示。随后,“华东”通过组织层级映射为 region_code = 'EAST',“SKU”绑定到当前 View 允许的商品维度。

{
  "metrics": [{"metric_id": "gmv_ops", "version": "2025Q1", "title": "运营 GMV"}],
  "dimensions": ["region_code", "sku"],
  "filters": [{"field": "region_code", "op": "eq", "value": "EAST"}],
  "time_range": {"grain": "week", "range": "last_week"},
  "view": "sales_ops"
}

Linking 失败通常表现为查询合法但口径错误,而非 SQL 语法错误。比如链接到废弃列、跨 View 组合字段、把同名不同义字段当成同一维度。DataAgent 应把候选、得分、最终选择和消歧原因写入 Trace,便于第38章回放。Linking 还需要评测集。评测样本除了工程师编写的标准问题,还要包含真实用户说法、缩写、错别字、跨部门叫法和需要拒答的边界问题。每个样本至少标注期望 Metric、Dimension、View、是否需要追问,以及必须排除的错误候选。这样才能发现模型看似答对 SQL、实际选错口径的问题。历史成功 Run 可以作为 Linking 的候选信号,但必须带版本校验。上个月某个用户问过“华东销售”,系统成功使用了 gmv_ops@2025Q1,这只能说明当时的绑定有效。如果语义层升级到 2025Q2,历史 Run 只能进入候选集,最终绑定仍要按当前版本和 View 重新确认。向量检索也要限制范围。把全库列名和注释都放进向量库,召回相似字段很容易;但如果不先按 View、租户和权限过滤,模型可能看到不该看的字段。正确顺序是先过滤可见范围,再在可见范围内召回和 rerank。检索负责辅助消歧,权限仍由语义层和 Policy 控制。


33.4 指标冲突、版本与适用范围

企业里经常存在多个合法口径。财务团队可能维护不含税 GMV,运营团队可能维护含促销调整的运营 GMV;总部可能有集团口径,区域团队可能有本地口径;2024 年和 2025 年的定义也可能不同。DataAgent 如果把这些冲突隐藏起来,用户会以为系统返回的是唯一事实。

图33-2:Glossary 多 Metric 消歧流程

图33-2:Glossary 多 Metric 消歧流程。来源:本书自绘。Alt text:当一个术语匹配多个 Metric 时,流程按视图作用域、用户角色、历史偏好逐步缩小候选,必要时向用户追问。

表33-4:指标冲突时的处理策略。来源:本书整理。

情况 处理方式 用户可见表达
View 过滤后唯一 自动选择 写出指标 title 和版本
同一 View 下仍有多个 追问或使用默认 Metric 说明默认来源
指标版本跨期 使用生效期匹配 标注 metric_id@version
无安全匹配 拒答或转人工 说明缺少可用口径

版本解决“同一指标随时间演变”的问题,适用范围解决“同一指标对谁有效”的问题。Run 中至少要记录 metric_idversion、生效时间、View、租户和默认过滤。用户追问“你刚才用的是哪个 GMV”时,系统应能直接回答,不要重新解释一遍自然语言。强制全公司只有一个口径,能减少对话复杂度,但在多业务线企业中经常不现实。允许多口径并存,则必须把选择过程显性化。更危险的是后台多口径并存,前台却只显示“销售额”。这种做法短期体验简单,长期会让 DataAgent 和正式报表无法对账。

指标版本变更要影响 DataAgent 的行为。新版本发布后,简单覆盖旧定义会破坏历史报告复现,未完成 Run 也可能仍在使用旧版本。比较稳的方式是新旧版本并存一段时间,语义层返回版本生效期,Planner 按问题的时间范围和当前 View 选择版本。跨版本对比时,系统应标注“口径发生变更”,必要时要求人工确认。用户默认策略也要可审计。运营总监默认使用运营 GMV,财务 Controller 默认使用财务 GMV,这种默认来自组织策略,而非模型偏好。策略来源、版本和适用角色应写入 Trace。否则同一句“销售额”在不同用户那里得到不同数字时,平台无法解释差异来源。当冲突无法消解时,拒答比错答更好。DataAgent 可以说“当前语义层中存在两个销售额口径,请选择运营 GMV 或财务 GMV”,也可以提供简短差异说明。用户完成选择后,系统再继续执行。这样的交互会多一步,但能避免把口径分歧埋进最终数字。


33.5 可信上下文:权限、血缘、质量和新鲜度

指标口径回答“数字怎么算”,可信上下文回答“用户能不能看、数据从哪来、质量如何、同步到什么时候”。DataAgent 只返回数字时,用户无法判断结果能不能进入会议材料;必要的权限、血缘、质量和新鲜度信号应写入回答脚注和 Trace。

表33-5:可信上下文的来源与用途。来源:本书整理。

维度 来源 DataAgent 用途
权限 语义层 RBAC、Policy 执行前拦截越权查询
血缘 OpenLineage、DataHub、元数据服务 说明数据来源和模型版本
质量 dbt tests、Great Expectations 质量异常时降低结论强度
新鲜度 分区时间、同步任务状态 标注数据截至时间或拒答

一次华东下滑分析中,trusted_context() 可能返回 View、policy 引用、底层表、模型版本、质量状态和最大同步时间。Planner 不需要把这些原始 JSON 全部展示给用户,但应转成必要的自然语言脚注。例如“数据来自 orders_fact v3,截至 2025-06-14 06:00 同步;SKU 空值率略高,下钻结论仅供参考。”如果新鲜度超过 SLA,系统可以拒答、提示重试,或进入 HITL 等人确认是否仍展示。多源查询时,还要避免只标注最快的数据源;更可靠的做法是取最差新鲜度,或分别标注关键数据源的同步时间。可信上下文要与 Memory 分开命名。Memory 可以记录用户偏好同比展示,Org Context 可以记录区域组织口径,语义层负责 Metric 定义和版本,元数据服务负责质量和新鲜度。把这些来源混在一个“上下文”字段里,容易让模型把偏好当事实,把旧记忆当口径。

可信上下文在回答中的呈现要有层次。普通查询不必展示完整血缘图,但至少应说明指标口径和数据时间;质量异常时应加一句限制条件;正式报告应把血缘、质量状态和执行 SQL 放到附录或审计面板。展示过多会打扰业务用户,展示过少会削弱信任。产品上可以把简短脚注放在正文,把完整证据放在可展开区域。质量信号还要影响结论强度。如果 SKU 空值率略高,系统可以继续回答 Top 品类,但应弱化 SKU 级结论;如果事实表延迟超过 SLA,系统应拒绝生成“最新”结论;如果血缘中某个上游任务失败,报告应进入人工确认。可信上下文会改变 Planner 是否继续、如何表达和是否需要 HITL。

多源查询尤其需要谨慎。一个问题可能同时读取订单表、退货表和促销表。每个数据源的新鲜度和质量状态不同,回答中应展示整体可用性。只展示状态最好的数据源,会让用户误以为所有数据都处在同一时间截面。对于经营分析,通常应取最保守的同步时间,或者明确说明“订单数据截至 06:00,退货数据截至 04:00”。


33.6 语义层接口与 DataAgent 查询链路

mini-platform 中,语义层目标接口位于 infra/semantic_layer/,DataAgent 的 Linker 位于 agents/data_agent/。当前仓库中部分实现仍是目标契约,本章重点是接口形状和依赖方向。

mini-platform/infra/semantic_layer/
├── client.py
├── models/
└── __init__.py

mini-platform/agents/data_agent/
└── linker.py

resolve_metric() 负责把口语指标解析为候选 Metric;compile_query() 负责把已消歧的 Metric、Dimension、filter 和 time range 编译成可执行查询;trusted_context() 负责返回权限、血缘、质量和新鲜度。Planner 可以读取结果,Measure 聚合逻辑则由语义层保持不可改写。

{
  "metrics": ["gmv_ops"],
  "dimensions": ["region_code", "sku"],
  "filters": [{"field": "region_code", "op": "eq", "value": "EAST"}],
  "time_range": {"start": "2025-06-09", "end": "2025-06-15", "grain": "week"},
  "view": "sales_ops",
  "tenant_id": "demo-tenant"
}

生产落地时,至少要守住四条线:生产查询经语义层 View,避免 DataAgent 长期直连物理表;Metric 变更有版本、owner 和审批记录;Linking 日志保留候选和最终选择理由;新鲜度或质量异常要能影响回答,不能只写进后台日志。常见故障也集中在这些边界。View 过大时,Linking 仍会超出上下文,需要按意图生成子 View;IAM 未注入 semantic_view 时,应拒答,降级到全库会放大越权风险;历史成功 SQL 的 Metric 版本过期时,需要重新校验版本;Cube 或 MetricFlow 冷启动超时时,应让 Run 失败或重试,不能让模型绕过语义层直接写物理 SQL。

落地时可以先实现一个窄接口,不必一次性接完整语义层产品。早期只需要支持核心 Metric、常用 Dimension、角色 View、Glossary 和 compile_query();等问数链路稳定后,再接入更多血缘、质量和复杂 Join 能力。接口要保持稳定,底层可以从自研 YAML 逐步迁移到 Cube 或 MetricFlow。测试也要围绕接口做。resolve_metric() 测歧义和拒答,compile_query() 测默认过滤和 View 限制,trusted_context() 测质量和新鲜度异常,Linker 测候选召回和版本一致性。只测最终 SQL 是否能执行,覆盖不到语义层最关键的风险。

语义层变更还要有发布纪律。新增 Metric、废弃别名、修改默认过滤、调整 View 权限,都会改变 DataAgent 的回答。每次变更都应生成影响范围:哪些金标准问题会受影响,哪些报告模板引用了该 Metric,哪些用户默认策略需要更新。变更发布后,旧 Run 仍按旧版本回放,新 Run 才使用新版本。否则用户在复盘上月报告时,看到的可能是今天的口径解释。运营上,语义层团队需要定期查看 DataAgent 失败样本。高频澄清说明 Glossary 不够清楚;高频拒答说明 View 设计过窄或权限提示不够明确;高频口径投诉说明 Metric 标题、默认策略或回答脚注需要改。DataAgent 除了消费语义层,也会把真实业务问法反馈回数据治理。


33.7 语义层进入生产链路的验收标准

语义层进入 DataAgent 生产链路后,就不再只是指标字典。它要同时服务 NL2SQL、权限过滤、结果解释、血缘追踪和评测集构建。一个指标是否可用,除了看公式能否编译,还要看版本、适用范围、维度约束、数据新鲜度和负责人是否明确。否则模型即使找到了指标名,也无法判断该指标是否适合当前问题。语义层与 NL2SQL 的关系要保持单向约束。NL2SQL 可以根据用户问题选择指标、维度和过滤条件,口径来源必须是已登记的 Metric;执行引擎可以编译 SQL,敏感明细访问仍要经过语义层和 Policy。这样的限制会让早期能力显得保守,却能减少“SQL 能跑但业务不认”的问题。

权限也应在语义层阶段尽早介入。若模型先看到完整 schema,再在执行前过滤权限,敏感表名、字段名和业务含义已经进入上下文和 trace。更稳的方式是先按用户、租户、数据域生成可见 Linked Schema,再交给 NL2SQL。这样模型只能在允许范围内生成查询,后续 Policy 仍负责执行前二次校验。验收还要包含“解释是否可被业务复核”。很多语义层测试只检查 SQL 是否编译,或者指标公式是否返回数值。DataAgent 还需要把指标标题、版本、默认过滤和数据时间写给用户看。业务用户读到“运营 GMV gmv_ops@2025Q1”时,应能知道它和财务收入不同;审计人员回放 Run 时,应能看到这个版本当时为什么适用。解释不可复核的语义层,即使编译正确,也很难支撑生产问数。语义层还要反哺评测。每次 NL2SQL 失败,都应标注失败原因:术语未覆盖、指标版本冲突、字段解释不足、权限过滤后候选缺失,还是模型选择错误。只有把这些原因回写到 Glossary、Metric 和 View 的治理流程,DataAgent 才会越用越稳。否则评测只会告诉团队“答错了”,不会告诉团队该修语义层还是修 prompt。

33.8 语义层变更的回归治理

语义层一旦进入生产,就要像软件版本一样发布。一个指标公式、维度枚举或字段别名的变化,会影响 NL2SQL 生成、历史报告复现、评测集结果和用户对口径的理解。平台应把语义层变更当成可发布对象:有版本、有评审、有回归、有灰度,也有回滚路径。最容易出问题的是“看似同义”的业务词。经营团队把“GMV”改成“成交额”,财务团队把“净收入”调整为扣除返利后的口径,区域团队把“华东”从销售组织改成履约组织,这些变化都可能让历史问题得到不同 SQL。模型不会天然知道口径变更背后的组织语义,它只会在可见上下文里选择最相近的解释。因此,Glossary 的别名、Metric 的版本和 View 的适用范围必须一起发布。

语义层回归样本应覆盖三类问题。第一类是稳定问题:原本能回答的问题,在口径变更后仍应得到同样业务含义的结果,或明确提示口径发生变化。第二类是边界问题:用户请求不在当前权限、时间范围或组织范围内时,系统应拒绝或澄清,选择相近字段凑出答案会制造错误信心。第三类是解释问题:结果返回后,报告应能说明使用了哪个指标版本、哪些过滤条件和哪些数据快照。这套治理会增加语义层发布成本,但能避免更昂贵的返工。没有版本治理时,DataAgent 的错误常表现为“SQL 没错,但业务不认”。有了回归治理,团队可以把争议定位到具体口径:是术语没有覆盖,是指标版本不对,是权限过滤改变了候选 schema,还是模型在多个合法口径之间选错了。问题被拆开之后,才有可能持续改进。

33.9 语义层与权限链路的共同设计

语义层经常被当成数据建模问题,权限则被当成安全系统问题。DataAgent 上线后,这两件事必须一起设计。模型看到的字段、指标和维度,已经会影响后续生成 SQL 的可能空间。如果权限只在 SQL 执行前拦截,模型仍可能在 prompt、trace 或错误消息中暴露用户无权知道的字段含义。更稳的方式,是在 Linked Schema 阶段就生成“按用户裁剪后的语义视图”。裁剪后的语义视图除了删表删字段,还要同步调整解释文本。一个用户看不到客户手机号字段时,字段说明、示例 SQL 或指标解释里也不应暴露它的业务含义。一个租户不能访问某区域数据时,维度枚举和示例问题也要随之收缩。否则模型虽然无法执行越权 SQL,却可能通过解释文本泄露组织结构或数据存在性。

这会影响语义层缓存设计。许多系统希望把 schema context 缓存在模型侧或应用侧,以减少延迟;但语义上下文一旦和用户权限绑定,全局复用就会带来越权风险。平台可以缓存公共指标定义和字段元数据,但最终进入模型的 Linked Schema 应按租户、角色、数据域和时间窗口生成,并记录版本。第38章的 Trace 至少要能说明某次 Run 使用了哪份语义视图,而非只记录“使用了语义层”。

权限链路还要支持业务解释。用户无权查看明细时,系统如果只返回技术报错,用户不知道下一步该申请权限还是改问聚合指标。更好的回答是说明可以查看的聚合层级、可申请的权限路径,或可转人工的处理方式。这样 DataAgent 不会因为安全边界变得不可用,也不会为了体验牺牲治理。语义层在这里承担的是“可见能力说明”的角色:告诉模型和用户,在当前权限下可以问到什么程度。

33.10 语义层变更的发布纪律

语义层一旦进入 DataAgent 主链路,就要按发布对象处理。指标口径、维度层级、同义词、字段别名和权限标签的变化,都会改变 NL2SQL 的候选空间,也会改变报告层对结果的解释方式。很多问数事故并非模型突然变差,而是语义层发生了未被评测覆盖的变化:一个字段从订单日期改成出库日期,一个指标把退款排除口径调整到新的状态码,或者一个业务词在不同数据域里被复用。读者在设计平台时,要把这些变化当成可发布的软件变更,而非后台运营人员随手维护的词表。

语义层发布至少需要经过三类校验。第一类是静态校验,检查指标引用的字段是否存在、聚合函数是否与字段类型匹配、时间粒度是否能向下钻取、权限标签是否完整。第二类是回归样本校验,把历史高频问题、事故问题和业务审核问题重新跑一遍,比较生成 SQL、执行结果、解释文本和 EvidenceRef 的变化。第三类是影响面校验,标出哪些 Agent、报表、数据产品和评测集会受到影响。只有三类校验都能留下记录,语义层版本才适合进入灰度。

灰度发布只看回答是否“看起来正确”,会漏掉 schema linking 和解释层的变化。平台应当记录旧版本和新版本在同一批问题上的 schema linking 结果、SQL 差异、执行耗时、返回行数和指标解释差异。对于数值变化,审核人需要知道变化来自口径调整、数据刷新、权限收缩还是生成错误。对于解释变化,审核人需要看到 EvidenceRef 是否仍然指向同一组指标和数据来源。这样做会增加发布检查,但能让 DataAgent 的行为变化可定位。没有这层纪律,后续第34章的 NL2SQL 校验、第38章的 Trace 回放和第39章的评测都只能看到现象,很难追到根因。

33.11 语义层在事故复盘中的定位

DataAgent 回答错误时,团队容易把问题直接归因于模型。但在生产环境里,语义层通常要先被排查。一个完整的复盘应当从用户原始问题开始,依次查看术语识别、数据域选择、指标匹配、维度过滤、权限裁剪、SQL 生成和报告解释。只要其中一个环节没有版本记录,复盘就会停在猜测层面。语义层工程的价值,正是在这些环节之间提供可检查的中间状态。事故复盘还要区分“语义层定义错误”和“语义层覆盖不足”。前者需要修正指标或字段关系,并触发历史样本回归;后者需要增加同义词、业务术语、示例问题或数据域说明。两类问题的修复方式不同,全部交给 Prompt 调整只会掩盖责任边界。Prompt 可以提示模型更谨慎,指标治理和权限系统仍要在语义层中完成。平台把复盘结论回写到语义层时,也要保留来源:来自业务审核、线上投诉、评测集失败还是数据质量告警。来源不同,置信度和发布节奏也不同。

在第32章的总体架构里,语义层处在用户问题和执行系统之间;在第38章的 Trace 体系里,它又是每次 Run 的中间证据。把这两层视角合起来,语义层就重点落在 DataAgent 可治理性的入口,问数知识库只是其中一部分。它既决定模型能看到什么,也决定平台事后能解释什么。早期系统可以先从少量核心指标做起,但必须从一开始就保存版本、样本和发布记录,否则后面很难补齐可信问数所需的证据。

33.12 语义层与数据质量的联动

语义层负责暴露数据质量状态,数据质量治理本身仍由数据平台承担。用户问“本月收入为什么下降”时,如果底层明细表延迟、维度表缺失、指标刷新失败或异常值未处理,DataAgent 给出确定解释会误导决策。语义层应把数据新鲜度、质量规则、异常告警和适用范围提供给 NL2SQL 和报告层,让回答在证据不足时保持克制。数据质量状态还涉及查询生成。某个指标当天未刷新,系统可以改用上一个完整账期,也可以要求用户确认是否接受未完成数据;静默混用新旧数据会让结果难以复核。某个维度质量不稳定,系统应避免把它作为归因结论的唯一依据。语义层把这些约束写进上下文,模型才有机会生成合适的查询和解释。这类联动让语义层从“指标字典”升级为“可信上下文服务”。它向上服务自然语言理解,向下连接数据治理,横向连接权限和质量。DataAgent 的可信度往往取决于这些上下文是否完整,而非模型是否更会写 SQL。

质量状态还要有用户可理解的表达。后台告警可以写成分区延迟、唯一性校验失败、外键缺失或空值率超阈值;业务回答直接抛出这些技术词,用户仍然不知道结果能不能用。更合适的表达是说明影响范围,例如“订单数据已同步到今天 06:00,但退货数据延迟到 04:00,本次毛利分析暂不用于关账判断”。这类表达让业务知道结果能用到什么程度,也让平台保留了证据。

质量信号还涉及自动化程度。数据新鲜度正常、指标版本稳定、权限清楚时,DataAgent 可以自动完成只读问数;质量异常但仍可参考时,系统可以生成带限制说明的草稿;质量严重异常时,系统应拒绝生成正式结论,并把任务转给数据负责人或等待刷新。把质量状态接入 Runtime 后,DataAgent 才能根据证据强弱调整任务路径,而非一律生成流畅答案。从组织协作看,语义层团队也需要固定的反馈入口。业务用户发现口径不符,DataAgent 应能记录问题对应的 Metric、View、用户角色和原始问法;数据团队修正后,应能看到哪些验收样本因此变化。这样语义层维护不再是后台文档工作,而是 DataAgent 生产运营的一部分。

语义层和数据质量的关系,还要落到责任分工上。数据平台团队负责质量规则、同步任务和血缘信息,DataAgent 团队负责把这些状态转成任务决策和用户表达,业务团队负责判断某个质量问题是否影响本次决策。比如退货数据延迟两小时,在日常经营看板里可能可以接受,在财务关账里则必须停止生成结论。平台不能替业务判断影响程度,但要把足够清楚的状态交给业务和审批人。

质量异常还应进入后续改进。某个指标反复因为上游同步延迟导致 DataAgent 拒答,说明问题可能不在问数产品,而在数据链路 SLA;某个维度反复空值率过高,说明语义层需要调整可下钻范围;某类报告经常因为质量限制被退回,说明模板应把风险提示放得更靠前。DataAgent 的失败样本能把这些问题暴露出来,语义层团队需要把它们纳入数据治理工作,不能只修自然语言映射。

最终,可信问数依赖的是一组共同工作的系统。模型负责理解和生成,语义层负责口径和可见范围,元数据服务负责质量和新鲜度,执行器负责只读和资源保护,Trace 负责回放。任何一层缺失,用户都可能看到一个表达顺畅但无法复核的数字。本章把语义层放在 DataAgent 主链路中讨论,就是为了让读者看到这些责任如何连接起来。语义层还要处理“局部正确”的问题。一个指标在总部经营会中定义清楚,在区域经营会上却可能需要额外过滤加盟门店;一个品类维度在零售业务中稳定,在供应链分析里却需要映射到仓库分类。DataAgent 如果只拿一个全局定义到处使用,就会在局部场景里答错。系统要把 Metric、View、角色和场景组合起来判断。全局口径解决一致性,场景 View 解决适用性,两者缺一不可。

这种设计会让语义层比传统指标字典更复杂。它需要同时有给人看的解释,也要有给机器执行的约束;需要同时支持稳定指标,也要允许某些业务域保留差异;需要同时让 DataAgent 少追问,又要在口径冲突时明确停下来。团队在早期可以只覆盖少量高频指标,但这些指标必须从一开始就包含 owner、版本、生效范围、默认过滤和质量信号。否则后续扩展到更多数据域时,早期的宽松做法会变成系统性风险。

评审语义层时,业务负责人也要参与。工程团队能判断字段是否存在、SQL 是否能编译、权限标签是否完整,却不一定能判断“销售额”在某个会议场景中应不应该扣除退货。业务负责人确认口径后,DataAgent 才能把默认策略写入 Profile 或 View。这个过程看起来像治理流程,实际是在为模型减少自由猜测空间。语义层还应承担培训作用。业务用户第一次看到 DataAgent 的回答时,往往会先看结论,再追问“这个销售额是哪一个销售额”。如果回答脚注、指标标题和可展开说明都来自同一套语义层,用户会逐渐形成稳定预期:什么问题可以直接问,什么问题需要先确认口径,什么结果只能作为草稿参考。这种预期建立以后,系统使用成本会下降,数据争议也更容易被定位到具体指标或版本。

语义层会直接进入产品体验、会议讨论和审计复盘,不再是后台工程资产的附属物。团队在设计 DataAgent 时,应把语义层当成用户信任的一部分来维护,而非只在 SQL 生成失败时才回头补字段说明。早期落地时,可以少做指标,但责任字段要齐。每个上线指标至少要有 owner、适用场景、默认时间口径、权限范围和版本说明。范围窄一点,系统仍然能建立信任;责任字段缺失,后续每次争议都会回到人工解释。

33.13 语义层运营中的口径争议处理

语义层上线后,口径争议会持续出现。同一个“活跃客户”“新增收入”“流失率”,在销售、财务、运营和管理层之间可能有不同解释。DataAgent 把这些指标放进自然语言回答后,争议会变得更明显,因为用户看到的是一句确定结论。平台需要把争议处理做成语义层运营的一部分,而不是在每次投诉后临时解释。

争议处理应从样本开始。每次用户质疑指标,平台记录用户问题、使用指标、语义层版本、SQL、数据快照、回答文本、争议原因和最终裁定。若争议来自字段选择错误,修 schema linking;若来自指标定义冲突,修语义层版本和适用范围;若来自数据延迟,修新鲜度提示;若来自业务口径不统一,则需要业务 owner 裁定。不同原因对应不同修复路径,不能全部归为模型理解错误。

语义层还要保存历史裁定。某个指标口径在六月改变后,五月的回答仍应能按当时版本解释。用户复盘历史会议材料时,平台不能用当前口径覆盖旧结果。语义层运营的质量,体现在它能让 DataAgent 的答案随业务更新,同时保留历史答案的解释能力。

33.14 语义层样本池的分层维护

语义层样本池要分层维护,否则很快会变成一堆难以使用的问句。第一层是基础覆盖样本,验证核心指标、常用维度、默认时间范围和权限裁剪能正常工作;第二层是业务争议样本,来自用户质疑、会议复盘和口径裁定;第三层是事故样本,记录曾经导致错误回答、错误 SQL 或错误解释的问题;第四层是发布样本,用来评估语义层版本变更对关键任务的影响。不同样本的 owner、发布门槛和复审周期不同,不能全部放进同一个“问数测试集”。

样本池还要保存中间过程,最终答案只是其中一项。一个样本应记录用户原话、识别出的业务术语、候选 Metric、候选 View、最终选择、被过滤的字段、生成 SQL、执行结果、解释文本和 EvidenceRef。这样当样本失败时,团队能判断问题发生在术语识别、schema linking、权限裁剪、SQL 生成还是解释层。只保存“正确答案”会让回归变成黑盒测试,修复效率很低。

分层样本能帮助团队控制发布成本。核心指标每次发布都要跑,低频业务争议可以按月复审,历史事故样本在相关语义对象变化时触发,探索性样本可以留在观察池。这样语义层发布不会被无关样本拖慢,也不会因为样本太少而漏掉高风险变化。对于早期平台,先维护少量高质量样本,比追求覆盖所有问法更有价值。

样本池最终要服务协作。业务 owner 用样本确认口径,数据团队用样本发现质量和血缘问题,平台团队用样本验证 Linking 和 Trace,评测团队用样本判断 DataAgent 行为是否稳定。样本池把“口径是否对”这类讨论变成可复现材料,减少了纯靠会议解释的成本。语义层能否长期稳定,取决于这些样本是否持续更新,而不是指标 YAML 是否写得整齐。

33.15 语义层变更的用户沟通

语义层变更会直接改变用户理解数据的方式。指标定义调整、默认时间口径变化、维度归属修正、废弃字段下线、权限规则收紧,都会让同一个问题得到不同回答。若平台只在后台更新 YAML 或指标配置,用户会把变化理解成 Agent 不稳定。语义层发布需要用户沟通,让业务方知道哪些问题会受影响,历史答案如何解释,新答案从什么时候生效。

用户沟通不等于把所有技术细节暴露出去。更合适的方式是给高频指标和关键业务域提供简短变更说明:变更对象、旧口径、新口径、影响范围、生效时间、历史结果处理方式和联系人。DataAgent 在回答受影响问题时,可以在脚注中提示“本指标已在某日期更新口径”,并提供展开说明。这样用户能把数字变化和口径变化联系起来,而不是反复质疑模型和数据。

沟通还要进入产品交互。对低风险指标,系统可以在回答后显示变更提示;对高风险经营指标,系统应在生成正式报告前要求确认口径;对历史会议材料,系统应保留当时语义层版本,不用当前口径覆盖旧结论。若用户追问“为什么和上个月不同”,DataAgent 应能从语义层变更记录中取到解释,而不是重新编写一个看似合理的原因。

早期可以先为核心指标建立语义层变更公告。公告进入指标详情页、DataAgent 回答脚注和报告发布记录。每次公告都关联样本回放和业务 owner 裁定。这样语义层不会只是后台配置,而会成为用户信任和组织沟通的一部分。

33.16 语义层变更的用户沟通

语义层变更会直接改变 DataAgent 的回答。指标口径调整、维度层级变化、字段别名修改、权限规则更新、血缘修正,都可能让同一个自然语言问题生成不同 SQL 或不同解释。若用户只看到答案变化,很难判断平台是否变好,还是口径发生了变化。语义层变更需要用户沟通机制,而不是只在数据团队内部发布。

沟通内容要面向任务。用户不需要阅读完整字段 diff,但需要知道哪些问题会受到影响,旧口径和新口径的差异是什么,历史报告是否需要重新生成,哪些场景进入过渡期。对于经营分析类任务,平台可以在回答中提示“该指标已在某版本调整口径”;对于正式报告,系统应要求重新引用新的 EvidenceRef;对于自动审批,变更期间可以暂停自动结论。

早期可以为语义层发布生成变更摘要:影响指标、影响维度、典型问题、样本回放结果、历史 artifact 处理方式和业务 owner 确认。摘要进入 DataAgent 上下文和报告页提示。这样语义层会从 NL2SQL 内部配置扩展为业务用户可理解的分析口径管理工具。

33.17 语义层变更的影响预估

语义层进入生产后,新增能力不能只看功能是否可用,还要看运行证据能否被不同角色复用。平台需要把指标依赖、下游问题、样本覆盖、权限变化、发布时间和用户通知记录成稳定字段,并和发布单、Trace、评测样本以及事故记录关联起来。这样一次线上问题发生后,团队可以沿着同一组事实判断影响范围、责任归属和修复顺序,而不是在模型日志、业务日志和人工说明之间来回拼接。

这类证据还要服务相邻章节的能力。它和第34章 NL2SQL、第36章报告和第39章 Eval相连:上游能力提供输入假设,下游能力使用执行结果,治理能力负责保存证据和复审结论。若这些材料没有统一编号和版本,章节里讨论的工程能力在生产中会被拆散。业务 owner 只能看到用户投诉,平台 owner 只能看到系统错误,安全或合规团队只能看到事后说明,最后很难判断问题到底来自数据、模型、工具、流程还是组织责任。

生产环境中常见的风险包括指标口径改变后旧问题继续命中、新权限未进入生成链路、报告解释和 SQL 结果不一致。这些问题在演示阶段不明显,因为演示通常只覆盖成功路径;上线后,用户会带来边界问题、重复请求、权限变化和长时间运行状态。平台团队应把失败样本纳入发布节奏,记录哪些样本需要阻断发布,哪些样本可以通过降级处理,哪些样本需要业务 owner 接受剩余风险。

语义层变更应先做影响预估,再进入样本回放和业务通知。这份记录不需要复杂,但要包含时间、版本、owner、样本、处置动作和下次复查条件。没有这些字段,复盘会停留在口头经验;有了这些字段,平台才能把一次问题转成后续发布、评测和培训材料。

早期平台可以从少量高风险场景开始。先选择调用量高、业务影响大或涉及敏感数据的路径,要求每次变更都留下证据包,再逐步推广到普通场景。这样章节里的能力不会停留在概念层,而会成为可运行、可解释、可退回的工程系统。

本章小结

语义层是 DataAgent 可信问数的地基,负责指标、维度、Join、权限和版本。DataAgent 应消费 Metric、Dimension、View 和 Glossary,而非把全库 DDL 直接塞进模型上下文。Schema Linking 要在 Glossary、View、向量检索和历史 Run 之间做消歧,并把选择过程写入 Trace。指标冲突不能被隐藏,Run 和回答都应记录 metric_id@version、View 和默认来源。权限、血缘、质量和新鲜度属于可信上下文。它们应进入回答脚注和审计回放,让用户知道数字来自哪里、是否有权查看、口径是否稳定。

参考文献

Cube. (2025). Introduction: Cube semantic layer. https://cube.dev/docs/product/introduction

dbt Labs. (2024). About MetricFlow. dbt Developer Hub. https://docs.getdbt.com/docs/build/about-metricflow

Liu, X., et al. (2025). A survey of Text-to-SQL in the era of LLMs. IEEE TKDE, 37(10), 5735-5754. https://doi.org/10.1109/TKDE.2025.3592032

Lei, F., et al. (2024). Spider 2.0: Evaluating language models on real-world enterprise text-to-SQL workflows. ICLR 2025. arXiv:2411.07763. https://arxiv.org/abs/2411.07763

Talaei, S., et al. (2024). CHESS: Contextual harnessing for efficient SQL synthesis. arXiv:2405.16755. https://arxiv.org/abs/2405.16755

OpenLineage. (2024). OpenLineage documentation. https://openlineage.io/docs/