Observabilidade para Sistemas de LLM: Métricas, Traces, Logs e Testes em Produção

Estratégia de observabilidade ponta a ponta para inferência de LLM e aplicações de LLM

Conteúdo da página

Os sistemas LLM falham de maneiras que a monitorização de APIs tradicional não consegue revelar — as filas enchem silenciosamente, a memória da GPU satura muito antes que a CPU pareça ocupada e a latência explode na camada de agrupamento (batching) em vez da camada de aplicação. Este guia cobre uma estratégia de ponta a ponta de observabilidade para inferência LLM e aplicações LLM: o que medir, como instrumentar com Prometheus, OpenTelemetry e Grafana, e como implementar o pipeline de telemetia em escala.

painel de monitorização de observabilidade utilizador feliz

TL;DR (Resumo executivo)

Os sistemas LLM degradam-se de maneiras que a monitorização clássica de “latência HTTP + taxa de erros” não consegue explicar. A Observabilidade para sistemas LLM de nível de produção deve responder, rapidamente e de forma defensável:

  • Se a experiência do utilizador está a degradar-se (latência de cauda, tempo para o primeiro token, latência entre tokens, erros e abortos).
  • Onde o tempo é gasto (filas vs agrupamento vs execução do modelo; recuperação/ferramentas/filtros de segurança vs inferência).
  • O que satura primeiro (utilização da GPU e pressão de memória, pressão de cache KV/fila, tokenização da CPU).
  • Como o custo e a capacidade divergem (tokens por pedido, tokens/seg por GPU, taxa de acerto no cache, gerações desperdiçadas).
  • Se a telemetia é segura para armazenar (os prompts podem conter PII; prevenir fugas sensíveis para logs/atributos).

O design mais resiliente é um pipeline de múltiplos sinais:

  • Métricas para deteção rápida e planeamento de capacidade (Prometheus + PromQL; armazenamento de longo prazo opcional via Thanos/Cortex/Mimir/VictoriaMetrics).
  • Traços (Traces) para causalidade a nível de pedido (OpenTelemetry com OTLP; backends como Tempo/Jaeger/Zipkin/Elastic APM).
  • Logs para contexto, correlacionados com traços (Loki/Elastic/OpenSearch), desenhados para metadados de baixa cardinalidade.
  • Perfilamento para pontos quentes de CPU/memória e latência de cauda (Grafana Pyroscope).
  • Testes sintéticos e de carga para detetar regressões antes dos utilizadores (Grafana k6; sondas estilo blackbox).
  • SLOs para medir resultados do utilizador e conduzir alertas acionáveis (orçamentos de erro; estilo taxa de queima).

O que torna a observabilidade para sistemas LLM diferente

Nota de escopo: o framework LLM de destino é não especificado. Os exemplos neste artigo cobrem servidores/frameworks comuns (Triton, vLLM, TGI, LangChain/LangSmith) e permanecem aplicáveis a outras pilhas substituindo métricas e spans equivalentes.

Os LLMs introduzem comportamentos operacionais que diferem dos serviços web convencionais:

  • Trabalho variável por pedido: as contagens de tokens (entrada/saída) variam amplamente, pelo que “pedidos por segundo” pode parecer estável enquanto o throughput de tokens colapsa. TGI e vLLM exportam explicitamente telemetia relacionada com tokens e latência para suportar este estilo de monitorização.
  • Filas + agrupamento contínuo (continuous batching): o throughput depende das disciplinas de agrupamento/fila; o tamanho da fila e o tamanho do lote tornam-se indicadores de primeira classe (TGI expõe ambos).
  • UX de streaming: os utilizadores preocupam-se com o TTFT e a latência entre tokens tanto quanto com o tempo total de resposta; o OpenTelemetry até padroniza métricas de servidor TTFT/tempo por token sob convenções semânticas GenAI.
  • A pressão da GPU domina os modos de falha: a utilização da GPU e a memória da GPU (incluindo memória usada) são centrais para a fiabilidade; o exportador DCGM da NVIDIA existe especificamente para expor telemetia da GPU num endpoint Prometheus /metrics.
  • Pipelines de múltiplos passos: recuperação, chamadas de ferramentas, filtros de segurança e pós-processamento significam que a latência de ponta a ponta é uma composição de múltiplos spans/filas — tornando o rastreamento distribuído e o design cuidadoso de métricas essenciais.

Exemplos concretos de servidores de inferência populares destacam isto:

  • NVIDIA Triton Inference Server expõe métricas como texto simples via /metrics (comumente :8002/metrics) e fornece flags para ativar/desativar métricas e selecionar uma porta de métricas.
  • vLLM expõe um endpoint Prometheus /metrics extenso com um prefixo vllm:; a sua documentação inclui contadores para tokens de geração e histogramas como tempo para o primeiro token.
  • Hugging Face TGI documenta um endpoint /metrics com tamanho da fila, tamanho do lote, duração do pedido de ponta a ponta, tokens gerados e duração da fila.

Tarefas centrais de observabilidade e telemetia LLM necessária

A observabilidade para sistemas LLM é mais fácil de implementar quando mapeia tarefas → sinais → ferramentas, e depois restringe a cardinalidade e a amostragem desde o primeiro dia.

Métricas: Para sistemas de serviço online, a própria orientação de instrumentação do Prometheus destaca contagem de consultas, erros e latência como métricas chave; os LLMs expandem isto com TTFT, throughput/latência por token, tamanho da fila, tamanho do lote e utilização da GPU.

Traços (Traces): Os traços são como atribuir latência e falhas através das etapas de recuperação/ferramentas/segurança/inferência; o OpenTelemetry enquadra traços/exportadores como uma forma neutra de fornecedor para emitir e enviar telemetia para coletores ou backends.

Logs: Os logs fornecem contexto legível por humanos e o “porquê”, mas só permanecem utilizáveis em escala se evitar a indexação de valores ilimitados (exemplo: Loki indexa apenas rótulos e armazena blocos de logs comprimidos em armazenamento de objetos).

Perfilamento: O perfilamento contínuo captura o comportamento de CPU/memória em produção com amostragem de baixa sobrecarga; o Grafana Pyroscope é explicitamente posicionado para isto.

Testes sintéticos e de carga: O Grafana k6 é uma ferramenta de teste de carga de código aberto, e o Grafana nota que o Monitoramento Sintético é alimentado pelo k6 e vai além de simples verificações de protocolo.

SLOs: A orientação SRE do Google define um SLO como um valor de alvo/faixa para um nível de serviço medido por um SLI, e fornece orientação para alertas sobre SLOs (compromissos precisão/recall/tempo de deteção).

Blueprint de métricas LLM chave

Categoria Exemplos de nomes de métricas (exemplos reais) Tipo Por que importa Fontes de exemplo
Latência de ponta a ponta tgi_request_duration Histograma A latência de cauda é a experiência do utilizador TGI exporta isto explicitamente
Tempo para o primeiro token vllm:time_to_first_token_seconds; gen_ai.server.time_to_first_token Histograma Streaming/delay no primeiro token é frequentemente o primeiro sinal de saturação vLLM e OTel semconv GenAI
Tempo por token de saída tgi_request_mean_time_per_token_duration; gen_ai.server.time_per_output_token Histograma Latência entre tokens; “parece lento” mesmo se o pedido completar TGI e OTel semconv GenAI
Uso/volume de tokens tgi_request_generated_tokens; gen_ai.client.token.usage Histograma / Contador Custo + capacidade são dirigidos por tokens TGI e OTel semconv GenAI
Pedidos tgi_request_count; vllm:request_success_total Contador Linha de base de tráfego e resultados TGI e vLLM
Tamanho da fila tgi_queue_size Indicador (Gauge) Filas preveem explosões de latência TGI
Tamanho do lote e limites de lote tgi_batch_current_size; tgi_batch_current_max_tokens Indicador (Gauge) Compromissos throughput–latência TGI
Utilização/memória da GPU DCGM_* (fornecido pelo exportador) Indicador (Gauge) Saturação, risco OOM, gatilho de escalabilidade Exportador DCGM expõe métricas GPU em /metrics
Endpoint de telemetia do servidor de inferência :8002/metrics (Triton padrão em docs/arquivos) Alvo de raspagem padrão para Prometheus Docs Triton

Convenções semânticas GenAI do OpenTelemetry para padronização

O OpenTelemetry fornece convenções semânticas GenAI (status: “Desenvolvimento”) com nomeação padrão para métricas GenAI, tais como:

  • gen_ai.client.token.usage e gen_ai.client.operation.duration
  • gen_ai.server.request.duration, gen_ai.server.time_per_output_token e gen_ai.server.time_to_first_token

Esta padronização é uma alavanca prática para estratégias portáveis de “monitorização de modelos LLM com OpenTelemetry”: emitir uma vez e rotear a mesma telemetia para backends OSS ou de fornecedor mais tarde.

Projetando o pipeline de telemetia

fluxograma de observabilidade LLM

Pull vs Push

O Prometheus é pull-first. Os processos expõem métricas num formato de exposição suportado, e o Prometheus raspá-los de acordo com trabalhos de raspagem configurados.

O Push é para exceções. O guia do Prometheus “Quando usar o Pushgateway” recomenda explicitamente o Pushgateway apenas em casos limitados (não como substituto geral de push), e o README do Pushgateway enfatiza que não pode “transformar o Prometheus num sistema de monitorização baseado em push”.

Padrão prático específico de LLM:

  • Usar pull para servidores de inferência/exportadores (endpoints de métricas Triton/vLLM/TGI; exportador DCGM; métricas de nó).
  • Usar OTLP push para traços/logs/métricas OTel (o Protocolo OpenTelemetry define transporte/codificação/entrega entre fontes, coletores e backends).
  • Usar escrita remota ao escalar além de um único Prometheus (Prometheus fornece orientação de ajuste de escrita remota; Mimir/Thanos/Cortex fornecem opções de armazenamento de longo prazo e/ou HA).

Agentes vs sidecar vs coletores de gateway

O OpenTelemetry documenta um padrão de implementação de agente, onde a telemetia é enviada para um Coletores executando ao lado da aplicação ou no mesmo host (sidecar/DaemonSet), e depois exportado.

Para Kubernetes, a injeção de sidecar é suportada via o OpenTelemetry Operator (injeção baseada em anotações).

Regra prática para pilhas LLM:

  • Usar um agente DaemonSet para enriquecimento a nível de host e pipelines partilhados entre muitos pods.
  • Usar um sidecar quando precisa de isolamento estrito por carga de trabalho ou filtragem local dedicada (comum quando prompts podem conter dados sensíveis).
  • Usar um coletor de gateway para amostragem de cauda centralizada, agrupamento, re-tentativas e dispersão de exportação.

Controlo de amostragem e cardinalidade

O OpenTelemetry esclarece que a amostragem de cauda (tail sampling) permite decisões de amostragem usando critérios derivados de um traço (não possível com amostragem de cabeça apenas).

A orientação de instrumentação do Prometheus adverte contra o excesso de uso de rótulos, fornece uma regra de polegar para manter a cardinalidade baixa e aconselha recriar métricas se a cardinalidade potencial exceder ~100.

“Armadilhas de cardinalidade” específicas de LLM para banir cedo:

  • Texto do prompt, texto da resposta, IDs de conversa, IDs de pedido como rótulos/atributos.
  • Blobs de argumentos de ferramentas como atributos de span.
  • Rótulos “user_id” ilimitados.

Prefira dimensões limitadas: model, model_family, endpoint, region, status_code, deployment, tenant (apenas se limitado).

Comparação de ferramentas de observabilidade LLM

Ferramentas mapeadas para tarefas de observabilidade

Ferramenta Métricas Traços Logs Perfilamento Testes sintéticos SLOs / alertas Relevância LLM
Prometheus ◻️ ◻️ ◻️ ◻️ Orientação de instrumentação + modelo de alerta; raspagem baseada em pull
Grafana ✅ (viz) ✅ (viz) ✅ (viz) Dashboards são painéis sobre fontes de dados; suporta fontes de dados amplas
OpenTelemetry ✅ (perfis em evolução) ◻️ ◻️ Especificação OTLP + convenções semânticas GenAI; instrumentação neutra
Jaeger ◻️ ◻️ ◻️ ◻️ ◻️ Aceita OTLP (gRPC/HTTP) e é um backend de traçagem comum
Grafana Tempo ◻️ ◻️ ◻️ ◻️ ◻️ Traçagem em grande escala; pode gerar métricas de spans via metrics-generator
Grafana Loki ◻️ ◻️ ◻️ ◻️ ◻️ Indexa apenas rótulos; armazena blocos comprimidos; reduz custo de logs em escala
Elastic Stack (ELK) ◻️ ◻️ Elastic Stack lista Elasticsearch + Kibana como fundamentos; Elastic APM suporta integração OTel
DCGM exporter ◻️ ◻️ ◻️ ◻️ ◻️ Exportador de métricas GPU expondo endpoint de raspagem /metrics
Mimir / Thanos / Cortex ◻️ ◻️ ◻️ ◻️ ◻️ Armazenamento de métricas compatível com Prometheus de longo prazo/HA
Datadog Aceita traços/métricas/logs OTel; inclui funcionalidades de verificação de dados sensíveis
New Relic Documenta configuração de endpoint OTLP e práticas OTLP/HTTP suportadas
Honeycomb ◻️ ◻️ Suporta receção OTLP sobre gRPC/HTTP; ingestão OTel-first
LangSmith ◻️ ◻️ ◻️ ◻️ ◻️ Suporta traçagem baseada em OpenTelemetry para apps LLM

Grafana vs alternativas para visualização

  • Os dashboards do Grafana são compostos por painéis que consultam fontes de dados (incluindo Loki e Mimir) para produzir gráficos e visualizações.
  • O Kibana fornece dashboards/visualizações como a camada UI dentro do Elastic Stack.
  • O OpenSearch Dashboards fornece ferramentas de visualização de dados para OpenSearch.
  • A documentação da InfluxData posiciona o Chronograf como o componente de visualização no ecossistema Influx.

Prometheus vs alternativas para backends de métricas

  • Armazenamento local do Prometheus: se as flags de retenção não estiverem definidas, a retenção padrão é 15d (planear retenção/custo cedo).
  • O Grafana Mimir é descrito como armazenamento de longo prazo horizontalmente escalável, HA e multi-inquilino para métricas Prometheus e OpenTelemetry.
  • O Thanos é descrito como uma configuração Prometheus altamente disponível com capacidades de armazenamento de longo prazo.
  • O Cortex descreve-se como uma solução de armazenamento de longo prazo horizontalmente escalável, HA e multi-inquilino para métricas Prometheus e OpenTelemetry.
  • A VictoriaMetrics Cloud documenta a integração de escrita remota Prometheus para armazenamento de longo prazo.
  • O Amazon Managed Service for Prometheus descreve uma oferta gerida que escala com necessidades de ingestão/consulta e suporta PromQL e escrita remota.

Cookbook de implementação prática

Nomes e tipos de métricas para implementar hoje

As convenções semânticas GenAI do OpenTelemetry (status: Desenvolvimento) definem nomes de métricas que pode padronizar imediatamente:

  • gen_ai.client.token.usage
  • gen_ai.client.operation.duration
  • gen_ai.server.request.duration
  • gen_ai.server.time_per_output_token
  • gen_ai.server.time_to_first_token

Exemplos de lado de servidor que pode raspar imediatamente:

  • O endpoint Prometheus do vLLM inclui contadores (ex: total de tokens de geração) e histogramas (TTFT) e documenta uma estratégia de rótulos model_name.
  • O TGI documenta métricas incluindo tamanho da fila, duração do pedido, tokens gerados e tempo médio por token.
  • O Triton documenta a exposição /metrics e alternadores de métricas.

Exemplos PromQL para dashboards de latência e throughput LLM

# Latência de ponta a ponta p95 para um histograma de aplicação
histogram_quantile(
  0.95,
  sum(rate(llm_request_latency_seconds_bucket[5m])) by (le, model)
)

# Porcentagem de taxa de erro (5xx)
100 *
(
  sum(rate(llm_requests_total{status_code=~"5.."}[5m]))
  /
  sum(rate(llm_requests_total[5m]))
)

# Tokens/seg (saída) em todos os modelos
sum(rate(llm_tokens_total{direction="out"}[5m]))

# Tamanho da fila TGI (gauge)
max(tgi_queue_size) by (instance)

# vLLM TTFT p95
histogram_quantile(
  0.95,
  sum(rate(vllm:time_to_first_token_seconds_bucket[5m])) by (le, model_name)
)

A orientação de histograma do Prometheus explica que os quantis de histograma são calculados no servidor a partir de baldes usando histogram_quantile().

Notas de instrumentação OpenTelemetry para sistemas LLM

  • O OTLP é o Protocolo OpenTelemetry especificando como a telemetia é codificada/transmitida entre fontes, coletores e backends.
  • A configuração do SDK OpenTelemetry documenta variáveis de ambiente como OTEL_EXPORTER_OTLP_ENDPOINT (e opções de protocolo) para exportar telemetia.
  • O OpenTelemetry Python contrib documenta suporte de instrumentação FastAPI para instrumentação automática e manual.
  • As convenções semânticas GenAI incluem um mecanismo de estabilidade opt-in via OTEL_SEMCONV_STABILITY_OPT_IN para migração de convenções GenAI.

Exemplo Python curto: métricas + traços + logs

O snippet abaixo demonstra:

  • Exposição de métricas Prometheus (/metrics) para “monitorização de inferência LLM com Prometheus”
  • Traços OpenTelemetry exportados via OTLP (neutro de fornecedor)
  • Logs estruturados correlacionados com contexto de traço, com padrão seguro de privacidade (não logar prompts brutos)
import logging
import time

from fastapi import FastAPI, Request
from pydantic import BaseModel

# Prometheus (métricas baseadas em pull)
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
from starlette.responses import Response

# OpenTelemetry (traços OTLP)
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

app = FastAPI(title="LLM Inference API", version="1.0.0")
FastAPIInstrumentor.instrument_app(app)

# --- Logging (padrão seguro de privacidade) ---
logger = logging.getLogger("llm")
logging.basicConfig(level=logging.INFO, format="%(message)s")

def trace_id_hex() -> str:
    span = trace.get_current_span()
    ctx = span.get_span_context()
    return format(ctx.trace_id, "032x") if ctx.is_valid else ""

# --- Métricas Prometheus ---
LLM_REQUESTS = Counter(
    "llm_requests_total",
    "LLM requests total",
    ["route", "status_code", "model"],
)
LLM_LATENCY = Histogram(
    "llm_request_latency_seconds",
    "End-to-end LLM request latency (seconds)",
    ["route", "model"],
    buckets=(0.1, 0.2, 0.35, 0.5, 0.75, 1, 1.5, 2, 3, 5, 8, 13),
)

# --- Provedor de rastreador OpenTelemetry ---
resource = Resource.create({"service.name": "llm-inference-api"})
trace.set_tracer_provider(TracerProvider(resource=resource))
trace.get_tracer_provider().add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter())  # configurar via OTEL_EXPORTER_OTLP_* env vars
)
tracer = trace.get_tracer(__name__)

class GenerateRequest(BaseModel):
    prompt: str
    model: str = "unspecified"
    max_tokens: int = 256

class GenerateResponse(BaseModel):
    model: str
    output: str
    latency_ms: int

@app.post("/v1/generate", response_model=GenerateResponse)
async def generate(req: GenerateRequest, request: Request):
    route = "/v1/generate"
    start = time.perf_counter()

    with tracer.start_as_current_span("llm.generate") as span:
        # Evitar logging do prompt completo; emitir metadados seguros
        span.set_attribute("gen_ai.request.model", req.model)
        span.set_attribute("gen_ai.request.max_tokens", req.max_tokens)

        # Substituir com chamada LLM real (cliente Triton/vLLM/TGI)
        time.sleep(0.15)
        output = "Hello from the model."

        latency_s = time.perf_counter() - start
        LLM_LATENCY.labels(route=route, model=req.model).observe(latency_s)
        LLM_REQUESTS.labels(route=route, status_code="200", model=req.model).inc()

        logger.info(
            {
                "msg": "llm_request_complete",
                "trace_id": trace_id_hex(),
                "model": req.model,
                "latency_ms": int(latency_s * 1000),
                # NÃO incluir prompt/saída bruta a menos que a política permita.
            }
        )

        return GenerateResponse(model=req.model, output=output, latency_ms=int(latency_s * 1000))

@app.get("/metrics")
def metrics():
    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)

Implementação, escalabilidade, segurança e resolução de problemas

implementação do painel LLM

Opções de implementação

Opção de implementação Melhor para Compromissos
Kubernetes + kube-prometheus-stack (Helm) Pacote de monitorização de cluster padronizado (Prometheus Operator, dashboards, regras) Gestão de ciclo de vida CRDs/operator
Kubernetes + OpenTelemetry Collector (DaemonSet/sidecar) Pipelines OTLP padronizados; filtragem sensível local Precisa de ajuste de amostragem/limite
Docker Compose Prototipagem rápida num único host Não HA; armazenamento manual
Instalações systemd / VM Frotas de GPU bare-metal e operações tradicionais Descoberta e configuração manual
Serviços geridos (Grafana Cloud / Datadog / New Relic / AMP) Tempo rápido para valor; escalabilidade gerida Custo e governança; compromissos de lock-in de fornecedor

Escalabilidade e retenção: restrições práticas

  • Armazenamento local do Prometheus: sem flags de tamanho/tempo explícitas, o tempo de retenção é 15d por defeito.
  • Escrita remota do Prometheus: o Prometheus documenta ajustes de escrita remota para escalar além de “padrões sensatos”.
  • Grafana Tempo: posicionado como backend de traçagem em grande escala e pode gerar métricas de spans usando o metrics-generator (escrita remota para uma fonte de dados Prometheus).
  • Armazenamento Loki: a documentação do Loki enfatiza indexação apenas por rótulos e armazenamento de blocos comprimidos (armazenamento de objetos), tornando a estratégia de rótulos central para escala e custo.

Segurança e privacidade: prompts podem conter PII

A orientação de segurança do OpenTelemetry enfatiza que a recolha de telemetia pode inadvertidamente capturar informações sensíveis/pessoais; é da sua responsabilidade lidar com isso adequadamente.

O modelo de segurança do Prometheus adverte que os endpoints Prometheus não devem ser expostos a redes acessíveis publicamente (como a internet) porque servem informações sobre sistemas monitorizados.

Controlos de privacidade operacionais que mantêm “observabilidade para sistemas LLM” seguros:

  • Padrão para não logar prompts/respostas brutas; logar contagens de tokens, nome do modelo, latência e IDs de traço em vez disso.
  • Redactar/soltar atributos sensíveis em coletores/pipelines (filtragem a nível de coletor é uma abordagem comum em ecossistemas).
  • Aplicar RBAC e políticas de retenção para logs/traços; considerar scanners de dados sensíveis onde apropriado (ex: fornecedores documentam scanners para telemetia).

Lista de verificação de resolução de problemas

Se o seu painel Grafana para latência LLM estiver errado, depure nesta ordem:

  • Saúde da ingestão
    • Prometheus: validar sucesso da raspagem e semântica da configuração (a configuração Prometheus define trabalhos/instâncias de raspagem).
    • OTLP: confirmar configuração do endpoint do exportador (SDKs usam OTEL_EXPORTER_OTLP_ENDPOINT, definições de protocolo).
  • Incompatibilidade de esquema
    • O dashboard espera model, mas o seu servidor emite model_name (vLLM documenta explicitamente rótulos model_name).
  • Explosão de cardinalidade
    • Alguém rotulou por IDs de pedido/hashes de prompt; o Prometheus adverte que conjuntos de rótulos aumentam custos RAM/CPU/disco/rede e fornece orientação de cardinalidade.
  • Uso incorreto de histogramas
    • Certifique-se de calcular quantis de séries _bucket com rate() e le; o Prometheus explica compromissos de cálculo de quantis de histograma.
  • Lacunas de amostragem de traços
    • Se amostrar pela cabeça demasiado agressivamente, traços lentos/erro raros desaparecem; a amostragem de cauda retém traços “importantes” com base em critérios de traço completo.
  • Problemas de métricas de span do Tempo
    • Se usar metrics-generator e span-metrics do Tempo, confirmar que está ativado e ajustado (Tempo documenta processadores metrics-generator e span-metrics; resolução de problemas existe para problemas de gerador).
  • Métricas GPU ausentes
    • Confirmar que o exportador DCGM está implementado e /metrics é acessível (exportador DCGM expõe métricas GPU sobre HTTP para Prometheus).