4、规则定义语言:规则语法设计、条件表达式、动作定义、规则优先级与冲突解决
各位好,我是老张。今天咱们聊聊规则定义语言——说白了,就是怎么让机器听懂你的风控逻辑。
我见过不少团队,规则引擎搞得很复杂,但最后发现是规则定义本身出了问题。语法设计得不好,业务人员看不懂,开发人员改不动,运维人员查不了。嗯,这其实是个沟通问题。
4.1 规则语法设计:让业务人员也能读懂
我个人习惯,规则语法一定要贴近自然语言。你想想看,风控规则是谁在维护?大部分时候是业务专家,不是程序员。所以语法设计的第一原则是:可读性优先。
举个例子,一个典型的硬件风控规则长这样:
RULE "温度过高保护"
WHEN
sensor.temperature > 85.0
AND duration > 5
THEN
ACTION: shutdown(priority=HIGH)
ACTION: log("温度异常", level=WARN)
ACTION: alert(recipient="ops_team")
END
你看,WHEN后面是条件,THEN后面是动作。业务人员一看就懂:温度超过85度持续5秒以上,就关机、记录、报警。
我在项目中遇到过,有些团队喜欢用JSON或XML来定义规则。说实话,机器解析是方便了,但人看着真头疼。比如:
{
"rule": "temp_protect",
"condition": {
"operator": "AND",
"operands": [
{"field": "sensor.temperature", "op": ">", "value": 85.0},
{"field": "duration", "op": ">", "value": 5}
]
},
"actions": [
{"type": "shutdown", "params": {"priority": "HIGH"}},
{"type": "log", "params": {"message": "温度异常", "level": "WARN"}}
]
}
这玩意儿,业务人员看了直接摇头。所以我的建议是:内部存储用结构化数据,对外展示用DSL。两者之间做个双向转换,既方便机器处理,也方便人阅读。
- 关键字大写(RULE, WHEN, THEN, AND, OR, NOT)
- 字段路径用点号分隔(sensor.temperature)
- 比较运算符直观(>, <, ==, !=, >=, <=)
- 动作列表用缩进或序号区分
- 支持注释(# 或 //)
4.2 条件表达式:从简单比较到复杂逻辑
条件表达式是规则的核心。说白了,就是判断「什么时候该触发」。我把它分成三个层次:
4.2.1 基础比较表达式
最简单的形式:字段 + 运算符 + 值。比如:
sensor.voltage < 3.3
device.temperature >= 85.0
status.code == 0xE001
这里要注意数据类型。我曾经踩过一个坑:温度值是浮点数,但规则里写成了整数比较。结果85.0和85在浮点运算里不完全等价,导致规则没触发。后来我强制要求:所有数值比较必须显式声明类型。
4.2.2 复合条件表达式
用AND、OR、NOT组合多个条件。我习惯用括号明确优先级,避免歧义:
WHEN
(sensor.temperature > 85.0 OR sensor.current > 2.0)
AND NOT device.status == "maintenance"
THEN
...
这里有个小技巧:AND的优先级高于OR,跟大多数编程语言一致。但为了保险,我建议业务人员写规则时,复杂条件一律加括号。
4.2.3 时间窗口与聚合表达式
硬件风控里,很多规则跟时间有关。比如「1分钟内连续3次过流」。这种就需要时间窗口支持:
WHEN
count(sensor.overcurrent, window=60s) >= 3
THEN
...
还有聚合函数:avg、max、min、sum。比如:
WHEN
avg(sensor.temperature, window=300s) > 80.0
THEN
...
4.3 动作定义:规则触发后做什么
动作就是规则触发后的执行逻辑。我把它分成三类:
| 动作类型 | 说明 | 示例 |
|---|---|---|
| 控制动作 | 直接操作硬件 | shutdown, reset, throttle |
| 通知动作 | 发送告警或日志 | alert, log, email |
| 数据动作 | 记录或更新状态 | set_flag, increment_counter |
动作定义时,我建议加上参数校验。比如shutdown动作必须带priority参数,取值范围是LOW/MEDIUM/HIGH/CRITICAL。如果漏了参数,规则引擎应该直接报错,而不是默默执行。
ACTION: shutdown(priority=HIGH, reason="温度超限")
ACTION: log(message="设备异常", level=ERROR, source="sensor_01")
ACTION: set_flag(name="overheat", value=true, ttl=3600)
这里有个细节:动作的执行顺序。我一般按优先级排序:先执行控制动作(比如关机),再执行通知动作(比如发告警)。如果反过来,告警发出去了但关机失败了,那就尴尬了。
4.4 规则优先级与冲突解决
当多条规则同时满足条件时,谁先执行?这就是优先级问题。我见过最惨的一次:两条规则同时触发,一条要关机,一条要降频,结果设备来回切换,直接挂了。
4.4.1 优先级设计
我习惯用数字表示优先级,数字越小优先级越高:
RULE "紧急关机" PRIORITY 1
WHEN sensor.temperature > 100.0
THEN ACTION: shutdown()
RULE "降频保护" PRIORITY 10
WHEN sensor.temperature > 85.0
THEN ACTION: throttle(50%)
当温度超过100度时,两条规则都满足。但优先级1的「紧急关机」先执行,设备关机后,「降频保护」虽然也满足条件,但设备已经关了,动作自然无效。
4.4.2 冲突解决策略
冲突分两种:互斥冲突和重叠冲突。
- 互斥冲突:两条规则的动作完全相反。比如一条要开机,一条要关机。这种必须通过优先级解决,或者直接报错让用户修改。
- 重叠冲突:两条规则的动作有部分重叠。比如一条要降频50%,另一条要降频30%。我建议取最严格的动作(即降频50%),因为硬件风控以安全为第一。
我曾经在项目中实现过一个冲突检测器:规则部署时自动扫描,发现互斥冲突直接拒绝部署,并给出冲突规则ID。这招很管用,上线后冲突问题减少了80%。
4.4.3 规则分组与覆盖
当规则数量超过100条时,全局优先级就不够用了。我建议引入规则组:
GROUP "温度保护" PRIORITY 10
RULE "高温关机" PRIORITY 1
RULE "中温降频" PRIORITY 2
END
GROUP "电流保护" PRIORITY 20
RULE "过流关机" PRIORITY 1
RULE "过流降频" PRIORITY 2
END
这里,组优先级决定哪个组先执行,组内规则优先级决定组内执行顺序。这样管理起来清晰多了。
- 规则部署时做静态冲突检测
- 运行时按优先级排序执行
- 高优先级规则执行后,低优先级规则自动跳过(如果动作互斥)
- 记录所有触发记录,方便事后审计
4.5 知识体系总览
下面这张图是我自己画的,把规则定义语言的核心要素串起来了:
这张图把规则定义语言的核心流程串起来了。从语法设计开始,到条件表达式、动作定义,再到优先级和冲突解决,最后交给规则引擎运行时去执行。每一步都环环相扣。
好了,关于规则定义语言,我就讲这么多。记住一句话:好的规则定义语言,应该是业务人员能写、开发人员能改、机器能高效执行。做到这三点,你的规则引擎就成功了一半。