语义层:Semantic Layer¶
本章所属 DDA 层:Semantic Layer
问题¶
为什么 AI 智能体(AI Agent)不应该直连裸库写 SQL?因为裸库不携带语义,Agent 写出的 SQL 没有业务正确性保障。
数据工程师为什么要学语义层(Semantic Layer,SL)?因为它是数据本体(Ontology)的工程化实现,是把上一章定义的"机器如何理解业务世界"变成"Agent 可调用的接口"的那一层。Ontology 回答"业务世界是什么意思",SL 回答"Agent 怎么按这个意思去取数据"。没有 SL,Ontology 就是悬空的概念模型;有了 SL,Agent 才能经稳定接口消费数据,而不是自己拼 SQL。
SL 解决的问题是:让 Agent 经语义接口访问数据,而非裸 SQL——在 Ontology 与消费方之间,SL 既是传递通道(对付传递不可靠),也是产品交付接口(把语义封装为可调用能力)。由此带来口径统一、字段改名不崩、查询可追责;口径漂移、RAG 与 Agent 各说各话,都是这一层失效时的典型症状。
需要强调的是,SL 不只服务 Agent 的结构化查询,也为知识库与检索增强生成(Retrieval-Augmented Generation,RAG)应用提供口径锚点。RAG 生成答案时引用的数据,必须与 SL 定义的业务口径一致,否则 AI 答案里的数字与报表对不上。SL 是跨消费方的单一口径来源,既给 Agent 调用,也给 RAG 生成时对齐数据口径。本章聚焦 SL 本身,RAG 如何对齐口径在后续章节展开。
传统方案¶
传统数据消费里,分析师直接写 SQL。口径写在 BI 语义层或 ETL 注释里。药明诺华的早期实践是:分析师查"在研的 c-Met 抑制剂",自己写:
SELECT research_code
FROM dwd_compound
WHERE target = 'c-Met'
AND status IN ('phase1','phase2','phase3');
字段名 target、取值 c-Met、状态过滤条件,全靠分析师记忆与口口相传。BI 语义层 1 会封装一部分指标定义,但它的服务对象是人读报表,不是 Agent 消费。
为什么失效¶
失效机制有四条,每条都有具体后果。
第一,字段改名即崩溃。上游把 research_code 改成 compound_code,所有依赖这张表的 SQL 与 Agent 提示词全部失效。没有语义层隔离,物理 schema 的任何变动直接冲击消费方。
第二,口径漂移。同一指标"在研化合物数",研发系统按 status IN ('phase1','phase2','phase3') 算,BI 报表把 preclinical 也算进去,Agent 又用了第三种口径。三个数字不一样,没人说得清哪个对。BI 语义层只管报表口径,管不到 Agent。口径不统一的代价,垂直数据行业早算得清楚:付费客户看到两个对不上的数字,信任就崩了,所以它们把单一口径定义点当作产品基础设施来建。语义层(Semantic Layer,SL)把这套经验接到 AI 消费上--同一个指标,报表、Agent、RAG 生成引用同一处定义,谁都不许自造口径。口径漂移是语义传递不可靠最直观的业务后果:同一条"消息"从不同出口发出,内容已经对不上。
第三,Agent 不懂"这张表到底算什么"。Agent 直连裸库时,它看到的是表名与字段名,不是业务语义。它不知道 dwd_compound 里 status='A' 是什么意思,只能猜,猜错就答错。裸库给不了 Agent 业务正确性。
第四,RAG 与 Agent 口径各说各话。没有 SL 时,RAG 应用自造口径,生成的数字与数仓报表不一致;Agent 查的结构化数据与 RAG 答案里的数字也各算各的。用户从 Agent 拿到一个数,从 RAG 答案拿到另一个数,两个数都对不上,因为没有任何一层统一口径。
这里必须澄清一个混淆:语义层不是 BI 语义层。 BI 语义层服务人读报表,容忍口径模糊与人工兜底;SL 服务 Agent 与 RAG 消费,要求契约稳定、单一口径定义点、可程序发现与调用。两者的稳定性、契约、消费要求完全不同。把 BI 语义层当作 SL 用,Agent 与 RAG 消费的稳定性就得不到保障。
flowchart LR
AGT[AI Agent] -->|直连裸库| DB[(裸库)]
DB -.字段改名即崩.-> X1[查询失效]
DB -.口径漂移.-> X2[数字不一致]
DB -.无业务语义.-> X3[Agent 猜测出错]
AGT -->|经 SL| SL[语义层]
SL -->|稳定语义接口| DB
SL -.单一口径.-> OK[业务正确]
RAG[RAG 应用] -->|生成时对齐口径| SL
SL -.统一口径.-> RAG
图:Agent 直连裸库与经语义层消费的对比(DDA 层:Semantic Layer)
解读:上半部分 Agent 直连裸库,遇到字段改名、口径漂移、无业务语义三类失效。下半部分 Agent 经 SL 消费,SL 提供稳定语义接口并向下封装裸库变动,单一口径定义保证业务正确。RAG 也在生成时经 SL 对齐口径,与 Agent 共享同一份口径来源。这张图说明 SL 的价值是隔离与统一:隔离物理变动,统一业务口径,且统一覆盖 Agent 与 RAG 两类消费方。
新的设计思想¶
DDA 方法重新看这一层:Agent 不该写 SQL,该调语义接口。SL 的设计思想有六点。
第一,语义 API 而非语义表。SL 对外暴露的是可调用的语义接口(Semantic API),不是又一张语义表。Agent 调用"查活性化合物"这个接口,不需要知道底层表结构。
第二,单一口径定义点。一个指标只在一处定义,所有消费方共用。"在研化合物数"在 SL 定义一次,报表、Agent、RAG 生成引用它。
第三,版本化。语义接口有版本,破坏性变更新主版本,老版本保留过渡期,消费方有迁移窗口。
第四,Agent 可发现、可调用。SL 的接口元数据本身可被 Agent 查询,Agent 知道有哪些语义接口、各自含义与参数。
第五,拒绝直连裸库。SL 是 Agent 访问数据的唯一通道,裸库不对 Agent 开放。这是边界,不是建议。
第六,跨消费方口径锚点。SL 不只封装 SQL,还封装"业务怎么说"。Agent 查询与 RAG 生成涉及数据时,都引用 SL 的口径定义,保证两类消费方的数字一致。
SL 是 Ontology 的工程化实现接口。Ontology 定义"业务世界是什么意思",SL 把这份意思封装成"Agent 与 RAG 都能调用的接口"。
架构设计¶
flowchart TB
AGT[AI Agent] -->|调用语义接口| SL[Semantic Layer]
SL -->|封装| ONT[Ontology]
ONT -->|绑定| DP[AI Ready Data Platform]
SL -->|翻译为受控 SQL| DB[(数据资产)]
SL -.暴露接口元数据.-> AGT
RAG[RAG 应用] -.生成时对齐口径.-> SL
图:Semantic Layer 在消费链中的位置(DDA 层:Semantic Layer)
解读:Agent 调用 SL 的语义接口,SL 基于下层 Ontology 理解业务语义,把调用翻译为受控 SQL 访问数据资产。SL 同时向 Agent 暴露接口元数据,让 Agent 能发现可调用的接口。RAG 在生成涉及数据的答案时,也向 SL 对齐口径。注意箭头方向:消费方向上指向下,Agent 经 SL、经 Ontology 到数据。SL 不是又一层存储,是消费通道上的语义封装层,且同时服务 Agent 与 RAG。
两层分离是这里的工程关键:语义面(定义业务口径)与数据面(执行物理查询)分开。语义面稳定,数据面可变。底层换表、换引擎,语义面不动,Agent 与 RAG 都不受影响。
工程实践¶
语义接口的定义¶
以药明诺华的语义接口为例,用 YAML 声明:
semantic_api:
name: list_active_compounds
version: 2.1.0
description: 查询活性化合物清单
business_definition: |
通过初筛、进入临床前或临床阶段的候选化合物。
口径:status IN ('preclinical','phase1','phase2','phase3')
parameters:
- name: target
type: string
optional: true
meaning: 按靶点过滤,如 c-Met
- name: phase
type: enum
optional: true
values: [preclinical, phase1, phase2, phase3]
returns:
fields: [compound_id, research_code, target, status]
underlying:
table: dwd_compound
filter: "status IN ('preclinical','phase1','phase2','phase3')"
owner: semantic-platform@novapharm.example
business_definition 是单一口径定义点,所有消费方引用它。underlying 封装了底层表与过滤条件,Agent 看不到也不需要看到。版本号控制变更:加参数是小版本,改口径是大版本。
两层分离¶
语义面负责"业务怎么说",数据面负责"数据怎么查"。药明诺华的实践是把两者分开维护:语义面用 YAML 定义接口与口径,数据面负责把语义翻译为具体 SQL 并执行。底层从 PostgreSQL 换到带向量扩展的引擎,语义面不动,Agent 与 RAG 都不受影响。
这种分离与 dbt MetricFlow 2、Cube 这类工具的思路一致(这些仅为实现选择,不是唯一方案)。它们都把指标定义从查询里抽出来集中管理。本书关心的是分离原则,不是某个工具。
SL 作为 Agent 与 RAG 的共同口径锚点¶
SL 不只服务 Agent 的结构化查询,也服务 RAG 的生成口径对齐。这里说明 RAG 如何消费 SL,而非以 RAG 为设计依据。
RAG 生成时对齐 SL 口径。当 RAG 生成的答案涉及数据指标(如"在研化合物数""c-Met 抑制剂数量"),这些指标的口径必须与 SL 定义一致。RAG 在生成前,从 SL 取对应指标的 business_definition,作为生成约束。这样 RAG 答案里的数字与 Agent 查询的数字、报表的数字三者一致,因为都引用同一份 SL 口径。
Agent 结合 SL 结构化查询与 RAG 知识答案。Agent 完成多步任务时,可能既经 SL 查结构化数据(如"在研化合物清单"),又经 RAG 取知识答案(如"试验终止的合规要求")。两类结果在 Agent 处汇总时,涉及数据的部分都以 SL 口径为准。SL 是 Agent 把结构化查询结果与 RAG 知识答案拼到一起时的口径基准。
口径变更同步两类消费方。SL 的口径定义变更时(如"在研"是否含 preclinical),Agent 与 RAG 都经版本化机制收到通知并迁移。不会出现 Agent 用新口径、RAG 还用老口径的不一致。
SL 的设计原则因此要补一条:口径定义要覆盖 Agent 查询与 RAG 生成两类场景,不能只管 Agent 不管 RAG。
五层 SQL 护栏¶
SL 把 Agent 的查询翻译为受控 SQL 时,需要护栏防止越权与出错。五层护栏由浅入深:
- 语法层:校验 SQL 语法合法性。
- 策略黑名单层:拦截危险操作(DROP、DELETE、无 LIMIT 的全表扫描)。
- AST 列白名单层:解析 SQL 抽象语法树,只允许访问白名单内的表与列。
- 术语语义层:校验查询用的术语是否与 Ontology 口径一致,拦截自造口径。
- 成本估算层:估算查询成本,超阈值拦截或降级,防止 Agent 跑垮平台。
五层叠起来,Agent 经 SL 发出的查询既语义正确又工程安全。注意这套护栏是 SL 的内部机制,不是 Agent 要学的东西。Agent 只管调语义接口,护栏由 SL 自动施加。
MCP 使语义层对 Agent 原生¶
语义层并非只有 AI 时代才需要。垂直数据服务商早就用数据即服务(Data-as-a-Service,DaaS)3 的形态实现了类似的东西:企业征信平台对外提供数百个数据 API,每个 API 背后是一个带口径定义、带 SLA、带版本的数据产品;专利数据平台提供三百多个数据 API 覆盖专利、化学、生物、市场情报,外加六十多个 AI 智能体(AI Agent)API。这些 API 就是语义接口的前身--封装了"业务怎么说",对客户隐藏底层表结构,口径在平台内部统一定义。
AI 时代的变化是:这些 API 从"给人的程序调用"变成"给 Agent 调用",从 REST 接口变成模型上下文协议(Model Context Protocol,MCP)4 工具。SL 暴露为 MCP Server 后,Agent 能像调用内置工具一样调用语义接口,不需要把 SQL 拼进提示词。两家公司都已把数据能力封装为 MCP Server 对外开放。语义层做的事,是把数据产品的交付接口升级为 Agent 原生——产品还是那些产品,通道从 REST 扩到 MCP。MCP 是通道,不是 SL 的定义。
企业转型的关键不是先上 MCP,而是先让内部能力达到数据产品级——每个对外暴露的能力都是语义接口,有单一口径、有版本,而非裸表。启信宝、智慧芽在已有数百个数据 API 的产品目录上叠加 Agent 能力;多数企业若跳过产品化、让 Agent 直连裸库或自建向量库语义,等于新产品消费者接入了一个未完工的产品目录。
最佳实践¶
单一口径定义点:一个指标只在一处定义,杜绝多口径并存。任何重复定义都是隐患。
接口优先于表:对外只暴露语义接口,不暴露表。物理 schema 变动不冲击消费方。
版本化与迁移窗口:破坏性变更新主版本,老版本保留过渡期,给消费方迁移时间。
护栏内建:SQL 护栏是 SL 的一部分,不是外挂。Agent 的查询必须过护栏,没有旁路。
与 Ontology 同源:SL 的口径定义必须与 Ontology 一致,不能自造。SL 是 Ontology 的工程投影。
不开放裸库给 Agent:这是硬边界。Agent 一旦能直连裸库,SL 的所有保障都失效。
口径覆盖两类消费方:SL 口径要覆盖 Agent 查询与 RAG 生成两类场景,不能只管 Agent 不管 RAG。
延伸阅读¶
- 语义层复兴:dbt MetricFlow 开源相关资料;Cube、AtScale、LookML 语义层对比资料;Open Semantic Interchange(OSI)标准。
- BI 语义层与 Agent 语义层的区别:语义层复兴讨论中关于 Agent 消费与 BI 消费差异的资料。
- MCP 协议:模型上下文协议(Model Context Protocol)规范与语义层暴露为 MCP Server 的实践资料。
Checklist¶
- Agent 是否经语义接口消费数据,而非直连裸库写 SQL?
- 每个指标是否有单一口径定义点,无重复定义?
- 语义接口是否版本化,破坏性变更是否有迁移窗口?
- 接口元数据是否可被 Agent 程序发现与调用?
- 是否澄清了 SL 与 BI 语义层的区别,未混用?
- SQL 护栏是否内建,覆盖语法、黑名单、列白名单、术语、成本五层?
- 语义面与数据面是否分离,底层变动不冲击 Agent?
- SL 口径是否与下层 Ontology 同源,未自造口径?
- SL 口径是否覆盖 Agent 查询与 RAG 生成两类场景,RAG 生成时是否对齐 SL 口径?
自检(依据 WRITING_STYLE §9):本章为何需要?因为 Agent 不应直连裸库,且 RAG 生成也需要口径锚点。数据工程师为何关心?SL 是 Ontology 的工程化实现,是数据工程师最该负责的 Agent 与 RAG 共同消费通道。解决什么问题?让 Agent 经稳定语义接口取数据、RAG 生成时对齐口径,口径统一、字段改名不崩。属哪一 DDA 层?Semantic Layer。改变什么架构?把数据消费从裸 SQL 转为语义 API,语义面与数据面分离,且 SL 成为 Agent 与 RAG 的共同口径锚点。
-
BI 语义层(BI Semantic Layer)的概念,参见 LookML、dbt MetricFlow 等工具的文档与语义层复兴相关讨论。 ↩
-
dbt MetricFlow 是 dbt 开源的语义层引擎,用 YAML 声明指标口径并从 SQL 抽离集中管理;Cube、AtScale、LookML 同属语义层工具家族,参见各自开源项目文档与语义层对比资料。 ↩
-
数据即服务(Data-as-a-Service,DaaS)是把数据封装为可调用 API 产品对外交付的模式,客户按调用或订阅付费,是数据服务商的主要商业模式。 ↩
-
模型上下文协议(Model Context Protocol,MCP)是让工具对 AI 智能体原生可调用的协议规范,参见 MCP 规范文档。 ↩