4. 规则引擎核心概念:规则、事实、规则集、上下文与冲突解决

规则引擎的五个核心概念构成了推理系统的骨架。理解它们之间的协作关系,是编写可维护、可扩展规则系统的前提。下面逐一拆解每个概念的定义、职责与交互方式。

4.1 核心概念总览

概念 英文 职责 类比(现实世界)
规则 Rule 定义条件-动作对,描述“当某条件成立时执行某操作” 法律条文
事实 Fact 表示已知的数据对象或状态,是规则推理的输入 案件证据
规则集 RuleSet 对规则进行分组、排序、命名空间管理 法律汇编
执行上下文 Context 承载规则执行过程中的临时数据、全局配置与生命周期 法庭庭审记录
冲突解决策略 Conflict Resolution 当多条规则同时满足条件时,决定执行顺序 法官裁决优先级
关键认知: 事实是静态输入,规则是逻辑判断单元,规则集是组织单元,上下文是运行时环境,冲突解决策略是调度仲裁器。五者缺一不可。

4.2 规则(Rule)

规则是规则引擎的最小逻辑单元。一个标准规则包含三个部分:名称、条件(LHS)、动作(RHS)。

  • 名称:唯一标识,便于日志追踪和调试。
  • 条件(LHS — Left Hand Side):对事实的布尔表达式,支持比较、包含、正则、自定义函数。
  • 动作(RHS — Right Hand Side):条件满足时执行的操作,如修改事实、触发外部服务、记录日志。
# 规则定义示例(伪代码风格)
rule "折扣规则-满100减20"
    when
        order.total >= 100
        order.user_level == "VIP"
    then
        order.discount = 20
        context.add_log("VIP用户触发满减")
实践建议: 规则的条件部分应保持幂等性——多次触发不应产生副作用。动作部分应尽量轻量,避免在规则内执行数据库写操作或远程调用。

4.3 事实(Fact)

事实是引擎推理的原材料。在 Python 规则引擎中,事实通常是一个普通的 Python 对象(dict、dataclass、Pydantic 模型)。引擎通过模式匹配将事实与规则条件进行比对。

  • 不可变性建议:事实在进入引擎后尽量不修改,如需变更应通过规则动作显式更新。
  • 类型支持:数字、字符串、列表、嵌套对象、枚举。
  • 事实插入:通过 engine.insert(fact) 或 context.add_fact(fact) 注入。
# 事实定义示例
from dataclasses import dataclass

@dataclass
class OrderFact:
    order_id: str
    total: float
    user_level: str
    items: list

# 插入事实
fact = OrderFact(order_id="ORD001", total=120.0, user_level="VIP", items=["A", "B"])
engine.insert(fact)

4.4 规则集(RuleSet)

规则集用于对规则进行逻辑分组和优先级管理。一个规则集可以包含多个规则,并支持继承、覆盖、条件激活等高级特性。

特性 说明 典型用途
分组 将同类规则放在一起 折扣规则、风控规则、校验规则
排序 定义规则集内规则的执行顺序 优先级高的规则先执行
命名空间 避免不同模块的规则名称冲突 订单模块 vs 用户模块
条件激活 根据上下文决定是否加载该规则集 仅当促销活动开启时加载促销规则
# 规则集定义示例
ruleset = RuleSet("order_discount_rules", priority=10)
ruleset.add_rule(rule_vip_discount)
ruleset.add_rule(rule_new_user_discount)
ruleset.add_rule(rule_seasonal_discount)

engine.register_ruleset(ruleset)

4.5 执行上下文(Context)

上下文是规则执行期间的“工作台”。它负责存储临时变量、全局配置、日志记录、事实变更追踪以及规则执行状态。

  • 全局配置:如阈值、开关、环境标识。
  • 临时数据:规则间共享的中间计算结果。
  • 日志与监控:记录每条规则的触发次数、耗时。
  • 生命周期管理:上下文在规则执行开始时创建,执行结束后销毁。
# 上下文使用示例
class RuleContext:
    def __init__(self, config: dict):
        self.config = config
        self.logs = []
        self.intermediate_results = {}
        self.execution_count = 0

    def add_log(self, message: str):
        self.logs.append(f"[{self.execution_count}] {message}")

    def get_config(self, key: str, default=None):
        return self.config.get(key, default)

# 使用
ctx = RuleContext({"max_discount": 50})
ctx.add_log("开始执行规则集")

4.6 冲突解决策略

当多条规则的条件同时满足时,引擎必须决定先执行哪一条。不同的策略适用于不同的业务场景。

策略名称 规则 适用场景
优先级优先 按规则显式指定的优先级降序执行 业务有明确的等级制度(如法律条款优先级)
最近更新优先 最近被修改过的事实所触发的规则先执行 实时监控、动态数据流
特定性优先 条件更具体(约束更多)的规则先执行 异常处理、精确匹配优于模糊匹配
先进先出 按规则加入引擎的顺序依次执行 简单线性校验流程
随机 随机选择一条满足条件的规则 A/B 测试、负载均衡
常见陷阱: 不配置冲突解决策略时,引擎可能按默认顺序执行,导致非预期的规则覆盖。始终为规则集显式指定策略,并在测试中验证执行顺序。

4.7 核心概念协作关系图

下图展示了五个核心概念在规则引擎执行过程中的协作关系:

规则引擎核心概念协作关系 事实 (Fact) 规则 (Rule) 规则集 (RuleSet) 执行上下文 冲突解决策略 模式匹配 分组 调度 读写 状态查询 执行流程 事实注入 → 规则模式匹配 → 规则集调度 → 冲突解决 → 动作执行(上下文全程参与)

4.8 实战案例:订单风控规则引擎

下面通过一个完整的 Python 代码片段,展示五个核心概念如何协同工作:

from dataclasses import dataclass, field
from typing import List, Dict

# 1. 事实定义
@dataclass
class OrderFact:
    order_id: str
    amount: float
    user_id: str
    ip_country: str
    is_new_user: bool

# 2. 规则定义
class Rule:
    def __init__(self, name: str, condition, action, priority: int = 0):
        self.name = name
        self.condition = condition
        self.action = action
        self.priority = priority

    def evaluate(self, fact: OrderFact, ctx: 'RuleContext') -> bool:
        return self.condition(fact, ctx)

    def execute(self, fact: OrderFact, ctx: 'RuleContext'):
        self.action(fact, ctx)

# 3. 上下文定义
class RuleContext:
    def __init__(self):
        self.logs: List[str] = []
        self.risk_score: float = 0.0
        self.blocked: bool = False

    def add_log(self, msg: str):
        self.logs.append(msg)

# 4. 规则集定义
class RuleSet:
    def __init__(self, name: str, strategy: str = "priority"):
        self.name = name
        self.rules: List[Rule] = []
        self.strategy = strategy

    def add_rule(self, rule: Rule):
        self.rules.append(rule)
        self.rules.sort(key=lambda r: r.priority, reverse=True)

    def fire(self, fact: OrderFact, ctx: RuleContext):
        for rule in self.rules:
            if rule.evaluate(fact, ctx):
                rule.execute(fact, ctx)
                ctx.add_log(f"触发规则: {rule.name}")

# 5. 实例化规则
def high_amount_condition(fact: OrderFact, ctx: RuleContext) -> bool:
    return fact.amount > 10000

def high_amount_action(fact: OrderFact, ctx: RuleContext):
    ctx.risk_score += 30
    ctx.add_log(f"高风险订单: {fact.order_id}")

def oversea_condition(fact: OrderFact, ctx: RuleContext) -> bool:
    return fact.ip_country != "CN"

def oversea_action(fact: OrderFact, ctx: RuleContext):
    ctx.risk_score += 20
    ctx.add_log(f"海外IP订单: {fact.order_id}")

rule1 = Rule("高金额风控", high_amount_condition, high_amount_action, priority=10)
rule2 = Rule("海外IP风控", oversea_condition, oversea_action, priority=5)

# 6. 组装并执行
ruleset = RuleSet("风控规则集", strategy="priority")
ruleset.add_rule(rule1)
ruleset.add_rule(rule2)

ctx = RuleContext()
fact = OrderFact("ORD999", 15000, "U001", "US", False)
ruleset.fire(fact, ctx)

print(ctx.logs)
# 输出: ['高风险订单: ORD999', '海外IP订单: ORD999']
print(f"最终风险分: {ctx.risk_score}")
# 输出: 最终风险分: 50.0
实验要点: 修改规则的 priority 值,观察执行顺序的变化。尝试添加一条新规则,验证规则集的分组和冲突解决策略是否按预期工作。