在分支上写定义
定义文件写在目录里;先试跑再写入再校验;在分支上自测;认出破坏性变更。

本课目标
读完这一课,你将能够
- 建分支,把新Object Type和关系写成目录里的定义文件
- 用
--dry-run试跑、validate校验,读懂结果并修正 - 按命名规则写定义,认出会变成破坏性变更的改动
建分支,写定义文件
智能体确认了缺口,第一步是开分支。分支从 main 当前的语义版本分出来,记下这个基线。在它上面怎么改,都不影响正在用的本体(Ontology)。
export AIDC_AGENT_ID=procurement-agent
aidc semantic branch create delivery-promise --description "让「哪些供应商在哪些物料上晚了」能回答"
分支名用小写字母、数字和 . _ -。定义写在一个目录里:每个 .json 文件放一个词条,也可以一个文件放一个数组。这次有两个词条:新的Object Type DeliveryPromise,和把它挂到采购订单上的关系。动笔前,先把说明书里相关的类型读一遍,确认名字不会撞。先写Object Type,放在 ontology-change/DeliveryPromise.json:
{
"kind": "objectType",
"apiName": "DeliveryPromise",
"title": "交期承诺",
"description": "供应商对某张采购订单承诺的到货日期,以及实际到货日期。一张订单可以有多次承诺。",
"schema": {
"pluralDisplayName": "交期承诺",
"synonyms": ["供应商承诺", "到货承诺", "交期"],
"titleColumn": "promiseId",
"columns": [
{ "name": "promiseId", "type": "string", "primaryKey": true, "title": "承诺编号" },
{ "name": "poNo", "type": "string", "title": "采购订单", "references": { "entity": "purchaseOrder", "column": "poNo" } },
{ "name": "promisedDate", "type": "date", "title": "承诺到货日", "synonyms": ["交期", "承诺日期"] },
{ "name": "receivedDate", "type": "date", "title": "实际到货日", "comment": "还没到货时为空" }
]
}
}
关系放在 ontology-change/purchaseOrderPromises.json:一张采购订单对应多个承诺,外键在承诺这一端。
{
"kind": "linkType",
"apiName": "purchaseOrderPromises",
"title": "采购订单的交期承诺",
"schema": {
"from": "purchaseOrder",
"to": "DeliveryPromise",
"cardinality": "ONE_TO_MANY",
"apiNameAtoB": "promises",
"apiNameBtoA": "purchaseOrder",
"foreignKey": { "side": "to", "property": "poNo" }
}
}
写对定义
- 名字:Object Type 与 Interface 用 PascalCase(
DeliveryPromise);属性和 Link Type 两端用 camelCase(promisedDate);Action 用 kebab-case。 - 主键:新 Object Type 只用一个主键属性(
promiseId)。新建或修改主键时,复合主键会被拒绝。仅原样保留的存量复合主键会收到警告。 - 属性要有业务含义:源系统里的技术列,例如同步时间、批次号,不要搬进来。
- 写说明和同义词:人和智能体都靠它们找到属性;
description是空的,校验会提醒。 - 引用要闭合:
references指向的purchaseOrder.poNo必须存在,否则校验失败,合并会被挡住。
这份定义里有一个刻意的选择:DeliveryPromise 是独立的对象,不是 purchaseOrder 上的一个属性。因为供应商可以反复改口,一张订单有好几次承诺,是一对多,属性装不下。
同一批里的定义可以互相引用。校验看的是整批改完之后的全体定义:关系引用了同一批里的 DeliveryPromise,不用分先后。分支上的改动以资源为单位记录,新建、修改、删除各算一项,将来审核时也是一个资源一项。
试跑、写入、校验
- 先试跑
--dry-run只校验、不写入,返回每一项检查的结果。试跑不通过时,命令的退出码是 2。 - 再写入
写入时带上
--expected-version。分支已经被别人或另一个智能体改过,就返回 409,不会互相覆盖。 - 最后校验
validate跑合并前的检查:引用是否闭合、主键规则、和 main 有没有冲突,另外还有说明是否为空这类设计提醒。失败的项会挡住合并,警告只是提醒。
aidc semantic branch modify delivery-promise ./ontology-change --dry-run
aidc semantic branch modify delivery-promise ./ontology-change --expected-version 0
aidc semantic branch validate delivery-promise
试跑可以反复做:它不写入,读报错、改文件、再试就行。检查结果分通过、警告、失败三档,常见的警告是说明为空、属性太多、名字像源系统的字段名,读一眼就知道怎么改。一个分支 35 天没有动静会转为不活跃,再过 7 天,分支上的改动会被删除,所以别把没用的分支留着。
在分支上自测,认出破坏性变更
按命令明确列出的参数使用 --branch。以下命令支持分支预览;Ontology SQL 的命令行选项没有 --branch。
aidc semantic object-types DeliveryPromise --branch delivery-promise
aidc semantic links purchaseOrder <采购订单主键> promises --branch delivery-promise
有一点要说清楚:分支只改定义,对象数据只有 main 一份。新类型在分支上能验证的是形状:名字、属性、关系走得通;它的对象要等合并、并把数据流绑进来之后才有。自测要如实写下验证了什么、没验证什么,下一节会用到。
加 Object Type、属性和同义词是加法。删类型、删属性、改属性类型、改主键,以及 Action 删参数或新增必填参数,是破坏性变更,审核时要确认。先加替代属性,迁移下游。旧属性是 active 时,先把它改为 DEPRECATED 或 EXPERIMENTAL,并落地这次状态改动,再另开提案删除。
要点
- 先开分支:它从 main 当前的语义版本分出来,怎么改都不影响正在用的本体。
- 定义是目录里的 JSON 文件。引用必须闭合。新 Object Type 和 Interface 用 PascalCase;新 Object Type 只用一个主键。
- 顺序是试跑、写入、校验:
--dry-run不写入,--expected-version防覆盖,validate跑合并前的检查。 - 分支只改定义,数据只有 main 一份:自测要写清验证了什么、没验证什么。
- 删和改类型是破坏性变更;默认先加后删,35 天不动的分支会转为不活跃。
练一练
在分支上写一次定义
用你自己的业务,或者示例工厂,需要一个有 AIDC_AGENT_ID 的终端。
照 DeliveryPromise 的写法,为你上一节找到的缺口写一个Object Type和一条关系,放进一个目录。
运行 aidc semantic branch modify … --dry-run。故意把 references 指向一个不存在的类型,看报错,再改对。
下面三个改动,哪个是破坏性的:给 supplier 加 onTimeRate 属性、把 material.leadTimeDays 改名、给 purchaseOrder 加同义词?说明理由。
小测
选一个答案,马上看解析。
Q1在分支上新建了 DeliveryPromise,objects DeliveryPromise --branch … 却一个对象也没有。最可能的原因是?
分支预览用的是分支上的定义,读的仍是 main 上的数据。新类型还没有数据流接进来,自然是空的;这不是故障,自测里要写明。
Q2下面哪一个改动是破坏性变更?
改属性类型会影响读写它的应用,是破坏性变更;加属性、加同义词都是加法。
Q3写入时带 --expected-version 0 是为了什么?
它是乐观并发:只有分支还在你读到的那个版本上,写入才会成功。试跑用的是 --dry-run,破坏性由平台对比定义得出。