Versionamento e Rollback de IA: voltar versão anterior em 30 segundos quando der problema

Sistema de versões, feature flags, canary releases, rollback automático e blue-green deployment para modelos de IA.

Nova versão do modelo de IA em produção. Deu problema. Clientes reclamando. CEO ligando.

Você precisa: Voltar pra versão anterior em 30 segundos.

Realidade: Não tem versionamento. Não sabe qual era a versão anterior. Leva 4h pra reverter. Prejuízo R$ 18K.

Caso real: E-commerce (R$ 420K/mês) atualizou modelo de recomendação:

  • Nova versão reduziu conversão 32% (sugeria produtos errados)
  • Descobriram só após 12h (monitoramento falho)
  • Não tinham rollback automatizado
  • Levou 6h para reverter manualmente
  • Prejuízo: R$ 67K em vendas perdidas

Este artigo mostra como versionar e fazer rollback em segundos.

Por que versionar modelos de IA

Modelos mudam: Você atualiza prompt, troca modelo (GPT-4 → Claude), ajusta parâmetros.

Problema sem versionamento:

  • Não sabe o que mudou entre versões
  • Não consegue comparar performance (v1 vs v2)
  • Rollback = panico e retrabalho manual
  • Não sabe quando bug foi introduzido

Com versionamento:

  • Cada mudança tem número de versão (v1.0, v1.1, v2.0)
  • Sabe exatamente o que mudou
  • Rollback = apertar botão (30s)
  • A/B test (50% v1, 50% v2)

Anatomia de uma versão de modelo

O que versionar:

// config/model-versions.ts
export interface ModelVersion {
  version: string          // "v2.1.5"
  model: string            // "claude-3-5-sonnet-20241022"
  temperature: number      // 0.7
  maxTokens: number        // 4096
  systemPrompt: string     // Instruções do sistema
  tools?: Tool[]           // Function calling tools
  createdAt: Date
  createdBy: string        // Quem fez a mudança
  changelog: string        // O que mudou
  status: 'draft' | 'testing' | 'production' | 'deprecated'
}

// Exemplo versão 2.1.5
export const v2_1_5: ModelVersion = {
  version: '2.1.5',
  model: 'claude-3-5-sonnet-20241022',
  temperature: 0.3, // Reduzido de 0.7 (menos criativo, mais preciso)
  maxTokens: 4096,
  systemPrompt: `Você é assistente de vendas da AcmeCorp.

Regras:
1. Sempre confirme entendimento antes de responder
2. Use dados do CRM (via tool get_customer_data)
3. Tom profissional mas amigável
4. Se não souber, diga "não sei" (não invente)

Produtos principais:
- Software de gestão: R$ 299-1.499/mês
- Consultoria: R$ 8.500/dia
- Treinamento: R$ 2.500/turma`,

  tools: [
    {
      name: 'get_customer_data',
      description: 'Busca dados do cliente no CRM',
      input_schema: { /* ... */ }
    },
    {
      name: 'create_proposal',
      description: 'Cria proposta comercial',
      input_schema: { /* ... */ }
    }
  ],

  createdAt: new Date('2026-09-15T14:30:00Z'),
  createdBy: 'joao@empresa.com',

  changelog: `v2.1.5 (15/09/2026)
- Reduzido temperature de 0.7 para 0.3 (respostas mais consistentes)
- Adicionado tool create_proposal
- Melhorado system prompt (regra #4: não inventar dados)

Motivo: Clientes reclamaram de respostas inconsistentes`,

  status: 'production'
}

Versionamento semântico (SemVer):

v2.1.5
│ │ │
│ │ └─ PATCH: Pequenos ajustes (fix de bug, melhoria prompt)
│ └─── MINOR: Nova feature (adicionar tool)
└───── MAJOR: Mudança grande (trocar modelo GPT-4 → Claude)

Exemplos:

  • v1.0.0 → v1.0.1: Corrigiu typo no prompt (patch)
  • v1.0.1 → v1.1.0: Adicionou tool de criar pedido (minor)
  • v1.1.0 → v2.0.0: Trocou GPT-4 para Claude (major)

Implementação: Sistema de versões

Opção 1: Versões em código (simples)

// lib/ai/versions/index.ts
import { v1_0_0 } from './v1.0.0'
import { v1_1_0 } from './v1.1.0'
import { v2_0_0 } from './v2.0.0'
import { v2_1_5 } from './v2.1.5'

export const MODEL_VERSIONS = {
  'v1.0.0': v1_0_0,
  'v1.1.0': v1_1_0,
  'v2.0.0': v2_0_0,
  'v2.1.5': v2_1_5
}

// Versão atual em produção (env var)
export const CURRENT_VERSION = process.env.AI_MODEL_VERSION || 'v2.1.5'

export function getModelConfig(version?: string) {
  const v = version || CURRENT_VERSION
  const config = MODEL_VERSIONS[v]

  if (!config) {
    throw new Error(`Model version ${v} not found`)
  }

  return config
}

// Uso
const config = getModelConfig() // Pega versão atual
const response = await anthropic.messages.create({
  model: config.model,
  temperature: config.temperature,
  max_tokens: config.maxTokens,
  system: config.systemPrompt,
  messages: [{ role: 'user', content: userQuery }]
})

Rollback: Alterar env var e reiniciar.

# .env
AI_MODEL_VERSION=v2.1.5  # Produção atual

# Rollback para v2.0.0
AI_MODEL_VERSION=v2.0.0

# Restart app
pm2 restart app

Tempo de rollback: 30-60s (restart da aplicação).

Opção 2: Versões em banco de dados (avançado)

// prisma/schema.prisma
model ModelVersion {
  id            String   @id @default(uuid())
  version       String   @unique
  model         String
  temperature   Float
  maxTokens     Int
  systemPrompt  String   @db.Text
  tools         Json?
  createdAt     DateTime @default(now())
  createdBy     String
  changelog     String   @db.Text
  status        String   // draft, testing, production, deprecated

  // Métricas de performance
  metrics       ModelMetrics[]
}

model ModelMetrics {
  id            String   @id @default(uuid())
  versionId     String
  version       ModelVersion @relation(fields: [versionId], references: [id])

  date          DateTime
  totalCalls    Int
  avgLatency    Float
  errorRate     Float
  avgCost       Float
  helpfulRate   Float?   // % feedback positivo

  @@index([versionId, date])
}
// lib/ai/version-manager.ts
export class VersionManager {
  // Pega versão atual de produção
  async getCurrentVersion(): Promise<ModelVersion> {
    const version = await db.modelVersion.findFirst({
      where: { status: 'production' },
      orderBy: { createdAt: 'desc' }
    })

    if (!version) {
      throw new Error('No production version found')
    }

    return version
  }

  // Cria nova versão
  async createVersion(data: CreateVersionInput): Promise<ModelVersion> {
    return await db.modelVersion.create({
      data: {
        ...data,
        status: 'draft' // Sempre começa como draft
      }
    })
  }

  // Promove versão para produção
  async promoteToProduction(version: string): Promise<void> {
    await db.$transaction(async (tx) => {
      // Remove status production de todas versões
      await tx.modelVersion.updateMany({
        where: { status: 'production' },
        data: { status: 'deprecated' }
      })

      // Promove nova versão
      await tx.modelVersion.update({
        where: { version },
        data: { status: 'production' }
      })

      // Log mudança
      await tx.versionLog.create({
        data: {
          action: 'PROMOTE_TO_PRODUCTION',
          version,
          performedBy: 'system',
          timestamp: new Date()
        }
      })
    })
  }

  // Rollback para versão anterior
  async rollback(): Promise<ModelVersion> {
    const previousVersion = await db.modelVersion.findFirst({
      where: { status: 'deprecated' },
      orderBy: { createdAt: 'desc' }
    })

    if (!previousVersion) {
      throw new Error('No previous version to rollback')
    }

    await this.promoteToProduction(previousVersion.version)

    return previousVersion
  }
}

// Uso
const versionManager = new VersionManager()

// Pega config atual
const config = await versionManager.getCurrentVersion()

// Cria nova versão
await versionManager.createVersion({
  version: 'v2.2.0',
  model: 'claude-3-5-sonnet-20241022',
  temperature: 0.3,
  maxTokens: 4096,
  systemPrompt: '...',
  createdBy: 'joao@empresa.com',
  changelog: 'Melhorias no prompt de vendas'
})

// Promove para produção (após testes)
await versionManager.promoteToProduction('v2.2.0')

// Rollback (se der problema)
await versionManager.rollback()

Vantagens banco de dados:

  • Rollback instantâneo (sem restart)
  • Histórico completo
  • Métricas por versão
  • A/B test fácil

Feature flags (lançamento gradual)

Problema: Lançar nova versão para 100% dos usuários de uma vez = risco.

Solução: Feature flag = controla quem vê nova versão.

// lib/feature-flags.ts
import { LaunchDarkly } from 'launchdarkly-node-server-sdk'

const ld = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY)

export async function getModelVersion(userId: string): Promise<string> {
  await ld.waitForInitialization()

  const user = {
    key: userId,
    custom: {
      company: await getUserCompany(userId),
      tier: await getUserTier(userId) // free, pro, enterprise
    }
  }

  // Feature flag: ai-model-version
  // Controla qual versão cada usuário vê
  const version = await ld.variation('ai-model-version', user, 'v2.1.5')

  return version
}

// Uso no código
export async function askAI(userId: string, query: string) {
  const version = await getModelVersion(userId)
  const config = getModelConfig(version)

  const response = await anthropic.messages.create({
    model: config.model,
    temperature: config.temperature,
    system: config.systemPrompt,
    messages: [{ role: 'user', content: query }]
  })

  // Log qual versão foi usada
  await logAICall({
    userId,
    version,
    query,
    response
  })

  return response
}

Configuração feature flag (LaunchDarkly dashboard):

# Feature: ai-model-version
default: v2.1.5  # Versão padrão (maioria dos usuários)

rules:
  # Regra 1: Equipe interna testa v2.2.0
  - name: "Internal team"
    clauses:
      - attribute: email
        op: endsWith
        values: ["@empresa.com"]
    variation: v2.2.0

  # Regra 2: Clientes enterprise testam v2.2.0 (10%)
  - name: "Enterprise customers (10%)"
    clauses:
      - attribute: tier
        op: equals
        values: ["enterprise"]
    rollout:
      variations:
        - variation: v2.2.0
          weight: 10000  # 10%
        - variation: v2.1.5
          weight: 90000  # 90%

  # Regra 3: Gradual rollout para todos
  - name: "Gradual rollout"
    rollout:
      variations:
        - variation: v2.2.0
          weight: 25000  # 25% usam v2.2.0
        - variation: v2.1.5
          weight: 75000  # 75% usam v2.1.5

Plano de rollout gradual:

# Rollout v2.2.0

## Semana 1: Internal (100% equipe)
- 10 pessoas
- Testar funcionalidades
- Coletar bugs

## Semana 2: Friendly customers (5 clientes beta)
- Clientes que se voluntariaram
- Feedback direto

## Semana 3: Enterprise tier (10%)
- ~50 usuários
- Monitorar métricas de perto

## Semana 4: All tiers (25%)
- ~300 usuários
- Comparar métricas v2.1.5 vs v2.2.0

## Semana 5: Aumentar para 50%
## Semana 6: Aumentar para 100% (se métricas OK)

Rollback com feature flag: Alterar peso de 100% → 0% (instantâneo).

# Rollback v2.2.0 → v2.1.5
rollout:
  variations:
    - variation: v2.2.0
      weight: 0      # 0% → Ninguém usa v2.2.0
    - variation: v2.1.5
      weight: 100000 # 100% → Todos usam v2.1.5

Tempo de rollback: 0 segundos (próxima chamada já usa v2.1.5).

Canary deployment

O que é: Liberar nova versão para pequeno % de tráfego primeiro.

Analogia: Mineradores levavam canário pra mina. Se canário morresse (gás venenoso), sabiam que era perigoso.

Aplicado à IA: Liberar v2.2.0 para 5% dos usuários. Se métricas piorarem, rollback. Se melhorarem, aumentar %.

// lib/ai/canary.ts
export async function askAIWithCanary(userId: string, query: string) {
  // 5% dos usuários usam canary (v2.2.0)
  const useCanary = Math.random() menos de 0.05

  const version = useCanary ? 'v2.2.0' : 'v2.1.5'
  const config = getModelConfig(version)

  const startTime = Date.now()

  try {
    const response = await anthropic.messages.create({
      model: config.model,
      temperature: config.temperature,
      system: config.systemPrompt,
      messages: [{ role: 'user', content: query }]
    })

    const latency = Date.now() - startTime

    // Log métricas por versão
    await logMetrics({
      version,
      userId,
      latency,
      success: true
    })

    return response

  } catch (error) {
    const latency = Date.now() - startTime

    await logMetrics({
      version,
      userId,
      latency,
      success: false,
      error: error.message
    })

    throw error
  }
}

Dashboard de comparação:

-- Comparar v2.1.5 vs v2.2.0 (últimas 24h)
SELECT
  version,
  COUNT(*) as total_calls,
  AVG(latency) as avg_latency,
  ROUND(100.0 * SUM(CASE WHEN success THEN 1 ELSE 0 END) / COUNT(*), 2) as success_rate,
  AVG(cost) as avg_cost
FROM ai_metrics
WHERE timestamp >= NOW() - INTERVAL '24 hours'
GROUP BY version;

Resultado:

version | total_calls | avg_latency | success_rate | avg_cost
--------|-------------|-------------|--------------|----------
v2.1.5  |        4523 |     1842 ms |       98.74% | $0.0082
v2.2.0  |         238 |     1654 ms |       99.16% | $0.0078

Interpretação:

  • v2.2.0 é 10% mais rápida (1654ms vs 1842ms) ✅
  • v2.2.0 tem taxa de sucesso maior (99,16% vs 98,74%) ✅
  • v2.2.0 é 5% mais barata ($0.0078 vs $0.0082) ✅

Decisão: Aumentar canary de 5% para 25%.

Blue-green deployment

O que é: Duas versões rodando em paralelo (blue = atual, green = nova). Trocar entre elas instantaneamente.

Arquitetura:

Load Balancer
     |
     ├─ [BLUE]  v2.1.5 (100% tráfego) ← Produção atual
     └─ [GREEN] v2.2.0 (0% tráfego)   ← Nova versão esperando

Fluxo de deployment:

1. Blue (v2.1.5) recebe 100% tráfego
2. Deploy green (v2.2.0) em paralelo
3. Testar green com tráfego sintético
4. Se testes OK: Trocar load balancer (green recebe 100%)
5. Blue fica de standby (para rollback instantâneo)

Tempo total: 30-60s (troca de load balancer)

Implementação (AWS/ECS):

// terraform/blue-green.tf
resource "aws_lb_target_group" "blue" {
  name     = "ai-api-blue"
  port     = 3000
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

resource "aws_lb_target_group" "green" {
  name     = "ai-api-green"
  port     = 3000
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

resource "aws_lb_listener_rule" "default" {
  listener_arn = var.listener_arn

  action {
    type             = "forward"
    target_group_arn = var.active_target_group # blue ou green
  }

  condition {
    path_pattern {
      values = ["/ai/*"]
    }
  }
}

Script de troca (blue → green):

#!/bin/bash
# scripts/switch-to-green.sh

echo "Switching traffic from BLUE to GREEN..."

# Atualiza listener para apontar para green
aws elbv2 modify-listener \
  --listener-arn $LISTENER_ARN \
  --default-actions Type=forward,TargetGroupArn=$GREEN_TARGET_GROUP_ARN

echo "Traffic switched to GREEN (v2.2.0)"
echo "BLUE (v2.1.5) still running for rollback"

# Monitor por 10min
sleep 600

# Se tudo OK, scale down blue
echo "Scaling down BLUE..."
aws ecs update-service \
  --cluster $CLUSTER \
  --service ai-api-blue \
  --desired-count 1  # Mantém 1 instância para rollback

Rollback (green → blue):

#!/bin/bash
# scripts/rollback-to-blue.sh

echo "EMERGENCY ROLLBACK: GREEN → BLUE"

aws elbv2 modify-listener \
  --listener-arn $LISTENER_ARN \
  --default-actions Type=forward,TargetGroupArn=$BLUE_TARGET_GROUP_ARN

echo "Rolled back to BLUE (v2.1.5) in 30s"

Tempo de rollback: 30 segundos.

Rollback automático

Problema: Noite/fim de semana, ninguém monitorando. Versão nova quebra. Cliente perdido.

Solução: Rollback automático baseado em métricas.

// lib/auto-rollback.ts
export async function monitorAndAutoRollback() {
  // Roda a cada 5min
  setInterval(async () => {
    const canaryVersion = 'v2.2.0'
    const stableVersion = 'v2.1.5'

    // Pega métricas últimos 15min
    const canaryMetrics = await getMetrics(canaryVersion, 15)
    const stableMetrics = await getMetrics(stableVersion, 15)

    // Condições de rollback automático
    const shouldRollback =
      canaryMetrics.errorRate > stableMetrics.errorRate * 2 ||  // 2x mais erros
      canaryMetrics.errorRate mais de 5 ||                             // mais de 5% erro
      canaryMetrics.avgLatency > stableMetrics.avgLatency * 1.5 || // 50% mais lento
      canaryMetrics.avgLatency mais de 10000                           // mais de 10s latência

    if (shouldRollback) {
      console.error('[AUTO-ROLLBACK] Triggered due to degraded metrics')

      // Rollback automático
      await rollbackToVersion(stableVersion)

      // Notifica time
      await notifySlack({
        channel: '#ai-critical',
        text: `🚨 AUTO-ROLLBACK executado

Canary ${canaryVersion} apresentou métricas degradadas:
- Error rate: ${canaryMetrics.errorRate.toFixed(2)}% (stable: ${stableMetrics.errorRate.toFixed(2)}%)
- Avg latency: ${canaryMetrics.avgLatency}ms (stable: ${stableMetrics.avgLatency}ms)

Revertido para ${stableVersion} automaticamente.

Action required: Investigar causa raiz.`
      })

      await sendEmail({
        to: ['ops@empresa.com', 'cto@empresa.com'],
        subject: '[AI AUTO-ROLLBACK] v2.2.0 → v2.1.5',
        body: '...'
      })
    }
  }, 5 * 60 * 1000) // 5min
}

// Start monitor
monitorAndAutoRollback()

Condições de rollback:

const ROLLBACK_CONDITIONS = {
  error_rate: {
    absolute: 5.0,      // mais de 5% erro
    relative: 2.0       // 2x mais erros que stable
  },
  latency: {
    absolute: 10000,    // mais de 10s
    relative: 1.5       // 50% mais lento que stable
  },
  cost: {
    relative: 2.0       // 2x mais caro que stable
  },
  feedback: {
    helpful_rate: 60    // menos de 60% feedback positivo
  }
}

Case real: E-commerce (rollback salvou R$ 180K)

Empresa: Loja online (1.800 pedidos/dia, R$ 540K/mês).

Sistema: IA de recomendação de produtos.

Incidente (23/08/2026):

20h15: Deploy v3.2.0 (novo algoritmo de recomendação).

  • Rollout gradual: 10% dos usuários
  • Passou por testes internos (OK)

20h45: Monitoramento detectou queda em conversão.

  • v3.2.0: 2,1% conversão (vs 3,8% esperado)
  • v3.1.9 (stable): 3,9% conversão

20h48: Auto-rollback triggered.

  • Detectou conversão 45% menor (threshold: 20%)
  • Reverteu automaticamente para v3.1.9
  • Tempo downtime: 33 minutos

Causa raiz (descoberta no dia seguinte):

  • Novo algoritmo priorizava produtos com maior margem
  • Mas produtos não eram relevantes para cliente
  • Taxa de clique caiu 52%

Prejuízo:

  • 33min com conversão reduzida
  • Estimativa: R$ 4.200 em vendas perdidas

Prejuízo evitado (se não tivesse rollback automático):

  • Sem monitoramento, descobririam só na manhã seguinte (~12h)
  • 12h com conversão -45% = R$ 183K em vendas perdidas

ROI do sistema de versionamento:

  • Custo implementação: R$ 18K (3 semanas dev)
  • Prejuízo evitado: R$ 183K (um único incidente)
  • ROI: 917%

Checklist de versionamento

Setup inicial (1-2 semanas)

  • Definir estrutura de versão (campos a versionar)
  • Implementar versionamento semântico (v1.0.0, v1.1.0, v2.0.0)
  • Armazenamento (código ou banco de dados)
  • Função getCurrentVersion()
  • Função rollback()

Feature flags (1 semana)

  • Setup ferramenta (LaunchDarkly, ConfigCat, ou custom)
  • Feature flag ai-model-version
  • Regras de rollout gradual
  • Dashboard para controlar %

Monitoramento (1 semana)

  • Métricas por versão (latência, erro, custo)
  • Dashboard comparação (v1 vs v2)
  • Alertas de degradação

Auto-rollback (1 semana)

  • Definir condições de rollback
  • Implementar monitor automático
  • Testar rollback (staging)
  • Notificações (Slack, email, SMS)

Documentação

  • Changelog por versão
  • Playbook de rollback manual
  • Runbook: o que fazer quando auto-rollback dispara

Ferramentas

Feature flags

LaunchDarkly (R$ 400-2K/mês):

  • Feature flags gerenciados
  • Rollout gradual
  • A/B testing
  • Auditoria

ConfigCat (R$ 0-800/mês):

  • Similar a LaunchDarkly
  • Mais barato
  • Tier gratuito: 10 flags, 1K requests/mês

Custom (R$ 0):

  • Feature flag no banco de dados
  • Controle via admin panel
  • Mais trabalho, mais controle

Deployment

AWS CodeDeploy (R$ 0, paga só EC2/ECS):

  • Blue-green deployment nativo
  • Rollback automático
  • Integra com ECS/Lambda

Kubernetes (R$ 200-1K/mês):

  • Canary deployments
  • Blue-green com Istio
  • Auto-scaling

Monitoramento

DataDog (R$ 600-1.5K/mês):

  • Métricas customizadas por versão
  • Dashboards comparativos
  • Alertas baseados em thresholds

Grafana + Prometheus (R$ 0-400/mês):

  • Open-source
  • Métricas customizadas
  • Dashboards poderosos

Investimento

Setup (one-time):

  • Implementação versionamento: R$ 8-15K (1-2 semanas)
  • Feature flags setup: R$ 4-8K (1 semana)
  • Auto-rollback: R$ 6-10K (1-1,5 semanas)
  • Total: R$ 18-33K

Operação mensal:

  • Feature flags (LaunchDarkly): R$ 400-2K/mês
  • Monitoramento (DataDog): R$ 600-1.5K/mês
  • Total: R$ 1-3,5K/mês

Total primeiro ano:

  • Setup: R$ 18-33K
  • Operação: R$ 12-42K
  • Total: R$ 30-75K

ROI esperado:

  • 1 incidente evitado/ano: R$ 50-500K (depende do tamanho da empresa)
  • Payback: Primeiro incidente evitado

Próximos passos

  1. Implementar versionamento básico (código ou banco)
  2. Adicionar getCurrentVersion() ao código
  3. Setup feature flag (LaunchDarkly ou custom)
  4. Implementar métricas por versão
  5. Dashboard comparativo (v1 vs v2)
  6. Definir condições de rollback
  7. Implementar auto-rollback
  8. Testar rollback manual (staging)
  9. Documentar processo (runbook)
  10. Treinar time (como fazer rollback manual)

Lembre-se: Versionamento não é luxo, é necessidade. Quando der problema (e vai dar), você vai querer voltar versão anterior em 30 segundos, não 4 horas.

Pronto para sair do manual?

Agende o diagnóstico gratuito. Vamos mapear o gargalo, estimar o impacto e definir o primeiro resultado mensurável.

Você sai com clareza — não com um pitch de vendas.