Traces

Toda execução de um agente deixa um registro que dá para reproduzir depois, mostrando exatamente o que aconteceu.

Toda execução de agente deixa um trace para trás: um registro duradouro do que aconteceu de verdade, reproduzível passo a passo, não importa se a execução partiu da CLI, da API HTTP, de um WebSocket, de uma mensagem no Telegram ou no WhatsApp, ou de uma tarefa agendada. É o trace que responde “por que o agente fez aquilo?” muito depois de tudo já ter terminado.

O que um trace guarda

Quando um agente chama outro por send_to_agent, essa subexecução entra no mesmo trace do pai, então um único registro já mostra a árvore inteira de trabalho.

No painel

Abra Traces na barra lateral e você verá as execuções mais recentes do workspace atual, com desfecho, duração e as ferramentas usadas em cada uma. Clicar em Replay numa execução abre uma linha do tempo passo a passo: o prompt no topo, depois cada chamada de ferramenta, resultado, failover, contagem de tokens, até chegar na resposta final.

Execuções em andamento

Uma execução aparece na lista assim que começa, marcada como em andamento, e os passos dela vão aparecendo enquanto o agente trabalha. Quando termina, a mesma linha vira ok ou um erro. Se a execução parou antes de registrar como terminou (o servidor reiniciou, ou o processo caiu), ela aparece como interrompida, então uma resposta que não chegou nunca fica sem explicação. Enquanto algo está rodando, a página se atualiza sozinha a cada poucos segundos, e o filtro Resultado tem as opções Em andamento e Interrompido.

Pela CLI

pepe traces                       # execuções recentes de todos os escopos
pepe traces --project acme        # apenas as execuções de um projeto
pepe traces --limit 10            # limita o tamanho da lista
pepe traces 1720000000123456      # reproduz uma execução por id, passo a passo

Onde os traces ficam guardados

Traces vivem no mesmo pequeno arquivo SQLite embutido que guarda compromissos e vigias, agrupados por projeto (o projeto default usa a chave default). Cada projeto mantém só uma quantidade limitada deles: à medida que traces novos chegam, os mais velhos vão sendo apagados, e o arquivo nunca cresce indefinidamente. Argumentos e resultados de ferramenta longos demais são encurtados antes de ir para o disco.

Enviando traces para uma ferramenta de observabilidade

Mandar dados para o Langfuse não pede nada além das credenciais que a maioria das instalações já tem configurada (LANGFUSE_PUBLIC_KEY/LANGFUSE_SECRET_KEY): assim que elas existem, toda execução concluída sai como um trace OTLP; sem elas, nada é enviado. E uma falha nesse envio jamais afeta a execução que estava sendo descrita.

Para qualquer outro backend que fale OTLP, use OTEL_EXPORTER_OTLP_ENDPOINT no lugar, e ele assume o processo por completo:

export OTEL_EXPORTER_OTLP_ENDPOINT=https://seu-coletor.exemplo.com
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64 de usuario:senha>"

OTEL_EXPORTER_OTLP_HEADERS recebe uma lista chave=valor separada por vírgulas, enviada como cabeçalhos literais na requisição. Cada span carrega tanto os atributos genéricos do OpenTelemetry (gen_ai.*) quanto os próprios do Langfuse (langfuse.*), então um endpoint Langfuse exibe tudo por completo e qualquer outro backend OTLP também recebe o trace inteiro. Há ainda duas variáveis padrão do OTEL que podem ser úteis: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT redireciona o sinal de traces para um caminho diferente de <endpoint>/v1/traces, e OTEL_SERVICE_NAME renomeia o serviço exportado (o padrão é pepe). O passo a passo completo está em Langfuse.

Além do prompt/resposta da execução e da entrada/saída de cada chamada de ferramenta, todo trace exportado carrega também: o canal de origem (Telegram, a API…) como metadado do trace; a chave da sessão como session.id; um user.id que assume o nome de exibição de quem realmente mandou a mensagem sempre que o canal consegue fornecer esse dado (Telegram, mesmo numa conversa privada e não só na marcação de grupo; WhatsApp, a partir do perfil do contato; Google Chat; Microsoft Teams; Discord), caindo de volta para a chave da sessão quando o canal não tem esse nome disponível, de forma que uma execução dentro de uma sessão compartilhada (um grupo do Telegram, ou de um webhook) é atribuída a quem de fato a enviou, e não a um id genérico cobrindo a conversa toda; a versão do Pepe rodando naquele momento (langfuse.release); um nível (DEFAULT/WARNING/ERROR) derivado de como a execução realmente terminou; e, em cada span de chamada de modelo, o custo daquela chamada na moeda configurada, calculado do mesmo jeito que o livro-razão de uso calcula, e simplesmente omitido em vez de aparecer como um zero enganoso quando o modelo não tem preço conhecido. Numa visualização em cascata, o tempo de cada etapa (uma chamada de ferramenta, uma geração de modelo) reflete o momento em que ela de fato aconteceu, não uma estimativa.

É diagnóstico, não registro de cobrança. Traces existem para explicar uma execução, e por isso os mais antigos ou grandes demais acabam sendo cortados. Para contagens de tokens e custos que você vai efetivamente faturar, use o livro-razão de uso, que é separado e nunca descarta um lançamento.