课程首页· 代码速查· 第 6 课· 第 7 课 / 共 8 课

Lesson 07 · 支柱 C · 部署

安全门控与云边部署

让一个"会试错的 RL"敢上 14,000 栋楼——靠的不是勇气,是四层兜底。

前面六课你训出了一个能预测、能控制的系统。但它离"能上真楼"还差最关键一步:RL 训练时会乱发动作,而真实楼宇里一次冻管、一次室温飙到 35°C,代价是真实的人、真实的钱、真实的设备损坏。BrainBox 能上 14,000 栋楼的真正秘密,不在模型多准,而在怎么把 RL 关进笼子

这一课给你四层安全门控(行业共识的可辩护实现),以及云边协同的部署拓扑。公开细节有限,但模式来自研究材料 §6.6 和 Safe RL 文献。

一、为什么直接上 RL 是灾难

风险机制后果
探索期乱发动作SAC 早期策略随机,可能发"冷冻水 5°C + 满风量"结露、冻管、人冻感冒
热惯性延迟坏设定点的影响 30–60min 后才显现等发现已过冲,难挽回
设备循环疲劳策略高频开关压缩机不可逆寿命损耗
模型 drift建筑用途/季节变了,模型过时预测失准→控制错误
网络中断云端模型连不上无人接管 → 失控

二、四层安全门控(核心架构)

这是整门课和真实楼宇之间最重要的那层。每一层都是独立的、可单独测试的兜底:

RL 控制器输出(每控制周期一次)
    │
    ▼
┌──────────────────────────────────────────────────┐
│ 第 1 层 · 硬约束检查                                │
│   温度 ∈ [18°C, 26°C]   CO₂ < 1000ppm            │
│   湿度 ∈ [30%, 70%%]     冷冻水温 ∈ [5°C, 12°C]   │
│   → 任一越界:否决该动作,用上一有效动作或 PID       │
├──────────────────────────────────────────────────┤
│ 第 2 层 · 限幅(rate limiting)                     │
│   单步变化 < Δ_max(如设定点每步最多变 ±2°C)       │
│   → 超出:截断到限幅值                              │
├──────────────────────────────────────────────────┤
│ 第 3 层 · 回退(fallback / shielding)             │
│   连续 N 步:预测误差 > ε ?                        │
│   传感器缺失 > 5min ? 网络中断 ?                  │
│   → 触发:切回 PID / 规则,标记"shielded"           │
├──────────────────────────────────────────────────┤
│ 第 4 层 · 人工接管                                  │
│   值班人员一键切回手动(最高优先级,随时可触发)     │
└──────────────────────────────────────────────────┘
    │
    ▼
  MQTT 下行控制指令(Pivot 现有通道)

关键设计原则:这四层是"串联兜底",不是"并联选择"。一个动作必须通过全部四层才下达;任何一层否决就用回退策略。人始终有最高优先级。

三、动手做:实现这个安全门控

动手做 7.1 · 安全门控类(包在 SAC 外面)
python · safety_gate.py复制
import numpy as np

class SafetyGate:
    def __init__(self, pid, thermal_model=None):
        self.pid = pid                          # 第 3 课的 PID,做回退
        self.model = thermal_model              # 支柱 A 的预测器(可选)
        self.prev_action = None
        self.err_streak = 0
        self.manual_override = False
        # 可调阈值
        self.HARD = {"T_lo":18.0, "T_hi":26.0, "co2":1000.0}
        self.DELTA_MAX = 2.0                   # 单步设定点最大变化 °C
        self.ERR_TOL = 1.5                     # 预测误差容忍 °C
        self.ERR_STREAK_MAX = 3               # 连续 N 步超差 → 回退

    def safe_action(self, raw_action, obs, prev_obs):
        if self.manual_override:
            return self.pid.step(obs[0]), "manual"

        # —— 第 1 层:硬约束 —— 用预测器前瞻 30min,提前拦截 ——
        if self.model is not None:
            pred_T = self.model.forecast(obs, raw_action, horizon=2)[-1]
            if pred_T < self.HARD["T_lo"] or pred_T > self.HARD["T_hi"]:
                return self.pid.step(obs[0]), "hard_violation"

        # —— 第 2 层:限幅 ——
        if self.prev_action is not None:
            delta = raw_action - self.prev_action
            clipped = self.prev_action + np.clip(delta, -self.DELTA_MAX, self.DELTA_MAX)
        else:
            clipped = raw_action

        # —— 第 3 层:回退(模型可信度监控)——
        if self.model is not None and prev_obs is not None:
            last_pred = self.model.forecast(prev_obs, horizon=1)[0]
            err = abs(last_pred - obs[0])
            self.err_streak = self.err_streak + 1 if err > self.ERR_TOL else 0
            if self.err_streak >= self.ERR_STREAK_MAX:
                return self.pid.step(obs[0]), "model_unstable"

        self.prev_action = clipped
        return clipped, "rl_ok"

    def engage_manual(self):  self.manual_override = True
    def disengage_manual(self): self.manual_override = False
预期结果:每步返回 (动作, 标签)。正常时标签是 "rl_ok";越界/模型不稳时是 "hard_violation"/"model_unstable" 并自动切 PID。把标签全量记日志——"shield 触发率"本身就是一个上线前的关键验收指标(应趋近 0)。

注意第 1 层用了预测器做前瞻拦截——这正是支柱 A 预测模型在部署时的一大用途:在动作下达前先"看一眼后果"。三支柱在这里第一次协同。

动手做 7.2 · 部署拓扑:云端训练 + 边缘推理

BrainBox 是云端 SaaS + 边缘数据采集。研究材料 §9.6 给了清晰分工,本课沿用:

┌─ 云端(训练 / 大模型推理)─────────────────────┐
│  · 离线:Neural ODE 训练、SAC 训练、重训       │
│  · 在线:DreamerV3? 不——SAC 推理(CPU 够)     │
│  · 周期:控制周期 5–15min,对延迟不敏感         │
└───────────────────┬───────────────────────────┘
                    │ MQTT 上行:传感器时序
                    │ MQTT 下行:安全门控后的控制指令
┌───────────────────┴───────────────────────────┐
│ 边缘(必须本地,断网也能用)──────────────────│
│  · 数据采集 + 预处理                            │
│  · 安全门控第 1/2 层(硬约束 + 限幅)← 关键!  │
│  · PID 回退(第 3 课)                          │
│  · 人工接管开关                                 │
└────────────────────────────────────────────────┘
python · 边缘侧最小闭环(断网兜底)复制
def edge_loop(gate, pid, cloud_policy=None, max_latency=5.0):
    # 每控制周期执行一次
    obs = read_sensors()                  # 本地传感器
    try:
        if cloud_policy and net_ok(max_latency):
            raw, _ = cloud_policy.predict(obs)       # 云端 SAC
            tag = "cloud"
        else:
            raise TimeoutError("cloud unreachable")
    except Exception:
        raw = pid.step(obs[0])                          # 断网 → 本地 PID
        tag = "offline_pid"
    action, reason = gate.safe_action(raw, obs, prev=None)
    send_mqtt(action)                                # 下行控制
    log(action, reason, tag)                         # 全审计
预期行为:正常走云端策略;网络抖动/超时自动落本地 PID;任何越界或模型异常被门控拦截。断网时楼依然能控——这是能上生产的硬要求。研究材料 §6.6 / §9.6 明确把"网络中断 → 边缘 PID 接管"列为必备。

四、上线前的验收指标

不是"模型训好了"就能上。研究材料 §6.6 给了决策门槛,本课补充 Safe RL 视角:

上线前必须过的关
指标门槛(建议起点)不过怎么办
节能率(vs PID)≥ 10%继续训练 / 调奖励
舒适违规率≤ PID 基线加大舒适权重
shield 触发率趋近 0(<5%)模型/策略不稳,不上线
断网兜底可用本地 PID 全自动不上线
人工接管通路实测一键可用不上线
灰度时长先"建议模式"≥1 月未达标不上闭环
本课收获

1. 裸 RL 不能上生产——热惯性、设备疲劳、模型 drift、断网都是真实风险。

2. 四层串联兜底:硬约束 → 限幅 → 回退(PID)→ 人工接管。每层独立可测。

3. 部署拓扑:云端训练/推理 + 边缘数据采集 + 边缘门控 + 边缘 PID 回退。断网必须能控。

4. 上线前过验收门槛(节能率、违规率、shield 触发率、兜底可用性),并先走"建议模式"灰度。

小测一下

安全门控的第 1 层(硬约束检查)放在云端还是边缘?为什么?

有疑问?尽管问。比如:"Δ_max / ERR_TOL 这些阈值怎么定?" 或 "shield 触发率高怎么排查?" 或 "多租户场景下模型怎么隔离 / 版本管理?"——都能展开(后者可接 Pivot 多租户架构)。
参考来源: