Observabilidade para apps de LLM

O que “observabilidade (observability)” significa para aplicações de modelos de linguagem de grande porte (large language models, LLMs)

Observabilidade (observability) é a capacidade de entender o comportamento interno de um sistema a partir da telemetria (telemetry) que ele emite. Na prática, a observabilidade é construída sobre três tipos principais de sinais:

  • Rastros (traces): causalidade de ponta a ponta (“o que aconteceu entre serviços/componentes para esta requisição?”)
  • Logs (logs): eventos detalhados e discretos (“o que registramos nesta etapa?”)
  • Métricas (metrics): séries temporais agregadas (“com que frequência/por quanto tempo/quantos?”)

A observabilidade web tradicional se concentra em requisições HTTP, consultas a bancos de dados e CPU/memória. Aplicações de LLM adicionam novos modos de falha (failure modes) e fatores de custo (cost drivers) que exigem instrumentação (instrumentation) especializada:

  • Prompts (prompts) são programas (e mudam com frequência).
  • Saídas são não determinísticas e podem estar “erradas” de formas sutis.
  • Muitos apps são pipelines (pipelines) (RAG, uso de ferramentas, agentes) com múltiplas etapas e dependências externas.
  • Recursos-chave são tokens (tokens), latência (latency) e chamadas de ferramenta (tool calls), não apenas CPU.
  • Depurar frequentemente exige contexto semântico (semantic context): documentos recuperados, templates de prompt, argumentos de ferramenta, configuração do modelo e filtros de segurança.

Este artigo se concentra em rastros, logs e métricas especializados para prompts, ferramentas e pipelines de recuperação (retrieval pipelines), e em como aplicá-los em sistemas reais.

Tópicos operacionais relacionados: Monitoramento, SLOs para Funcionalidades de IA, Privacidade em Logs, PromptOps, Avaliação em Produção e Padrões de Design de Sistemas de LLM.

Por que a observabilidade de apps de LLM é diferente

1) A “lógica de negócio” vive nos prompts e na orquestração (orchestration)

Uma mudança em um template de prompt, em uma regra de roteamento (routing) de ferramentas ou em uma configuração de recuperação pode causar regressões tão sérias quanto uma mudança de código. A observabilidade deve rastrear:

  • Versão do template de prompt e prompt renderizado
  • Nome/provedor do modelo e parâmetros de geração (generation parameters)
  • Decisões de seleção de ferramenta e E/S de ferramenta (tool I/O)
  • Resultados de recuperação (documentos top-k, pontuações, filtros)

2) Falhas frequentemente são semânticas, não binárias

A requisição pode retornar HTTP 200 e ainda assim ser uma falha:

  • Resposta alucinada
  • Citação incorreta
  • Ferramenta chamada com argumentos sutilmente errados
  • Injeção de prompt (prompt injection) bem-sucedida
  • Recusa (refusal) quando deveria responder (ou vice-versa)

A observabilidade deve capturar sinais de qualidade, não apenas a saúde da infraestrutura. Isso frequentemente se sobrepõe à Avaliação em Produção.

3) Custo e latência são dominados por tokens e chamadas externas

As métricas devem incluir:

  • Tokens de entrada/saída, tokens totais, estimativas de custo
  • Tempo em fila do modelo, tempo até o primeiro token (time-to-first-token, TTFT), duração do streaming
  • Latência de recuperação e latência de ferramenta por dependência

Isso se conecta diretamente a Custo/Desempenho, Cacheamento & Limitação de Taxa e Serving de LLM.

Os sinais centrais para apps de LLM

Rastros: a espinha dorsal para depurar pipelines

Um rastro representa uma requisição de usuário e contém segmentos (spans) para cada etapa (recuperação, reranqueamento, construção de prompt, chamada ao modelo, chamada de ferramenta, pós-processamento). Para apps de LLM, o rastreamento responde perguntas como:

  • “Qual consulta de recuperação foi usada e quais documentos foram retornados?”
  • “O agente chamou uma ferramenta? Com quais argumentos? Deu erro?”
  • “Qual versão de prompt e quais parâmetros do modelo foram usados?”
  • “Onde o tempo foi gasto: recuperação, modelo, ferramenta ou reranqueamento?”

Muitas equipes padronizam em OpenTelemetry (OTel) para rastreamento agnóstico de fornecedor e propagação de contexto (context propagation).

Logs: eventos estruturados com controles cuidadosos de privacidade

Logs são inestimáveis para:

  • Capturar por que um roteador (router) escolheu um modelo
  • Registrar decisões de filtro de segurança
  • Auditar chamadas de ferramenta
  • Análises pós-incidente (postmortems) de incidentes de alta severidade

Mas logs podem facilmente vazar dados sensíveis. Para apps de LLM, você deve tratar logs de prompt/resposta como potencialmente sensíveis por padrão e aplicar técnicas de Privacidade em Logs (redação, hashing, amostragem seletiva, criptografia, controles de acesso).

Métricas: saúde, custo e qualidade agregados

Métricas alimentam painéis (dashboards), alertas (alerting) e SLOs. Para apps de LLM, métricas devem cobrir:

  • Confiabilidade/latência por etapa
  • Uso de tokens e custo
  • Taxas de erro e timeouts de ferramentas
  • Proxies de “saúde” da recuperação (resultados vazios, baixa similaridade, mudanças de versão de índice)
  • Métricas de resultado (joinha para cima/para baixo, taxa de sucesso de tarefa, escores de fundamentação (groundedness scores))

O que instrumentar em uma aplicação de LLM

A maioria dos apps de LLM pode ser decomposta em alguns componentes recorrentes. Instrumente cada componente com segmentos de rastro, logs estruturados e métricas.

Telemetria do ciclo de vida de prompts

Acompanhe prompts como artefatos de primeira classe:

  • prompt_template_id (identificador estável)
  • prompt_version (versão semântica ou hash de commit)
  • prompt_render_time_ms
  • prompt_tokens (tokens de entrada atribuíveis a system/dev/user/contexto recuperado, se possível)
  • model / provider
  • parâmetros de geração: temperatura, top_p, max_tokens, sequências de parada
  • response_tokens, finish_reason
  • streaming: TTFT, tokens/seg, tempo até o último token

Boa prática: separar o que você armazena em métricas vs logs.

  • Coloque contagens e durações em métricas.
  • Coloque trechos do prompt renderizado, prompt completo e resposta completa atrás de logs controlados (amostragem + redação), ou armazene apenas referências com hash.

Isso complementa PromptOps, onde versões e experimentos de prompt são gerenciados como código.

Telemetria de ferramentas e agentes

Se seu sistema usa ferramentas (function calling) ou loops de agente, instrumente:

  • Nome da ferramenta, versão e endpoint da dependência
  • Argumentos da ferramenta (frequentemente sensíveis; considere redação/hashing)
  • Latência da ferramenta, tentativas, timeout
  • Tamanho da resposta da ferramenta e códigos de erro
  • Contagem de loops/passos do agente
  • “Motivo da chamada de ferramenta” (saída do roteador/plano), quando disponível

A observabilidade de ferramentas é crítica para diferenciar:

  • “A saída do modelo está errada” vs “A ferramenta retornou dados errados” vs “A ferramenta expirou”

Telemetria do pipeline de recuperação (RAG)

Para geração aumentada por recuperação (retrieval-augmented generation, RAG), instrumente cada etapa:

  • Construção de consulta (incluindo reescrita de consulta)
  • Modelo de embeddings (embedding model) e latência de embeddings
  • Parâmetros de busca vetorial (top_k, filtros, namespace/tenant)
  • Distribuições de pontuação de similaridade (mín/méd/máx)
  • Modelo/versão do reranqueador (reranker) e latência de reranqueamento
  • IDs de documentos recuperados, IDs de chunks e versão do corpus/índice
  • Flags de “recuperação vazia” e “recuperação de baixa confiança”
  • Mapeamento de citações: quais documentos foram usados na resposta final

Muitos bugs de RAG são, na verdade, incompatibilidades de índice/versão ou erros de filtro (tenant errado, janela de tempo errada). Capturar metadados do índice em rastros se paga rapidamente.

Telemetria de segurança e políticas (frequentemente como eventos de segmento)

Segurança não é apenas uma “barreira de proteção (guardrail)”; é uma fonte de indisponibilidades (outages) e regressões. Acompanhe:

  • Quais políticas/verificações rodaram (detecção de PII, detector de jailbreak, classificador de toxicidade)
  • Decisão de bloquear/permitir e códigos de motivo
  • Etapas de sanitização aplicadas à entrada do usuário ou à saída de ferramenta

Mantenha isso alinhado aos seus objetivos de governança e aos SLOs para Funcionalidades de IA.

Desenhando um esquema de rastros para apps de LLM

Um bom esquema de rastros é consistente, minimamente “vazador” e útil sob pressão de incidentes.

Estrutura de segmentos recomendada

Uma requisição típica de RAG + ferramentas pode se parecer com:

  • http.request (root span)
    • authz.check
    • rag.query_rewrite
    • rag.retrieve
    • rag.rerank
    • prompt.render
    • llm.generate (or llm.chat)
      • tool.call (0..n)
    • output.postprocess
    • safety.classify
    • response.write

Cada segmento deve ter atributos que permitam fatiamento e depuração.

Atributos úteis (exemplos)

Comuns

  • request_id, trace_id, user_tier, tenant_id (cuidado com PII)
  • env (prod/staging), release_version

Segmentos de LLM

  • llm.provider (openai/anthropic/self-hosted)
  • llm.model (e.g., gpt-4.1, claude-3.x, llama-3.x)
  • llm.temperature, llm.max_tokens
  • llm.prompt_version
  • llm.input_tokens, llm.output_tokens, llm.total_tokens
  • llm.finish_reason
  • llm.cache_hit (se cacheamento de prompt/resultado for usado)

Segmentos de recuperação

  • rag.index_version
  • rag.top_k, rag.filters (registre com segurança)
  • rag.num_results
  • rag.score_max, rag.score_min, rag.score_mean

Segmentos de ferramenta

  • tool.name, tool.status (ok/error/timeout)
  • tool.retries, tool.latency_ms

Propagação de contexto

Se seu app chama múltiplos serviços (gateway → orquestrador → recuperador → gateway de modelo), você precisa de propagação consistente do contexto de rastros (trace context propagation) (por exemplo, W3C Trace Context via OpenTelemetry). Sem isso, você obtém rastros desconectados e não consegue responder “para onde foi o tempo?”

Amostragem sem perder os casos importantes

A telemetria de LLM pode ser cara (logs grandes, atributos de alta cardinalidade (high-cardinality)). Estratégias comuns:

  • Amostragem na entrada (head-based sampling): amostrar uma porcentagem fixa de requisições (barato, mas pode perder falhas raras)
  • Amostragem na saída (tail-based sampling): manter rastros que atendam a condições (erros, requisições lentas, bloqueios de segurança)
  • Amostragem dinâmica (dynamic sampling): aumentar a amostragem quando alertas disparam ou para tenants/funcionalidades específicos
  • Registro seletivo de payload (selective payload logging): sempre registrar metadados; amostrar prompts/respostas completos apenas para depuração com opt-in

Métricas para apps de LLM: o que medir e por quê

Métricas devem orientar painéis, alertas e SLOs. Evite transformar métricas em logs de alta cardinalidade (por exemplo, não rotule por texto bruto do prompt).

Métricas de confiabilidade e latência

Acompanhe ponta a ponta e por etapa:

  • request_latency_ms (p50/p95/p99)
  • llm_latency_ms, retrieval_latency_ms, tool_latency_ms
  • ttft_ms (time to first token) para UX com streaming
  • tool_error_rate, llm_error_rate (timeouts, rate limits, erros do provedor)
  • fallback_rate (por exemplo, fallback de roteamento de modelo)

Isso se conecta naturalmente a Monitoramento e Serving de LLM.

Métricas de tokens e custo

Tokens são os “ciclos de CPU” de apps de LLM:

  • llm_input_tokens, llm_output_tokens, llm_total_tokens
  • Distribuição de tokens_per_request por endpoint/funcionalidade
  • cost_usd_estimate (derivado de contagens de tokens e tabelas de preço)
  • cache_hit_rate (cache de prompt, cache de recuperação)

Visibilidade de custo é essencial para planejamento de capacidade e se relaciona com Custo/Desempenho.

Proxies de saúde da recuperação (específicos de RAG)

Você frequentemente não consegue medir “recall” verdadeiro online, mas pode instrumentar proxies fortes:

  • rag_empty_result_rate
  • rag_low_score_rate (por exemplo, similaridade máxima abaixo de um limiar)
  • rag_score_mean por versão de índice
  • rag_docs_used_count (quantos chunks recuperados entraram no prompt)
  • citation_coverage_rate (fração de respostas com citações quando esperado)

Picos nessas métricas frequentemente indicam bugs de indexação, deriva do modelo de embeddings, ou problemas de filtro/permissão.

Métricas de resultado e qualidade

Algumas métricas de qualidade são diretas; outras são baseadas em modelos ou feedback humano:

  • Feedback do usuário: joinha para cima/para baixo, taxa de “resposta útil”
  • Sucesso de tarefa (específico do domínio): ticket resolvido, SQL correto executado, reembolso concluído
  • Segurança: taxa de bloqueio/recusa, gatilhos de detecção de jailbreak
  • Avaliadores automáticos: escore de fundamentação, checagens de veracidade factual (factuality), restrições baseadas em regex

Essas métricas fazem a ponte entre observabilidade e Avaliação em Produção. Elas também alimentam Volantes de Dados quando usadas com responsabilidade.

Logs para apps de LLM: como registrar sem criar risco

Use logs estruturados e IDs estáveis

Prefira logs JSON com campos consistentes:

  • trace_id, span_id, request_id
  • prompt_version, model, tool_name
  • error_type, error_message (remova conteúdo sensível)

Trate o registro de prompt/resposta explicitamente

Logs de prompt/resposta são úteis para depuração, mas perigosos. Padrões comuns:

  • Metadados sempre, conteúdo às vezes: sempre registrar contagens de tokens, prompt_version, model; amostrar conteúdo apenas sob controles estritos.
  • Pipelines de redação (redaction pipelines): remover emails, números de telefone, endereços, segredos, tokens de acesso.
  • Hashing: armazenar hashes da entrada do usuário para deduplicação sem armazenar texto bruto.
  • Criptografia + controle de acesso: separar um “repositório de conteúdo de depuração” com retenção curta e acesso auditado.

Para um tratamento mais profundo, veja Privacidade em Logs.

Exemplo prático: instrumentando um endpoint de RAG (Python)

A seguir, um exemplo simplificado mostrando como você poderia estruturar rastreamento e métricas em torno de um pipeline de RAG usando conceitos do OpenTelemetry. (APIs exatas variam por linguagem e versão do OTel; trate isto como um blueprint.)

from opentelemetry import trace, metrics
from opentelemetry.trace import Status, StatusCode
import time

tracer = trace.get_tracer("rag-app")
meter = metrics.get_meter("rag-app")

req_latency = meter.create_histogram("request_latency_ms")
llm_tokens = meter.create_histogram("llm_total_tokens")
rag_empty = meter.create_counter("rag_empty_result_total")
tool_errors = meter.create_counter("tool_error_total")

def handle_question(request):
    start = time.time()
    with tracer.start_as_current_span("http.request") as root:
        root.set_attribute("endpoint", "/ask")
        root.set_attribute("release_version", "2026.01.06")

        question = request["question"]
        tenant_id = request.get("tenant_id", "unknown")
        root.set_attribute("tenant_id", tenant_id)

        # Retrieval
        with tracer.start_as_current_span("rag.retrieve") as s:
            s.set_attribute("rag.top_k", 8)
            s.set_attribute("rag.index_version", "kb-v17")

            docs = retrieve_docs(question, top_k=8, tenant_id=tenant_id)
            s.set_attribute("rag.num_results", len(docs))

            if not docs:
                rag_empty.add(1, {"tenant_id": tenant_id})
                s.add_event("rag.empty_results")

        # Prompt render
        with tracer.start_as_current_span("prompt.render") as s:
            prompt_version = "support-rag@1.4.2"
            s.set_attribute("llm.prompt_version", prompt_version)
            prompt = render_prompt(question, docs, version=prompt_version)
            # Consider NOT logging full prompt here; store securely if needed.

        # LLM call
        with tracer.start_as_current_span("llm.generate") as s:
            s.set_attribute("llm.provider", "openai")
            s.set_attribute("llm.model", "gpt-4.1-mini")
            s.set_attribute("llm.temperature", 0.2)

            try:
                result = call_llm(prompt, model="gpt-4.1-mini", temperature=0.2)
                s.set_attribute("llm.finish_reason", result.finish_reason)
                s.set_attribute("llm.input_tokens", result.usage.input_tokens)
                s.set_attribute("llm.output_tokens", result.usage.output_tokens)
                s.set_attribute("llm.total_tokens", result.usage.total_tokens)

                llm_tokens.record(result.usage.total_tokens, {"model": "gpt-4.1-mini"})
            except Exception as e:
                s.record_exception(e)
                s.set_status(Status(StatusCode.ERROR, str(e)))
                raise

        # Optional tool call (example)
        if result.needs_tool:
            with tracer.start_as_current_span("tool.call") as s:
                s.set_attribute("tool.name", "order_lookup")
                try:
                    tool_resp = order_lookup(result.tool_args)
                except TimeoutError as e:
                    tool_errors.add(1, {"tool": "order_lookup"})
                    s.record_exception(e)
                    s.set_status(Status(StatusCode.ERROR, "timeout"))
                    raise

        # Finalize
        elapsed_ms = (time.time() - start) * 1000
        req_latency.record(elapsed_ms, {"endpoint": "/ask"})
        root.set_attribute("response_latency_ms", elapsed_ms)

        return {"answer": result.text}

Ideias-chave demonstradas:

  • Cada etapa do pipeline tem um segmento.
  • Segmentos carregam atributos que são seguros e consultáveis (versões, contagens, latência).
  • Contagens de tokens viram métricas (histogramas), não logs.
  • Eventos como rag.empty_results capturam ocorrências semânticas importantes sem registrar conteúdo sensível.

Playbooks de depuração: como a observabilidade ajuda na prática

Alucinações ou citações incorretas em RAG

Sintomas: usuário relata resposta errada, ou citações não sustentam as afirmações.

O que inspecionar:

  • Rastro: resultados de rag.retrieve, pontuações e rag.index_version
  • Rastro/log: metadados de prompt.render (versão de prompt, tamanho do contexto)
  • Segmento de LLM: contagens de tokens (o contexto foi truncado?), modelo/versão
  • Métricas: pico em rag_low_score_rate ou rag_empty_result_rate

Causas raiz comuns:

  • Filtros de recuperação errados (incompatibilidade de tenant/ACL)
  • Versão do índice mudou sem validação
  • Regressão de template de prompt (formatação de citações quebrou)
  • Truncamento de contexto devido a prompt de sistema mais longo ou top_k maior

Falhas de ferramenta em fluxos agentivos

Sintomas: timeouts intermitentes, uso incorreto de ferramentas, falhas em cascata.

O que inspecionar:

  • Quebra por segmentos: o tempo foi para tool.call ou llm.generate?
  • Métricas de erro de ferramenta por nome/status
  • Argumentos de ferramenta (com cuidado) e erros de validação do esquema de resposta

Mitigações informadas pela telemetria:

  • Adicionar tentativas/backoff para códigos de erro específicos de ferramentas
  • Adicionar timeouts e fallbacks (veja Padrões de Design de Sistemas de LLM)
  • Melhorar o esquema da ferramenta ou restrições de function calling

Regressões após mudanças de prompt/modelo

Sintomas: queda de qualidade, maior taxa de recusa, maior custo.

O que inspecionar:

  • Fatiar métricas por prompt_version e llm.model
  • Acompanhar fallback_rate e refusal_rate após a implantação gradual (rollout)
  • Comparar distribuições de tokens antes/depois da mudança

É aqui que observabilidade encontra PromptOps e CI/CD para Modelos: você quer rollouts seguros, canários (canaries) e reversão (rollback) rápida quando métricas mudam.

Armadilhas operacionais e boas práticas

Gerencie alta cardinalidade

Apps de LLM naturalmente produzem dados de alta cardinalidade (texto de prompt, IDs de usuário, IDs de documento). Regras gerais:

  • Métricas: apenas rótulos de baixa cardinalidade (endpoint, model, prompt_version, tool_name)
  • Rastros: permitir atributos mais ricos, mas ainda evitar texto bruto por padrão
  • Logs: manter conteúdo sensível fora, ou armazená-lo em um sistema separado e controlado

Trate versões como dimensões de primeira classe

Sempre marque a telemetria com:

  • versão de release do app
  • versão de prompt
  • versão/provedor do modelo
  • versão do índice/corpus
  • versão do modelo de embeddings

Sem tags de versão, você não consegue correlacionar mudanças com incidentes de forma confiável.

Alinhe observabilidade com SLOs

Equipes operacionais precisam de metas claras: latência, taxa de erro e também confiabilidade comportamental (por exemplo, respostas fundamentadas). Conecte painéis e alertas a SLOs para Funcionalidades de IA, não apenas à disponibilidade da infraestrutura.

Mantenha um loop de feedback, mas evite registrar tudo

O objetivo é visibilidade acionável, não coleta máxima de dados. Use:

  • amostragem
  • retenção baseada em tail para falhas
  • “sessões de depuração” explícitas para captura mais profunda
  • padrões com preservação de privacidade (veja Privacidade em Logs)

Checklist: um baseline sólido para observabilidade de apps de LLM

  • Instrumentar rastros de ponta a ponta com segmentos para recuperação, renderização de prompt, chamada ao modelo e ferramentas
  • Emitir métricas de tokens e custo (tokens de entrada/saída/totais, taxa de acerto de cache)
  • Acompanhar prompt_version, model e index_version em todos os lugares
  • Capturar proxies de saúde de RAG: recuperação vazia, baixa similaridade, indicadores de incompatibilidade de índice
  • Registrar erros e latência de ferramenta por nome/status
  • Adicionar eventos de decisão de segurança/política com códigos de motivo (sem vazar conteúdo)
  • Implementar amostragem e armazenamento controlado para conteúdo de prompt/resposta
  • Construir painéis e alertas alinhados com Monitoramento e SLOs para Funcionalidades de IA
  • Conectar observabilidade a práticas de rollout em PromptOps e loops de qualidade em Avaliação em Produção

A observabilidade não elimina a imprevisibilidade de LLMs, mas transforma “o modelo fez algo estranho” em fatos concretos e diagnosticáveis — tornando aplicações de LLM operáveis em escala de produção.