Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现

0 阅读9分钟

image.png

一、规则引擎是什么

规则引擎,简单说是:给业务逻辑提供一种专门的表达语言,而不用每次用代码重写一遍。

物联网的场景联动,就是规则引擎最常见的一种形态:一段规则 = 触发器(什么时候开始)+ 条件(满足什么判断)+ 动作(做什么事)。比如:

  • 触发器:设备上报温度(device-report);

  • 条件:温度 > 30℃;

  • 动作:发一条告警短信、给设备下一条指令。

这样的场景在物联网里随处可见:空调温度联动、设备离线告警、电表定时上报、门磁触发摄像头抓拍、无人值守设备异常停机保护…… 它们数量庞大、规则各不相同、还随业务不断调整,无法靠硬编码塞进业务代码里—— 一旦写死,每改一次就要发一次版,成本巨大。

二、为什么需要规则引擎

没有规则引擎前:

  • 改规则要发版:改个阈值都要改代码、重新编译、重新部署,无法热更新;
  • 逻辑越搅越乱:业务规则和设备接入、协议解析、数据存储纠缠在一起,越来越难维护;
  • 业务人员插不上手:规则写在代码里,业务方改一个告警阈值都要排队找开发;
  • 无法统一治理:规则散落各端,看不到全局,没法统一审计、测试、回溯;
  • 换平台就报废:规则跟着平台走,换技术栈、换厂商,全部重写。

有了规则引擎,把大大小小各种不同的场景联动从代码里解放出来,变成一份规则资产后:

  • 可编排: 用可视化画布或声明式配置搭出规则链

  • 可热更新: 改规则不碰代码,加载即生效

  • 可读: 业务人员也看得懂 "温度 > 30 就发短信"

  • 可复用: 一条规则在云端、边缘、多语言实现间共享

  • 可测试、可审计: 规则是数据,可以校验、追踪、回归

设备规模越大、联动越复杂,"规则即资产" 的价值就越大

三、Node-RED

Node-RED 是 2013 年由 IBM Emerging Technology Services 团队开源的流式编程工具,如今由 OpenJS 基金会维护。它用 "拖拽节点 + 连线" 的浏览器画布编排数据流,社区贡献了数千个节点,是物联网低代码领域绕不开的标杆。

它验证了一件重要的事:用 "节点 + 连线" 的流式模型表达场景联动

但它的形态有两个 "绑定":

  • 绑定运行时,独立运行在 Node.js 上
  • 绑定编辑器,难以脱离编辑器独立流转、迁移

Node-RED 是一个产品,它证明了规则该长什么样;但它没有回答另一个问题:规则的 "语法" 能不能成为一份与实现无关的公共标准?

四、乐吾乐的选择:先定义标准,再写实现

乐吾乐(le5le.com)的做法是倒过来做的:

第一步,定义语法标准:规则节点声明、连线路由数据、消息流转、节点分类、执行动作 —— 这些规则与任何语言、任何运行时、任何前端无关,它只规定 "规则应该怎么写、应该怎么执行"。

第二步,给出参考实现:官方标准语法,用纯 Go 实现了一版可嵌入的规则引擎 ——github.com/le5le-com/rule-flow,以 MIT 协议开源。注意定位:它是标准的 "官方实现之一",不是唯一的实现和使用方式。

语法是标准,Go 版是参考实现 —— 这个是整个设计最核心的地方。

五、为什么 "标准 + 参考实现" 更好

1. 规则与运行时解耦:一种标准语法,多种实现、集成和使用方式

标准描述的是 "规则语义",不规定用什么语言实现。因此:

  • Rust 写边缘网关,可以基于标准实现一个高性能引擎;

  • Java 写平台服务端,可以基于标准实现一个企业版引擎;

  • Node / C++ / Python 团队,都可以各自实现,同一份规则 JSON 原样迁移

规则文件从此是用户的资产,不再是某个运行时的附属品。

2. 规则与可视化解耦:任意前端技术都能做编辑器

标准定义的是语义,不是画布。可视化编辑器只是规则的 "编辑入口":

  • 官方编辑器基于乐吾乐自研的 Meta2d.js 实现,即将开源;

  • 第三方完全可以基于 Vue、React、原生 Canvas 做自己的编辑器;

  • 编辑器的产出是同一份标准 JSON,谁画的规则,换到别的编辑器都能打开。

"编辑器换一家,规则不报废"—— 这对平台选型是巨大的安全感。

3. 多语言生态可互操作

同一份规则 JSON 可以跨实现流转;测试用例、语法校验器、规则模板库可以跨语言共享。Go 版自带的单元测试,某种意义上就是标准的 "可执行规格"。

4. 标准越清晰,越容易做校验、测试与审计

语法边界明确(节点类型、参数槽、出口、作用域),就很容易写出:

  • 规则语法校验器(加载前检查,而不是运行时才发现);

  • 规则执行追踪(每条消息走了哪条路径);

  • 规则回归测试(同样的输入,不同实现应有同样的输出)。

5. 平台中立,规则可迁移

用户在一家平台编排好的联动规则,理论上可以带着走。规则不再被某个厂商的运行时或编辑器绑架 —— 这正是标准化带来的长期价值。

六、这套标准到底规定了什么

1. 节点模型

每个规则节点由六部分组成:id / type / config / inputs / inputMode / payload / outputs

type 定义了六类节点,各司其职:

类型职责
trigger触发器:cron 定时 /interval 周期 /countdown 倒计时 / 消息监听 / 第三方订阅(http、mqtt、sse、websocket + 脚本过滤)
condition条件:= != > >= < <=、区间 [)、集合 []AND/OR、自定义脚本或子流
switch多路分支:first 命中即停 / all 全命中,支持 default 兜底
action动作:设备指令、http、mqtt、db、email、sms、voice、alert、message、emit 等,副作用由宿主回调执行
function函数:内置函数(uuid7、avg、sum、merge、pick、debounce、throttle…)、goja 脚本、子流
block组合节点:把一段子流封装成一个可复用节点

2. 连线与数据路由

规则链是一张有向图:上游执行完,按 outputs.ids 触发下游,数据落到连线 key 指定的输入槽:

"outputs": {
  "ids": [{ "id": "a1", "key": "temp" }],  // 触发 a1,数据落到 a1 的 temp 参数
   "elseIds": [],                            // 条件为假时的出口(仅 condition)
   "errorIds": []                            // 执行失败的异常出口
}

关键设计:inputs** 是形参声明,路由信息集中在上游**。节点可任意复制、组合节点可多处复用,参数签名不变、上游各指各的。

3. 消息与作用域

节点间流转统一用一条 msg

{ payload: {...}, value: any, error: string }
  • payload:流作用域,贯穿整条链路,分支扇出后写时拷贝(COW)隔离;

  • value:传递作用域,只往下走一跳,落进下游输入槽;

  • error:仅异常出口非空,带 errorId 指明失败节点。

4. 执行语义

  • 串行、并行、条件分支都支持:触发层并发,传播层深度优先展开,按路径做环检测;

  • 多输入扇入靠 inputMode 控制:缺省 pair(到齐才执行一次)、any(任一到达即执行)、continuous(到齐后任一更新即重算);

  • 条件为真走 ids、为假走 elseIds、执行异常走 errorIds—— 三个出口语义互不混淆。

七、官方参考实现:Go 版 rule-flow

标准可以有很多实现,官方先出了 Go 版:github.com/le5le-com/r…

使用

// 1. 全局动作处理器:所有动作副作用都回调到这里
ruleflow.ActionHandler = func(msg string, params map\[string]any) (any, error) {
return "ok", nil // 非 nil 覆盖 msg.value;nil 则 msg 原样流向下游

}


// 2. 全局错误上报(可选)
ruleflow.ErrorHandler = func(nodeID string, err error) { /\* 记日志/告警 \*/ }
  
// 3. 注册并启动场景,触发器自动后台运行;宿主随时可主动投递消息
_ = ruleflow.Start("scene-1", nodesJSON)
ruleflow.Emit("scene-1", "device-report", 36.5)

生命周期 Start / Restart / Stop / StopAll / Remove 齐全;多节点集群里非 leader 节点设 SelfDriven = false,避免定时类触发器重复触发。一个 "温度超限 → 短信告警" 的规则,就是一段纯声明 JSON:

[  {"id": "t1", "type": "trigger", "config": { "message": "device-report", "deviceId": "dev-1"},"outputs": { "ids": [{ "id": "c1", "key": "temp" }] } },
  { "id": "c1", "type": "condition", "config": { "relation": ">" },"inputs": [{ "key": "temp" }, { "key": "limit", "value": 30 }],"outputs": { "ids": [{ "id": "a1" }], "elseIds": [{ "id": "a2" }] } },
  { "id": "a1", "type": "action", "config": { "kind": "sms", "to": "13800000000", "text": "温度超限!" } },
  { "id": "a2", "type": "action", "config": { "kind": "http", "http": "http://le5le.com", "method": "POST" } }
]

八、生态与路线图:多语言、多前端

  • 多语言实现:Rust / C++ / Java / Node 等团队都可以基于这套语法实现自己的引擎,规则 JSON 互通;

  • 可视化开源:官方编辑器基于乐吾乐自研的 Meta2d.js 实现,即将开源,第三方也可以基于任意前端技术做编辑器;

  • 标准工具链:语法校验器、规则模板库、跨实现回归测试,都可以围绕标准长出来。

维度Node-RED这套标准 + Go 参考实现
定位一个完整的可视化编程产品一份语法标准 + 官方参考实现
运行时绑定 Node.js与语言无关,官方先实现 Go 版
规则形态画布 JSON(含坐标等 UI 信息)纯声明式标准 JSON,引擎直接消费
与编辑器关系编辑器即产品解耦,任意前端可做编辑器(官方基于 Meta2d.js)
多语言生态依赖 npm 社区节点各语言可基于标准各自实现,规则互通
许可Apache 2.0参考实现 MIT

九、适合谁、怎么开始

  • 物联网平台 / 网关团队
  • 边缘计算团队
  • 想做规则编辑器的人
  • 规则引擎学习者

仓库自带完整语法文档(节点类型、config 字段速查、作用域与数据流、异常语义)和覆盖全部节点类型的示例与单元测试,上手成本极低。

十、结语

物联网规则引擎的真正价值,不该是 "我们家的引擎多好用",而是 "规则本身能不能成为一份公共资产"。

Node-RED 证明了流式规则模型的正确性;乐吾乐往前走了一步 ——把规则提炼成与语言无关的语法标准,并开源了官方 Go 参考实现。Rust、C++、Java、Node 都可以基于同一份规范给出自己的答案,可视化编辑器也可以基于任意前端技术实现。

标准先行,实现随行。这才是规则引擎领域值得期待的方向。

链接

引擎标准语法定义文档:乐吾乐文档中心 - 引擎标准语法定义文档
Github: github.com/le5le-com/r…

其他

乐吾乐可视化规则引擎编辑器前端即将开源,敬请期待

参考

乐吾乐官方文档:doc.le5le.com
Node-RED 官方文档:nodered.org