Sexto post da série. No anterior, automatizamos provisioning de clusters GPU. Agora vamos falar do que acontece depois do hardware estar pronto: como um modelo vai de “funciona no meu notebook” pra “roda em produção com SLA”.

O modelo que chegou sem certidão de nascimento

Um data scientist manda uma mensagem no canal do time com um link pra um shared drive: “Aqui está o modelo. É um checkpoint PyTorch de 15 GB. Precisamos em produção até sexta.”

Você abre a pasta e encontra um único arquivo: model_final_v2_FIXED.pt.

Começa a perguntar. Qual versão? Treinado com quais dados? Plano de rollback se as predições derem errado? SLAs de latência e throughput? Qual framework e versão de CUDA? As respostas são vagas. “É o último. Funciona na minha máquina. Só coloca atrás de uma API.”

Esse filme você já viu antes, só com atores diferentes. Developers costumavam te dar um binário compilado e dizer “deploya isso”. Esse caos levou a indústria a construir container registries, pipelines CI/CD, semantic versioning e rollback automatizado. Modelos não são diferentes. São artefatos: grandes, versionados, dependentes de ambiente. Merecem o mesmo lifecycle management.

Modelos são artefatos: trate como tal

Se você já puxou uma imagem de um container registry, tageou um release no Git, ou promoveu um build de staging pra produção, já entende os conceitos core de model lifecycle.

Conceito de InfraEquivalente ML
Container imageModel checkpoint (arquivo de pesos)
Container registry (ACR)Model registry (Azure ML, MLflow)
CI buildTraining run
CD release pipelineModel deployment pipeline
Dockerfile (build manifest)Training config (hyperparameters, data version, framework version)
Artifact signatureModel provenance e lineage
Blue/green deploymentA/B testing com traffic splitting

Um arquivo de modelo sem metadados é como uma container image sem tag. Você pode deployar, mas não reproduzir, auditar, ou fazer rollback seguro.

Model registries

O registry é a single source of truth pros modelos da organização. Guarda artefatos com metadados: versão, métricas de training, lineage e status de deployment.

Azure Machine Learning Model Registry

# Registrar modelo de arquivo local
az ml model create \
  --name sentiment-classifier \
  --version 3 \
  --path ./outputs/model.pt \
  --type custom_model \
  --tags task=sentiment framework=pytorch \
  --resource-group ml-prod-rg \
  --workspace-name ml-prod-ws

# Listar versões do modelo
az ml model list \
  --name sentiment-classifier \
  --resource-group ml-prod-rg \
  --workspace-name ml-prod-ws \
  --output table

# Ver lineage: qual run produziu esse modelo
az ml model show \
  --name sentiment-classifier \
  --version 3 \
  --resource-group ml-prod-rg \
  --workspace-name ml-prod-ws \
  --query "jobs"

MLflow (open-source, multi-framework)

MLflow é o padrão open-source pra experiment tracking e model management. Framework-agnostic, wrapa PyTorch, TensorFlow, scikit-learn. Azure ML integra nativamente com MLflow.

# Servidor MLflow local (dev/test)
mlflow server \
  --backend-store-uri sqlite:///mlflow.db \
  --default-artifact-root ./mlruns \
  --host 0.0.0.0 --port 5000

# Registrar modelo via CLI
mlflow models register \
  --model-uri runs:/<run-id>/model \
  --name sentiment-classifier

# Promover pra produção
mlflow models transition-stage \
  --name sentiment-classifier \
  --version 3 \
  --stage Production

Container Registry pra model serving

Quando modelos são servidos via containers (Triton, TorchServe, FastAPI wrapper), a imagem vira o artefato deployável:

# Build e push do container de serving
az acr build \
  --registry mlmodelsacr \
  --image sentiment-classifier:v3 \
  --file Dockerfile.serve .

# Verificar imagem
az acr repository show-tags \
  --name mlmodelsacr \
  --repository sentiment-classifier \
  --output table

Qual registry usar?

CritérioAzure ML RegistryMLflow RegistryACR (Container)
Melhor praTimes Azure-nativeMulti-cloud / OSSServing containerizado
VersionamentoBuilt-in, imutávelBuilt-in com stagesImage tags
Lineage trackingProfundo (jobs, data, env)Run-levelDockerfile only
Infra overheadManagedSelf-hosted ou Azure MLManaged (ACR)
Quando evitarNecessidade multi-cloudPrecisa deep Azure integrationModelos sem containers

Cuidado: Nunca use shared file systems ou blob storage como “registry”. Sem versões imutáveis e APIs de metadata, você acaba com model_final_v2_FIXED_actually_final.pt.

CI/CD pra modelos: o pipeline de promoção

┌─────────┐     ┌─────────────┐     ┌──────────────┐
│   DEV   │────▶│   STAGING   │────▶│  PRODUCTION  │
│         │     │             │     │              │
│ Train   │     │ Validate    │     │ Serve        │
│ Track   │     │ Benchmark   │     │ Monitor      │
│ Version │     │ Security    │     │ Auto-rollback│
└─────────┘     └─────────────┘     └──────────────┘
     │               │                    │
  GPU Compute    Inference Infra      Load Balanced
  Blob Storage   Test Data Access     Multi-replica
  Experiment     Isolated Network     Prod Network
  Tracking                            SLA-bound

Validation gates entre stages

GateO que verificaInfra necessária
Accuracy thresholdMétricas ≥ baseline (ex: F1 > 0.92)Storage de test dataset, compute pra avaliação
Latency benchmarkP95 ≤ SLA (ex: < 200ms)Infra de load testing
Throughput testRequests/sec ≥ target sob cargaLoad generator (k6, Locust)
Security scanSem deps vulneráveis, artefato assinadoContainer scanning (Defender)
Cost estimateCusto projetado dentro do budgetCost modeling baseado no SKU

GitHub Actions workflow pra deploy de modelo

name: Model Deployment Pipeline

on:
  workflow_dispatch:
    inputs:
      model_name:
        description: 'Model name in registry'
        required: true
      model_version:
        description: 'Model version to deploy'
        required: true

env:
  AZURE_RG: ml-prod-rg
  AZURE_ML_WS: ml-prod-ws

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Download model from registry
        run: |
          az ml model download \
            --name ${{ inputs.model_name }} \
            --version ${{ inputs.model_version }} \
            --download-path ./model \
            --resource-group ${{ env.AZURE_RG }} \
            --workspace-name ${{ env.AZURE_ML_WS }}
      - name: Run accuracy validation
        run: |
          python scripts/validate_model.py \
            --model-path ./model \
            --test-data ./data/holdout.csv \
            --min-accuracy 0.92

  deploy-staging:
    needs: validate
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to staging endpoint
        run: |
          az ml online-deployment create \
            --name staging-${{ inputs.model_version }} \
            --endpoint-name sentiment-staging \
            --model azureml:${{ inputs.model_name }}:${{ inputs.model_version }} \
            --instance-type Standard_NC4as_T4_v3 \
            --instance-count 1 \
            --resource-group ${{ env.AZURE_RG }} \
            --workspace-name ${{ env.AZURE_ML_WS }}

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy canary (10% traffic)
        run: |
          az ml online-deployment create \
            --name prod-${{ inputs.model_version }} \
            --endpoint-name sentiment-prod \
            --model azureml:${{ inputs.model_name }}:${{ inputs.model_version }} \
            --instance-type Standard_NC4as_T4_v3 \
            --instance-count 2 \
            --resource-group ${{ env.AZURE_RG }} \
            --workspace-name ${{ env.AZURE_ML_WS }}

          az ml online-endpoint update \
            --name sentiment-prod \
            --traffic "prod-stable=90 prod-${{ inputs.model_version }}=10" \
            --resource-group ${{ env.AZURE_RG }} \
            --workspace-name ${{ env.AZURE_ML_WS }}

Tradução infra ↔ AI: Isso é seu pipeline blue/green, mas pra model weights ao invés de container images. A flag --traffic funciona exatamente como weighted routing no Azure Front Door: você shifta percentual de requests pro novo modelo enquanto o antigo continua servindo.

Suas responsabilidades em cada stage

Como engenheiro de infra, seu ownership cobre o pipeline todo:

  • Compute provisioning: GPU node pools pra training (Dev), VMs de inference pra validação (Staging), clusters GPU com autoscaling pra serving (Prod)
  • Networking: VNets isoladas pra staging, private endpoints pro model registry, load balancer pra traffic splitting
  • Storage: High-throughput blob pra dados de training, low-latency pra model artifacts, retention policies pra versões antigas
  • Secrets management: Key Vault pra API keys, managed identity pra auth do pipeline, RBAC pro model registry
  • Monitoring: Dashboards de deployment health, alerting de latência, triggers de rollback automatizado

Traffic splitting: canary e blue/green pra modelos

Deploying um modelo não é evento binário. Você shifta tráfego gradualmente:

PadrãoComo funcionaQuando usar
Canary5-10% do tráfego pro novo modelo, aumenta gradualmenteDefault pra a maioria dos deployments
Blue/GreenAmbiente completo paralelo, switch instantâneoQuando precisa rollback instantâneo
ShadowNovo modelo recebe tráfego real mas respostas são descartadasQuando quer testar sem impactar usuários
# Promover canary pra 100% após validação
az ml online-endpoint update \
  --name sentiment-prod \
  --traffic "prod-v3=100" \
  --resource-group ml-prod-rg \
  --workspace-name ml-prod-ws

No próximo post

Agora que modelos estão deployados e servindo tráfego, como saber se estão saudáveis? No próximo post: monitoramento e observabilidade pra AI, incluindo model drift, GPU metrics, e como detectar degradação antes que o usuário perceba.