Agent 系统的零停机升级:蓝绿部署与金丝雀发布在 AI 服务中的应用

一、AI 服务部署的特殊挑战

传统微服务的零停机升级相对成熟:滚动更新 + 健康检查 + 优雅关闭,基本能满足需求。但 AI 服务有额外的复杂度:

  1. 模型状态的连续性:Agent 在对话中维持上下文,升级会导致上下文丢失
  2. 推理的不可中断性:一次 LLM 推理可能持续数秒,中断意味着 Token 浪费
  3. 供应商侧的模型切换:升级可能涉及模型版本变更,新模型的输出格式可能不同
  4. 工具调用的幂等性问题:Agent 在执行多步任务时,中断后重试可能重复执行同一步骤

这些特点让"直接滚动重启"的方案不可行——你无法在中断一个正在执行 10 步任务的 Agent 后,简单地让新版本接手。

当新版本 Agent 就绪后,我们需要在蓝绿部署、金丝雀发布和滚动更新之间做出策略选择。蓝绿部署侧重于环境隔离与一键切换,金丝雀发布侧重于小流量验证与逐步放量,而滚动更新则是逐个实例替换。考虑到 Agent 系统对状态连续性的严格要求,蓝绿部署往往能提供更安全的切换保障,因此成为许多团队的首选。

二、蓝绿部署:为 Agent 系统定制的双环境方案

蓝绿部署的核心是维护两套完全独立的环境(蓝/绿),切换时通过流量网关将全部流量从旧环境转移到新环境。

# docker-compose.blue.yml — 当前生产环境(蓝)
version: '3.8'
services:
  agent-service:
    image: agent-service:v2.4.0
---
ports: ["8000:8000"]
environment:
  - ENV_COLOR=blue
  - LLM_MODEL=gpt-4o-2024-08-06

docker-compose.green.yml — 新版本(绿)

version: '3.8'
services:
agent-service:
image: agent-service:v2.5.0
ports: ["8001:8000"]
environment:
- ENV_COLOR=green
- LLM_MODEL=gpt-4o-2024-11-20


流量切换网关(Nginx/Caddy 配置):

```nginx
upstream agent_backend {
    # 默认指向蓝环境
    server blue:8000 weight=1;
    # green 环境 weight=0,不接收流量
    server green:8001 weight=0;
}

# 切换脚本
# switch_to_green.sh
sed -i 's/blue:8000 weight=1/blue:8000 weight=0/' nginx.conf
sed -i 's/green:8001 weight=0/green:8001 weight=1/' nginx.conf
nginx -s reload

Agent 系统的特殊处理——优雅排空

type GracefulDrainer struct {
    activeSessions sync.Map
    drainTimeout   time.Duration // 最长排空时间
}

func (d *GracefulDrainer) StartDrain() {
    // 1. 停止接收新请求(网关已切换流量到新环境)
    // 2. 等待现有 Agent 任务完成
    deadline := time.Now().Add(d.drainTimeout)
    
    for {
        count := d.countActive()
        if count == 0 {
            break
        }
        if time.Now().After(deadline) {
            // 超过排空时间,强制中断并保存状态
            d.forceSaveAndExit()
            break
        }
        time.Sleep(5 * time.Second)
    }
}

func (d *GracefulDrainer) forceSaveAndExit() {
    d.activeSessions.Range(func(key, value interface{}) bool {
        session := value.(*AgentSession)
        // 保存 Agent 上下文到持久化存储
        session.SaveCheckpoint()
        // 通知用户:任务将在新版本中继续
        session.NotifyUser("系统升级中,你的对话将在新版本中继续")
        return true
    })
}

三、金丝雀发布:渐进式验证

对于风险较高的升级(如切换底层 LLM 模型、工具调用协议变更),蓝绿部署的一刀切切换风险太大。金丝雀发布通过逐步增加新版流量来验证稳定性。

// 金丝雀流量控制中间件
func CanaryMiddleware(weight int) gin.HandlerFunc {
    return func(c *gin.Context) {
        userID := c.GetHeader("X-User-ID")
        hash := fnv.New32a()
        hash.Write([]byte(userID))
        
        // 基于用户 ID 哈希的一致性路由
        // 同一用户始终路由到同一版本,避免 Agent 上下文切换
        if int(hash.Sum32()%100) < weight {
            c.Set("version", "canary")
            c.Request.URL.Host = "agent-canary:8001"
        } else {
            c.Set("version", "stable")
        }
        c.Next()
    }
}

// 金丝雀升级脚本
func progressiveRollout() {
    weights := []int{1, 5, 10, 25, 50, 100}
    
    for _, w := range weights {
        log.Printf("金丝雀比例: %d%%", w)
        setCanaryWeight(w)
        
        // 观察 5 分钟
        if err := monitorMetrics(5 * time.Minute); err != nil {
            log.Printf("异常检测到,回滚到稳定版: %v", err)
            setCanaryWeight(0)
            return
        }
    }
}

四、回滚策略与状态恢复

回滚场景

  • 新模型输出格式不兼容,Agent 工具调用失败率 > 5%
  • 新版本内存泄漏导致 OOM
  • 新 Prompt 模板导致 Token 消耗翻倍
type RollbackManager struct {
    checkpointStore CheckpointStore
}

func (rm *RollbackManager) Rollback(sessionID string, targetVersion string) error {
    // 1. 读取最近的 Agent 上下文快照
    checkpoint, err := rm.checkpointStore.Load(sessionID)
    if err != nil {
        return fmt.Errorf("no checkpoint found: %w", err)
    }
    
    // 2. 用旧版本 Agent 恢复上下文
    oldAgent := NewAgent(targetVersion)
    oldAgent.RestoreSession(checkpoint)
    
    // 3. 重新执行从快照点开始的步骤
    // 注意:已完成的工具调用如果是幂等的,无需重试
    for _, step := range checkpoint.PendingSteps {
        if step.IsIdempotent() {
            oldAgent.Execute(step)
        } else {
            // 非幂等步骤需要人工介入或标记为"可能重复"
            oldAgent.ExecuteWithWarning(step, "此步骤可能被重复执行")
        }
    }
    
    return nil
}

五、总结

Agent 系统的零停机升级需要处理模型状态连续性、推理不可中断性、工具调用幂等性三个特殊约束。蓝绿部署适合低风险升级(配置变更、Prompt 优化),通过双环境 + 一键流量切换实现秒级回滚,但需要排空现有 Agent 任务。金丝雀发布适合高风险升级(模型切换、协议变更),通过用户 ID 哈希的一致性路由,逐步增加新流量的同时保持同一用户的上下文连续性。不管哪种策略,Agent 上下文的保存和恢复是降级和回滚的基础。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐