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
- Implementar versionamento básico (código ou banco)
- Adicionar getCurrentVersion() ao código
- Setup feature flag (LaunchDarkly ou custom)
- Implementar métricas por versão
- Dashboard comparativo (v1 vs v2)
- Definir condições de rollback
- Implementar auto-rollback
- Testar rollback manual (staging)
- Documentar processo (runbook)
- 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.