闭环四:设备与预测维护
用时间序列读数和阈值触发维保工单,引入 MaintenanceTask 对象与 request-maintenance。

本课目标
读完这一课,你将能够
- 读懂时间序列属性的三个读取接口和 1,000 个点的内联上限,并据此设计存什么
- 写出
MaintenanceTask对象类型和request-maintenanceAction,让重复申请被拒绝 - 设计两级阈值的触发条件,并说出传感器掉线这种静默故障怎么兜底
读数是时间序列,阈值是数据
前三个闭环的数据都是一件一件到来的事件,这一课的数据是连续不断的读数。这个闭环的决定是:这台设备要不要现在安排维保?对象是 machine,它通过 lineMachines 属于一条 productionLine,身上有两个时间序列属性:vibration 和 temperature。设备对象就是设备的孪生:读数、位置、维保历史都挂在这一个对象上。
车间里的三维位置,可以用建模 SDK 的锚点绑到这个对象上。生成的空间只是看起来合理,不是测绘,锚点在有人核对前要标 verified: false。
时间序列属性的值是 { seriesId, points },points 是一列 { time, value }。AIDC 内联最多 1,000 个点,读取有三个接口:firstPoint、lastPoint 和 streamPoints。这个上限决定了设计:本体(Ontology)里只放最近一段有意义的读数,比如每小时的最大值;每秒几百个点的原始波形留在物联网系统里。
# 最新的一个点
curl -H "Authorization: Bearer $AIDC_API_KEY" \
"https://www.ai-dc.ai/api/v1/ontologies/cell-example/objects/machine/M-07/timeseries/vibration/lastPoint"
# 一段时间内的点
curl -X POST -H "Authorization: Bearer $AIDC_API_KEY" -H "Content-Type: application/json" \
-d '{"range":{"type":"absolute","startTime":"2026-09-29T00:00:00Z","endTime":"2026-09-29T12:00:00Z"}}' \
"https://www.ai-dc.ai/api/v1/ontologies/cell-example/objects/machine/M-07/timeseries/vibration/streamPoints"
阈值不要写死在触发条件里。给 machine 加两个小属性:vibrationLimit 和 temperatureLimit。阈值是数据,随设备走,改它不需要重新发布工作流。下面只写振动,温度照抄;任一读数超线都算,在 when 里用 || 连起来。
新对象与新动词:维保工单
本课引入一个只存在于语义层的对象类型 MaintenanceTask,用 request-maintenance 来建。它和 machine 之间是一对多的 machineMaintenanceTasks,外键在维保工单这一端:
{
"kind": "objectType",
"apiName": "MaintenanceTask",
"title": "维保工单",
"description": "一次设备维保:由自动化或人申请,只在语义层,用 Action 记。",
"schema": {
"titleColumn": "reason",
"columns": [
{ "name": "taskId", "type": "string", "primaryKey": true, "title": "编号" },
{ "name": "machineId", "type": "string", "title": "设备", "references": { "entity": "machine", "column": "machineId" } },
{ "name": "status", "type": "string", "title": "状态" },
{ "name": "reason", "type": "string", "title": "原因", "notNull": true },
{ "name": "triggerReading", "type": "double", "title": "触发时的读数" },
{ "name": "createdAt", "type": "timestamp", "sharedProperty": "createdAt" }
]
}
}
request-maintenance 一次做两件事:建一张维保工单,并把设备的 maintenanceState 标为 requested。这个属性只在语义层维护(writeback: true),提交条件用它挡住重复申请。两条规则在同一个事务里:
{
"kind": "actionType",
"apiName": "request-maintenance",
"title": "申请维保",
"schema": {
"parameters": [
{ "name": "machine", "type": "object", "objectType": "machine", "required": true },
{ "name": "reason", "type": "string", "required": true, "maxLength": 300 },
{ "name": "reading", "type": "double" }
],
"rules": [
{ "type": "createObject", "objectType": "MaintenanceTask", "values": { "taskId": "$uuid", "machineId": "$machine", "status": "open", "reason": "$reason", "triggerReading": "$reading", "createdAt": "$now" } },
{ "type": "modifyObject", "objectType": "machine", "object": "$machine", "values": { "maintenanceState": "requested" } }
],
"submissionCriteria": [
{ "condition": { "type": "comparison", "left": { "param": "machine", "property": "maintenanceState" }, "operator": "isNot", "right": { "literal": "requested" } },
"failureMessage": "这台设备已经有未完成的维保申请" }
],
"summary": "{machine} 申请维保:{reason}",
"actionLog": true
}
}
有了这条提交条件,触发条件被反复满足也不会堆出十张任务。维保完成时把 maintenanceState 改回去的 Action 写法与它对称,这里从略。
自动化:两级阈值
触发条件取最后一个点。points 已按时间排好,last 就是最新读数,用 80% 做预警线:
"trigger": {
"change": {
"type": "machine",
"when": "=last(pluck(object.vibration.points, 'value')) > object.vibrationLimit * 0.8",
"cooldown": "12h",
"input": { "machine_id": "=object.machineId" }
}
}
- 01读数最新点和最近一段的最大值
- 02定级别超过 80% 预警,超过 100% 超限
- 03AI 分析结合趋势解释原因
- 04申请维保
request-maintenance,仅超限时 - 05通知维保主管
两个级别用步骤自己的 when 区分:预警只通知,超限才写维保工单并通知。计算步骤先把一段读数缩成几个数,最大值、平均值,再交给模型解释,不要把上千个点塞进提示词。
自主程度是「自动」:建维保工单风险低、随时能取消,所以自动做。停机和排产是人的决定,也是这个闭环的人工关口。智能体读读数、判断级别、写说明,不停任何设备。
出错与验证:最危险的是没有变化
- 传感器掉线:没有新读数,就没有变化,也就没有触发。这是静默故障,
change抓不到,要用一个时间是条件的看门狗,按hoursSince判断「读数多久没来」。 - 读数抖动:一次尖峰就申请维保。冷却 12 小时,加上「每台设备一张未完成申请」,已经把噪声挡在外面;还不够,就让计算步骤要求最近几个点都超线。
- 阈值设错:太低就天天告警。第一个版本只通知,按一周的告警数调阈值,再加写入。维保工单关闭时记下有没有发现故障,日后调阈值才有证据。预警线放在 80%,是给维保留一个班次的提前量;这个比例是示例,按设备劣化的速度定。
- 窗口太短:窗口决定能看多远。每小时一个点,1,000 个点约 41 天;每分钟一个点,只有不到 17 小时。先定窗口,再定规则。
- 对照现场
用
lastPoint取一台设备的最新读数,和现场仪表对一对,再谈阈值。 - 先申请,再校验
在一台测试用的设备上真的申请一次,再对同一台设备
--validate-only:这一次应当失败,给出那句失败信息。 - 预演
对一台超限和一台正常的设备各预演一次,只有超限那台的计划里有
request-maintenance。
aidc semantic apply request-maintenance --param machine=M-07 --param reason="振动超限" --param reading=7.4 --validate-only
aidc semantic automate run machine-watch --param machine_id=M-07 --channel test --preview
aidc semantic edits-history machine --pk M-07
要点
- 时间序列内联最多 1,000 个点,读取用
firstPoint、lastPoint、streamPoints;本体里只放有意义的摘要。 - 阈值是数据,写成设备的属性,而不是写死在工作流里。
request-maintenance用maintenanceState加提交条件,保证一台设备同时只有一张未完成申请。- 没有变化就没有触发:传感器掉线要靠以时间为条件的看门狗兜底。
练一练
为你的设备读数设计阈值
选一种有读数的东西:设备、温湿度、库存水位或系统延迟都可以。
写出每个读数的采样间隔,算一算 1,000 个点能覆盖多长时间,再决定存原始值还是每小时摘要。
照 request-maintenance 写一个创建型 Action,并加一条防止重复的提交条件。
写出「读数多久没来就告警」的定时间隔和判断表达式,并说明为什么它属于 schedule。
小测
选一个答案,马上看解析。
Q1传感器掉线了,没有新读数进来。change 触发的维保工作流会怎样?
change 只对变化起反应。「该来的数据没来」是时间本身的条件,用 schedule 加 hoursSince。
Q2为什么把 vibrationLimit 做成设备的属性,而不是写在触发条件里?
写死的阈值每改一次就要升一个应用版本;放在对象上,改的是数据,留有记录。
Q3同一台设备的振动连续几小时超线,会建多少张未完成的维保工单?
冷却限制同一对象的重复运行,提交条件保证即使运行了,第二张也会被拒绝。