4.3 复飞程序:误差处理、恢复与鲁棒性


4.3 复飞程序:误差处理、恢复与鲁棒性

本节摘要:失败不是意外,是运行的常态成本。本节给误差分类定级(瞬态、持续、致命),排出分级响应阶梯——带退避的重试、能力降级、中止与安全态,预制恢复行为库,并把整机鲁棒性设计(输入验证、异常处理、超时控制、冗余)合流为复飞的结构性支撑。复飞的精神只有一条:把失败后的处置从即兴发挥变成肌肉记忆。

航空业把"复飞"写进条例之前,硬着陆曾是飞行员荣誉感的牺牲品——明明条件不满足,偏要赌一把落地。后来行业承认了常识:跑道被占用、气象低于标准,拉起来重飞不丢人,坠机才丢人。复飞从此从个人决断变成预制程序:触发条件、改出航迹、油门配置,全在飞行前就写死。智能体的行动舱需要同样的条例。上一节的监控负责发现失败,本节回答失败之后的事——而且要提前回答,因为失败发生后的那段时间,人来不及思考,只有预制程序靠得住。

飞行问题:失败后的头几秒

复盘大量执行事故会发现同一个模式:压垮系统的不是失败本身,而是失败发生后没有预案的那段时间。抓取失败后盲目重试,把一次失败拖成十次;通信抖动后全系统连锁告警,把局部故障放大成停机;模块抛出未捕获异常,让整架飞行器为一个探头的感冒躺进重症监护。这些都不是算法问题,是条例缺失问题——本节的复飞程序就是那份条例。

误差分类:先分诊再用药

响应之前先分诊。按持续时间分:瞬态误差(通信抖动、单帧误检,重试即可自愈)、持续误差(执行器退化、环境结构性变化,重试无效需换路径或降级)、致命误差(硬件损坏、安全越线,立即中止进安全态)。按来源分:感知误差(读数错,找 2.3 节的估计兜底)、执行误差(动作没到位,找本节阶梯)、规划误差(航线本身不可行,回 3.4 节重规划)。分诊的价值在于防止用重试对付持续误差——那是最常见的资源黑洞:同一堵墙撞了满页日志。

分级响应阶梯

阶梯的次序体现代价梯度,每级只处理自己能处理的,处理不了就带着完整上下文上抛

import time class RecoveryLadder: """复飞阶梯:重试 -> 降级 -> 中止 -> 安全态。""" def __init__(self, action, board, tower): self.action = action self.board = board self.tower = tower # 4.4 节的塔台频道 self.attempts = 0 def run(self): while True: receipt = self.action.execute() if receipt.ok: return receipt self.attempts += 1 kind = classify(receipt) # 分诊 if kind == "transient" and self.attempts <= MAX_RETRY: backoff = min(2 ** self.attempts * 0.1, 3.0) time.sleep(backoff) # 指数退避防风暴 continue if kind == "persistent": degraded = self.action.degrade() # 降级:慢速、短距、降载 if degraded: self.board.write("behavior", "degraded_mode", writer="recovery") continue if kind == "fatal" or self.attempts > MAX_RETRY: self.action.abort() self.action.enter_safe_state() # 安全态:断力、停稳、留证 self.tower.request_takeover(receipt) # 上抛人工 return receipt def classify(receipt): """分诊:按原因码与重试史归类,绝不凭感觉。""" if receipt.reason in ("通信抖动", "单帧误检", "瞬时超时"): return "transient" if receipt.reason in ("执行器退化", "路径被占", "目标丢失"): return "persistent" return "fatal"

阶梯的关键机制有几点。指数退避让重试频率随失败次数衰减,防止把对方打瘫(对软件接口尤其重要——对方服务可能正是被你的重试压垮的);降级是"换一种没那么好的干法"——速度降半、精度放宽、载荷减重,能力换可用性,这条腿走通了任务就还能交付;安全态有严格定义:断力或缓停、记录现场、停止一切计划推进,它是全机唯一无条件执行的指令,任何歧义都不许有;上抛交 4.4 节塔台,人工接管不是失败,是阶梯的顶端出口。

恢复行为库是阶梯的弹药:倒车重试(路径堵死退一段再走)、回充(电量触底先去充电)、换道重规划(结构路障改走备用走廊)、求助(向其他系统或人请求支援)。预制成库的意义与飞行程序一样——临场不发明,只调用。

恢复行为库是阶梯的弹药架,接口统一定义如下:

class RecoveryBehavior: """恢复行为:可否行、代价与执行接口三件套。""" def __init__(self, name, applies, cost_estimate, run): self.name = name self.applies = applies # (kind, receipt) -> bool self.cost = cost_estimate # 预估代价,供阶梯排序 self.run = run RECOVERY_LIBRARY = [ RecoveryBehavior( "倒车重试", lambda kind, r: kind == "persistent" and r.reason == "路径被占", cost=1.0, run=lambda act: act.backup_then_retry()), RecoveryBehavior( "换道重规划", lambda kind, r: kind == "persistent" and r.reason == "路径被占", cost=2.0, run=lambda act: act.request_replan()), RecoveryBehavior( "回充", lambda kind, r: r.reason == "电量触底", cost=4.0, run=lambda act: act.go_charge()), ] def pick_recovery(kind, receipt): """按适用性与代价选恢复行为:临场不发明,只调用。""" options = [b for b in RECOVERY_LIBRARY if b.applies(kind, receipt)] return min(options, key=lambda b: b.cost, default=None)

鲁棒性设计:复飞的地基

复飞是事后的药,鲁棒性是事前的骨。四项设计在代码里必须先于复飞存在:输入验证(一切外部输入过校验门,垃圾进不来就没有垃圾触发的病)、异常处理(单舱段异常就地捕获、留证、降级,绝不裸奔到主循环——第 1.2 节的"故障不上交"是总纲)、超时控制(一切等待带期限,阻塞是隐形的坠机)、冗余与降级路径(关键探头双份、关键动作有降级档)。可扩展性也在这层落实:模块间只靠接口耦合(第 6 章的挂架标准),坏模块能被拔掉换上降级件——系统的可扩展性,本质是"换件不停机"的能力。

联调测试:故障注入是主科目

复飞程序的联调叫故障注入:在台架与仿真里按剧本制造失败——掐断通信看退避重试的节奏、让执行器持续退化看降级是否接管、伪造致命码看安全态是否干净利落。每个剧本都要核对三件事:阶梯停在了正确的级、状态板与日志留下了完整轨迹、恢复时间在指标内。故障注入库要随故障史的丰富而扩容——每一次真实故障都应该变成一个注入剧本,这是第 7 章测试体系的一部分。

⚠️ 常见坑:把"能重试"当成"有恢复"。无分诊的重试是把同一堵墙撞出不同音量;退避、降级、安全态缺任何一级,阶梯都会在最需要它的那天表现成死循环。

本节要点回顾

  • 失败是常态成本:复飞条例把失败后处置从即兴发挥变成预制程序,价值集中在失败后的头几秒。
  • 先分诊再用药:瞬态重试、持续降级、致命中止;用重试对付持续误差是最常见的资源黑洞。
  • 阶梯四极:退避重试、能力降级、中止与安全态、上抛人工,每级只管自己能管的。
  • 安全态无条件:断力、停稳、留证,全机唯一不容歧义的指令。
  • 鲁棒性是地基:输入验证、异常处理、超时控制、冗余降级,四件先于复飞存在。

阶梯的顶端出口是人工接管。人怎么接、机器怎么交、信任怎么校准——下一节的塔台频道,让"人不是旁观者"落地成协议。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U