> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/ai_security_guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/ai_security_guide/di-san-bu-fen-fang-yu-pian/10_operations/10.5_fallback_strategy.md).

# 10.5 服务降级与回退策略

服务降级与回退（Fallback）在模型服务异常或安全策略触发阻断时，切换到预定的服务方式。降级既要维持业务连续性，也要保留安全约束：服务故障可以触发重试，安全拒绝不能通过切换模型绕过，所有模型输出仍须经过同一审核出口。

## 10.5.1 为什么需要降级策略

LLM 系统的降级比传统 Web 服务更复杂：传统 Web 服务的降级通常是“返回缓存/静态页面”，而 LLM 系统在各类故障下都需要给出自然语言的安全响应。两者的对比如下：

| 场景     | 传统 Web 降级 | LLM 系统降级        |
| ------ | --------- | --------------- |
| 服务不可用  | 返回缓存页面    | 返回预制安全回复        |
| 输入异常   | 返回 400 错误 | 需要自然语言解释拒绝原因    |
| 输出有毒   | 过滤/替换     | 需要重新生成或切换模型     |
| 安全策略触发 | 拦截请求      | 需要平滑过渡，避免暴露防御细节 |

**核心原则：即使系统处于降级状态，也要向用户提供有意义的、安全的响应，而不是错误栈或静默失败。**

## 10.5.2 降级层级设计

降级可按异常的严重程度分为四个层级：轻微异常时重试，中等时切换备用模型，严重时返回预制安全回复，极端时转人工接管。下面的 `L1-L4` 是示例性的分层策略，也是一种常见的降级框架。具体层级、触发条件和是否切换模型，需按业务风险、依赖关系、权限范围和 SLO 单独设计。

```mermaid
flowchart TB
    A["正常服务"] --> B{"异常检测"}
    B --> |轻微| C["L1：模型重试"]
    B --> |中等| D["L2：切换备用模型"]
    B --> |严重| E["L3：预制安全回复"]
    B --> |极端| F["L4：人工接管"]

    C --> G["恢复正常"]
    D --> G
    E --> H["降级服务"]
    F --> H
```

图 10-10：降级层级设计流程图

各层级的触发条件、响应方式和恢复策略如下：

| 层级      | 触发条件        | 响应方式         | 恢复策略       |
| ------- | ----------- | ------------ | ---------- |
| L1 模型重试 | 超时、格式异常     | 重新生成（可调低温度）  | 自动恢复       |
| L2 备用模型 | 主模型不可用、持续异常 | 切换到备用模型或简化模型 | 主模型恢复后自动切回 |
| L3 预制回复 | 安全策略触发、输出有毒 | 返回预定义的安全话术   | 人工审核后恢复    |
| L4 人工接管 | 高危攻击、系统性故障  | 转交人工客服或运营团队  | 故障排除后恢复    |

## 10.5.3 预制安全回复设计

预制回复是降级策略的核心组件，它应按场景分别预制，并且不暴露触发了哪条安全规则。分场景预制的示例如下：

```
场景：输入被检测为注入攻击
回复："抱歉，我无法处理该请求。请尝试重新描述您的问题。
       如需帮助，请联系客服。"

场景：输出安全审核未通过
回复："抱歉，我暂时无法回答这个问题。
       您可以尝试换一种方式提问，或咨询相关专业人士。"

场景：模型服务不可用
回复："系统正在维护中，预计很快恢复。
       您可以稍后再试，或通过其他渠道联系我们。"
```

设计原则如下：

| 原则     | 说明                |
| ------ | ----------------- |
| 不暴露细节  | 不告知用户具体触发了哪条安全规则  |
| 提供替代方案 | 引导用户使用其他渠道或重新提问   |
| 语气友好   | 避免生硬的错误信息，保持品牌一致性 |
| 可配置    | 不同业务线可定制回复内容      |

## 10.5.4 自动降级与恢复

自动降级与恢复依靠健康检查驱动：服务异常时切到降级路由，并定时探测，恢复后切回正常路由。

```mermaid
flowchart LR
    A["健康检查"] --> B{"服务状态"}
    B --> |健康| C["正常路由"]
    B --> |异常| D["降级路由"]
    D --> E["定时探测"]
    E --> |恢复| C
    E --> |未恢复| D
```

图 10-11：自动降级与恢复流程图

下面是依赖注入后的控制流示例：模型、审核器、静态回复、人工队列和计数方法由应用实现。`ModelUnavailableError` 只表示可重试的模型服务故障，`SafetyCheckUnavailableError` 表示审核不可用。主模型、重试与备用模型的成功输出经过同一审核出口。

实现中有两条关键规则：

* 审核器不可用时整体进入 L3。
* 单次安全拒绝只让当前请求返回静态回复，不换模型重试以绕过策略，也不改变全局层级；否则任何用户只要诱导出一次不安全输出，就能把所有用户降到 L3。拒绝按速率计数，是否整体降级交给阈值或运营人员判定。

静态回复须事先审核且不拼接不可信输入，人工接管返回已验证的排队回执。

```python
class FallbackManager:
    def __init__(self):
        self.fallback_level = 0  # 当前降级层级
        self.error_window = []   # 滑动窗口错误计数
        self.canned_responses = load_canned_responses()

    def handle_request(self, request: Request) -> Response:
        if self.fallback_level == 4:
            return self.route_to_human(request)
        if self.fallback_level == 3:
            return self.get_canned_response(request.category)

        try:
            if self.fallback_level == 0:
                response = self.primary_model.generate(request)
            elif self.fallback_level == 1:
                response = self.retry_with_lower_temperature(request)
            else:  # L2
                response = self.use_backup_model(request)
        except ModelUnavailableError:
            self.record_failure()  # 每次模型调用失败计一次。
            return self.escalate_fallback(request)

        try:
            safe = self.safety_check(response)
        except SafetyCheckUnavailableError:
            self.record_safety_unavailable()
            self.fallback_level = 3
            return self.get_canned_response(request.category)

        if not safe:
            self.record_safety_rejection()  # 不计入模型服务故障；按速率另行告警。
            return self.get_canned_response(request.category)  # 只影响本次请求

        self.record_success()
        return response

    def escalate_fallback(self, request: Request) -> Response:
        self.fallback_level = min(self.fallback_level + 1, 4)
        return self.handle_request(request)
```

连续模型故障最多尝试主模型、L1 重试和 L2 备用模型三次，再进入 L3。高危事件或运营人员可从 L3 显式调用 `escalate_fallback` 进入 L4；L4 不会被 L3 的静态回复分支截断。层级恢复由独立健康探测和安全复核决定，单次成功只记账；生产实现还须保护共享状态、设置调用超时，并为静态回复或人工队列故障接入 10.5.5 的终极兜底。

## 10.5.5 终极兜底机制

终极兜底（Ultimate Safety Net）是指当 L1-L4 所有降级层均失败时启用的最后安全网，其目标是最小化风险，而不是维持完整服务。设计原则有三条：

1. 优先最小化风险：终极兜底的目标不是维持完整服务，而是避免高风险动作和误导性输出
2. 静态化回复：使用完全预制的静态消息，不涉及任何模型推理，避免因模型故障产生不可预期的输出
3. 自动降级到非 AI 模式：如提供传统的搜索/FAQ 界面，或直接转接人工

终极兜底回复模板：

```
非常抱歉，系统当前无法处理您的请求。
您可以：
1. 稍后重试
2. 联系人工客服：[客服渠道]
3. 查阅帮助文档：[文档链接]

请求编号：[request_id]（如需反馈请提供此编号）
```

各失败场景对应的降级决策如下：

| 失败场景    | 用户影响 | 决策                      |
| ------- | ---- | ----------------------- |
| 单次请求超时  | 低    | L1 重试                   |
| 主模型连续失败 | 中    | L2 备用模型                 |
| 所有模型不可用 | 高    | L3 预制回复                 |
| 安全组件失效  | 极高   | L3 预制回复（必要时由运营人员升级至 L4） |
| 全面服务故障  | 极高   | 终极兜底：静态页面 + 人工转接        |

进入终极兜底后的监控与恢复要求：

* 进入终极兜底状态后，应按影响范围和严重性评估升级级别，并激活所需值班与业务负责人
* 因可用性故障失败的请求，可在恢复后按幂等性和用户同意策略重试；因安全拦截或审批失败而被拒绝的请求，不应自动重放
* 恢复探测频率应可配置，并结合 failure threshold、探测成本和多地域探针行为确定

## 10.5.6 降级监控与告警

降级本身也需要监控，以免系统长期处于降级状态而无人知晓。监控指标如下：

| 监控指标      | 示例阈值                    | 说明       |
| --------- | ----------------------- | -------- |
| 降级触发次数/分钟 | 按 error budget / 攻击基线设定 | 可能遭受持续攻击 |
| 降级持续时间    | 按 SLO 和恢复目标设定           | 需要人工介入排查 |
| 预制回复占比    | 按用户体验预算设定               | 用户体验明显受损 |
| 人工接管队列长度  | 按运营容量设定                 | 运营资源不足   |
