2. 规则引擎基础

在融合决策流中,规则引擎承担“可解释、可配置、可快速变更”的决策职责。理解规则引擎,不能停留在“写 if-else”的层面,而要掌握它如何把业务策略抽象为规则、如何匹配事实、如何在多条规则同时命中时做出选择。本章围绕规则、条件、动作、优先级、冲突消解、Rete 算法与常见引擎展开,为后续评分模型融合打下工程基础。

一、核心原理:规则引擎到底在做什么

规则引擎的本质是一个“事实驱动的推理机”。它把业务知识拆成若干条规则,每条规则由条件(Condition)和动作(Action)组成。运行时,引擎将输入数据作为事实(Fact)放入工作内存(Working Memory),通过模式匹配找出所有条件成立的规则,再按冲突消解策略选择执行顺序,最终触发动作并可能修改事实,形成链式推理。

  • 规则(Rule):一条独立的业务判断单元,通常包含名称、条件、动作、优先级和元数据。
  • 条件(Condition):对事实的约束,如“用户等级为黄金且订单金额大于 500”。
  • 动作(Action):条件满足后执行的操作,如“发放优惠券”“标记风险等级”“拒绝授信”。
  • 优先级(Salience):数值越大越先执行,用于表达业务上的强弱顺序。
  • 冲突消解(Conflict Resolution):当多条规则同时命中时,决定先执行哪一条的策略集合。
规则引擎的价值不在于“能判断”,而在于“判断逻辑与代码解耦”。业务人员可以修改规则文件,系统无需重新编译即可生效,同时保留完整的命中日志,便于审计与回溯。

二、方法流程:从规则定义到执行

一个典型的规则引擎执行流程可以概括为:加载规则、插入事实、模式匹配、冲突集排序、触发动作、更新事实、循环直至无规则可触发。下面用一段伪代码展示核心循环:

// 规则定义示例(DRL 风格)
rule "黄金会员大额订单折扣"
  salience 100
  when
    $u: User(level == "GOLD")
    $o: Order(amount > 500, userId == $u.id)
  then
    $o.setDiscount(0.15);
    update($o);
end

// 执行循环
while (conflictSet.notEmpty()) {
    Rule r = conflictSet.selectByStrategy();
    r.fire();
    conflictSet.rebuild();
}

其中“冲突集重建”是关键:动作可能修改事实,导致原本不成立的规则变为成立,或已成立的规则失效。因此规则引擎通常采用“匹配—选择—执行—再匹配”的循环,而不是一次性匹配后顺序执行。

三、冲突消解策略与优先级设计

当多条规则同时命中,引擎必须决定执行顺序。常见策略包括:优先级数值、最近使用、最具体条件优先、规则定义顺序、随机或轮询。工程上最常用的是“显式优先级 + 条件具体度”组合。

策略 说明 适用场景 风险
Salience 优先级 数值大者先执行 风控拦截优先于营销 优先级膨胀,难以维护
具体度优先 条件更具体的规则先执行 特例覆盖通用规则 具体度难以量化
定义顺序 按加载顺序执行 简单流程 隐式依赖,易被覆盖
最近使用 优先复用最近命中的规则 性能优化 行为不稳定
优先级建议分段管理:0–99 为数据校验,100–199 为风险拦截,200–299 为评分计算,300–399 为营销权益。每段预留间隔,避免频繁调整。

四、Rete 算法:为什么规则引擎能跑得快

如果每次循环都遍历所有规则的所有条件,复杂度会随规则数量线性甚至指数上升。Rete 算法通过构建有向无环图,把条件拆成节点,共享相同模式,缓存中间匹配结果,从而在事实变化时只重新计算受影响的部分。

Rete 网络主要包含:Alpha 节点(单事实条件过滤)、Beta 节点(多事实连接)、Join 节点(连接匹配)、Terminal 节点(规则命中)。当新事实插入时,它沿网络传播,只有相关分支被激活。

Rete 网络简化结构 事实输入 Alpha 节点 Beta 节点 规则命中 共享条件缓存,事实变化时仅传播受影响分支 避免全量重匹配,显著降低规则数量增长带来的开销
Rete 并非万能。规则数量少、事实结构简单时,Rete 的建网与维护成本可能高于直接遍历。是否使用 Rete,应结合规则规模、变更频率和延迟要求评估。

五、常见规则引擎与选型对比

不同引擎在表达方式、执行模型和生态上差异明显。选型时要关注:规则语言是否易读、是否支持热更新、是否可嵌入现有服务、是否有审计与调试工具。

  • Drools:Java 生态成熟,支持 DRL、决策表、CEP,适合复杂企业级规则。
  • Easy Rules:轻量级 Java 引擎,API 简单,适合中小规模规则。
  • NRules:.NET 平台,基于 Rete,适合 C# 服务。
  • JSON Logic / 自研表达式引擎:规则以 JSON 描述,前端可编辑,适合配置化场景。
  • Flink CEP / Esper:面向事件流与时间窗口,适合实时风控与监控。

六、案例与复盘:优惠券发放规则

场景:电商大促期间,需要根据用户等级、订单金额、历史退款率和库存状态决定是否发放优惠券。规则如下:

rule "高退款用户拦截"
  salience 300
  when
    $u: User(refundRate > 0.3)
  then
    reject("高退款用户不发放");
end

rule "黄金会员大额券"
  salience 200
  when
    $u: User(level == "GOLD", refundRate <= 0.3)
    $o: Order(amount >= 800)
  then
    grantCoupon($u, 50);
end

rule "普通用户满减券"
  salience 100
  when
    $u: User(level == "NORMAL")
    $o: Order(amount >= 300)
  then
    grantCoupon($u, 10);
end

复盘时常见误区有三类:其一,优先级设置过粗,导致拦截规则被营销规则覆盖;其二,动作中修改事实后未重新匹配,造成重复发券;其三,规则条件之间隐含依赖,却没有显式声明,导致新增规则时行为漂移。

建议为每条规则补充“业务意图、负责人、生效时间、互斥规则”四类元数据。规则数量超过 50 条后,元数据比规则本身更能决定可维护性。

掌握规则、条件、动作、优先级、冲突消解与 Rete 之后,下一步才能把规则引擎的输出与评分模型结果进行融合。规则负责硬约束与可解释分支,模型负责概率与排序,两者在决策流中各有边界,不能互相替代。