O que é Observabilidade para IA?
Observabilidade para IA (Observability for AI) é um fundamento de engenharia de IA para quem trabalha com LLMs. Traces, spans e logs que deixam você responder: por que o agente fez isso?
Observability for AI
Observabilidade para IA (Observability for AI) é um fundamento de engenharia de IA para quem trabalha com LLMs. Traces, spans e logs que deixam você responder: por que o agente fez isso?
Às 3h da manhã, o agente de incidentes recebeu um alerta de latência no serviço de pagamentos. Ele leu logs, consultou métricas e reiniciou o serviço de catálogo. O alerta continuou. O plantonista acordou com dois problemas em vez de um.
Na reunião do dia seguinte, a pergunta era uma só: por que o agente fez aquilo? O log da aplicação mostrava “restart solicitado pelo agente” e nada mais. Não dava para saber o que o modelo leu, qual ferramenta retornou o quê, nem qual versão do prompt estava rodando.
Em software comum, um stack trace conta a história do erro. Num sistema com IA, a decisão nasce do que o modelo viu no contexto. Se você não guardou o que ele viu, a decisão não tem explicação. E sem explicação, a única correção possível é chute: trocar o prompt, trocar o modelo, torcer.
Observabilidade para IA é registrar cada execução de forma que você consiga responder, depois: o que entrou, o que o modelo decidiu, o que as ferramentas fizeram, quanto custou e quanto demorou. A unidade básica é o trace (o registro de uma execução inteira), dividido em spans (os trechos dessa execução).
flowchart TD
T(["1. Trace: uma tarefa"]):::io --> S1(["2. Span: chamada ao modelo"]):::llm
S1 --> S2["3. Span: ferramenta"]:::tool
T --> S3(["2. Span: nova chamada ao modelo"]):::llm
S1 --> A["4. Atributos: prompt, versão, tokens, custo"]:::tool
S2 --> B["4. Atributos: argumentos, resultado, erro"]:::tool
T --> D[("5. Armazenamento de traces")]:::store
D --> Q{"6. Busca e análise"}
Volte às 3h da manhã. Suponha que o agente tivesse trace. Abrindo a execução, você veria algo assim (exemplo ilustrativo):
trace incident-7f3a total 48s custo US$ 0,21
├─ llm decidir_proximo_passo prompt=sre@12 in=3.104 out=88
│ └─ tool buscar_logs args={"servico": "pagamentos", "limite": 50}
│ resultado: 50 linhas, todas "timeout ao chamar catalogo:8080"
├─ llm decidir_proximo_passo prompt=sre@12 in=6.877 out=41
│ └─ tool reiniciar_servico args={"servico": "catalogo"} resultado: ok
└─ llm resposta_final "Reiniciei o catálogo, causa provável dos timeouts."
Agora a decisão tem explicação. A ferramenta de logs devolveu só as 50 últimas linhas, e todas falavam do catálogo. O modelo fez uma inferência razoável com o que viu. O defeito não está no modelo: está no limite de 50 linhas e no fato de reiniciar_servico rodar sem aprovação. Você sai da reunião com duas correções concretas, em vez de “melhorar o prompt”.
| Span | Atributos mínimos |
|---|---|
| Chamada ao modelo | modelo, versão do prompt, mensagens de entrada, saída, tokens de entrada e saída, tokens de cache, latência, motivo de parada |
| Ferramenta | nome, argumentos, resultado (ou resumo), erro, latência |
| Decisão em código | rota escolhida, confiança, limite atingido |
| Humano | quem aprovou ou recusou, quando, o que foi mostrado |
O motivo de parada parece detalhe e não é. Uma resposta cortada por limite de tokens (max_tokens) e uma resposta completa podem parecer iguais no log da aplicação. No span, a diferença está escrita.
Os três se completam. A métrica de custo por hora dispara o alerta. O filtro “traces com custo acima de US$ 1” mostra quais execuções puxaram a média. Abrir uma delas mostra o porquê.
O padrão de mercado para isso é o OpenTelemetry, que tem convenções semânticas próprias para IA generativa (atributos gen_ai.*). Essas convenções ainda estão marcadas como em desenvolvimento, então nomes de atributos podem mudar entre versões. Várias ferramentas de observabilidade de LLM leem esse formato.
Traces guardam o texto que o usuário mandou. Isso inclui dados pessoais: CPF, endereço, histórico de compras, às vezes dados de saúde. Defina quem pode abrir os traces, por quanto tempo eles ficam guardados e o que é mascarado antes de gravar.
Mascare antes de gravar, não depois. Um trace com CPF em texto puro, guardado por um ano e aberto por qualquer pessoa do time, é um problema de LGPD esperando para acontecer. Troque o dado por um marcador ([CPF]) ou por um hash quando você precisar correlacionar execuções do mesmo usuário.
Este exemplo cria um trace mínimo com OpenTelemetry e imprime no terminal. Instale opentelemetry-sdk e anthropic.
import anthropic
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("ai-guru.demo")
client = anthropic.Anthropic()
MODEL = "claude-haiku-4-5"
PROMPT_VERSION = "classifier@3"
with tracer.start_as_current_span("handle_message") as root:
root.set_attribute("user.id", "u-123")
with tracer.start_as_current_span(f"chat {MODEL}") as span:
reply = client.messages.create(
model=MODEL, max_tokens=50,
system="Classifique em: fatura, pedido ou outro.",
messages=[{"role": "user", "content": "Fui cobrado duas vezes"}],
)
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.request.model", MODEL)
span.set_attribute("prompt.version", PROMPT_VERSION)
span.set_attribute("gen_ai.usage.input_tokens", reply.usage.input_tokens)
span.set_attribute("gen_ai.usage.output_tokens", reply.usage.output_tokens)
span.set_attribute("gen_ai.response.finish_reasons", [reply.stop_reason])
span.set_attribute("app.output", reply.content[0].text)
Rode e leia o JSON que aparece. Repare em três coisas:
chat claude-haiku-4-5 tem um parent_id igual ao span_id de handle_message.trace_id. É ele que junta todos os passos de uma tarefa.prompt.version está lá. Mude para classifier@4, rode de novo e veja como fica fácil separar as execuções por versão.Agora imagine uma tarefa com 15 spans assim, e um trace aberto numa tela que mostra a árvore inteira. É isso que faltou na reunião do começo desta página. Em produção, troque o ConsoleSpanExporter por um exportador OTLP que envia para a sua ferramenta de observabilidade.
Observabilidade para IA (Observability for AI) é um fundamento de engenharia de IA para quem trabalha com LLMs. Traces, spans e logs que deixam você responder: por que o agente fez isso?