Sétimo post da série. No anterior, colocamos modelos em produção com pipelines CI/CD. Agora: como saber se estão saudáveis?

A falha silenciosa

Seu endpoint Azure OpenAI retorna 200 OK em todo request. Latência normal, P95 abaixo de 800ms. CPU e memória dentro dos thresholds. Kubernetes mostra pods saudáveis, sem restarts. Por toda métrica de infra que você confia, o sistema está perfeito.

Mas os tickets de suporte não param. Usuários reportam que o chatbot “dá respostas piores”. Respostas fluentes mas factualmente erradas. Alucinações aumentaram, sumarizações perdem pontos chave, sugestões de código introduzem bugs sutis.

Você puxa o monitoring stack. Azure Monitor: verde. Application Insights: verde. Grafana: tudo verde. Parede de métricas saudáveis enquanto o sistema está ativamente falhando seus usuários.

O problema? Model drift. Um fine-tuning recente introduziu regressão na qualidade. As saídas degradaram gradualmente em duas semanas, mas nenhum alerta disparou porque você monitora métricas de infraestrutura, não de AI. Seu stack de observabilidade foi construído pra workloads tradicionais onde “o servidor está up e respondendo” = “o sistema está funcionando”. Em AI, um modelo pode estar rodando perfeitamente e mesmo assim estar errado.

As 6 dimensões de observabilidade AI

Monitoramento tradicional cobre compute, rede e storage. Necessário mas insuficiente pra AI.

#DimensãoO que monitorarPrioridade
1Compute (GPU)Utilização, memória, temperatura, ECC errorsP0
2CustoGPU spend, tokens consumidos, custo por inferenceP0
3ModeloAccuracy, drift, latência, error ratesP1
4SegurançaPrompt injection, data exfiltration, consumo anômaloP1
5RedeInfiniBand health, cross-node latency, throughputP2
6DataPipeline freshness, qualidade, falhas de ingestãoP2

Tradução infra ↔ AI: Monitorar um web server é acompanhar CPU, memória, disco e rede. Monitorar um workload de AI é como monitorar um web server, um banco de dados, um sistema de billing e um departamento de QA simultaneamente. O modelo não apenas consome recursos; ele produz outputs que têm uma dimensão de corretude que infra tradicional não tem.

GPU monitoring: o fundamento

DCGM Exporter no AKS

NVIDIA DCGM Exporter roda como DaemonSet (um pod por nó GPU) e expõe métricas em formato Prometheus:

# Adicionar repo Helm da NVIDIA
helm repo add nvidia https://nvidia.github.io/dcgm-exporter/helm-charts
helm repo update

# Instalar DCGM Exporter como DaemonSet nos nós GPU
helm install dcgm-exporter nvidia/dcgm-exporter \
  --namespace gpu-monitoring \
  --create-namespace \
  --set nodeSelector."agentpool"="gpu"

Azure Managed Prometheus

Elimina necessidade de rodar seu próprio Prometheus server:

# Habilitar Azure Monitor managed Prometheus
az aks update \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --enable-azure-monitor-metrics

# Verificar se está habilitado
az aks show \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --query "azureMonitorProfile.metrics.enabled"

Managed Prometheus descobre e scrapa DCGM Exporter pods automaticamente via Kubernetes service discovery. Não precisa configurar scrape targets manualmente.

Métricas GPU e thresholds de alerta

MétricaDCGM NameWarningCriticalSignifica
GPU UtilizationDCGM_FI_DEV_GPU_UTIL< 30% sustentado< 10% sustentadoDesperdício de spend
GPU Memory UsedDCGM_FI_DEV_FB_USED> 85%> 95%Risco de OOM
GPU TemperatureDCGM_FI_DEV_GPU_TEMP> 78°C> 83°CThermal throttling
ECC ErrorsDCGM_FI_DEV_ECC_DBE_VOL_TOTAL> 0> 0Hardware degradando

Nuance: Low GPU utilization nem sempre é problema. Workloads de inference latency-sensitive intencionalmente mantêm utilização baixa pra manter respostas rápidas. Verifique se o workload otimiza pra throughput (training, alta utilização esperada) ou latência (inference, moderada OK).

Monitoramento Azure OpenAI

Métricas-chave

MétricaO que éQuando investigar
TPM (Tokens Per Minute)Throughput contra capacity alocada> 80% sustentado do limite
RPM (Requests Per Minute)Calls individuais independente de tokensMuitos requests pequenos saturando antes de TPM
TTFT (Time to First Token)Latência percebida pra streaming> 2 segundos (sente lento pro usuário)
HTTP 429 RateSinal de throttling> 1% sustentado

Tradução infra ↔ AI: TPM limits são como bandwidth throttling. RPM limits são como connection-rate limiting. Token budgets são equivalente AI de data transfer quotas.

Habilitar diagnostic logging

az monitor diagnostic-settings create \
  --resource "/subscriptions/<sub-id>/resourceGroups/myRG/providers/Microsoft.CognitiveServices/accounts/myAOAI" \
  --name "aoai-diagnostics" \
  --workspace "/subscriptions/<sub-id>/resourceGroups/myRG/providers/Microsoft.OperationalInsights/workspaces/myWorkspace" \
  --logs '[{"category":"RequestResponse","enabled":true},{"category":"Audit","enabled":true}]' \
  --metrics '[{"category":"AllMetrics","enabled":true}]'

Cuidado com volume: Um deployment processando 1.000 RPM gera ~1.4 milhão de log entries por dia. Configure retention policies no Log Analytics: 30 dias pra debugging operacional, mais pra compliance.

Observabilidade na aplicação

OpenTelemetry pra distributed tracing

Aplicações AI modernas envolvem múltiplos serviços: API gateway, preprocessing, embedding, vector search, LLM inference, post-processing. OpenTelemetry segue um request por todo o pipeline:

from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry import trace

configure_azure_monitor()
tracer = trace.get_tracer("inference-pipeline")

def process_request(user_query):
    with tracer.start_as_current_span("inference-pipeline") as span:
        with tracer.start_as_current_span("generate-embedding"):
            embedding = embed(user_query)

        with tracer.start_as_current_span("vector-search"):
            context = search(embedding, top_k=5)

        with tracer.start_as_current_span("llm-inference") as llm_span:
            response = generate(user_query, context)
            llm_span.set_attribute("tokens.prompt", response.usage.prompt_tokens)
            llm_span.set_attribute("tokens.completion", response.usage.completion_tokens)

        return response

Métricas custom pra AI

  • Inference latency percentiles (P50, P95, P99): P50 = experiência típica, P95/P99 = tail latency
  • Tokens per second: throughput de LLM inference. Caindo = memory pressure ou degradação
  • Queue depth: requests esperando GPU. Crescendo com throughput estável = precisa scale out
  • Cache hit rate: pra semantic caching. Hit rate alto = menos latência e custo

Structured logging (obrigatório)

import logging
import json

class StructuredFormatter(logging.Formatter):
    def format(self, record):
        log_entry = {
            "timestamp": self.formatTime(record),
            "level": record.levelname,
            "service": getattr(record, "service", "inference-api"),
            "model_version": getattr(record, "model_version", "unknown"),
            "request_id": getattr(record, "request_id", None),
            "tokens_used": getattr(record, "tokens_used", None),
            "latency_ms": getattr(record, "latency_ms", None),
        }
        return json.dumps(log_entry)

Sempre logue model version e deployment name com toda trace e métrica. Quando deploar nova versão e latência subir 40%, você precisa correlacionar.

No próximo post

Com monitoring cobrindo as 6 dimensões, vamos falar de segurança pra AI: prompt injection, data leakage, managed identities, private endpoints e as ameaças que seu WAF não vai pegar.