4. 报警分级规则引擎

固定阈值分级只能回答“当前值是否越限”,而真实设备报警往往需要回答更复杂的问题:这个越限持续了多久?是否同时满足多个测点条件?当两条规则给出不同级别时,最终应该听谁的?规则引擎的价值,就是把“分级判断”从散落在代码里的 if-else 中抽离出来,变成可配置、可解释、可追溯的规则集合。

规则引擎的基本工作模型可以概括为:事实(Fact)进入工作内存 → 规则条件(LHS)匹配 → 冲突集(Agenda)产生 → 冲突消解策略选择 → 执行动作(RHS)输出分级结果。其中“冲突消解”正是处理优先级冲突的核心环节。下面这张图展示了从设备测点数据到最终报警级别的完整规则处理链路,包括阈值规则、持续时间规则、组合条件规则以及优先级仲裁的汇合点。

事实 Fact 测点值 / 时间戳 设备状态 / 工况 工作内存 Working Memory 滑动窗口缓存 规则条件匹配(LHS) 阈值规则 value > 85 → 预警 持续时间规则 持续 > 30s → 升级 组合条件规则 温度∧振动 → 严重 冲突集 Agenda 多条规则同时命中,等待仲裁 冲突消解策略 ① 显式优先级 salience 高者先执行 ② 同优先级按“严重度取最高”合并 ③ 互斥规则用 activation-group 分组 分级结果输出(RHS) 报警级别 + 触发规则ID + 证据快照 → 写入报警事件表 / 推送责任路由 规则要素与示例参数 阈值规则示例: 温度 > 85℃ → 预警(salience=10) 温度 > 95℃ → 严重(salience=20) 持续时间规则示例: 温度 > 85℃ 且持续 ≥ 30s → 严重 振动 > 4.5mm/s 且持续 ≥ 60s → 严重 组合条件示例: 温度 > 85℃ ∧ 振动 > 4.5mm/s → 严重(salience=30) 优先级冲突处理: 同设备同测点,取最高级别输出 规则ID与证据一并记录,便于追溯

规则的四类核心要素

一条报警分级规则通常由四部分构成:条件(LHS)、动作(RHS)、优先级(salience)和生效范围(agenda-group / activation-group)。条件决定“什么时候触发”,动作决定“输出什么级别”,优先级决定“多条规则同时命中时谁先执行”,生效范围决定“哪些规则互斥、哪些规则可以并行”。

以温度测点为例,可以定义三条规则:

rule "温度预警"
  salience 10
  when
    $t : Temperature( value > 85, value <= 95 )
  then
    raiseAlarm("TEMP_HIGH", "预警", $t.getValue());
end

rule "温度严重"
  salience 20
  when
    $t : Temperature( value > 95 )
  then
    raiseAlarm("TEMP_CRITICAL", "严重", $t.getValue());
end

rule "温度持续升级"
  salience 30
  when
    $t : Temperature( value > 85 )
    $w : DurationWindow( duration >= 30s )
  then
    raiseAlarm("TEMP_SUSTAINED", "严重", $t.getValue());
end

当温度达到 96℃ 且持续 35 秒时,三条规则可能同时命中。此时 salience 最高的“温度持续升级”先执行,输出“严重”;“温度严重”也输出“严重”;“温度预警”输出“预警”。最终结果取最高级别“严重”,并记录触发规则为 TEMP_SUSTAINED。这就是冲突消解的基本逻辑:先按优先级排序,再按严重度合并。

持续时间规则的实现要点

持续时间规则不能简单地在单次事实中判断,需要引入滑动窗口或状态累积。常见做法有两种:一是用规则引擎的 DurationWindow 事实,由外部定时器每 5 秒更新一次窗口内满足条件的持续时长;二是在规则中维护一个 Accumulate 累积器,统计最近 N 个采样点中连续越限的次数。

以 1 秒采样周期为例,若要求“温度 > 85℃ 持续 30 秒”,则窗口内需要至少 30 个连续采样点满足条件。规则可以写成:

rule "温度持续30秒升级"
  salience 30
  when
    $t : Temperature( value > 85 )
    accumulate(
      $s : Temperature( value > 85 ) over window:length(30),
      $cnt : count($s);
      $cnt >= 30
    )
  then
    raiseAlarm("TEMP_SUSTAINED", "严重", $t.getValue());
end

这里的关键参数是窗口长度和采样周期。窗口长度 30 对应 30 秒,前提是采样周期为 1 秒。如果采样周期变为 500 毫秒,窗口长度应调整为 60,否则持续时间判断会缩短一半。工程上建议把窗口长度和采样周期都作为可配置参数,避免硬编码。

组合条件与优先级冲突的工程处理

组合条件规则用于表达“多个测点同时异常”的场景。例如“温度 > 85℃ 且 振动 > 4.5mm/s”比单一温度越限更严重,因为两者同时出现往往意味着设备存在复合故障。组合条件规则的 salience 通常设置得比单条件规则更高,以确保复合异常优先输出。

优先级冲突的常见来源有三类:同一测点的不同阈值规则冲突、不同测点的规则同时命中、持续时间规则与瞬时规则冲突。处理策略如下:

  • 同一测点不同阈值:按 salience 排序,高优先级先执行;若输出级别不同,取最高级别。
  • 不同测点同时命中:若属于同一设备,合并为一条报警,级别取最高,证据字段记录所有触发测点。
  • 持续时间规则与瞬时规则冲突:持续时间规则 salience 更高,因为它代表异常已持续,风险更高。
  • 互斥规则:使用 activation-group 分组,同组内只执行 salience 最高的一条,避免重复报警。
规则引擎的输出不应只有“级别”一个字段。建议同时输出:触发规则ID、触发时间、测点当前值、持续时间、组合条件命中详情。这些证据字段是后续责任路由和报警复盘的基础。

一个可执行的规则配置示例

下面给出一个面向温度与振动测点的规则配置表,可直接作为规则引擎的输入。表中 salience 值越大优先级越高,activation-group 相同的规则互斥。

规则ID 条件 输出级别 salience activation-group
TEMP_WARN 温度 > 85 且 ≤ 95 预警 10 temp_level
TEMP_CRIT 温度 > 95 严重 20 temp_level
TEMP_SUSTAINED 温度 > 85 持续 ≥ 30s 严重 30 temp_level
VIB_WARN 振动 > 4.5 且 ≤ 7.1 预警 10 vib_level
VIB_CRIT 振动 > 7.1 严重 20 vib_level
COMBO_CRIT 温度 > 85 且 振动 > 4.5 严重 40 combo_level

假设某时刻温度 88℃、振动 5.2mm/s,且温度已持续 35 秒。此时 TEMP_WARN、TEMP_SUSTAINED、VIB_WARN、COMBO_CRIT 四条规则同时命中。按 salience 排序:COMBO_CRIT(40)先执行,输出“严重”;TEMP_SUSTAINED(30)输出“严重”;TEMP_WARN(10)和 VIB_WARN(10)输出“预警”。最终合并结果为“严重”,触发规则记录为 COMBO_CRIT 和 TEMP_SUSTAINED,证据字段包含温度 88℃、振动 5.2mm/s、持续 35 秒。

规则引擎的优先级冲突处理必须保证确定性:相同输入必须得到相同输出。避免在规则中使用随机数、当前系统时间等不确定因素作为条件。持续时间窗口的更新应由外部定时器驱动,而不是在规则内部依赖系统时钟。