Methodology · 方法论精读

Ontology Development 101,
提炼出来,再拿去用

Noy 与 McGuinness(斯坦福,2001)用 25 页讲清了这些事:本体为什么存在、里面装的是什么、先于一切步骤的三条规则、七个步骤的方法、类层级里的陷阱、一个槽的槽面,以及命名约定。本页以提炼的形式承载了论文的整条论证——然后做那件论文自己做不到的事:把每条规则拿到一个活体领域本体上跑一遍,而这个本体正是智能体在动手编辑之前要加载的。

全篇使用两种标记。101 §x.y 是对论文的引用——那是论文的主张,不是我们的。VLSC 标记本站自身实践回应这条规则的地方,并且点名对应工件,让这层映射可被核查,而不是只能被相信。

7 个步骤 20 个层级陷阱 5 类槽面 24 条清单

一份 2001 年的指南,早已预见了智能体

它是写给领域专家的,不是写给 AI 实验室的;成文于 Protégé-2000 与框架系统(frame system)的年代。它列出的第一个构建理由是「在人与软件智能体之间共享对信息结构的共同理解」(to share common understanding of the structure of information among people or software agents)——这句话在 2001 年读来像套话,如今却是全篇的要点。

字段 内容
标题 Ontology Development 101: A Guide to Creating Your First Ontology(本体开发 101:创建你的第一个本体)
作者 Natalya F. Noy、Deborah L. McGuinness —— 斯坦福
篇幅 25 页,8 节,9 幅图
工具年代 Protégé-2000(示例)、Ontolingua(本体库)、Chimaera(诊断工具);RDF 与 DAML 被点名为 W3C/DARPA 正在成形的工作
贯穿示例 葡萄酒与食物搭配,源自 CLASSIC 教程知识库(Brachman 等,1991)
思想谱系 Gruber 1993(定义)、Gruninger 与 Fox 1995(能力问题)、Uschold 与 Gruninger 1996 及 Gómez-Pérez 1998(其他方法论)、Rosch 1978(概括层级)
来源 protege.stanford.edu — ontology101.pdf

构建本体的五个理由(§1)

共享理解

在人与软件智能体之间共享。如果各站点发布的是同一套底层本体,智能体就能跨站点抽取并汇总信息。

复用领域知识

时间、单位、设备:建模一次,处处复用;或者把若干已有本体整合进一个更大的本体。

假设显式化

硬编码的假设难以找到、难以理解、难以修改——对没有编程背景的人尤其如此。

领域 ≠ 操作实现

把任务领域与求解它的程序分开描述:同一个配置算法,喂进各自的本体,既能驱动 PC,也能驱动电梯。

形式化分析

术语一旦被声明,就可以被形式化地分析——这在复用或扩展别人的本体时最要紧。

Often an ontology of the domain is not a goal in itself. Developing an ontology is akin to defining a set of data and their structure for other programs to use.

101 §1 — 「领域的本体往往本身并不是目的。开发一个本体,类似于定义一组数据及其结构,供其他程序使用。」正是这句话让本体作为智能体上下文变得名正言顺:它是给消费者用的数据,不是一座纪念碑。

Noy & McGuinness 2001, §1
VLSC。这里的消费者就是智能体。同样八个顶层概念、同样的关系、同样的不变量,被三种方式读取:作为编辑之前的智能体上下文,作为可以拒绝这次编辑的编辑前门禁,作为人工审查所用的词汇表。一套语义,三方消费——见Agentic · 领域本体。
这不是面向对象设计(§ About this guide)。OO 设计按一个类的操作性属性来决断——它带哪些方法。本体设计按结构性属性来决断——它是什么、它有什么、它与什么相关。论文说得很明确:由此得到的类结构,与在 OO 程序里建模同一领域所得到的结构并不相同。

类、槽、槽面、实例——以及知识库

这是论文自己的工作定义,因为 AI 文献里的定义很多,而且彼此矛盾(§2)。

术语 又称 它是什么(101 §2) 葡萄酒示例
类(class) 概念(concept) 论述领域中的一个概念;多数本体的焦点所在。 Wine、Red Wine、 Pauillac、Winery
槽(slot) 角色(role)、属性(property) 类或实例的一项属性,用来描述它的某个特征或性质。 body、maker、color、 produces
槽面(facet) 角色限制(role restriction) 对槽的限制:值类型、允许值、基数、默认值。 body:枚举 {light, medium, full}; produces:多值,实例类型 Wine
实例(instance) 个体(individual) 类的某个具体成员。本体加上实例,构成一个知识库。 Chateau-Morgon-Beaujolais、某家酒庄、某个年份

An ontology together with a set of individual instances of classes constitutes a knowledge base. In reality, there is a fine line where the ontology ends and the knowledge base begins.

101 §2 — 「一个本体,加上各类的一组个体实例,就构成了一个知识库。现实中,本体在哪里结束、知识库从哪里开始,其间只有一条极细的界线。」

Noy & McGuinness 2001, §2

落到实操,开发一个本体就是四件事(§2)

定义类→把它们排成
分类层级
→定义槽及其
允许值
→为实例
填充槽值
VLSC。同样这四项活动,一一对应:八个顶层类(主体 Agent、物理实体 Physical Entity、软件系统 Software System、活动 Activity、信息对象 Information Object、能力 Capability、策略/约束 Policy/Constraint、证据 Evidence);把它们排布起来的关系(requests、changes、yields、 sampled-as、framed-as,外加产品族之间的 inherits / consumes / implements / inspired-by);52 条机器可读约束所携带的槽面(severity、sdd_ref、scope glob、patterns);以及实例——电台 Profile、具体台站、带日期的证据记录。普查 2026-09-12。

论文在一切步骤之前先立下的规则

「这些规则可能显得相当教条。但在很多情形下,它们能帮你做出设计决定」(§3)。指南后面的一切,都是这三条规则的应用。

没有唯一正确的模型

「为一个领域建模,不存在唯一正确的方式——永远有可行的替代方案。最佳解几乎总是取决于你心里想着的那个应用,以及你预期会有的那些扩展。」101 §3

必然是迭代过程

「本体开发必然是一个迭代过程。」先做粗糙版本,再细化,再补足细节——并且预期第一版一旦碰上真实应用或真实专家,就要被改写。101 §3

贴近领域

「本体中的概念应当贴近你所关心领域里的对象(物理的或逻辑的)与关系」——最可能对应的,就是描述这个领域的那些句子里的名词和动词。101 §3

论文自己的谦辞,逐字保留。「不存在唯一正确的本体设计方法论,我们也没有试图去定义一个」(§ About this guide);到了结论部分则是:「任何领域都不存在唯一正确的本体。本体设计是一种创造性过程,不同的人设计出的两个本体不会相同……布丁好不好,吃了才知道(The proof is in the pudding)——我们只有在把本体用于当初为它设计的那些应用时,才能评估它的质量」(§8)。一个最后把手指向「使用」的方法,就是一个必须配上证据的方法——而这恰好是下一节的起点。
VLSC。规则二与规则三决定了本站本体的形状:重复的概念与约束,只有在证据跨产品边界反复出现之后才被合并——从来没有先在白板上设计好。那些名词和动词来自事故报告与 SDD 裁决,而不是来自某人觉得优雅的 taxonomy。

七个步骤,按序而行

这是整份指南的脊柱(§3)。第 4 步与第 5 步「紧密交织……也是本体设计过程中最重要的两步」——所以论文的 §4 与 §5 又回过头把它们细讲一遍,下面的 05、06 两节也一样。

步骤 101 要你回答什么 决定它的规则 VLSC 工件
1 领域与范围 哪个领域?做什么用?它必须回答哪些问题?谁使用、谁维护? 范围由任务塑形:同一个领域,面向不同消费者会得到不同的本体。 12 个能力问题,五份产品族 Profile
2 复用 已经存在哪些可以被细化或扩展的东西? 一旦其他系统已经承诺了某套词汇,复用就可能是一项要求,而不是一种偏好。 W3C SSN/SOSA、PROV-O、OWL-Time、SKOS、SAREF/QUDT ——作为概念参照;Hamlib 词汇——作为事实上的强制复用
3 列举术语 我们想就哪些术语作出陈述,或者向用户解释哪些术语? 先把清单做全;此时先不用操心概念重叠、术语间关系,也不用操心某个概念该做类还是该做槽。 双语术语表:CommandIntent、Actuation、Observation、StateReport、DeviceAdapter、Protocol Binding、Control Lease……
4 类与层级 哪些术语指称具有独立存在性的对象?它们如何逐级概括? is-a 检验:B 的每一个实例,必然也是 A 的实例。 八个顶层类;产品族互为兄弟;不造人为的中间类
5 槽 哪些属性描述每个类?剩下的每个术语属于哪个类? 把槽挂在能够拥有该属性的最概括的那个类上。 关系 requests / changes / yields;能力槽与协议绑定槽
6 槽面 值类型、允许值、基数、定义域、值域、默认值? 取最概括、但又不过度概括的定义域与值域——永远不要写成 THING。 约束的 severity / sdd_ref / scope / patterns;单一所有者的基数不变量
7 实例 哪些个体?取什么粒度?带哪些槽值? 个体实例是应用需要表示的最具体的概念。 电台 Profile(FT-710、IC-7300、IC-7300MK2)、带日期的证据记录、公开看板上的 🐞 上报

第 1 步 —— 领域与范围(§3, Step 1)

四个问题

本体要覆盖的领域是什么?我们打算拿它做什么用?它应当回答哪些类型的问题?谁会使用并维护它?这些答案在设计过程中可能变化,「但在任一给定时刻,它们都有助于限定模型的范围」。

范围由任务塑形

论文自己的演示:同一个葡萄酒领域,做自然语言处理需要同义词与词性数据,顾客挑一瓶酒需要零售价,采购为酒窖备货需要批发价与库存可得性。三个任务,三个本体。

维护者的语言 ≠ 用户的语言

「如果将要维护本体的人描述该领域所用的语言,与本体使用者所用的语言不同,我们可能就需要提供两种语言之间的映射。」101 §3

能力问题(competency questions,§3, Step 1)。先勾画出「建立在这个本体之上的知识库必须能够回答哪些问题」;它们会成为「事后的试金石」,用来检验本体是否装下了足够信息、并且细到恰当的程度。它们只是一份草稿,不必穷尽。葡萄酒那组能力问题,从「Bordeaux 是红葡萄酒还是白葡萄酒?」一直排到「Napa Zinfandel 哪些年份是好年份?」——读完它们,在还没画出任何一个类之前,你就已经知道年份与食物分类属于范围之内,而酒庄库存与餐厅员工不属于。VLSC:十二个能力问题发布在证据纪律的附录里——从「哪一个软件系统拥有某台电台的权威状态」到「哪一条安全性主张背后有真实的传感器或观测路径」。
VLSC 对语言规则的落实。本站刻意用两种语言维护每一个本体术语——CommandIntent 对应控制意图,Field verified 对应现场验证——因为维护者用一种语言思考,而一部分读者用另一种语言阅读。这层映射是公开写出来的,不是靠暗示。

第 2 步 —— 复用(§3, Step 2)

几乎总值得先查一遍

「考虑别人已经做过什么、检查我们能否针对自己的特定领域与任务去细化和扩展现有来源,这几乎总是值得的。」

有时是一项要求

当「我们的系统需要与那些已经承诺了特定本体或受控词汇的其他应用交互」时,复用就不再是可选的。

形式化语言通常不重要

多数知识表示系统都能导入导出;即便不能,在不同形式化语言之间翻译一个本体「通常也不是一件困难的事」。

VLSC —— 复用的是概念,不是运行时。W3C SOSA/SSN 提供了观测—传感器—执行的三分,PROV-O 提供了溯源字段,OWL-Time 提供了时间区间词汇,SKOS 提供了双语概念模式,SAREF/QUDT 提供了设备—功能—物理量的拆分,WoT Thing Description 提供了能力即可供性(affordance)的思路。这些都不意味着要引入 RDF 存储、三元组数据库或者推理机:本体仍然是一份轻量的双语契约,由产品证据兜底。另外,Hamlib 自己的词汇才是这条规则严格意义上的受控本体复用——本站的 MRRC 产品族别无选择,只能承诺它,因为 rigctld 早就承诺了。

第 3 步 —— 列举术语(§3, Step 3)

把你想就其作出陈述、或想向用户解释的每一个术语都写下来,连同它的属性以及你想说的内容。先把清单做全:「先不必操心它们所表示的概念之间是否重叠、术语之间有何关系、概念可能有哪些属性,也不必操心这些概念究竟是类还是槽」。分拣发生在第 4 到第 6 步;论文说得很清楚,第 4 步与第 5 步是交织的——先定义几个类,再定它们的属性,再回头定义更多的类。

第 4 步 —— 类与类层级(§3, Step 4)

自顶向下

从最概括的概念开始,逐级特化:Wine → 红 / 白 / 桃红 → Syrah、Red Burgundy、Cabernet Sauvignon。

自底向上

从叶子开始,向上归组:Pauillac 与 Margaux → Medoc → Bordeaux。

组合法

先定义那些最显要的概念,再向上概括、向下特化。「对许多本体开发者来说这往往最省事,因为『中间层』的概念通常是领域里最具描述性的那些概念」(Rosch 1978)。

三者本身并无高下。选择「强烈依赖于个人对领域的看法」。从第 3 步的清单里,挑出那些描述具有独立存在性的对象的术语——而不是描述这些对象的术语——它们就成为层级的锚点。然后用一条检验来排布它们:若类 A 是类 B 的父类,则 B 的每一个实例也必然是 A 的实例;换句话说,B 是 A 的「一种」(kind of)。每一支 Pinot Noir 都必然是红葡萄酒,所以 Pinot Noir 是 Red Wine 的子类。101 §3–§4.1

第 5 步 —— 槽(§3, Step 5)

只有类是不够的

「仅有这些类,不足以回答第 1 步提出的能力问题。」第 3 步清单里剩下的术语,大多会变成类的属性。

四种属性

内在属性(一支酒的风味)、外在属性(它的名字、它的产区)、组成部分——物理的或抽象的(一顿饭的几道菜)——以及与其他个体的关系(maker,把一支酒连到一家酒庄)。

挂得越高,继承越广

「槽应当挂在能够拥有该属性的最概括的那个类上。」body 与 color 挂在 Wine 上;tannin level 挂在 Red Wine 上,因为白葡萄酒不用它来描述。所有子类都继承下来。

第 6 步 —— 槽的槽面(§3, Step 6)

槽面 它约束什么 论文的例子
基数(cardinality) 一个槽可以有多少个值:单值还是多值,或者显式给出最小值与最大值。最大值取 0 是合法的——它表示某个子类根本不可以填这个槽。 body 单值;produces 多值;单一品种酒的 grape 最小 1、最大 1
值类型(value type) 什么样的值可以填进这个槽:String、Number(Float/Integer)、Boolean、Enumerated(在 Protégé-2000 里叫 Symbol),或者 Instance 并附一份允许的类的清单。 name 是 String;flavor 是枚举 {strong, moderate, delicate};produces 是 Wine 的 Instance
定义域(domain) 这个槽挂在哪些类上——也就是它所描述的是哪些类的属性。 Winery 是 produces 的定义域
值域(range) 对实例类型的槽而言,它的值允许是哪些类。 Wine 是 produces 的值域
默认值(default value) 一种便利:为新实例自动填好的值,并且与槽值不同,它是可以被改的。见下面第 06 节。 当范围内多数酒都是醇厚型时,把 body 的默认值设为 "full"
定义域与值域的四步心法(§3, Step 6)。(1)找出能够充当定义域或值域的最概括的类。(2)但不可过度概括:定义域里的每一个类都必须真的能被这个槽描述,值域里的每一个类都必须是潜在的填充者——「没有人会把值域设成 THING」。(3)如果清单里同时有一个类和它的子类,删掉子类——它不带来任何信息。(4)如果清单里有 A 的全部子类却没有 A,那就只用 A;如果清单里有 A 的绝大多数子类只差几个,就该重新考虑 A 是不是更好的答案。槽挂在哪里也遵循同一套规则,因为挂槽就等于声明定义域:tannin level 属于 Red Wine,不属于每一个红葡萄品种,也不属于 Wine。
VLSC。第(2)步正是本站把 Protocol Binding ≠ Capability 当作公理而非偏好的原因:一个声明在过度概括值域(「任意后端」)上的能力,是一条没有任何测试能否证的主张。具体锚点是 audio-pyaudio-rate 这条约束——音频采样率来自后端上报的能力,不来自调用点硬编码的机型名 [AD-011,经 V2.9/V2.14 修订]。基数在这里表现为一条不变量,而不是一个槽面取值:一个权威状态所有者,一个串口所有者(ft8 no-direct-serial [AD-008];ft710 / modern cat-direct-serial-io [AD-002])。

第 7 步 —— 实例(§3, Step 7)

三个动作:选一个类,创建该类的一个个体,填入它的槽值。论文亲手做的那个实例 Chateau-Morgon-Beaujolais 带了八个值——body 为 light、color 为 red、flavor 为 delicate、tannin level 为 low、grape 为 Gamay(Wine Grape 的一个实例)、maker 为 Chateau-Morgon(Winery 的一个实例)、region 为 Beaujolais(Wine-Region 的一个实例)、sugar 为 dry。留意这个实例示范了什么:八个值里有三个本身就是别的类的实例——知识库正是靠这一点保持可查询,而不是退化成一堆字符串。
VLSC。实例是证据存放的地方。一个电台 Profile(FT-710、IC-7300、IC-7300MK2)是携带能力值的实例;一条带日期的证据记录是携带来源、版本、环境、方法、结果与限制的实例;公开看板上的一条 🐞 上报是携带分类结论的实例。论文的粒度规则——「个体实例是知识库中所表示的最具体的概念」——正是本站把一次发布当作实例、而把一个电台型号当作类的原因:发布是被清点的,型号是被描述的。

类层级出错的二十种方式

论文第 4 节是一份缺陷目录,不是一份教程:「在定义了相当数量的新类之后,退后一步、检查正在成形的层级是否符合这些准则,是有帮助的」。把它当审查清单来读——这也正是智能体能用它的用法。

# 陷阱 规则(101 §4) 为什么会崩
1 把 is-a 读成「与……相关」 只有当 B 的每一个实例都必然是 A 的实例时,A 才是 B 的父类——这是「一种」(kind of)关系。§4.1 任何沾点边的东西都变成子类,继承于是开始携带子类根本不具有的属性。
2 单数挂在复数之下 绝不要先定义 Wines、再把 Wine 定义成它的子类;选定一种数,全篇保持一致。§4.1、§6.2 「一支酒并不是『诸酒』的一种」——层级于是对领域说了一句假话。
3 忘了传递性 若 B ⊂ A 且 C ⊂ B,则 C ⊂ A。§4.1 挂在高处的约束会悄悄作用到三层之下,而那里没人预料到它。
4 混淆直接子类与间接子类 直接子类与父类之间不隔任何类;Chardonnay 是 White Wine 的直接子类,不是 Wine 的。§4.1 兄弟类分析、「把槽挂在最概括的类上」这两件事,需要的都是直接关系,不是传递闭包。
5 领域在演化,层级却冻结了 当白 Zinfandel 出现时,Zinfandel 不得不拆成红、白两个子类,分别挂到不同的父类之下。§4.1 领域动了;本体于是断言了一种颜色,而它自己的部分实例并不具备这种颜色。
6 把类和它的名字混为一谈 「类表示的是领域中的概念,而不是指称这些概念的那些词。」把 Shrimps 改名成 Prawns,别的东西一样也没变。§4.1 一次术语变更被误当成一次建模变更,下游的一切都被重建一遍。
7 把同义词做成不同的类 一个概念,一个类;同义词、译名与展示名要么挂成一份清单,要么写进文档。§4.1 把 Shrimp、Prawn 和 Crevette 做成三个类,意味着同一个事实要在三个地方维护。
8 成环 A ⊂ B 与 B ⊂ A 同时成立,等于宣布 A 与 B 等价。§4.1 层级不再是层级;遍历可能不终止。
9 兄弟类处在不同的概括层级 除根层的类之外,所有兄弟类都必须处在同一概括层级上——White Wine 与 Chardonnay 不是兄弟。根层的类是大的分野,可以豁免。§4.2 这棵树读起来像一份书稿目录:一章和一个三级小节并排站着。
10 只有一个子类 「如果一个类只有一个直接子类,那可能是建模出了问题,也可能是本体还不完整。」就像一份只有一条的项目符号清单。§4.2 要么这两个类等价(删掉一个),要么那些缺失的兄弟类还没被找出来。
11 子类多过一打 结构良好的本体,直接子类数在两个到一打之间;超出这个范围,多半就需要中间范畴了。§4.2 把所有葡萄酒类型都平铺在 Wine 之下,就把领域本身已经有的 Medoc / Bordeaux 与 Côtes d'Or / Burgundy 结构藏了起来。
12 凭空造出归组用的类 如果没有自然的类可以归拢一长串兄弟,就让它平铺——「本体是对真实世界的反映」。§4.2 人为的中间类是一个领域里没人认得的范畴,而将来每一个实例都必须被硬塞进去。
13 害怕多重继承 多重继承是合法的:Port 既是 Red Wine 又是 Dessert Wine,从一个父类继承 sugar = SWEET,从另一个父类继承 tannin level。§4.3 拒绝它,就会造出平行的重复层级,只能靠人手保持同步。
14 新类无新话可说 当一个子类带来额外属性、不同限制或不同关系时,才引入它;落到实操,它应当增加槽、增加槽值,或者覆盖继承来的槽面。§4.4 一个除了父类之外无话可说的类,是一个名字,不是一个概念。
15 为每个限制各开一个子类 不要为某个槽的每一个取值都造出 Delicate Wine、 Moderate Wine……这类区分属于槽值。§4.4–§4.5 类爆炸,并且一个取值的每一个侧面都变成树上的一个节点。
16 否认术语性层级的价值 参考层级(比如一套疾病分类)可能一个新属性都不增加,却仍然值得拥有:它们支撑导航,让用户自己挑一个概括层级。§4.4 坚持每个类都要挣来新槽,会把那些本职工作就是组织术语的词汇表压平。
17 实例在类之间来回迁移 「一个个体实例所属的类,不应当经常变化。」Chilled Wine 是一项属性,不是一个类。§4.5 把外在属性当成划类标准,会让实例在有生之年换类——并且把继承来的槽面一起带走。
18 明明有层级,却做成实例 如果一组概念构成自然的层级,就把它们做成类——所有葡萄酒产区都是类,没有直接实例的那些标为抽象类。不存在「子实例」这种东西。§4.6 把 Bourgogne 做成实例,就没法把 Côtes d'Or 挂在它下面,自然结构于是丢失。
19 范围过宽或过窄 不要特化或概括得超出应用所需——「两个方向各多一层,到此为止」;也不要把每一个属性、每一种想得到的关系都收进来。§4.7 标签纸和虾仁菜谱混进了一个葡萄酒配餐本体;维护成本上升,能力问题却没有增加。
20 不声明不相交 当两个类不可能共享实例时,就声明它们不相交(disjoint)——Red Wine 与 White Wine 是,Dessert Wine 与 White Wine 不是。§4.8 缺了这条声明,系统就没法把一个同时挂在 Riesling 和 Port 之下的类标记为它本该是的建模错误。

三个艰难决定,细说

做成新类,还是做成属性值?(§4.5)

当(a)取值不同的那些概念会变成对其他类的槽的限制,或者(b)这个区分在领域里确实要紧、你把两者想成不同种类的对象时,才为这个区分建一个类。否则就把它留在槽值里。葡萄酒的颜色是论文给出的那个「反例反而证明规则」的例外:颜色通常只是取值,但红葡萄酒与白葡萄酒配的食物不同,所以 Red Merlot 与 White Merlot 是两个类。

做成类,还是做成实例?(§4.6)

先定下应用所需的最低粒度——「那些将构成[能力问题]之答案的最具体概念,是个体的极佳候选」。葡萄酒配餐到 Sterling Vineyards Merlot 就停;加上餐厅库存,就把每一瓶酒压到实例;要记录逐年份的属性,就让年份成为实例、让酒成为类。

限定范围(§4.7)

真的陈述也可能是范围之外的。一位实验者确实是一个生物体,但对一个生物学实验本体来说,那个子类会给每一位实验者都挂上体重、年龄、物种槽——无关数据,也是给复用者埋的坑。论文那条指令才是重要的一半:把这类设计决定写进文档,这样别人把本体复用到另一种应用上时才会知道,这条事实是被刻意排除的。

VLSC —— 陷阱 20 在本站是一条活的不变量。声明不相交,是一个模型变得可检验的方式;本站声明了若干条:发射态与接收态不相交,一个台站必须恰好处在其中之一;权威状态所有者与客户端投影不相交——这正是「客户端可以投影或请求状态,但不得悄悄变成台站权威」的形式化内容。同一手也守着证据阶梯:过程徽章(B1–B4,工程是否被约束?)与产品徽章(设计目标 → 现场验证,行为是否为真?)被刻意声明为不相交,于是再多绿色的约束条数,也不可能被读成一次台架结果。见证据纪律。
VLSC —— 陷阱 10 到 12,由证据来裁决。五个产品族在同一个工程体系之下互为兄弟,没有为了让树好看而凭空造出第六个归组类;而在确实存在自然中间概念的地方,就用上了——RadioBackend 与 RadioCapabilities 把 FT-710 那条纵向切片概括进了 Modern 平台,这正是陷阱 11 被一个领域真在使用的中间范畴修好的样子。反面情形也记录在案:SunsdrMobile 是 SunMRRC 的客户端,不是一个产品族;把这句话说清楚,才阻止了它旁边长出一条只有一个类的分支。

互逆槽,以及默认值与槽值之分

论文第 5 节很短,很容易被跳过。它的两个主题都关乎冗余与强制——而这两件事恰恰决定一个模型能否被机器信任。

互逆槽(§5.1)

Wine 上的 maker 与 Winery 上的 produces,是同一个事实说了两遍。两个方向都存是冗余的:应用总能从一个推出另一个。但从知识获取的角度看,两者都方便,因为用户可能这一次知道的是酒、另一次知道的是酒庄——于是系统自动填充互逆方向,并保持基座一致。

值得留下的规则是:声明这一对,只存一次,让系统去维护那面镜子。

默认值 vs 槽值(§5.2)

默认值是便利:当多数实例共享同一个取值时,新实例被预填,之后仍可修改。它「不会给模型强加任何新限制,也不会以任何方式改变模型」。

槽值是另一回事:如果 sugar = SWEET 是 Dessert Wine 上的一个值,那么它的每一个子类和每一个实例都带着它,而且改不了。一个是起点,另一个是约束。

VLSC —— 这个区分赔进去过一次真实事故。FT-710 链路上的音频采样率,曾被当成一个固定值(44.1 kHz,挂在机型上),而它其实是后端上报的一项能力。修正被记录为 AD-011,经 V2.9 与 V2.14 修订,并由 audio-pyaudio-rate 这条约束钉住:采样率来自后端能力。用论文的话来读,就是在本该放默认值——或者更好,放一次查询——的地方,声明了一个值,于是模型断言了一件硬件完全可以反驳的事。
VLSC —— 互逆对,以及哪一侧是权威。本站有若干关系是真正互逆的:一个台站的控制租约持有者,与持有者名下的租约台站;一个 CommandIntent,与回答它的那份 StateReport;一条 🐞 上报,与把它关闭的那个答复页。那面镜子由服务端维护,从不由客户端维护——而这种不对称是一条安全不变量,不是一种便利:投影方可以显示镜像值,但只有权威方可以写它。CommandIntent ≠ Actuation 与 Observation → StateReport 是本体把同一句话说两遍:一条指令不是被确认的状态,只有一次观测才能闭环。ft710 的 ptt-release-no-verify 约束则是那个诚实的例外,并且被声明为例外——TX0 是发完即忘,因此既没有镜子要维护,也没有确认可以推断 [AD-007;Ch15;V1.2]。

「为类和槽定义一套命名约定,并且遵守它」

论文第 6 节。命名被当作一种建模安全装置来讲,不是化妆术:一致性才是防止「单数/复数类」错误的那道保险,而一套写明的约定,才让一个术语一眼就能被认出是类还是槽。

决定项(101 §6) 论文怎么说 VLSC 约定
先看系统约束 围绕你的知识表示系统来选约定:类、槽、实例是共用一个命名空间还是各用各的;是否大小写敏感;哪些分隔符合法。Protégé-2000 大小写敏感且只有一个命名空间,所以类 Winery 与槽 winery 可以共存,但两个 winery 不行。 这里的「系统」是一个仓库加一个智能体运行时:名字必须能作为标识符在代码里活下来、作为键在 harness/index.json 里活下来、作为检索词在约束注册表里活下来——所以用 ASCII、不留空格、大小写有意义。
大小写 在系统大小写敏感的前提下,类名首字母大写,槽名全小写。 类与本体术语用 PascalCase:CommandIntent、StateReport、DeviceAdapter、ControlLease。关系用小写:requests、changes、yields、 inherits、consumes、 implements、inspired-by。
分隔符 空格、CamelCase,或者下划线 / 连字符——而且一旦用了分隔符,还要决定每个词是否大写。空格直观,但未必能在你要互操作的那些系统里活下来。 约束 ID 用 kebab-case,并且读起来像一条规则而不像一个东西:cat-no-dn、no-direct-serial、 poll-stale-guard、vendor-readonly、 ptt-authority。多词的本体关系也出于同样理由用连字符。
单数还是复数 两者没有谁更好;实践中单数更常见。选定一种,全篇保持——有些系统要求你事先声明这个选择。一致性也正是防止 Wine 挂在 Wines 之下的那道保险。 每个类和每个术语一律单数:Product Family、Physical Entity、Information Object。复数只出现在行文里,绝不出现在术语里。
前缀 / 后缀 在槽名上加 has- 或 -of,能让一个术语自我标明它是槽,代价是名字更长。 不用:动词形式的关系(requests、yields)对着 PascalCase 的类名已经毫无歧义,再加前缀就是噪声。
不要把种类写进名字 绝不要在概念名上加「class」「property」或「slot」——上下文和约定已经说明了它是什么。 照办。唯一一处刻意的例外是证据阶梯:徽章文字自带种类(Field verified、Bench pending),因为徽章是脱离上下文被读的,出现在表格和发布说明里。
避免缩写 「用 Cabernet Sauvignon,而不是 Cab。」 照办,但有一句诚实的但书:电台领域的受控词汇本身就是缩写——PTT、CAT、SWR、IQ、EFHW、QSO、VFO、DNR。这些是术语,不是偷懒的简写,双语术语表里带着它们的展开形式。真正适用的那条规则是:不许自造缩写。
子类命名 一组直接子类,要么全都带上父类名,要么全都不带:Red Wine 与 White Wine,或者 Red 与 White——绝不能一个带一个不带。 产品名跟着自己的产品族走:MRRC Universal、MRRC FT-710、MRRC Modern、MRRC-FT8——族名标记在每一个产品名里都在场;而 SunMRRC 保留自己的词根,因为它是一条不同的轨道,不是一个子类。
同义词与译名 许多系统允许给一个类挂上一份同义词、译名或展示名清单;不支持的系统,就把它们写进类的文档里。§4.1、§6 双语术语表就是这份清单,而且是公开的那份:控制意图 / CommandIntent、执行活动 / Actuation、观测活动 / Observation、现场验证 / Field verified。两个名字,一个概念——绝不是两个概念。

整份指南,压成 24 条检查

写下来的目的,是让审查模型的人能照着逐条跑一遍,也能把它当作一次本体变更的验收清单交给智能体。每一条都能追到论文的某一节。

A · 建模之前

  1. 把四个范围问题写下来。
    领域、预期用途、要回答的问题、谁来维护——并且注上日期,因为它们会变。§3 Step 1
  2. 勾画能力问题。
    它们是后面一切产出的试金石,而且不必穷尽。§3 Step 1
  3. 先去找已经存在的东西。
    记下你采纳了什么、只参考了什么、以及被迫承诺了什么。§3 Step 2
  4. 先列举术语,再分拣。
    清单先求全;类还是槽,留到后面再定。§3 Step 3

B · 搭建层级

  1. 刻意选定一条路线。
    自顶向下、自底向上,或者组合——最后一种通常最省事,因为中间层概念最具描述性。§3 Step 4
  2. 以「独立存在性」为锚。
    要那些指称对象的术语,不要那些描述对象的术语。§3 Step 4
  3. 对每一对类都跑一遍 is-a 检验。
    子类的每一个实例,必然也是父类的实例。§4.1
  4. 让兄弟类处在同一概括层级。
    根层的类豁免:它们是大的分野。§4.2
  5. 子类数在两个到一打之间。
    只有一个是一种坏味道;超过一打就该要一个中间范畴——但绝不能是凭空造出来的那种。§4.2
  6. 不许成环,不许把同义词做成类。
    环等于宣布等价;同义词只是同一概念的另一个名字。§4.1

C · 槽与槽面

  1. 把每个槽挂到它站得住的最高处。
    也就是能够拥有该属性的最概括的类。§3 Step 5
  2. 给每一项属性归类。
    内在属性、外在属性、组成部分,还是与另一个个体的关系。§3 Step 5
  3. 声明基数与值类型。
    包括最小值、最大值,以及那个合法的最大值 0。§3 Step 6
  4. 定义域与值域要取得概括——但不要 THING。
    定义域里的每个类都必须能被这个槽描述;值域里的每个类都必须是潜在的填充者。§3 Step 6
  5. 修剪定义域与值域清单。
    父类已在清单里时删掉子类;枚举完整时收拢成父类;只差几个子类没列全时,重新考虑父类。§3 Step 6

D · 类、值,还是实例

  1. 只有当新类有新话可说时才引入它。
    新属性、不同限制,或者不同关系。§4.4
  2. 默认把区分留在槽值里。
    当这些取值在别处变成限制,或者领域把它们当作不同种类的东西时,才升格为类。§4.5
  3. 不要做那种实例会来回迁移的类。
    冰镇过的酒是一项属性,不是一个分类单元。§4.5
  4. 粒度由能力问题来定。
    并且把自然层级升格为类——没有直接实例的那些标为抽象类。§4.6

E · 命名

  1. 把约定写下来,然后照着做。
    大小写、分隔符、单数还是复数——围绕你真正身处其中的那个系统来选。§6
  2. 不许自造缩写,不许把种类写进名字。
    并且子类名要么全带父类名,要么全都不带。§6.2–§6.4
  3. 一个概念,多个名字。
    同义词与译名挂在类上;它们绝不变成兄弟类。§4.1, §6

F · 治理

  1. 记下你排除了什么,以及为什么。
    实验者是一个生物体;这个本体偏说不是——是刻意的,那么文档就必须写明,否则复用者会被误导。§4.7
  2. 声明不相交,然后去用这个模型。
    凡是两个类不可能共享实例,就把它说出来——这才是让工具抓得住错误的前提。然后用论文允许的唯一方式评估质量:拿它去用。§4.8, §8

七个步骤,对着一个活体本体审计

论文要什么、本站有什么,以及——因为一份只列成绩的审计就是广告——缺什么。普查 2026-09-12;每一行都点名工件,好让它可被核查。

步骤 是否具备 锚点 缺口 / 局限
1 范围与能力问题 有 12 个已发布的能力问题;五份产品族 Profile;范围按族陈述在产品族一节 这些问题是散文,不是可执行的:其中某一条变得无法回答时,不会有任何构建因此失败。
2 复用 有,概念层面 W3C SOSA/SSN、PROV-O、OWL-Time、SKOS、WoT TD;ETSI SAREF 与 QUDT;Hamlib 词汇——一次被迫的承诺 没有形式化导入:运行时不从那些命名空间加载任何东西,所以这层对齐是一份靠人手维护的主张。
3 术语列举 有 双语核心术语表,12 对术语,发布在附录里 除英中这一对之外没有同义词清单;电台领域的别名(CAT 与 rig control、PTT 与 transmit trigger)没有被作为已声明的同义词承载。
4 类与层级 有,刻意做浅 八个顶层类;产品族互为兄弟;RadioBackend / RadioCapabilities 是唯一挣来的那一层中间层 深度最多到顶层之下两级。这是一个范围决定,不是意外——但它意味着 is-a 检验很少受到真正的压力检验。
5 槽 有 requests、changes、 yields、sampled-as、 framed-as;族间关系 inherits / consumes / implements / inspired-by 关系被记录在散文和 SVG 图里,而不是在一个工具可以遍历的 schema 里。
6 槽面 部分具备——而且在要紧的地方比散文更强 三个仓库共 52 条机器可读约束,每条都带 severity(block / warn / info)、sdd_ref、scope glob 与 patterns;基数以不变量的形式存在(一个权威状态所有者、一个串口所有者) 这些是施加在代码上的强制槽面,不是声明在本体槽上的槽面。关系的定义域与值域从未被形式化陈述过。
7 实例 有 电台 Profile(FT-710、IC-7300、IC-7300MK2);带日期的证据记录;在公开看板上被分类的 🐞 上报 实例分散在三个地方(代码里的 Profile、发布说明、看板),彼此之间没有共享的身份方案。
§4.8 不相交 只在散文里 发射态与接收态;权威所有者与客户端投影;过程证据(B1–B4)与产品证据(设计目标 → 现场验证) 没有机器可读的声明,因此没有工具能标出违规——这项检查是人去读那些不变量。
§6 命名 有 术语 PascalCase、关系小写、约束 ID kebab-case、类名单数、双语对照已发布 这套约定可被观察,但没有成文:它活在工件里,不在一份智能体能加载的风格文档里。
§8 以使用来评估 有——比论文更强 一套语义,三方消费:智能体上下文、PreToolUse(Edit|Write) 门禁、人工审查;一条可复现的阻断轨迹(sdd_context.py check → exit 2) 使用的度量是被阻断的编辑数,不是被回答的能力问题数。第 1 步的那块试金石,仍然是手动的。
诚实的总结。这个本体恰好强在论文沉默的地方——运行时消费、强制执行、溯源——也恰好弱在论文强的地方:形式化的定义域与值域、已声明的不相交、成文的命名约定、可执行的能力问题。两半谁也抵不掉谁。一个智能体要加载、却无法被推理的本体,和一个推理得很漂亮却没人消费的本体,是两种不同的失败。

101 止步之处——以及智能体补上了什么

在 2026 年读一份 2001 年的指南,需要先把它的取景框说出来。这些都不是批评;论文自己说它是一个「起点」,而它至今仍是最清楚的那个起点。

除了「用」之外没有度量

质量的评估方式,是把本体用到当初为它设计的那个应用里——「布丁好不好,吃了才知道」(§8)。被点名的工具只有 Chimaera,用来查逻辑正确性与常见设计错误。没有成本模型,没有覆盖度指标,没有回归这个概念。

没有时间维度上的治理

演化只出现过一次,还是作为白 Zinfandel 的一则轶事(§4.1)。没有版本管理,没有所有权,没有裁决流程,也没有交代谁可以改一个类、凭什么证据改。

没有对抗性的消费者

它设想的消费者,是那些读取模型的应用与基于知识的系统。论文从未考虑一种能编辑代码库的消费者——而正是这种消费者,把一个本体从文档变成了一道门禁。

框架系统,不是语义网

槽挂在类上;默认值存在;RDF 与 DAML 被点名为正在成形的工作。换成 OWL 2 来读,差别是种类上的:属性是全局的、带已声明的定义域与值域,开放世界假设成立,而且根本没有默认值这回事。

没有责任

整份指南没有一处问:模型错了谁来负责,谁有权批准依据它采取的行动,一个决定又怎样被追回到做出它的那个人。

谈节点,不谈边

101 是一门让节点有意义的纪律。它没有处理节点之间那些链接的质量——而恰恰是这个变量,决定了一张由模型、工具与人组成的网络是在复利累积,还是只在放大噪声。

智能体场景补上了什么

本体变成运行时上下文

在第一次编辑之前就被加载,而不是等问题冒出来之后才被翻查——AGENTS.md、活体 SDD,以及一份不装内容、只装路由的索引,好让引用永远不会过期。

槽面变成可强制的

severity、sdd_ref、scope 与 patterns 把一条建模规则变成一个 PreToolUse 钩子,能在编辑落地之前拒绝它,并以一个非零退出码作为回执。

溯源变成必填项

每一条主张都带来源、版本、环境、方法、结果、日期与限制——而且证据是被快照的,不是被累积的,因为一个没有截止时间的数字,只是一条带小数点的谣言。

事故变成公理

论文那个迭代循环有了一个具体的驱动力:一次现场事故变成一条 SDD 裁决,裁决变成一条机器可读约束,约束阻止它被重新引入。事故只有变成护栏才算修好。

能力图旁边多了一张责任图

对每一条让某个东西得以行动的链接:谁供的数据、谁选的目标、谁授权了行动、谁观察了后果、谁能把它停下来。只有当能力链接与责任链接一起生长时,递归式改进才是可持续的。

边的质量是一门姊妹纪律

六个属性——语义清晰、溯源可追、反馈闭环、权限有界、故障隔离、目标可审查——正是 101 的节点纪律需要在节点之间的链接上补齐的东西。见连接质量。

There is no single correct ontology for any domain. Ontology design is a creative process and no two ontologies designed by different people would be the same. "The proof is in the pudding" — we can assess the quality of our ontology only by using it in applications for which we designed it.

101 §8 — 「任何领域都不存在唯一正确的本体。本体设计是一种创造性过程,不同的人设计出的两个本体不会相同。『布丁好不好,吃了才知道』——我们只有在把本体用于当初为它设计的那些应用时,才能评估它的质量。」而在 2026 年,这个「应用」里包含一种会读模型、会改代码、并且可能被模型拒绝的消费者。

Noy & McGuinness 2001, §8

出处,以及下一步读什么

论文及其谱系

  • Noy 与 McGuinness,Ontology Development 101 (2001) —— 本页每一处 101 §x 引用的出处。
  • Gruber(1993)—— 把本体定义为一份显式规约。
  • Gruninger 与 Fox(1995)—— 能力问题既是划定范围的手段,也是试金石。
  • Uschold 与 Gruninger(1996);Gómez-Pérez(1998)—— 论文指向的其他方法论。
  • McGuinness 等(2000),Chimaera —— 针对逻辑正确性与常见设计错误的诊断工具。
  • Brachman 等(1991),CLASSIC —— 葡萄酒与食物那个示例的来源;Rosch(1978)—— 概括层级。
  • Duineveld 等(2000),WonderTools? —— 一项本体工程工具的对比研究。

一套方法论的价值,恰好等于它在实际使用中活下来的那部分

那七个步骤是 25 页的常识。有意思的问题是:当本体的消费者同时也能改代码、并且可能被这套本体拒绝时,这些步骤会变成什么。那就是总纲页。