当 AI agent 接入模型、检索、数据库、业务 API 以后,系统最容易出现的假动作就是“出错了就再试一次”。单看每个请求似乎合理,但只要依赖已经抖动,这种策略会迅速演变成重试风暴:上游更慢、队列更长、更多请求超时,最后把原本局部的问题放大成全链路故障。
所以熔断、背压与降级要解决的,不是“让系统永远不停”,而是让系统在依赖变坏时,优先保护整体可用性,而不是继续把压力推给已经不健康的下游。
建议先结合 AI Agent 并发与可靠性、AI agent 任务优先级队列、AI agent Deadline 与超时预算 和 AI agent 灰度发布与功能开关 一起看。
先给结论:控制面至少要同时管 3 件事
| 机制 | 解决什么问题 | 典型动作 |
|---|---|---|
| Circuit breaker | 坏依赖还要不要继续打 | 打开后只放探活流量 |
| Backpressure | 系统还能不能继续接更多请求 | 排队、延后、拒绝 |
| Degrade | 即使依赖变差,用户还能得到什么 | 缩短结果、切模板、转人工 |
少任意一层,系统都会在高峰和抖动时变得很脆。
一、先区分坏依赖类型,不是所有失败都该开熔断
更有用的分类通常是:
| 失败类型 | 说明 | 建议 |
|---|---|---|
| 429 / quota exhausted | 对方明确说太多了 | 退避 + 限流 + 背压 |
| 连续 timeout | 依赖明显变慢 | 熔断 + degrade |
| 少量 5xx | 短时抖动 | 允许少量重试 |
| schema invalid / bad output | 质量问题 | 不该靠 breaker 解决 |
如果系统把所有失败都当成“依赖坏了”,熔断会变成误伤;如果所有失败都继续重试,系统又会把下游打穿。
二、熔断不是一个布尔开关,而是状态机
一个最小 breaker 通常至少有三态:
| 状态 | 含义 |
|---|---|
closed | 依赖健康,正常放量 |
open | 依赖明显不稳,暂时停止正常流量 |
half_open | 只放少量探活请求,判断是否恢复 |
这套状态如果不存在,系统很容易在“坏了 -> 全停”与“坏了 -> 继续打”之间来回摇摆。
但真正让 breaker 可运行的,不只是三态名字,而是清楚的 trip threshold 和 probe budget。例如:
| 信号 | trip 条件 | open 保持时间 | half-open 探活 |
|---|---|---|---|
| 429 激增 | 30 秒窗口内连续超阈值 | 15 - 60 秒 | 只放少量只读请求 |
| timeout 连续出现 | 连续 N 次超时 | 30 秒起步 | 单 worker 探活 |
| 5xx 波动 | 错误率超过阈值 | 10 - 30 秒 | 按 tenant 抽样 |
没有这些阈值,breaker 往往只是一个被人工拍脑袋切换的开关,而不是系统自带的收敛机制。
三、背压要先决定谁该被保护,不是所有请求一视同仁
更健康的背压策略通常会区分:
- 关键业务流量
- 普通自动化流量
- 可以稍后再做的批量任务
例如:
| 请求类型 | 依赖抖动时策略 |
|---|---|
| 人工正在等待的审批辅助 | 优先保留 |
| 一般内容生成 | 延后或降级 |
| 批量离线回放 | 暂停 |
如果背压只会“全量排队”,最有价值的请求也会被重任务淹没。
四、降级设计要提前写清楚,不要出事后临时编
最有用的 degrade 不是“返回系统繁忙”,而是给用户一个仍可继续的路径:
- 模型不可用时,返回结构化模板或已缓存建议
- 检索变慢时,减少上下文范围继续执行
- 写操作不稳时,转入人工 review 或 outbox
也就是说,降级不是假装成功,而是明确告诉系统和用户:在当前条件下,最安全的下一步是什么。
在此基础上,背压最好再配一层 shed policy,明确谁先被削峰,谁必须保留:
| 流量类 | 依赖抖动时处理 |
|---|---|
| protected interactive | 优先保留,不轻易 shed |
| standard interactive | 允许降级或短暂排队 |
| async batch | 首先延后或暂停 |
| replay / backfill | 默认被最先 shed |
这样 breaker 打开以后,系统不只是“少打下游”,还知道具体该牺牲哪部分流量。
五、breaker、deadline 和队列必须协同,不然会互相打架
如果 breaker 已经打开,但队列还在不断吞请求;或者请求早已没预算,但 half-open 还在反复试探,下游依赖仍然会被拖垮。
所以这几个模块至少要共享:
- 当前依赖健康状态
- 当前队列压力
- 当前 run 剩余预算
这样系统才能知道:现在该继续探活、该丢弃探活、还是该直接走降级链路。
六、上线后要看“抖动时是否缩容成功”,而不是只看平时成功率
建议重点看:
| 指标 | 用途 |
|---|---|
| breaker open rate | 看依赖是否经常进入危险状态 |
| open 状态下的 downstream call volume | 看熔断后是否真的减压 |
| probe recovery success rate | 看 half-open 探活是否有效 |
| backlog growth under degrade | 看背压是否有效 |
| shed load ratio | 看系统是否真的主动削减了低优先级流量 |
| degraded but accepted runs | 看降级是否保住业务可用性 |
如果 breaker open 了但 downstream 调用量没降,说明你只是记了状态,没有真正挡住流量。
七、失败案例:429 后固定间隔重试,把轻故障打成雪崩
某个 agent 在模型供应商短时 429 后启用了 1s, 1s, 1s 固定重试。原始问题只是瞬时配额拥堵,但三轮回潮很快把轻任务、重任务和探活流量全挤到一起,最终人工审批辅助也排队超时。
修复后,团队做了三件事:
- breaker 达阈值后进入 open,只保留少量 half-open 探活
- 普通内容生成走 degrade,直接返回模板化结果
- 批量异步任务暂停,不和交互流量竞争
问题的关键不是“能不能重试”,而是“依赖已经不稳时,系统是否先学会减压”。
八、熔断、背压与降级 Checklist
- 是否先区分 429、timeout、5xx 和质量问题
- breaker 是否建成 closed/open/half-open 三态
- 是否为不同故障类型设置 trip threshold、open window 和 probe budget
- 背压是否按业务优先级保护关键流量
- 是否预先定义 degrade 路径,而不是只会返回繁忙
- 是否明确了各类流量的 shed policy
- breaker、队列和 deadline 是否共享健康状态
- 是否监控 open 状态下的真实减压效果
- 是否验证降级后仍有 accepted run,而不是全部失败
结语
AI agent 的熔断、背压与依赖降级,不是为了把所有错误挡在系统外,而是为了在依赖变坏时,先保护整体可用性和关键任务。真正成熟的系统,不是在坏依赖前更激进,而是在坏依赖前更克制。
延伸阅读:


