ZOT(Zai Ontology)把「客户、订单、毛利、齐套」这些经营概念, 从各家 ERP 的字段里抽出来,变成一份可版本化、可签字、可审计的资产。 上层 ZAI 不碰语义,只调工具;下层 ZDC 不认口径,只认能力位; 口径只在这里定义一次。
# 1) 校验本体:错误定位到 文件:行:字段 $ zot-validate ontology/ ✓ 14 objects · 91 properties · 25 relations ✓ 7 terms · 12 mappings · 6 constraints ✗ metrics/M-KIT-01.yaml:9:dimensions 引用了未定义的对象 production_order # 2) 把一句经营问题解析成语义契约 $ zot resolve "上个季度毛利为什么掉了" { "terms": ["gross_margin", "customer", "month"], "measure": { "kind": "ratio", "numerator": "revenue", "denominator": "revenue_cost" }, "constraints": ["c-order-completed", "c-exclude-internal"], "mappings": [ { "connection": "kingdee-cloud", "confidence": "high" } ], "signature": { "status": "published", "signed_by": "财务负责人" } }
工业客户的验收动作只有一个:点回原始单据。这个动作能不能成立,取决于「口径」是不是一个可以被指着看的东西。
销售额在报表里、在驾驶舱里、在老板手机里各算一遍,差别藏在一条 WHERE 里。人一走,口径就失传;新人只能重新猜一遍。
计算逻辑写成 SQL 字符串时,金蝶换 SAP 就是推倒重来——虽然业务口径一个字都没变。这是「实施公司」而非「产品公司」的根源。
「只算已完成订单」「排除关联交易」散落在 SQL、散文说明与排除清单里。客户问"这个数字受哪些约束",答不出结构化的答案。
结论出来了,证据是当场拼的:没有采集时间、没有有效期、不能被别的指标复用。审计时只能再跑一遍,结果还可能不一样。
本体不是一份文档。它是运行时的契约:谁问、怎么算、受哪些约束、证据在哪,四件事都有唯一的、可版本化的答案。
繁琐与强关联的物理来源只有一个——每个属性、每个指标都被迫回答"我怎么被过滤、怎么被展示、我从哪张表来"。拆开之后,加行业、换数据源、加约束,都不必动指标本身。
| 层 | 内容 | 变的频率 | 换什么只动这一层 |
|---|---|---|---|
| L1 结构层 | Object / Property(含类型、精度、单位、ref)/ Relation | 低 | 换行业:换对象集合,词汇与契约大部分可复用 |
| L2 词汇层 | Term:纯词汇,带别名、定义、口径范围,不带任何能力字段 | 低 | 加同义词、改定义,不触碰任何查询能力 |
| L3 契约层 | Mapping(概念→落地,可多套)/ Constraint(独立节点)/ Evidence(独立节点) | 中 | 换 ERP:只加一组 mappings;加约束:只加 constraint |
| L4 呈现层 | filter / drill / precision / unit / default_dimensions | 高 | 换前端、换报表引擎:只动呈现配置 |
| L5 执行层 | 编译器:mapping + constraint → SQL(或 DAX / MDX) | 低 | 换查询引擎:只换编译器,口径一行不动 |
code: customer
name: 客户
aliases: [买方, 甲方, 客户单位]
definition: 购买我方产品/服务的组织或个人
scope: 集团口径,含关联方;关联方标记见 constraint
lifecycle: {state: active}
code: c-order-completed targets: [M-SO-AMOUNT-01, M-GROSS-01, M-ORDER-KIT-01] trigger_keywords: [订单, 销售额, 毛利, 齐套] severity: block # block | warn | info expr: "sales_order.status = 'COMPLETED'" # 同一概念可挂多套落地方式 code: map-customer-kingdee term: customer connection: kingdee-cloud target: {table: t_BD_Customer, key: FCUSTID, label: FName} confidence: high
指标卡退化为「视图」:只写 term + measure + constraints 引用,不再复制 WHERE、不再内联表名。一个 term 可以同时挂金蝶与第二数据源两套 mapping,并排对比含税 / 不含税两种口径。(五层分离按 M1–M7 分阶段落地,当前状态见下方「现在到哪一步」。)
「证据」和「约束」不再是查询时临时生成的副产品,而是有编号、可复用、带有效期的节点。这是证据链能落到原始单据的前提。
| 节点 | 回答的问题 | 关键字段 |
|---|---|---|
| Object 对象 | 业务世界里有哪些东西 | 编码 / 名称 / 同义词 / 生命周期 / ref 引用 |
| Property 属性 | 它有哪些事实 | 类型 / 精度 / 单位 / 是否可下钻 / 同义词 |
| Relation 关系 | 它和谁有关,为什么有关 | source → target / 关系类型 / 中文证据句 |
| Term 词汇 | 客户嘴里那个词到底指什么 | 定义 / 别名 / 口径范围 / 状态(在用·废弃·并入) |
| Mapping 落地 | 这个概念在这套系统里怎么取 | connection / 表·列·键 / 过滤 / 聚合 / 粒度 / 置信度 |
| Constraint 约束 | 算的时候必须遵守什么 | targets(可多指标引用)/ 触发词 / 严重级别 / 表达式 |
| Evidence 证据 | 凭什么相信这个数字 | 来源 / 查询 / 结果摘要 / 验证方式 / 采集时间 / 有效期 |
每次发布是一个不可变版本(versions/<v> + active 指针):发布即切换,回滚即改指针,不需要"改回去再改回来"。
草稿版本可以在影子模式跑同一批问题,比对结果差异后再决定发布——口径变更不再靠"上线后看客户反应"。
口径带 signature{status, signed_by, signed_at}:未签字的卡可以算,但不能作为结算、考核与对外披露的依据。
轨迹驱动的自进化闭环:记录真实任务、判定是否该演进、在评测闸门内产出候选、过闸才晋级。LLM 不直连写库。
按工具调用级记录每一次问答:问了什么、调了哪些工具、拿到什么结果、在哪里卡住。可回放、可截断、可脱敏。
双条件触发:新增任务数 + 时间窗。避免"问了两次就改本体"的抖动,也避免半年不演进。
GT 对(标准答案)与 LLM 评判配对调度,聚合门槛不过则不晋级。评分口径固定,不能事后调整。
演进会话是显式状态机(含轮次预算与终止态):产出候选版本 → 人工签字 → 发布;任何一步不达标即回滚。
为什么这么保守:口径是结算与考核的依据。一条"自动优化"的口径如果让客户的毛利数字变了 3%,那不是智能,是事故。
ZOT 以 MCP 工具面向上暴露语义能力:ZAI 的会话、dip-mcp 的实施工具、门户生成器,调的是同一组工具。
| 工具 | 用途 | 返回 |
|---|---|---|
| zot_manifest | 取"本次会话该知道什么" | 把整套本体压成紧凑清单,喂给模型、控制上下文成本 |
| zot_browse | 按关键词找概念 | 候选 term / object,带定义与同义词命中情况 |
| zot_resolve | 把一句话解析成语义契约 | term / measure / constraints / 候选 mappings / 签字状态 |
| zot_validate | 发布前校验 | 引用完整性、类型、必填;错误定位到 文件:行:字段 |
from zot import SemanticStore, SemanticLayer
store = SemanticStore("ontology/")
layer = SemanticLayer(store.load_active())
# 一句话 → 语义契约(不执行查询)
plan = layer.resolve(
mentions=["毛利", "客户"],
dimension="month",
)
print(plan["constraints"]) # 命中的口径约束
print(plan["mappings"]) # 候选落地方式 + 置信度
code: M-GROSS-01
term: gross_margin
measure:
kind: ratio
numerator: revenue # 语义表达式,不是 SQL
denominator: revenue_cost
constraints: [c-order-completed, c-exclude-internal]
presentation: {unit: "%", decimals: 2, default_dims: [month]}
owner: 财务负责人
signature: {status: published, signed_by: 李四,
signed_at: 2026-10-20T09:00:00+08:00}
ZOT 自 2026-10 起作为 DIP v3 的语义层运行。我们把"已经能用的"和"还在补的"分开写,避免把路线图当现状。
| 能力 | 状态 | 说明 |
|---|---|---|
| 核心包(记录模型 + 版本化存储 + 校验 + 可视化) | 已上线 | 保存 / 加载 / 发布 / 回滚;校验错误定位到 文件:行:字段 |
| 语义运行时 + MCP 工具面 | 已上线 | manifest / browse / resolve 已可被 ZAI 与 dip-mcp 调用 |
| 轨迹记录 · 触发判定 · 评测闸门 · 演进会话 | 已上线 | 显式状态机 + 轮次预算 + 终止态;晋级需过闸门 |
| 五层分离(M1–M7:冻结计数 → 拆证据 → 拆约束 → 拆映射 → 剥呈现 → 编译器 → 词汇层) | 进行中 | 约 10 人天,逐阶段上线,加载器双读可随时回退 |
| Postgres 存储后端 + 多租户 + Actor/RBAC | 规划 | 当前文件后端用于单机与离线交付;多站点需库后端 |
| 版本 diff 视图("口径什么时候改的、改了啥") | 规划 | 当前靠版本目录比对,尚无面向客户的 diff 页面 |
边界说明:ZOT 不负责取数(那是 ZDC),不负责会话与工具调度(那是 ZAI),也不直接写客户系统——写动作只出草稿,走人在环。
本体不是交付物清单里的一行,它是一次口径工作坊的产物:客户业务负责人签字,才是真正落地。
与客户业务负责人逐条过:这个词指什么、算完给谁看、哪些单不算。产出签字版口径清单。
落成 YAML:对象 / 属性 / 关系 / term / mapping / constraint;zot-validate 全绿才算完成。
草稿版本影子比对,差异逐条确认;业务负责人签字后发布,未签字口径不进生产查询。
把 ZDC 的现场 profile 绑到 mapping 上,跑通 20 条问句;口径变更走同一套版本流程。
不是一类东西。知识图谱解决实体与关系的存储和遍历,数据中台解决数据的汇聚与分发;ZOT 解决的是「一句话里的经营概念,在客户这套系统里到底指什么、怎么算、受哪些约束、证据在哪」。它输出的是可执行的语义契约,不是一张关系图。
因为耦合点不同。概念(term)、落地方式(mapping)、口径约束(constraint)、展示能力(presentation)、计算生成(compiler)混在一起时,换一个 ERP、加一条约束、换一个前端,都要动指标本身。分开之后:换 ERP 只加 mappings,加约束只加 constraint 节点,换引擎只换编译器。
不会直接改。演进过程只允许三件事:记录轨迹、判定是否需要演进、在评测闸门内产出候选版本。任何候选都要过 GT / LLM 评判配对与聚合门槛,再经人工签字发布;不过闸门就回滚,LLM 不直连写库。
答到四层:用了哪个 term、哪套 mapping(哪张表哪列、什么聚合与粒度)、命中了哪些 constraint(含严重级别与触发词)、引用了哪条 evidence(含采集时间与有效期)。这是 DIP「点回原始单据」验收的上游。
共管。通用对象与关系由我们提供基线(客户 / 供应商 / 物料 / 订单 / 应收等),客户业务口径由客户业务负责人确认并签字;FDE 负责把口径落成 YAML、校验、发布,并把现场 profile 绑到本体的 mapping 上。
能。核心包、版本化存储、语义运行时、MCP 工具面、校验器已可用;五层分离按 M1–M7 分阶段落地,每阶段可独立上线与回滚。上方「现在到哪一步」列了当前状态与边界。
带上一份客户的口径争议清单来找我们:我们用它跑一遍建模与校验,给出可签字的本体草稿与差异报告。