Agent 降级策略模型挂了业务不能跟着停一、一个凌晨三点的告警模型超时引发订单积压凌晨三点监控面板上订单队列的红色数字在跳动。12 分钟内积压了 3000 多单原因很直接——大模型 API 返回了 503。Agent 在等待模型响应时同步阻塞整个任务链卡死。这不是模型质量问题这是架构设计缺陷。把 Agent 的生命周期和大模型可用性强绑定等于把业务的命脉交给了一个你无法控制的外部服务。任何依赖外部 API 的系统默认假设都应该是它随时可能挂。生产环境中模型不可用的原因比想象中多服务商限流、网关超时、内容安全拦截、模型版本回滚。每一条都足以让你的 Agent 停摆。所以降级策略不是锦上添花而是上线前的必选项。二、降级决策的核心模型条件判断 路由分发Agent 降级的本质是在模型不可用时系统如何优雅地继续运作。设计上分三层检测层捕获错误类型超时、限流、内容过滤、服务不可用区分可重试和不可重试错误。决策层根据错误类型和上下文选择降级路径——重试、切换备选模型、使用缓存结果、回退到规则引擎或者直接返回兜底响应。执行层执行降级动作并记录决策链路用于后续分析。flowchart TD A[用户请求] -- B[Agent 接收任务] B -- C{调用大模型} C --|成功| D[返回结果] C --|失败| E{错误类型判断} E --|超时 5xx| F[指数退避重试] F --|重试耗尽| G{降级决策} E --|限流 429| H{降级决策} E --|内容过滤| G H -- G G --|缓存命中| I[返回缓存结果] G --|备选模型| J[切换到 GPT-4o-mini] G --|规则引擎| K[规则匹配返回] G --|兜底响应| L[返回预设回复] I -- M[记录降级日志] J -- M K -- M L -- M M -- D这个流程的关键在于决策层不是固定的 if-else而是可配置的。不同业务场景对可接受的降级定义不同。客服场景可以返回预设话术但金融交易场景必须保证数据一致性宁可排队也不返回不确定的结果。三、Go 实现带重试和降级的 Agent 调用器package agent import ( context errors fmt math sync time github.com/sony/gobreaker ) // FallbackStrategy 降级策略枚举 type FallbackStrategy int const ( FallbackCache FallbackStrategy iota // 使用缓存 FallbackAltModel // 切换备选模型 FallbackRule // 规则引擎 FallbackDefault // 兜底响应 ) // DegradeDecision 降级决策结果 type DegradeDecision struct { Strategy FallbackStrategy Reason string Latency time.Duration } // ModelCaller 模型调用器内置重试降级 type ModelCaller struct { primary LLMClient // 主模型客户端 fallback LLMClient // 备选模型客户端如 GPT-4o-mini cache *ResponseCache // 响应缓存 rules *RuleEngine // 规则引擎 breaker *gobreaker.CircuitBreaker maxRetries int baseBackoff time.Duration mu sync.RWMutex } // CallWithFallback 带降级策略的模型调用 func (m *ModelCaller) CallWithFallback( ctx context.Context, prompt string, msgHistory []Message, ) (string, *DegradeDecision, error) { // 先查缓存——零成本降级的第一选择 if cached, ok : m.cache.Get(prompt); ok { return cached, DegradeDecision{ Strategy: FallbackCache, Reason: cache_hit, }, nil } // 熔断器检查如果主模型已经被熔断直接降级 if m.breaker.State() gobreaker.StateOpen { return m.degrade(ctx, prompt, msgHistory, circuit_open) } // 尝试主模型调用带指数退避重试 result, err : m.callWithRetry(ctx, prompt, msgHistory) if err nil { // 成功异步写入缓存 go m.cache.Set(prompt, result, 5*time.Minute) return result, nil, nil } // 主模型失败触发降级决策 return m.degrade(ctx, prompt, msgHistory, err.Error()) } // callWithRetry 指数退避重试 func (m *ModelCaller) callWithRetry( ctx context.Context, prompt string, history []Message, ) (string, error) { var lastErr error for attempt : 0; attempt m.maxRetries; attempt { // 每次重试前检查 context 是否已取消 select { case -ctx.Done(): return , fmt.Errorf(context cancelled: %w, ctx.Err()) default: } result, err : m.primary.Call(ctx, prompt, history) if err nil { return result, nil } // 不可重试的错误直接返回 if isNonRetryable(err) { return , fmt.Errorf(non-retryable error: %w, err) } lastErr err // 指数退避100ms, 200ms, 400ms... backoff : m.baseBackoff * time.Duration(math.Pow(2, float64(attempt))) // 加上随机抖动避免惊群效应 backoff time.Duration(randInt63n(int64(backoff / 2))) select { case -ctx.Done(): return , ctx.Err() case -time.After(backoff): } } return , fmt.Errorf(max retries exceeded: %w, lastErr) } // degrade 执行降级决策 func (m *ModelCaller) degrade( ctx context.Context, prompt string, history []Message, reason string, ) (string, *DegradeDecision, error) { // 策略 1尝试备选模型 if m.fallback ! nil { if result, err : m.fallback.Call(ctx, prompt, history); err nil { return result, DegradeDecision{ Strategy: FallbackAltModel, Reason: fmt.Sprintf(primary_failed: %s, reason), }, nil } } // 策略 2规则引擎匹配 if m.rules ! nil { if result, ok : m.rules.Match(prompt); ok { return result, DegradeDecision{ Strategy: FallbackRule, Reason: fmt.Sprintf(rule_match: %s, reason), }, nil } } // 策略 3兜底响应根据业务场景定制 defaultResp : 系统繁忙请稍后重试。您的问题已记录客服将在工作时间回复。 return defaultResp, DegradeDecision{ Strategy: FallbackDefault, Reason: fmt.Sprintf(all_fallback_exhausted: %s, reason), }, nil } // isNonRetryable 判断是否不可重试 func isNonRetryable(err error) bool { // 内容安全过滤、参数错误等不应重试 return errors.Is(err, ErrContentFilter) || errors.Is(err, ErrInvalidParam) }四、降级策略的边界与权衡不是所有场景都适合降级。比如支付确认、合同签署这类强一致性场景返回一个可能对的结果比返回错误更危险。对于这类场景降级策略应该是快速失败 异步补偿立即返回失败同时把请求写入死信队列等服务恢复后重放。缓存是把双刃剑。缓存能大幅降低延迟和成本但过期数据可能导致过时回答。必须设置合理的 TTL并且在知识库更新时主动失效相关缓存。备选模型有隐形成本。GPT-4o-mini 比 GPT-4o 便宜但如果降级频率过高总额外成本可能超预期。建议对降级调用量做独立计费和告警。熔断器阈值需要调优。太敏感会导致误降级太迟钝则失去保护作用。建议基于历史错误率设定阈值并在运行时动态调整。半开状态的探测间隔也需要根据恢复速度灵活配置。五、总结Agent 的降级策略本质上是外部依赖不可靠这一前提下的系统工程。三层架构检测→决策→执行提供了清晰的关注点分离。核心原则缓存优先、备选兜底、规则保底、快速失败留给强一致性场景。生产部署时务必监控降级率、降级延迟和降级类型分布这些指标直接反映系统的韧性边界。模型会挂业务不能停——这是 AI 工程化的第一课。
Agent 降级策略:模型挂了,业务不能跟着停
发布时间:2026/7/12 15:07:08
Agent 降级策略模型挂了业务不能跟着停一、一个凌晨三点的告警模型超时引发订单积压凌晨三点监控面板上订单队列的红色数字在跳动。12 分钟内积压了 3000 多单原因很直接——大模型 API 返回了 503。Agent 在等待模型响应时同步阻塞整个任务链卡死。这不是模型质量问题这是架构设计缺陷。把 Agent 的生命周期和大模型可用性强绑定等于把业务的命脉交给了一个你无法控制的外部服务。任何依赖外部 API 的系统默认假设都应该是它随时可能挂。生产环境中模型不可用的原因比想象中多服务商限流、网关超时、内容安全拦截、模型版本回滚。每一条都足以让你的 Agent 停摆。所以降级策略不是锦上添花而是上线前的必选项。二、降级决策的核心模型条件判断 路由分发Agent 降级的本质是在模型不可用时系统如何优雅地继续运作。设计上分三层检测层捕获错误类型超时、限流、内容过滤、服务不可用区分可重试和不可重试错误。决策层根据错误类型和上下文选择降级路径——重试、切换备选模型、使用缓存结果、回退到规则引擎或者直接返回兜底响应。执行层执行降级动作并记录决策链路用于后续分析。flowchart TD A[用户请求] -- B[Agent 接收任务] B -- C{调用大模型} C --|成功| D[返回结果] C --|失败| E{错误类型判断} E --|超时 5xx| F[指数退避重试] F --|重试耗尽| G{降级决策} E --|限流 429| H{降级决策} E --|内容过滤| G H -- G G --|缓存命中| I[返回缓存结果] G --|备选模型| J[切换到 GPT-4o-mini] G --|规则引擎| K[规则匹配返回] G --|兜底响应| L[返回预设回复] I -- M[记录降级日志] J -- M K -- M L -- M M -- D这个流程的关键在于决策层不是固定的 if-else而是可配置的。不同业务场景对可接受的降级定义不同。客服场景可以返回预设话术但金融交易场景必须保证数据一致性宁可排队也不返回不确定的结果。三、Go 实现带重试和降级的 Agent 调用器package agent import ( context errors fmt math sync time github.com/sony/gobreaker ) // FallbackStrategy 降级策略枚举 type FallbackStrategy int const ( FallbackCache FallbackStrategy iota // 使用缓存 FallbackAltModel // 切换备选模型 FallbackRule // 规则引擎 FallbackDefault // 兜底响应 ) // DegradeDecision 降级决策结果 type DegradeDecision struct { Strategy FallbackStrategy Reason string Latency time.Duration } // ModelCaller 模型调用器内置重试降级 type ModelCaller struct { primary LLMClient // 主模型客户端 fallback LLMClient // 备选模型客户端如 GPT-4o-mini cache *ResponseCache // 响应缓存 rules *RuleEngine // 规则引擎 breaker *gobreaker.CircuitBreaker maxRetries int baseBackoff time.Duration mu sync.RWMutex } // CallWithFallback 带降级策略的模型调用 func (m *ModelCaller) CallWithFallback( ctx context.Context, prompt string, msgHistory []Message, ) (string, *DegradeDecision, error) { // 先查缓存——零成本降级的第一选择 if cached, ok : m.cache.Get(prompt); ok { return cached, DegradeDecision{ Strategy: FallbackCache, Reason: cache_hit, }, nil } // 熔断器检查如果主模型已经被熔断直接降级 if m.breaker.State() gobreaker.StateOpen { return m.degrade(ctx, prompt, msgHistory, circuit_open) } // 尝试主模型调用带指数退避重试 result, err : m.callWithRetry(ctx, prompt, msgHistory) if err nil { // 成功异步写入缓存 go m.cache.Set(prompt, result, 5*time.Minute) return result, nil, nil } // 主模型失败触发降级决策 return m.degrade(ctx, prompt, msgHistory, err.Error()) } // callWithRetry 指数退避重试 func (m *ModelCaller) callWithRetry( ctx context.Context, prompt string, history []Message, ) (string, error) { var lastErr error for attempt : 0; attempt m.maxRetries; attempt { // 每次重试前检查 context 是否已取消 select { case -ctx.Done(): return , fmt.Errorf(context cancelled: %w, ctx.Err()) default: } result, err : m.primary.Call(ctx, prompt, history) if err nil { return result, nil } // 不可重试的错误直接返回 if isNonRetryable(err) { return , fmt.Errorf(non-retryable error: %w, err) } lastErr err // 指数退避100ms, 200ms, 400ms... backoff : m.baseBackoff * time.Duration(math.Pow(2, float64(attempt))) // 加上随机抖动避免惊群效应 backoff time.Duration(randInt63n(int64(backoff / 2))) select { case -ctx.Done(): return , ctx.Err() case -time.After(backoff): } } return , fmt.Errorf(max retries exceeded: %w, lastErr) } // degrade 执行降级决策 func (m *ModelCaller) degrade( ctx context.Context, prompt string, history []Message, reason string, ) (string, *DegradeDecision, error) { // 策略 1尝试备选模型 if m.fallback ! nil { if result, err : m.fallback.Call(ctx, prompt, history); err nil { return result, DegradeDecision{ Strategy: FallbackAltModel, Reason: fmt.Sprintf(primary_failed: %s, reason), }, nil } } // 策略 2规则引擎匹配 if m.rules ! nil { if result, ok : m.rules.Match(prompt); ok { return result, DegradeDecision{ Strategy: FallbackRule, Reason: fmt.Sprintf(rule_match: %s, reason), }, nil } } // 策略 3兜底响应根据业务场景定制 defaultResp : 系统繁忙请稍后重试。您的问题已记录客服将在工作时间回复。 return defaultResp, DegradeDecision{ Strategy: FallbackDefault, Reason: fmt.Sprintf(all_fallback_exhausted: %s, reason), }, nil } // isNonRetryable 判断是否不可重试 func isNonRetryable(err error) bool { // 内容安全过滤、参数错误等不应重试 return errors.Is(err, ErrContentFilter) || errors.Is(err, ErrInvalidParam) }四、降级策略的边界与权衡不是所有场景都适合降级。比如支付确认、合同签署这类强一致性场景返回一个可能对的结果比返回错误更危险。对于这类场景降级策略应该是快速失败 异步补偿立即返回失败同时把请求写入死信队列等服务恢复后重放。缓存是把双刃剑。缓存能大幅降低延迟和成本但过期数据可能导致过时回答。必须设置合理的 TTL并且在知识库更新时主动失效相关缓存。备选模型有隐形成本。GPT-4o-mini 比 GPT-4o 便宜但如果降级频率过高总额外成本可能超预期。建议对降级调用量做独立计费和告警。熔断器阈值需要调优。太敏感会导致误降级太迟钝则失去保护作用。建议基于历史错误率设定阈值并在运行时动态调整。半开状态的探测间隔也需要根据恢复速度灵活配置。五、总结Agent 的降级策略本质上是外部依赖不可靠这一前提下的系统工程。三层架构检测→决策→执行提供了清晰的关注点分离。核心原则缓存优先、备选兜底、规则保底、快速失败留给强一致性场景。生产部署时务必监控降级率、降级延迟和降级类型分布这些指标直接反映系统的韧性边界。模型会挂业务不能停——这是 AI 工程化的第一课。