返回博客

混合推理模式:当规则引擎遇上机器学习

单一推理模式无法满足企业级决策的复杂需求。coomia-dip 采用规则层 + ML 层 + 人工审核层的三层混合推理架构,将确定性规则推理、概率性机器学习推断和人工专家判断有机结合。本文深入解析三层架构的设计原理、层间路由机制、置信度融合算法以及降级策略,展示如何在 Reasoning & Decision Layer 中构建一个既精确又智能的决策系统。

Coomia发布于 2025年8月25日19 分钟阅读
分享本文Twitter / X

系列:S5 智能决策 · 第 3 篇 | 难度:高级 | 阅读时间:20 分钟

混合推理模式:当规则引擎遇上机器学习

#TL;DR

单一推理模式无法满足企业级决策的复杂需求。coomia-dip 采用规则层 + ML 层 + 人工审核层的三层混合推理架构,将确定性规则推理、概率性机器学习推断和人工专家判断有机结合。本文深入解析三层架构的设计原理、层间路由机制、置信度融合算法以及降级策略,展示如何在 Reasoning & Decision Layer 中构建一个既精确又智能的决策系统。

#1. 为什么需要混合推理

#1.1 单一推理的局限

Code
单一推理模式的问题:

规则引擎(确定性)                ML 模型(概率性)
+-------------------+            +-------------------+
| 优势:             |            | 优势:             |
|  - 可解释          |            |  - 处理模糊场景    |
|  - 可审计          |            |  - 发现隐含模式    |
|  - 响应快          |            |  - 自适应学习      |
+-------------------+            +-------------------+
| 局限:             |            | 局限:             |
|  - 无法处理模糊    |            |  - 黑箱不可解释    |
|  - 规则爆炸        |            |  - 需要大量数据    |
|  - 无法自学习      |            |  - 合规风险高      |
+-------------------+            +-------------------+
场景类型规则引擎适合度ML 适合度推荐
合规检查(法规明确)规则
欺诈检测(模式复杂)ML
信用评估(规则+趋势)混合
库存预警(阈值+预测)混合
客户流失(多因子)ML + 人工

#1.2 三层混合架构总览

Code
三层混合推理架构:

               请求入口
                 |
                 v
        +--------+--------+
        |   路由分发器     |
        |  (Router/Triage) |
        +--------+--------+
                 |
    +------------+------------+
    |            |            |
    v            v            v
+--------+  +--------+  +-----------+
| Layer 1|  | Layer 2|  |  Layer 3  |
| 规则层  |  | ML 层  |  | 人工审核层 |
| (确定)  |  | (概率)  |  |  (判断)   |
+--------+  +--------+  +-----------+
    |            |            |
    +------+-----+------+----+
           |            |
           v            v
    +------------+ +----------+
    | 置信度融合  | | 审批队列  |
    | (Fusion)   | | (Queue)  |
    +------+-----+ +-----+----+
           |            |
           v            v
      最终决策 <--------+

#2. 路由分发器设计

#2.1 请求分类与路由

路由分发器根据请求特征决定推理路径:

Python
from enum import Enum, auto
from dataclasses import dataclass, field
from typing import Any


class ReasoningPath(Enum):
    """推理路径类型"""
    RULE_ONLY = auto()        # 纯规则,不需要 ML
    ML_ONLY = auto()          # 纯 ML,无规则覆盖
    RULE_THEN_ML = auto()     # 规则初筛 + ML 精细化
    ML_THEN_RULE = auto()     # ML 预测 + 规则验证
    PARALLEL_FUSION = auto()  # 规则与 ML 并行 + 融合
    HUMAN_REVIEW = auto()     # 直接人工审核


@dataclass
class ReasoningRequest:
    """推理请求"""
    request_id: str
    domain: str              # "fraud", "credit", "inventory" 等
    facts: dict[str, Any]
    urgency: str = "normal"  # "critical", "normal", "low"
    confidence_threshold: float = 0.85


@dataclass
class RoutingRule:
    """路由规则"""
    domain: str
    condition: str           # 条件表达式
    path: ReasoningPath
    priority: int = 0


class ReasoningRouter:
    """推理请求路由分发器"""

    def __init__(self):
        self._rules: list[RoutingRule] = []
        self._domain_config: dict[str, dict] = {}
        self._default_path = ReasoningPath.RULE_THEN_ML

    def configure_domain(self, domain: str, config: dict) -> None:
        """配置领域路由策略"""
        self._domain_config[domain] = config
        # 自动注册路由规则
        if config.get("rules_complete", False):
            self._rules.append(RoutingRule(
                domain=domain,
                condition="rules_coverage >= 0.95",
                path=ReasoningPath.RULE_ONLY,
                priority=10,
            ))
        if config.get("ml_model_available", False):
            self._rules.append(RoutingRule(
                domain=domain,
                condition="ml_model_accuracy >= 0.90",
                path=ReasoningPath.PARALLEL_FUSION,
                priority=5,
            ))

    def route(self, request: ReasoningRequest) -> ReasoningPath:
        """决定推理路径"""
        config = self._domain_config.get(request.domain, {})

        # 紧急请求:跳过 ML,仅用规则
        if request.urgency == "critical":
            return ReasoningPath.RULE_ONLY

        # 检查规则覆盖率
        rules_coverage = config.get("rules_coverage", 0.0)
        ml_available = config.get("ml_model_available", False)

        if rules_coverage >= 0.95 and not ml_available:
            return ReasoningPath.RULE_ONLY
        if rules_coverage < 0.3 and ml_available:
            return ReasoningPath.ML_ONLY
        if ml_available:
            return ReasoningPath.PARALLEL_FUSION

        return self._default_path

#2.2 路由决策矩阵

Code
路由决策矩阵:

                       ML 模型可用
                    Yes              No
               +------------+  +------------+
规则覆盖 >= 95%|  PARALLEL   |  | RULE_ONLY  |
               |  _FUSION    |  |            |
               +------------+  +------------+
规则覆盖 30-95%|  RULE_THEN  |  | RULE_ONLY  |
               |  _ML        |  | + HUMAN    |
               +------------+  +------------+
规则覆盖 < 30% |  ML_ONLY    |  | HUMAN      |
               |             |  | _REVIEW    |
               +------------+  +------------+

#3. Layer 1:规则推理层

#3.1 确定性规则执行

规则层处理具有明确条件和结论的业务逻辑:

Python
from dataclasses import dataclass
from typing import Optional
import time


@dataclass
class RuleResult:
    """规则层推理结果"""
    rule_ids: list[str]         # 触发的规则
    conclusion: str             # 结论
    confidence: float           # 确定性规则置信度通常为 1.0
    explanation: list[str]      # 解释链
    elapsed_ms: float
    is_conclusive: bool = True  # 是否得出最终结论


class RuleReasoningLayer:
    """Layer 1: 确定性规则推理"""

    def __init__(self, rete_network, working_memory):
        self._rete = rete_network
        self._wm = working_memory
        self._inconclusive_threshold = 0.7

    def reason(self, request: ReasoningRequest) -> RuleResult:
        """执行规则推理"""
        start = time.monotonic()

        # 将请求事实注入工作记忆
        for key, value in request.facts.items():
            self._wm.assert_fact(key, value)

        # 执行 Rete 前向链
        fired_rules = self._rete.run_to_completion(max_cycles=500)

        elapsed = (time.monotonic() - start) * 1000

        if not fired_rules:
            return RuleResult(
                rule_ids=[],
                conclusion="no_match",
                confidence=0.0,
                explanation=["无规则匹配当前事实集合"],
                elapsed_ms=elapsed,
                is_conclusive=False,
            )

        # 聚合规则结论
        conclusion = self._aggregate_conclusions(fired_rules)
        coverage = self._compute_coverage(request.facts, fired_rules)

        return RuleResult(
            rule_ids=[r.rule_id for r in fired_rules],
            conclusion=conclusion,
            confidence=min(coverage, 1.0),
            explanation=self._build_explanation(fired_rules),
            elapsed_ms=elapsed,
            is_conclusive=coverage >= self._inconclusive_threshold,
        )

    def _aggregate_conclusions(self, fired_rules) -> str:
        """聚合多条规则的结论"""
        # 按优先级取最高的
        sorted_rules = sorted(fired_rules, key=lambda r: r.priority, reverse=True)
        return sorted_rules[0].conclusion

    def _compute_coverage(self, facts: dict, fired_rules) -> float:
        """计算规则对事实的覆盖程度"""
        total_facts = len(facts)
        covered_facts = set()
        for rule in fired_rules:
            for cond in rule.conditions:
                covered_facts.add(cond.attribute)
        return len(covered_facts) / max(total_facts, 1)

    def _build_explanation(self, fired_rules) -> list[str]:
        """构建推理解释链"""
        explanations = []
        for rule in fired_rules:
            conditions_text = " AND ".join(
                f"{c.attribute} {c.operator} {c.value}"
                for c in rule.conditions
            )
            explanations.append(
                f"规则 [{rule.name}]: 因为 {conditions_text} -> {rule.conclusion}"
            )
        return explanations

#4. Layer 2:ML 推理层

#4.1 模型注册与管理

Python
from dataclasses import dataclass, field
from typing import Protocol
import numpy as np


class MLModel(Protocol):
    """ML 模型接口"""
    def predict(self, features: dict[str, Any]) -> tuple[str, float]: ...
    def predict_proba(self, features: dict[str, Any]) -> dict[str, float]: ...

    @property
    def model_id(self) -> str: ...
    @property
    def version(self) -> str: ...


@dataclass
class ModelMetadata:
    """模型元数据"""
    model_id: str
    version: str
    domain: str
    accuracy: float
    f1_score: float
    training_date: str
    feature_names: list[str]
    is_active: bool = True


class ModelRegistry:
    """ML 模型注册表"""

    def __init__(self):
        self._models: dict[str, MLModel] = {}
        self._metadata: dict[str, ModelMetadata] = {}
        self._domain_index: dict[str, list[str]] = {}

    def register(self, model: MLModel, metadata: ModelMetadata) -> None:
        key = f"{metadata.model_id}:{metadata.version}"
        self._models[key] = model
        self._metadata[key] = metadata
        self._domain_index.setdefault(metadata.domain, []).append(key)

    def get_best_model(self, domain: str) -> tuple[MLModel, ModelMetadata] | None:
        """获取指定领域最佳活跃模型"""
        keys = self._domain_index.get(domain, [])
        active = [
            (self._models[k], self._metadata[k])
            for k in keys
            if self._metadata[k].is_active
        ]
        if not active:
            return None
        # 按 F1 分数排序
        active.sort(key=lambda x: x[1].f1_score, reverse=True)
        return active[0]

#4.2 ML 推理执行

Python
@dataclass
class MLResult:
    """ML 推理结果"""
    model_id: str
    model_version: str
    prediction: str
    confidence: float
    probabilities: dict[str, float]
    feature_importance: dict[str, float]
    elapsed_ms: float


class MLReasoningLayer:
    """Layer 2: 机器学习推理"""

    def __init__(self, model_registry: ModelRegistry):
        self._registry = model_registry
        self._feature_extractors: dict[str, callable] = {}

    def register_feature_extractor(self, domain: str, extractor: callable):
        self._feature_extractors[domain] = extractor

    def reason(self, request: ReasoningRequest) -> MLResult | None:
        """执行 ML 推理"""
        result = self._registry.get_best_model(request.domain)
        if result is None:
            return None

        model, metadata = result
        start = time.monotonic()

        # 特征提取
        extractor = self._feature_extractors.get(request.domain)
        if extractor:
            features = extractor(request.facts)
        else:
            features = request.facts

        # 推理
        prediction, confidence = model.predict(features)
        probabilities = model.predict_proba(features)

        # 特征重要性(如果模型支持)
        importance = self._compute_importance(model, features)

        elapsed = (time.monotonic() - start) * 1000

        return MLResult(
            model_id=metadata.model_id,
            model_version=metadata.version,
            prediction=prediction,
            confidence=confidence,
            probabilities=probabilities,
            feature_importance=importance,
            elapsed_ms=elapsed,
        )

    def _compute_importance(self, model: MLModel,
                            features: dict) -> dict[str, float]:
        """计算特征重要性(SHAP 近似)"""
        base_pred, base_conf = model.predict(features)
        importance = {}
        for key in features:
            modified = {**features}
            del modified[key]
            _, mod_conf = model.predict(modified)
            importance[key] = abs(base_conf - mod_conf)
        # 归一化
        total = sum(importance.values()) or 1.0
        return {k: v / total for k, v in importance.items()}

#4.3 ML 模型的沙箱执行

coomia-dip 使用 nsjail 隔离 ML 模型推理,防止恶意模型:

Code
ML 模型沙箱执行流程:

  +---------------------+
  |  ReasoningEngine     |
  |                     |
  |  1. 提取特征向量     |
  |  2. 序列化请求       |
  +----------+----------+
             |
             v
  +----------+----------+
  |  nsjail Sandbox     |
  |  +-----------------+|
  |  | Model Runtime   ||
  |  | - 只读文件系统   ||
  |  | - 无网络         ||
  |  | - CPU/内存限制   ||
  |  | - 超时 5s        ||
  |  +-----------------+|
  +----------+----------+
             |
             v
  +----------+----------+
  |  结果反序列化        |
  |  + 置信度校验        |
  +---------------------+

#5. Layer 3:人工审核层

#5.1 审核触发条件

Python
@dataclass
class HumanReviewRequest:
    """人工审核请求"""
    request_id: str
    original_request: ReasoningRequest
    rule_result: RuleResult | None
    ml_result: MLResult | None
    trigger_reason: str
    priority: str = "normal"
    deadline_hours: int = 24


class HumanReviewTrigger:
    """判断是否需要人工审核"""

    def __init__(self):
        self._confidence_threshold = 0.7
        self._conflict_threshold = 0.3
        self._high_impact_domains = {"credit", "fraud", "compliance"}

    def should_review(self, rule_result: RuleResult | None,
                      ml_result: MLResult | None,
                      request: ReasoningRequest) -> tuple[bool, str]:
        """
        判断是否需要人工审核

        Returns: (是否需要, 原因)
        """
        # 条件 1:规则和 ML 结果冲突
        if rule_result and ml_result:
            if rule_result.conclusion != ml_result.prediction:
                conflict_severity = abs(
                    rule_result.confidence - ml_result.confidence
                )
                if conflict_severity < self._conflict_threshold:
                    return True, "规则与 ML 结论冲突且置信度接近"

        # 条件 2:两层均低置信度
        rule_conf = rule_result.confidence if rule_result else 0.0
        ml_conf = ml_result.confidence if ml_result else 0.0
        max_conf = max(rule_conf, ml_conf)
        if max_conf < self._confidence_threshold:
            return True, f"最高置信度 {max_conf:.2f} 低于阈值"

        # 条件 3:高影响领域
        if request.domain in self._high_impact_domains:
            if max_conf < 0.95:
                return True, f"高影响领域 {request.domain} 需要高置信度"

        # 条件 4:规则层不确定
        if rule_result and not rule_result.is_conclusive:
            return True, "规则层未得出确定性结论"

        return False, ""

#5.2 审核队列管理

Python
from collections import deque
from datetime import datetime, timedelta


class ReviewQueue:
    """人工审核队列"""

    def __init__(self):
        self._queue: deque[HumanReviewRequest] = deque()
        self._assigned: dict[str, HumanReviewRequest] = {}
        self._completed: dict[str, dict] = {}

    def enqueue(self, review: HumanReviewRequest) -> int:
        """入队,返回队列位置"""
        self._queue.append(review)
        return len(self._queue)

    def assign_next(self, reviewer_id: str) -> HumanReviewRequest | None:
        """分配下一个审核任务给审核员"""
        if not self._queue:
            return None
        # 按优先级和截止时间排序
        sorted_queue = sorted(
            self._queue,
            key=lambda r: (
                0 if r.priority == "critical" else 1,
                r.deadline_hours,
            ),
        )
        review = sorted_queue[0]
        self._queue.remove(review)
        self._assigned[review.request_id] = review
        return review

    def complete_review(self, request_id: str, decision: str,
                       reviewer_id: str, notes: str) -> None:
        """完成审核"""
        review = self._assigned.pop(request_id, None)
        if review is None:
            raise KeyError(f"审核 {request_id} 未在分配列表中")
        self._completed[request_id] = {
            "review": review,
            "decision": decision,
            "reviewer_id": reviewer_id,
            "notes": notes,
            "completed_at": datetime.utcnow().isoformat(),
        }

    @property
    def pending_count(self) -> int:
        return len(self._queue) + len(self._assigned)

#6. 置信度融合算法

#6.1 融合策略

当规则层和 ML 层同时产生结果时,需要智能融合:

Code
置信度融合流程:

  Rule Result                ML Result
  conclusion: "approve"      prediction: "approve"
  confidence: 0.92           confidence: 0.87
       |                          |
       +----------+---------------+
                  |
                  v
         +--------+--------+
         |  Fusion Engine   |
         |                  |
         | 1. 一致性检查     |
         | 2. 加权融合       |
         | 3. 校准调整       |
         +--------+---------+
                  |
                  v
         Final: "approve"
         confidence: 0.94

#6.2 融合实现

Python
from dataclasses import dataclass


@dataclass
class FusionResult:
    """融合后的推理结果"""
    conclusion: str
    confidence: float
    rule_contribution: float     # 规则层贡献度
    ml_contribution: float       # ML 层贡献度
    fusion_method: str
    explanation: list[str]


class ConfidenceFusion:
    """置信度融合引擎"""

    def __init__(self):
        # 领域权重配置
        self._domain_weights: dict[str, tuple[float, float]] = {
            # (rule_weight, ml_weight)
            "compliance": (0.9, 0.1),   # 合规偏规则
            "fraud": (0.3, 0.7),        # 欺诈偏 ML
            "credit": (0.5, 0.5),       # 信用均衡
            "inventory": (0.4, 0.6),    # 库存偏 ML
        }
        self._default_weights = (0.5, 0.5)

    def fuse(self, rule_result: RuleResult | None,
             ml_result: MLResult | None,
             domain: str) -> FusionResult:
        """融合规则和 ML 结果"""

        # 只有规则结果
        if rule_result and not ml_result:
            return FusionResult(
                conclusion=rule_result.conclusion,
                confidence=rule_result.confidence,
                rule_contribution=1.0,
                ml_contribution=0.0,
                fusion_method="rule_only",
                explanation=rule_result.explanation,
            )

        # 只有 ML 结果
        if ml_result and not rule_result:
            return FusionResult(
                conclusion=ml_result.prediction,
                confidence=ml_result.confidence,
                rule_contribution=0.0,
                ml_contribution=1.0,
                fusion_method="ml_only",
                explanation=[
                    f"ML 模型 {ml_result.model_id} 预测: "
                    f"{ml_result.prediction} (置信度: {ml_result.confidence:.2f})"
                ],
            )

        # 双层融合
        rule_w, ml_w = self._domain_weights.get(domain, self._default_weights)

        if rule_result.conclusion == ml_result.prediction:
            # 结论一致:加权提升
            return self._fuse_agreement(
                rule_result, ml_result, rule_w, ml_w, domain
            )
        else:
            # 结论冲突:加权竞争
            return self._fuse_conflict(
                rule_result, ml_result, rule_w, ml_w, domain
            )

    def _fuse_agreement(self, rule: RuleResult, ml: MLResult,
                        rw: float, mw: float, domain: str) -> FusionResult:
        """双层结论一致时的融合"""
        # 加权平均,结论一致时提升置信度
        weighted_conf = rule.confidence * rw + ml.confidence * mw
        # 一致性加成(Bayesian update 近似)
        boosted = 1 - (1 - weighted_conf) * (1 - min(rule.confidence, ml.confidence))

        return FusionResult(
            conclusion=rule.conclusion,
            confidence=min(boosted, 0.99),
            rule_contribution=rw,
            ml_contribution=mw,
            fusion_method="weighted_agreement",
            explanation=rule.explanation + [
                f"ML 模型同意此结论 (置信度 {ml.confidence:.2f}),融合后提升"
            ],
        )

    def _fuse_conflict(self, rule: RuleResult, ml: MLResult,
                       rw: float, mw: float, domain: str) -> FusionResult:
        """双层结论冲突时的融合"""
        rule_score = rule.confidence * rw
        ml_score = ml.confidence * mw

        if rule_score >= ml_score:
            winner = "rule"
            conclusion = rule.conclusion
            confidence = rule_score / (rule_score + ml_score)
            explanation = rule.explanation + [
                f"注意: ML 模型给出不同结论 '{ml.prediction}' "
                f"(置信度 {ml.confidence:.2f}),但规则层加权分更高"
            ]
        else:
            winner = "ml"
            conclusion = ml.prediction
            confidence = ml_score / (rule_score + ml_score)
            explanation = [
                f"ML 模型结论 '{ml.prediction}' (置信度 {ml.confidence:.2f}) "
                f"加权分高于规则层"
            ] + [f"[被否决的规则推理]: {e}" for e in rule.explanation]

        # 冲突惩罚:降低最终置信度
        conflict_penalty = 0.15
        confidence = max(confidence - conflict_penalty, 0.1)

        return FusionResult(
            conclusion=conclusion,
            confidence=confidence,
            rule_contribution=rw if winner == "rule" else 1 - mw,
            ml_contribution=mw if winner == "ml" else 1 - rw,
            fusion_method=f"conflict_resolution_{winner}_wins",
            explanation=explanation,
        )

#7. 混合推理编排器

#7.1 完整编排流程

Python
@dataclass
class HybridReasoningResult:
    """混合推理最终结果"""
    request_id: str
    conclusion: str
    confidence: float
    path_taken: ReasoningPath
    rule_result: RuleResult | None
    ml_result: MLResult | None
    fusion_result: FusionResult | None
    human_review_needed: bool
    review_reason: str
    total_elapsed_ms: float
    trace: list[str]


class HybridReasoningOrchestrator:
    """混合推理编排器 —— 核心协调组件"""

    def __init__(
        self,
        router: ReasoningRouter,
        rule_layer: RuleReasoningLayer,
        ml_layer: MLReasoningLayer,
        fusion: ConfidenceFusion,
        review_trigger: HumanReviewTrigger,
        review_queue: ReviewQueue,
    ):
        self._router = router
        self._rule_layer = rule_layer
        self._ml_layer = ml_layer
        self._fusion = fusion
        self._review_trigger = review_trigger
        self._review_queue = review_queue

    async def reason(self, request: ReasoningRequest) -> HybridReasoningResult:
        """执行混合推理"""
        start = time.monotonic()
        trace = []

        # Step 1: 路由
        path = self._router.route(request)
        trace.append(f"路由决策: {path.name}")

        rule_result = None
        ml_result = None
        fusion_result = None

        # Step 2: 按路径执行推理
        if path == ReasoningPath.RULE_ONLY:
            rule_result = self._rule_layer.reason(request)
            trace.append(f"规则层: {rule_result.conclusion} "
                        f"(置信度 {rule_result.confidence:.2f})")

        elif path == ReasoningPath.ML_ONLY:
            ml_result = self._ml_layer.reason(request)
            trace.append(f"ML 层: {ml_result.prediction} "
                        f"(置信度 {ml_result.confidence:.2f})")

        elif path == ReasoningPath.RULE_THEN_ML:
            rule_result = self._rule_layer.reason(request)
            trace.append(f"规则层: {rule_result.conclusion}")
            if not rule_result.is_conclusive:
                ml_result = self._ml_layer.reason(request)
                trace.append(f"规则层不确定,进入 ML 层: {ml_result.prediction}")

        elif path == ReasoningPath.PARALLEL_FUSION:
            # 并行执行(在实际异步环境中)
            rule_result = self._rule_layer.reason(request)
            ml_result = self._ml_layer.reason(request)
            trace.append(f"并行执行: 规则={rule_result.conclusion}, "
                        f"ML={ml_result.prediction}")

        elif path == ReasoningPath.HUMAN_REVIEW:
            trace.append("直接进入人工审核")

        # Step 3: 融合
        if rule_result or ml_result:
            fusion_result = self._fusion.fuse(
                rule_result, ml_result, request.domain
            )
            trace.append(f"融合结果: {fusion_result.conclusion} "
                        f"(置信度 {fusion_result.confidence:.2f})")

        # Step 4: 人工审核判断
        need_review, review_reason = self._review_trigger.should_review(
            rule_result, ml_result, request
        )
        if path == ReasoningPath.HUMAN_REVIEW:
            need_review = True
            review_reason = "路由指定人工审核"

        if need_review:
            self._review_queue.enqueue(HumanReviewRequest(
                request_id=request.request_id,
                original_request=request,
                rule_result=rule_result,
                ml_result=ml_result,
                trigger_reason=review_reason,
            ))
            trace.append(f"已提交人工审核: {review_reason}")

        elapsed = (time.monotonic() - start) * 1000

        return HybridReasoningResult(
            request_id=request.request_id,
            conclusion=fusion_result.conclusion if fusion_result else "pending_review",
            confidence=fusion_result.confidence if fusion_result else 0.0,
            path_taken=path,
            rule_result=rule_result,
            ml_result=ml_result,
            fusion_result=fusion_result,
            human_review_needed=need_review,
            review_reason=review_reason,
            total_elapsed_ms=elapsed,
            trace=trace,
        )

#8. 降级与容错策略

#8.1 降级场景

Code
降级策略矩阵:

场景                    | 降级动作                    | 日志级别
-----------------------|----------------------------|---------
ML 模型服务不可用        | 回退到纯规则推理             | WARN
ML 推理超时 (>5s)       | 使用规则结果 + 标记           | WARN
规则引擎异常            | 使用 ML 结果 + 强制人工审核    | ERROR
两层均失败              | 进入人工审核队列              | CRITICAL
人工审核队列积压 >100    | 自动按 ML 结论执行低风险请求    | WARN

#8.2 断路器模式

Python
from datetime import datetime, timedelta


class CircuitBreaker:
    """ML 推理断路器"""

    def __init__(self, failure_threshold: int = 5,
                 recovery_timeout_s: int = 60):
        self._failure_count = 0
        self._failure_threshold = failure_threshold
        self._recovery_timeout = timedelta(seconds=recovery_timeout_s)
        self._last_failure_time: datetime | None = None
        self._state = "CLOSED"  # CLOSED, OPEN, HALF_OPEN

    def record_success(self) -> None:
        self._failure_count = 0
        self._state = "CLOSED"

    def record_failure(self) -> None:
        self._failure_count += 1
        self._last_failure_time = datetime.utcnow()
        if self._failure_count >= self._failure_threshold:
            self._state = "OPEN"

    def allow_request(self) -> bool:
        if self._state == "CLOSED":
            return True
        if self._state == "OPEN":
            if (datetime.utcnow() - self._last_failure_time
                    > self._recovery_timeout):
                self._state = "HALF_OPEN"
                return True
            return False
        # HALF_OPEN: 允许一个试探请求
        return True

    @property
    def state(self) -> str:
        return self._state

#9. 性能与监控

#9.1 关键指标

指标目标值监控方式
规则层 P99 延迟< 50msPrometheus histogram
ML 层 P99 延迟< 200msPrometheus histogram
融合层延迟< 10msPrometheus histogram
人工审核比例< 15%每日报表
规则-ML 冲突率< 10%实时告警
端到端 P99< 500ms全链路追踪

#9.2 gRPC 接口定义

PROTOBUF
// hybrid_reasoning.proto
syntax = "proto3";
package onto.reasoning.v1;

service HybridReasoningService {
    rpc Reason(HybridReasoningRequest) returns (HybridReasoningResponse);
    rpc GetReasoningTrace(TraceRequest) returns (ReasoningTrace);
    rpc GetQueueStatus(QueueStatusRequest) returns (QueueStatusResponse);
}

message HybridReasoningRequest {
    string request_id = 1;
    string domain = 2;
    map<string, string> facts = 3;
    string urgency = 4;
    double confidence_threshold = 5;
}

message HybridReasoningResponse {
    string conclusion = 1;
    double confidence = 2;
    string path_taken = 3;
    bool human_review_needed = 4;
    string review_reason = 5;
    repeated string trace = 6;
    double elapsed_ms = 7;
}

#10. 实战案例:信用风控混合推理

Python
# 场景:信用申请审批

# 1. 配置领域
router = ReasoningRouter()
router.configure_domain("credit", {
    "rules_coverage": 0.7,
    "ml_model_available": True,
    "ml_model_accuracy": 0.92,
})

# 2. 发起推理请求
request = ReasoningRequest(
    request_id="CR-2026-001",
    domain="credit",
    facts={
        "applicant_age": 35,
        "annual_income": 250000,
        "debt_ratio": 0.45,
        "credit_score": 680,
        "employment_years": 3,
        "previous_defaults": 0,
    },
    confidence_threshold=0.85,
)

# 3. 路由决策
path = router.route(request)
# -> ReasoningPath.PARALLEL_FUSION (因为 rules_coverage=0.7 且 ML 可用)

# 4. 规则层结果
# Rule: credit_score >= 650 AND debt_ratio < 0.5 -> "conditional_approve"
# confidence: 0.85

# 5. ML 层结果
# Model: gradient_boosting_v3
# prediction: "approve"
# confidence: 0.91

# 6. 融合 (credit 领域权重 0.5:0.5)
# 结论一致方向 ("approve" 系列)
# 融合后置信度: 0.94 (一致性加成)
# 最终: "approve", confidence=0.94

# 7. 人工审核:不需要 (confidence 0.94 > 0.85 阈值)

#Key Takeaways

  1. 三层架构(规则 + ML + 人工审核)覆盖从确定性到模糊性的全部决策场景
  2. 路由分发器根据领域配置、规则覆盖率和 ML 可用性动态选择推理路径
  3. 置信度融合使用加权平均 + 一致性加成/冲突惩罚,确保最终决策可靠
  4. 人工审核触发基于置信度阈值、层间冲突和领域风险等级自动判断
  5. 断路器模式防止 ML 服务故障拖垮整个推理系统
  6. 全链路追踪记录每个推理步骤的决策和耗时,支持事后审计
  7. 通过 gRPC 与 Reasoning & Decision Layer 其他组件集成,实现毫秒级推理响应

#Next Article

下一篇 S5-04 低代码规则:用 YAML 定义复杂业务规则 将展示如何让业务人员通过 YAML 配置文件而非编程代码来定义和管理业务规则。

tags: #hybrid-reasoning #rule-engine #machine-learning #confidence-fusion #human-review #circuit-breaker #coomia-dip