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?
tl;dr: Dashboard verde não basta. Você precisa observar GPU, custo, modelo, segurança, rede e dados ao mesmo tempo.
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. Isso continua necessário, mas em AI não basta.
| # | Dimensão | O que monitorar | Prioridade |
|---|---|---|---|
| 1 | Compute (GPU) | Utilização, memória, temperatura, ECC errors | P0 |
| 2 | Custo | GPU spend, tokens consumidos, custo por inference | P0 |
| 3 | Modelo | Accuracy, drift, latência, error rates | P1 |
| 4 | Segurança | Prompt injection, data exfiltration, consumo anômalo | P1 |
| 5 | Rede | InfiniBand health, cross-node latency, throughput | P2 |
| 6 | Data | Pipeline freshness, qualidade, falhas de ingestão | P2 |
Tradução infra ↔ AI: Monitorar um web server é acompanhar CPU, memória, disco e rede. Monitorar um workload de AI parece juntar web server, banco de dados, billing e QA no mesmo painel. O modelo consome recurso, mas também produz saída que pode estar certa ou errada. Infra tradicional quase nunca mede isso.
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 \
--set serviceMonitor.enabled=true
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"
Com Azure Managed Prometheus, o caminho mais previsível é expor o exporter via ServiceMonitor ou annotations compatíveis com o scraper. Não conte com descoberta automática só porque o pod apareceu no cluster.
Métricas GPU e thresholds de alerta
Use esses números como ponto de partida, não como regra universal. Ajuste por SKU, workload, modelo, região e SLO, e valide com baseline do seu ambiente.
| Métrica | DCGM Name | Warning | Critical | Significa |
|---|---|---|---|---|
| GPU Utilization | DCGM_FI_DEV_GPU_UTIL | < 30% sustentado | < 10% sustentado | Desperdício de spend |
| GPU Memory Used | DCGM_FI_DEV_FB_USED | > 85% | > 95% | Risco de OOM |
| GPU Temperature | DCGM_FI_DEV_GPU_TEMP | > 78°C | > 83°C | Thermal throttling |
| ECC Errors | DCGM_FI_DEV_ECC_DBE_VOL_TOTAL | > 0 | > 0 | Hardware 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étrica | O que é | Quando investigar |
|---|---|---|
| TPM (Tokens Per Minute) | Throughput contra capacity alocada | > 80% sustentado do limite |
| RPM (Requests Per Minute) | Calls individuais independente de tokens | Muitos 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 Rate | Sinal 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 o equivalente em AI das quotas de transferência.
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,44 milhão de log entries por dia. Configure retention no Log Analytics: 30 dias pra debugging operacional e mais tempo só quando houver requisito de compliance.
Observabilidade na aplicação
OpenTelemetry pra distributed tracing
Aplicações AI modernas envolvem vários serviços: API gateway, preprocessing, embedding, vector search, LLM inference, post-processing. OpenTelemetry acompanha um request pelo pipeline inteiro:
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 junto com trace e métrica. Quando você fizer deploy de uma versão nova e a latência subir 40%, precisa ligar os pontos rápido.
No próximo post
Com monitoring cobrindo as 6 dimensões, você consegue explicar por que o dashboard estava verde enquanto o chatbot piorava. No próximo post, 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.