
接入一台设备,平台要回答的问题从来不止"它有什么数据"。以电机为例:转速、温度要采上来,启停、调速要控下去,过热、故障要报出来------采集、控制、上报三条线,加上同型号设备批量接入的复用诉求,构成设备建模的全部命题。
行业的通行答案是物模型(Thing Model):以产品为单位,把设备的属性、服务、事件定义一遍。这一抽象成立,DC3 亦沿用其框架;但落到平台实现,物模型只是起点------属性怎么从寄存器里读出来?服务调用失败由谁负责?事件报上来之后谁被通知?模型变更如何做到不影响已在运行的百台设备?这些问题,物模型本身没有给答案。
IoT DC3 的答案是语义模板(Semantic Profile)------四个概念组成的一副骨架:模板(Profile)承载定义,位号(Point)、指令(Command)、事件(Event)是三类能力,设备(Device)按需引用。本文将这套体系完整拆开:先界定四个概念并建立与物模型的对应,再从六个维度说明语义模板超出通行物模型之处,继而下钻实现原理与五类对象的字段级配置,最后论证它如何直接成为智能体的工作接口------每个论断都落到表与链路上。
四个概念,一副骨架

四个概念均有一句话定义与对应的数据库表,一行记录即一份定义。
**模板(Profile,dc3_profile)**是一类设备的能力模板,回答"这类设备能采什么、能控什么、会报什么"。它是聚合根,但不存储任何能力的数据------位号、指令、事件都是独立实体,靠各自的 profileId 外键挂回模板。
**位号(Point,dc3_point)**是数据面的能力,一个可读或可写的量,携带数据类型、读写标志、单位与线性换算。它是平台中数据的最小语义单元,监控、告警、分析都建立在它之上。
**指令(Command,dc3_command)**是动作面的能力,一次带参数、要回执、有超时的动作请求:重启、校准、切换模式。输入输出参数在 dc3_command_param 中逐条声明。
**事件(Event,dc3_event)**是上报面的能力,设备主动上报的一次离散发生:故障、告警、生命周期变化。它回答的不是"某个量现在是多少",而是"发生了什么"。参数在 dc3_event_param 中声明。
四个概念之间存在两组对偶。第一组是下行与上行的对偶:指令下行(平台说"去做什么"),事件上行(设备说"发生了什么")。第二组是量与发生的对偶:位号是连续的量(转速此刻是 2980 RPM),事件是离散的发生(绕组温度越限这一件事)。一台门禁设备的"温度 = 25.3℃"是位号值,"门被强行打开"是一个事件------前者进时序库画曲线,后者进事件流水触发告警。
这套骨架与物模型的对应关系一目了然:
| 物模型三要素 | DC3 概念 | 承载表 | 回答的问题 |
|---|---|---|---|
| 属性 Property | 位号 Point | dc3_point |
这类设备有什么可读写的量 |
| 服务 Service | 指令 Command | dc3_command + dc3_command_param |
这类设备能被触发哪些动作 |
| 事件 Event | 事件 Event | dc3_event + dc3_event_param |
这类设备会主动上报什么 |
| (产品 Product) | 模板 Profile | dc3_profile |
把上面三类聚合为一份可复用的定义 |
对应之外还有差异,差异正是语义模板超出通行物模型的来源。
语义模板与物模型:六个维度的差距

这套体系在本文中称为语义模板(Semantic Profile):与物模型同级,叠加治理与语义两层,可理解为物模型的加强版。它与通行物模型的差距,可以落在六个具体维度上逐一核对:数据面、动作面、上报面、平台面、结构面、语义面。物模型回答"一类设备能说什么",语义模板在每个面上多回答一层------每一层都对应到确切的字段、约束与链路。
数据面:属性之外,还有方向、换算与采集契约。 物模型的属性通常只是"名称 + 数据类型"。DC3 的位号在此之上补齐三组字段。其一,读写标志(rwFlag)三档:只读、只写、读写。方向写入定义而非留在驱动约定里:向只读位号下发写请求,会在平台侧的写校验中被直接拒绝,错误在进入驱动之前就被拦截。其二,工程换算:基值(baseValue,默认 0)与倍率(multiple,默认 1)构成线性映射,工程值 = 原始值 × multiple + baseValue,配合小数位(valueDecimal,默认 6)与单位(unit)------变送器寄存器读数 2531,配倍率 0.01,落库即 25.31 ℃,调整量程不改一行驱动代码。其三,类型系统被复用:位号的八种数据类型(string/byte/short/int/long/float/double/boolean)与指令参数、事件参数共用同一套类型枚举,全模型一套类型语言。
动作面:服务之外,还有调用语义与执行状态机。 物模型的服务只定义"能调什么",DC3 的指令还定义"如何调用、调用之后如何认定结果"。指令分三类(custom 自定义、config 配置、action 动作),调用方式分同步与异步(callType),超时以秒为单位显式声明(默认 30 秒);输入参数带方向、类型、必填标志与默认值,输出参数声明返回内容。每一次调用都生成一条带唯一指令号(UUIDv7)的执行记录,在八态状态机中流转直至终态------除成功外,失败、超时、过期、不可恢复与重复各有独立终态,细节见下文实现原理一节。下发是否送达、执行是否成功、超时归因于哪一侧,均有记录可查;动作由此获得与数据同级的可观测性。
上报面:事件之外,还有分类、级别与确认流转。 物模型的事件通常是"名称 + 参数"。DC3 给事件两个正交的维度:类型四分类(info 信息 / alert 告警 / fault 故障 / lifecycle 生命周期)与级别四档(low / medium / high / critical)。类型决定事件的性质,级别决定事件的紧急性,告警规则可以分别依赖两者。事件上报落库时,参数以 JSONB 结构化存储,并附带当时的配置快照(config_snapshot)------事后审计看到的不仅是"报了什么",还有"当时设备是什么配置"。事件记录同时携带确认字段:确认标志、确认时间与确认人(acknowledge_flag / acknowledge_time / acknowledge_user_id),一条告警从产生到被认领处理,全程留痕。
平台面:定义之外,还有治理。 这是最本质的差距。物模型通常"一产品一模型",定义即终点;模板之上叠加了一层治理能力:
| 治理维度 | 物模型(行业通行) | 模板 Profile(DC3) |
|---|---|---|
| 复用范围 | 按产品固定 | profileShareFlag 三档:租户 / 驱动 / 用户 |
| 创建来源 | --- | profileTypeFlag 三档:系统 / 驱动 / 用户 |
| 版本演进 | 一般无显式版本 | version 显式版本,随更新递增,可作查询条件 |
| 并发保护 | --- | 版本号作乐观锁,并发修改冲突被拒绝 |
| 扩展方式 | 结构相对固定 | profileExt JSONB 弱结构化扩展 |
| 删除保护 | --- | 仍有设备引用时删除被拒绝 |
| 变更传播 | --- | 设备、属性配置等元数据事件广播到各驱动实例;模板变更本身不广播,依赖按需重拉 |
其中两处机制值得展开。版本号不只是展示字段:更新语句以 version 为条件执行递增(version = version + 1,WHERE version = 期望值),并发修改的一方会因版本冲突被拒绝,版本因此同时承担变更留痕、并发控制与查询定位三重职责。删除同样以"仍有设备引用"为前置检查,引用未解除时删除请求被拒绝------定义一经使用,便进入受控状态。
结构面:语义与连接显式分离。 多数物模型把"属性怎么读"留白,或塞进私有扩展。DC3 把配置显式拆成三层:Param(业务层)描述指令与事件的输入输出参数,与协议无关;Attribute(协议层)由驱动在启动时向平台注册,声明该协议需要哪些配置项------Modbus 驱动会声明每个位号需要从站号、功能码、偏移量;Config(实例层)存放具体设备为这些配置项填写的值,粒度到"租户 + 设备 + 位号 + 属性"。Attribute 定义配置项的形状,Config 填写配置项的值。这层分离的直接收益是:换协议不改语义模型------同一份位号定义,今天挂 Modbus 驱动,明天挂 OPC UA 驱动,能力定义原样保留,只换一套采集配置。
语义面:配置之外,还有机器可读的本体。 通行物模型的产物通常是一份给人看的文档;DC3 的建模产物是一套机器可读的本体(ontology)。标识稳定------编码在"租户 + 父资源"内唯一,引用一个概念不需要猜;类型明确------位号、指令参数、事件参数共用一套八种类型与枚举,没有自由文本歧义;关系显式------单一外键的绑定与挂载,能力来源可计算;契约完整------指令的入参、出参、必填与超时全部结构化;轨迹可查------指令有八态状态机,事件有快照与确认。这五条性质让模型不仅能被人读懂,也能被程序直接消费------这是它面向 AI 与智能体的基础,具体如何被消费,见下文"语义本体"一节。
六个维度合起来,语义模板与通行物模型的差距就有了确切的位置:物模型是建模语言,语义模板是围绕它的治理框架。物模型能表达的,语义模板都能表达;物模型没有回答的,语义模板在每个维度上各有一层机制承接。
把一台电机抽象成一套模板

抽象方法以一台编号 MOTOR_001 的电机为例展开,从设备到模板的完整过程分五步。
第一步:盘点能力清单。 从设备说明书出发,将全部功能点归纳为三个问题:哪些量要采(转速反馈、端电压、定子电流、绕组温度、轴承振动)?哪些动作要控(启动、停机、设定目标转速)?哪些情况要报(绕组过热、变频器故障、投入运行)?归纳的结果是一张三栏清单,此步骤不涉及平台操作,却决定了建模质量------漏了能力,后补定义虽可行,采集配置却要逐设备补齐后才真正生效;多了能力,异构设备就多出永远读不到值的冗余定义。
第二步:定语义。 给清单里每一条能力编码、定型、定向。位号逐条定数据类型与读写方向,需要工程量的补单位与换算;指令定类型与调用方式,拆出入参与出参;事件定类型与级别,声明携带的参数。电机的能力清单落到定义层:
| 位号编码 | 类型 | 读写 | 单位 | 说明 |
|---|---|---|---|---|
| MOTOR_SPEED | float | r | RPM | 转速反馈 |
| MOTOR_TARGET_SPEED | float | w | RPM | 目标转速给定 |
| MOTOR_VOLTAGE | float | r | V | 端电压 |
| MOTOR_CURRENT | float | r | A | 定子电流 |
| MOTOR_TEMPERATURE | float | r | ℃ | 绕组温度,倍率 0.01 |
| MOTOR_VIBRATION | float | r | mm/s | 轴承振动速度 |
| MOTOR_FAULT_CODE | string | r | --- | 变频器故障码 |
| 指令编码 | 类型 | 调用 | 参数 |
|---|---|---|---|
| MOTOR_START | action | async | 无入参;出参 resultCode |
| MOTOR_STOP | action | async | 无入参;出参 resultCode |
| MOTOR_SET_SPEED | config | sync | 入参 speed(float,必填);出参 appliedValue |
| 事件编码 | 类型 | 级别 | 参数 |
|---|---|---|---|
| MOTOR_OVERHEAT | alert | critical | temperature(float) |
| MOTOR_VFD_FAULT | fault | high | faultCode(string) |
| MOTOR_COMMISSIONED | lifecycle | low | --- |
目标转速的处理需要辨析:它是"一个可写的量",不是指令------建模成只写位号,写值即生效;"设定转速并确认电机已接受"是带回执的动作,才走 MOTOR_SET_SPEED 指令。判断标准:能落到"改某个位号的值"即是写位号,属于"触发一段动作流程"才是指令。这个边界在空调上同样成立:把目标温度设为 26 ℃ 是写位号,执行一次自清洁是指令。
第三步:归模板。 决定模板边界。模板该建多大,取决于现场的设备同质程度。若电机全部同型同配,建一个"电机模板"装下全部定义,一次绑定全量继承;若设备异构------比如经济型电机不带振动传感器------或视角多样,监控、能耗、安全各关心一部分能力,则按关注点拆成几个小模板,每台设备按自身角色选绑其一。此步骤受一条硬约束:设备与模板之间是单一外键的绑定关系,一台设备至多绑定一个模板,能力不能跨模板叠加。因此拆分的正确用法是"按角色各建小模板、逐台设备选绑其一",而不是给一台设备同时挂多个模板。这条约束换来的收益同样明确:能力来源确定,看到设备,就知道它的全部能力从哪里来。本例七位号、三指令、三事件,规模适中,单模板即可。
第四步:补连接。 模板只含语义,连接配置按设备补齐:设备级填驱动属性(Modbus TCP 下即 IP 与端口),位号级为每个位号填采集配置------从站号、功能码与偏移量,如 MOTOR_TEMPERATURE 配从站 1、功能码 03(保持寄存器)、偏移量 0x0012。语义与连接至此各就各位:换一种协议的同型电机,前三步的成果原样复用,只有这一步重做。
第五步:绑定验证。 设备绑定模板与驱动,执行一轮闭环验证:读取数据(六个只读位号出值)、写入值(MOTOR_TARGET_SPEED 下发目标值)、下发指令(MOTOR_SET_SPEED 带参调用拿到回执)、接收事件(MOTOR_COMMISSIONED 上报落库)。四条链路全部贯通,这套抽象方算成立。
五步走完,100 台同型电机共享这一份定义;第 101 台接入,只剩第四步与第五步。
实现原理:定义如何变成运转的链路
抽象的成立最终由实现支撑。本节沿存储、继承、指令、事件、变更传播五条线拆解。
存储模型:一个归属根,七张表。 dc3_profile 是归属根,dc3_point、dc3_command、dc3_event 通过 profile_id 挂回,参数表 dc3_command_param、dc3_event_param 再挂回各自的指令与事件;设备表 dc3_device.profile_id 是单一外键------一台设备至多绑定一个模板,位号集合只来自所绑定的模板,不跨模板混取,能力来源因此确定。所有编码唯一性都约束在"租户 + 父资源"范围内:位号编码在租户与模板内唯一,指令编码、事件编码同理,跨模板可重名。运行态数据与定义分属不同存储:位号值进时序库,指令执行记录进 dc3_point_command_history 与 dc3_command_history,事件流水进 dc3_event_history,各自独立演进。

继承解析:一次联接。 查一台设备的能力,平台按"设备.profileId = 能力.profileId"联接取出该模板下全部定义。没有运行时的合并逻辑,没有继承树,继承就是一次按外键的批量查询------结构简单,也正因简单,足以支撑百台设备的高频解析。
指令下发:一条带状态机的异步链路。 以写位号为例(POST /api/v3/data/point_command/write),平台先做一轮校验:设备存在且启用、设备持有活跃的驱动租约、位号存在且启用、位号的 profileId 与设备的 profileId 一致、写操作要求 rwFlag 为只写或读写------只读位号的写请求在这里被拒。校验通过后生成 UUIDv7 指令号,记录以 PENDING 态落库(过期时间 10 秒),经消息总线的 point_command 主题发往目标驱动实例,接口立即返回 HTTP 202,响应 Location 头指向历史查询端点------调用方凭指令号轮询结果,而不是阻塞等待。驱动侧依次做去重与过期检查、陈旧归属校验(ownerNode 与 fencingToken,拦截租约过期的陈旧节点),再按设备加锁串行执行,经 DriverWriteService.write() 写入设备;写成功后驱动将写入值本身回发做回显,结果经 point_command_result 主题回传数据中心,更新执行记录的终态。状态机全程可查:
| 状态 | 含义 |
|---|---|
| PENDING | 已受理,待发送 |
| SENT | 已送达驱动,执行中 |
| SUCCESS | 执行成功(写路径回显写入值) |
| FAILED | 驱动执行失败 |
| TIMEOUT | 超时未回执 |
| EXPIRED | 入队后过期,未执行 |
| DEAD | 发布失败等不可恢复终态 |
| DUPLICATE | 重复指令,被去重拒绝 |

设备级自定义指令(POST /api/v3/data/command_history/call)走同构链路,差异只在执行入口:DriverCustomService.execute() 按指令定义执行动作流程,超时取指令声明的 timeout(默认 30 秒)。两条链路共享同一套设计:异步受理、状态机跟踪、幂等去重、设备级串行------同步与异步的差别体现在元数据与超时预算上,派发本身统一走可靠的消息通道。
事件上报:从一次发生到一条通知。 驱动是事件的产生源------MQTT 驱动收到匹配订阅主题的设备消息,按配置的 JSON 路径抽取事件码与参数后上报;虚拟驱动则周期性模拟上报。事件经 event 主题到达数据中心,三道校验(设备存在且启用、事件定义存在且启用、事件的 profileId 与设备一致)通过后落入 dc3_event_history:参数值存 JSONB,附带配置快照,确认标志默认未确认。落库后链路继续延伸:事件进入告警规则管线,事件类型与级别作为规则条件变量参与评估,命中的生成告警记录写入 dc3_entity_alarm,再按规则配置的通知渠道(邮件、飞书、Webhook)发出通知任务。定义时的类型与级别两个维度,在这里变成规则引擎可用的判断条件------建模时多写的每个字段,运行时均有其消费者。设备离线这类状态变化不混入事件流水,走独立的状态检测与状态告警链路,两条链路互不混杂。

变更传播:广播与按需重拉。 驱动侧为每台接入设备维护元数据缓存,缓存不设 TTL,新鲜度靠两个机制保证:一是元数据主题的广播------设备、驱动、属性配置、指令参数与事件参数发生增删改时,管理域发布元数据事件,每个驱动实例收到后刷新对应缓存;二是按需重拉------缓存未命中时,驱动经 gRPC 从管理域按设备单条获取。需要划清的边界是:指令与事件实体级、位号的广播接口已预留(元数据类型枚举与驱动端处理分支均在),但广播链路尚未打通,管理域发布的事件当前不产生实际通知;模板定义本身则没有广播通道。这些场景依赖驱动的按需重拉兜底------模板改一处后,驱动侧按新定义采集的生效时机取决于重拉触发,生产环境变更前需评估影响面。
如何配置:五类对象,两条路径

配置分布在两层:模板层定义能力------模板、位号、指令、事件四类对象,一次定义、百台复用;设备层落实连接------驱动、位号、指令、事件四级属性配置,逐台填写。五类对象逐一拆开,每类均按字段清单、配置示例、注意事项三部分展开。
模板:能力定义的容器。 配置项最少,字段清单:
| 字段 | 取值 | 说明 |
|---|---|---|
| 名称 | 文本,必填 | 租户内不可重复,平台在保存时校验 |
| 编码 | 文本,可留空 | 租户内唯一;留空由平台自动生成 |
| 共享范围 | 租户内共享 / 驱动内共享 / 用户私有 | 默认租户内共享 |
| 创建来源 | 系统 / 驱动 / 用户 | 手工创建默认用户 |
| 版本 | 数字,默认 0 | 随更新递增;更新时需带当前版本,平台校验一致才执行(乐观锁) |
| 备注与扩展 | 文本 + JSONB | remark 与 profileExt,弱结构化补充 |
模板创建后只是空容器,能力来自后续挂入的位号、指令与事件。命名建议采用"设备型号 + 用途"的形式(如"变频电机 - 泵组监控"),共享范围在创建时确定。
位号:数据面,配"量"的语义。 在模板下逐条添加,字段清单:
| 字段 | 取值 | 说明 |
|---|---|---|
| 名称 / 编码 | 文本 | 编码在"租户 + 模板"内唯一,跨模板可重名 |
| 数据类型 | string / byte / short / int / long / float / double / boolean | 默认 string;读取管线的转换契约 |
| 读写标志 | r 只读 / w 只写 / rw 读写 | 默认 r;写路径的闸门 |
| 单位 | 自由文本 | 工程单位,展示与理解用 |
| 小数位 | 默认 6 | 浮点值按此保留 |
| 基值 / 倍率 | 默认 0 / 1 | 线性换算:工程值 = 原始值 × 倍率 + 基值 |
绕组温度位号的完整填法:名称"绕组温度"、编码 MOTOR_TEMPERATURE、类型 float、只读、单位 ℃、倍率 0.01、小数位 2------寄存器读数 2531,落库即 25.31 ℃。注意事项:新建位号若不做任何配置,按 string 只读、无换算处理;采集数值量必须显式改类型并按需配换算,否则采集值为无法参与计算的字符串。
指令:动作面,配"动作"的契约。 本体五项,参数逐条声明:
| 字段 | 取值 | 说明 |
|---|---|---|
| 名称 / 编码 | 文本 | 编码在"租户 + 模板"内唯一 |
| 类型 | custom 自定义 / config 配置 / action 动作 | 决定执行语义 |
| 调用方式 | sync 同步 / async 异步 | 影响超时预算与调用方等待策略 |
| 超时 | 秒,默认 30 | 执行回执晚于此即判超时 |
| 参数字段 | 取值 | 说明 |
|---|---|---|
| 名称 / 编码 | 文本 | 编码在"租户 + 指令"内唯一 |
| 方向 | input 入参 / output 出参 | 入参由调用方传入,出参由驱动返回 |
| 类型 | 复用位号的八种类型 | 全模型一套类型语言 |
| 必填标志 | 是 / 否 | 契约要求调用方必传的参数 |
| 默认值 | 文本,可空 | 调用方未传时生效 |
MOTOR_SET_SPEED 的配置即:类型 config、调用 sync、超时 30;入参 speed(float,必填)、出参 appliedValue(float)。注意事项:指令本体(类型、调用方式、超时)的变更当前不广播到驱动侧缓存,依赖按需重拉;参数增删改会广播。修改既有指令契约前评估影响面,并在低峰期执行。
事件:上报面,配"发生"的分级。 本体四项,参数逐条声明:
| 字段 | 取值 | 说明 |
|---|---|---|
| 名称 / 编码 | 文本 | 编码在"租户 + 模板"内唯一 |
| 类型 | info 信息 / alert 告警 / fault 故障 / lifecycle 生命周期 | 决定事件的性质 |
| 级别 | low / medium / high / critical | 决定事件的紧急性 |
| 参数字段 | 取值 | 说明 |
|---|---|---|
| 名称 / 编码 | 文本 | 编码在"租户 + 事件"内唯一 |
| 类型 | 复用位号的八种类型 | 上报时按此类型解析,运行时以 JSONB 落库 |
MOTOR_OVERHEAT 的配置即:类型 alert、级别 critical、参数 temperature(float)。注意事项:类型与级别是告警规则的条件变量------修改已有事件的类型或级别,会改变既有规则对它的匹配行为,修改前需评估。
设备:缝合定义与连接。 设备层做两类事:基本信息与绑定关系,以及四级属性配置的填值。
| 字段 | 取值 | 说明 |
|---|---|---|
| 名称 / 编码 | 文本 | 租户内标识一台设备 |
| 模板绑定 | 单一 profileId | 能力来源;一台设备至多绑定一个模板 |
| 驱动绑定 | 单一 driverId | 连接通道;决定用哪套协议与这台设备通信 |
| 扩展字段 | JSONB | deviceExt,补充信息 |
| 启用标志 | 启用 / 停用 | 停用后数据读写、指令下发与事件上报均被平台拒绝 |
属性配置填值,源自驱动的属性注册机制:平台不为任何协议预设配置字段,每个驱动启动时向平台注册自己需要哪些配置项,分四个层级------驱动级属性声明设备连接需要什么(Modbus TCP 声明 IP、端口),位号级属性声明每个位号的采集需要什么(从站号、功能码、偏移量),指令级与事件级属性声明执行与上报各自的配置项。属性注册只定"形状",具体值按设备逐项填写:接 10 台 Modbus 设备,就是 10 份连接参数,外加每台设备逐位号的采集配置;换 OPC UA 驱动,所需填写的更换为节点 ID 与命名空间索引,模板上的语义定义一字不动------驱动属性是协议的形状,模板定义是业务的形状,互不越界。
注意事项有三。其一,先绑模板再填配置:设备的位号、指令、事件集合完全由所绑模板解析而来,未绑模板时没有位号矩阵可填。其二,改绑模板等于整体更换能力集:已填的采集配置随之失效,需按新模板重填。其三,模板新增位号后,定义是批量的,采集配置要逐设备补齐,新位号才真正参与采集。
五类对象的配置通过两条路径完成:
前端路径。 模板列表页(/profile)以卡片网格组织,新建走表单弹窗;进入模板详情页,五个标签页纵览全局------模板信息、关联位号、关联指令、关联事件、关联设备,其中"关联设备"页签直接列出绑定了该模板的所有设备。位号、指令、事件三个页签均为"工具条 + 卡片 + 弹窗编辑 + 抽屉详情"的形态,编辑指令或事件时可在同一弹窗内维护参数列表。设备侧的连接配置在设备编辑页完成,页内按设备信息、驱动、位号、指令、事件五个维度组织页签------后四个页签正是四级属性的填值矩阵,填的即三层配置里 Config 层的值。
API 路径。 管理域四组 CRUD 与运行域三个端点,路径即语义(单一资源用 get_by_id,集合用 list):
| 操作 | 端点(POST,除注明外) |
|---|---|
| 模板增删改查 | api/v3/manager/profile/add / update / delete / get_by_id(GET) / list |
| 位号增删改查 | api/v3/manager/point/...(同构) |
| 指令与参数 | api/v3/manager/command/... + api/v3/manager/command_param/... |
| 事件与参数 | api/v3/manager/event/... + api/v3/manager/event_param/... |
| 位号采集配置 | api/v3/manager/point_attribute_config/add(attributeId / deviceId / pointId / configValue) |
| 读写位号 | api/v3/data/point_command/write / read,返回指令号与轮询地址 |
| 调用指令 | api/v3/data/command_history/call |
| 上报事件 | api/v3/data/event_history/report(亦为驱动 gRPC 入口) |
以电机为例的完整序列:建模板 → 建七个位号 → 建三条指令并逐条添参数 → 建三个事件并添参数 → 为设备填驱动属性与位号采集配置 → 设备绑定模板 → point_command/read 下发读指令,凭返回的指令号轮询历史端点拿到第一批转速值。该序列不依赖界面,可直接脚本化,即批量接入 100 台同型设备的完整流程。
五重收益
把设备抽象成一套模板配置,收益落在五点。
一次定义,百台复用。 能力变更只发生在模板一处,版本递增留痕,百台设备共享新定义。
语义与连接解耦。 换协议不动模型,位号表与采集配置各司其职,驱动可插拔而语义资产长存。
能力来源确定。 单一外键的绑定关系,看到设备即知其全部能力的出处,没有跨模板的隐式合并。
动作可审计。 每次指令下发有唯一指令号与八态轨迹,每次事件上报有快照与确认标志,追责与回放有据。
建模即治理。 类型、方向、级别、参数这些定义期多写的字段,在告警规则、通知路由、审计查询中逐一兑现------模型不是文档,是运行时的一部分。
语义本体:面向智能体的建模接口

模型不是文档,是运行时的一部分------既是运行时的一部分,就不仅能被人读取,也能被机器直接消费。"语义模板与物模型"一节将机器可读本体列为第六个维度,落在建模端;本节展开其消费面:这套语义对智能体的具体意义,以及平台提供的两层消费入口。
确定性词汇表,替代自然语言的歧义。 大模型最擅长、也最容易出错的,是把自然语言意图翻译成确定的操作。建模时写下的每一个编码与枚举,都是在为这一步铺路:"读取 MOTOR_001 的 MOTOR_SPEED"不是一句待猜的话,而是一次按编码定位的查询------位号编码在"租户 + 模板"内唯一,类型只有八种,读写方向只有三档。智能体拿到的词汇表本身就是答案,无需再做自然语言解析。
契约完整,调用可以按 schema 进行。 指令定义包含智能体调用所需的全部要素:入参的名称、类型、必填标志与默认值,出参的类型,超时预算,同步与异步语义------这与函数调用(function calling)所需的 JSON Schema 一一对应,平台对设备的每一项操作能力,天然带有一份可发布的工具描述。事件定义同理:类型与级别两个正交维度,既是告警路由的语义,也是智能体分类、聚合、研判时可以直接引用的字段。
状态可验证,行动形成闭环。 智能体区别于脚本之处,在于它要观察行动的结果并修正下一步。每次指令下发携带唯一指令号,在八态状态机中流转至终态,调用方凭指令号轮询结果------对智能体而言,每一步行动都有确定的结果可以读取,而非发出之后无结果可查。事件侧的快照与确认标志,则让"当时发生了什么、由谁处理"成为可回放的事实。
本体即接口,消费它的通道已经存在。 该本体已具备实际的消费通道,平台提供两层 AI 入口。其一,网关经 /mcp 路由开放 MCP(Model Context Protocol)入口(需在网关配置中显式启用),把平台能力以工具形式暴露给外部智能体,工具的可见范围由管理面配置。其二,平台内置的智能体模块(dc3-common-agentic)提供一组与语义对象一一对应的工具------ProfileTool、PointTool、CommandTool、EventTool、DeviceTool,外加 DriverTool、PointValueTool 等------工具的组织方式就是这套建模的镜像。人通过界面与 CLI 操作同一套语义,智能体通过工具操作同一套语义,两个入口共享一份本体。
需要划定的边界是:本体由人设计、机器消费------能力盘点与语义定义(前文的五步)仍是人的工作,平台不承诺 AI 自动建模;智能体的角色是辅助诊断、查询与决策,而非替代人工处置。当 AI 加入时,它面对的将是一份结构完整、标识稳定、可验证的领域本体,而非一格格待填的表单。
适用范围与限制
- 单绑定是硬约束。 一台设备至多绑定一个模板,跨模板组合能力不可行;确有组合需求时,应把能力收敛进一个模板,或按角色拆分设备;
- 模板变更影响全部引用设备。 位号定义修改对所有引用设备生效,生产环境变更前需评估影响面;当前版本指令与事件实体级、位号与模板定义的变更广播尚未接入,驱动侧以按需重拉兜底,高频变更场景建议在低峰期执行;
- 线性换算是位号换算的边界。 基值与倍率只覆盖线性映射,查表、分段、曲线标定需在设备侧或自定义驱动内完成;
- callType 目前是元数据语义。 同步与异步的调用方式、超时预算已随指令定义落库并在超时控制中生效,但派发链路统一为异步加轮询,同步阻塞语义尚未在传输层区分;
- 模板不承载运行态数据。 位号值、指令历史、事件流水都按设备维度落库,跨设备聚合统计需按位号编码自行组织。
结语
物模型回答"一类设备有什么能力",这是设备建模的第一层;DC3 的语义模板在它之上补齐了其余各层:位号带方向与换算,能力定义不止于名称;指令带参数、超时与状态机,动作调用可审计;事件带类型、级别与告警管线,上报从流水变成流程;模板带共享范围、版本与引用保护,定义成为可治理的资产。四个概念、七张表、一条异步链路与一条告警链路,把"接入一台设备"变成了"复用一份定义"。理解了这套抽象,再看 DC3 的设备接入,看到的就不是一格格表单,而是一套可以被批量执行、版本化演进、面向智能体开放的语义模板体系。
IoT DC3 · GitHub | Gitee | 文档 docs.dc3.site | 在线书 book.dc3.site | 演示 demo.dc3.site | 官网 dc3.site