在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、前言思考

1.1 AI 功能"偶尔失灵"是必然

AI 模型不是确定性程序,它的"失败"多种多样:

  • 输入畸形(模糊照片、生僻方言)→ 模型输出不可信;
  • 模型文件损坏 / 版本不兼容 → 推理直接抛异常;
  • NPU 资源不足 / 被抢占 → 推理超时或 OOM;
  • 设备过载 → 推理队列堆积,卡死 UI。

生产环境里,AI 功能必须像普通功能一样稳定:不能因为模型异常就闪退、卡死、白屏。这就是端侧 AI 异常处理体系要解决的问题。

1.2 异常处理的目标

目标 含义
不崩溃 任何异常都不能导致 App 崩溃
不卡顿 推理失败不能阻塞主线程
有反馈 用户看到可理解的降级结果,而非报错
可恢复 故障恢复后自动回到正常状态
可观测 异常被记录上报,供持续改进

二、底层原理

2.1 异常分类决策树

AI 调用异常
  │
  ├─ 输入异常 → 输入校验管道 → 返回明确提示
  ├─ 模型异常 → 模型完整性/兼容性检测 → 修复或重装
  ├─ 资源异常 → 等待/降级 → 重试
  └─ 结果异常 → 置信度校验 → 二次确认/降级

每一类都有独立的处理策略,互不干扰。

2.2 降级策略阶梯

第一级: 端侧模型推理(最快, 离线)
   ↓ 失败/精度不足
第二级: 云端模型推理(更强, 需网络)
   ↓ 失败/无网
第三级: 规则兜底(最弱, 永不失败)
   ↓ 
最终: 明确告知用户"能力受限"

降级原则:能出结果就出结果,结果差也比没结果强;实在不行也要给用户一个清楚的说法

2.3 输入数据校验管道

模型对"垃圾输入"没有防御力,必须在入口校验:

原始输入 → 格式校验 → 尺寸/采样率校验 → 内容合法性校验 → 质量校验 → 送入模型
    │           │            │                │              │
    └── 失败 ────┴────────────┴────────────────┴──────────────┘
                         返回明确错误码 + 友好提示
校验项 例子
格式 图片是否可解码
尺寸 是否小于模型最小输入(如 32×32)
内容 纯色图/全黑图无检测意义
质量 模糊度、噪声水平

三、实战落地

3.1 推理异常捕获与容错

import { mindSporeLite } from '@kit.MindSporeLite';

class SafeInference {
  private model: mindSporeLite.Model | null = null;
  private modelVersion: string = '';

  async safePredict(input: any): Promise<SafeResult> {
    // 1. 输入校验
    const check = this.validateInput(input);
    if (!check.ok) {
      return { ok: false, code: check.code, message: check.message, fallback: 'none' };
    }

    // 2. 模型可用性检查
    if (!this.model || this.modelVersion !== EXPECTED_VERSION) {
      await this.reloadModel();   // 模型损坏/版本不符 → 重载
    }

    // 3. 带超时的推理
    try {
      const outputs = await Promise.race([
        this.model.predict([input]),
        timeout(3000)             // 3s 超时
      ]);
      return { ok: true, data: outputs };
    } catch (e) {
      LoggerUtil.error(TAG, '推理异常: ' + JSON.stringify(e));
      return this.degrade(input);  // 降级
    }
  }

  private async degrade(input: any): Promise<SafeResult> {
    // 第一级降级: 云端
    if (netConnected()) {
      try {
        const cloud = await cloudPredict(input);
        return { ok: true, data: cloud, fallback: 'cloud' };
      } catch (e) { /* 继续降级 */ }
    }
    // 第二级降级: 规则
    const rule = ruleBasedPredict(input);
    if (rule) {
      return { ok: true, data: rule, fallback: 'rule' };
    }
    // 最终: 明确告知
    return { ok: false, code: 'AI_UNAVAILABLE', message: 'AI 能力暂时不可用,请稍后重试', fallback: 'none' };
  }
}

function timeout(ms: number): Promise<never> {
  return new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), ms));
}

3.2 模型完整性/兼容性校验

// 模型加载前校验
async function verifyModel(modelPath: string, expected: { hash: string, version: string }): Promise<boolean> {
  // 1. 文件完整性
  const fileHash = await sha256File(modelPath);
  if (fileHash !== expected.hash) {
    LoggerUtil.error(TAG, '模型文件损坏, 需重新下载');
    await modelManager.redownload('com.demo.ocr');
    return false;
  }

  // 2. 版本兼容性
  const appVersion = getAppVersion();
  const minApp = modelManager.getModelMinAppVersion('com.demo.ocr');
  if (compareVersion(appVersion, minApp) < 0) {
    LoggerUtil.warn(TAG, '模型版本高于App版本, 走降级');
    return false;
  }
  return true;
}

3.3 资源不足时的等待与重试

class BackoffRetry {
  private retryCount = 0;

  async runInferenceWithRetry(infer: () => Promise<any>): Promise<any> {
    const maxRetry = 3;
    for (let i = 0; i < maxRetry; i++) {
      try {
        return await infer();
      } catch (e) {
        if (!isResourceError(e)) throw e;   // 非资源错误不重试
        await sleep(200 * Math.pow(2, i));  // 指数退避: 200ms, 400ms, 800ms
      }
    }
    throw new Error('resource exhausted');
  }

  private isResourceError(e: any): boolean {
    return e?.code === 'NPU_BUSY' || e?.code === 'OOM' || e?.code === 'TIMEOUT';
  }
}

3.4 结果置信度校验

模型"输出了"不代表"输出对",低置信度结果要二次处理:

function checkResultConfidence(outputs: any[], threshold: number): SafeResult {
  const top = outputs[0];
  if (top.confidence < threshold) {
    // 低置信度: 重新采集输入 or 降级 or 询问用户
    return {
      ok: false,
      code: 'LOW_CONFIDENCE',
      message: '识别结果不太确定, 请重新拍摄',
      data: null
    };
  }
  return { ok: true, data: outputs };
}

四、性能排查与优化

问题 表现 优化手段
反复重载 模型加载多次失败 加载前校验 + 失败计数熔断
重试风暴 资源紧张时疯狂重试 指数退避 + 最大次数 + 熔断
降级感知差 用户不知道降级了 降级标记透出 + UI 提示
异常淹没 日志被刷屏 错误聚合 + 采样上报
恢复滞后 故障恢复后仍降级 健康检查定时探测恢复

4.1 熔断器

连续失败快速失败,避免资源耗尽:

class CircuitBreaker {
  private failures = 0;
  private state: 'closed' | 'open' | 'half' = 'closed';

  async call(fn: () => Promise<any>): Promise<any> {
    if (this.state === 'open') {
      throw new Error('circuit open');   // 直接失败, 不进推理
    }
    try {
      const r = await fn();
      this.failures = 0;
      if (this.state === 'half') this.state = 'closed';
      return r;
    } catch (e) {
      this.failures++;
      if (this.failures > 5) {
        this.state = 'open';
        setTimeout(() => { this.state = 'half'; }, 30000);  // 30s后试探
      }
      throw e;
    }
  }
}

4.2 健康检查恢复

// 定时探测模型是否恢复
setInterval(async () => {
  if (this.state === 'degraded') {
    const ok = await probeModel();   // 跑一次极小的推理
    if (ok) {
      this.state = 'normal';
      LoggerUtil.info(TAG, 'AI 能力已恢复');
    }
  }
}, 60 * 1000);

五、总结

  1. AI 异常处理的目标不是"永不失败"(不可能),而是失败时优雅降级、快速恢复、不打扰用户
  2. 四道防线:输入校验(防垃圾进)、模型校验(防坏模型)、超时重试(防资源抖)、置信度校验(防错误出)。
  3. 降级阶梯:端侧 → 云端 → 规则 → 明确告知,永远有最后一手。
  4. 工程三件套:熔断器防雪崩、指数退避防重试风暴、健康检查自动恢复。

一句话记住:入口要校验,模型要体检,失败要降级,恢复要自愈。


🚀 演示功能优化(随项目同步更新)

本文对应的 ArkTS 演示页面已随项目整体优化,主要改进:

  1. 独立主题风格:暗红警示 · 深色告警琥珀强调,与其余章节演示页明显区分,不再千篇一律。
  2. 步骤回放动画:点击演示按钮后,结果行按 260~320ms/步 逐步展示,模拟真实推理过程。
  3. 运行态保护:演示过程中按钮置灰防重复触发,页面退出自动清理定时器。
  4. 结果摘要:演示结束后自动给出「一句话结论」,并 Toast 提示完成。
  5. AI 对话演示:新增 AiChatDemo(根目录 main.py 的 ArkTS 移植),真实 SSE 流式大模型请求,首页「★ AI Chat 流式对话演示」可进入。

对应页面:entry/src/main/ets/pages/AiFaultToleranceDemo.ets


🧪 演示优化:真实 AI 推理接入(v3)

本演示页顶部新增 AI 容错专家主卡,点击即真实调用云端大模型(SSE 流式),不再是纯模拟回放:

  • 请求链路utils/AiClient.ets(ArkTS 封装 OpenAI 兼容接口)→ POST https://api-ai.gitcode.com/v1/chat/completions,模型 deepseek-ai/DeepSeek-V4-Flash,流式 stream: true
  • 演示场景:推理失败诊断 / 模型降级 / 自动恢复 —— 每个场景绑定不同可靠性专家 Prompt,返回内容各有差异
  • 交互体验:进入页面自动触发一次真实推理;点场景标签切换并重新请求;按钮手动触发;输出区打字机流式展示
  • 真实标识:卡片右上角 LIVE 徽标 + 端点/模型名水印,保证"所见即所调"
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐