05Detalhamento · traces
Rastrear um agente de LLM: depurar o que o modelo realmente fez
Cada turno, cada chamada de ferramenta, cada pedaço de prompt, gravado e pesquisável. Os relatos de bug deixaram de ser 'a IA tá estranha' e viraram um id de rastro.
O problema
"A IA tá esquisita" não é relatório de bug, e era o que eu recebia. Um agente que lê mensagem, chama ferramenta e decide sozinho não repete o erro na hora em que você vai olhar — então, sem registro, eu estava sempre adivinhando. Passei a gravar cada turno: o que o modelo viu, quais ferramentas ele chamou, o que elas devolveram e o que ele respondeu. Hoje uma reclamação vira um id que eu abro e leio.
As restrições
- 01Capturar a decisão, não o mundo. O prompt inteiro é enorme; eu precisava do suficiente pra reproduzir o turno sem guardar o universo em cada mensagem.
- 02Fora do caminho quente. Gravar não pode atrasar a resposta que o cliente está esperando.
- 03Consultável depois. Se eu não consigo buscar, não adianta ter gravado.
- 04Seguro de reusar. Esses mesmos traces alimentam o escritório 3D público, então a escrita tinha que sair limpa o bastante pra uma visão filtrada ser construída em cima.
A arquitetura
runner do agente
cada turno: as mensagens que entram, as ferramentas chamadas, a resposta que sai
escritor do trace
gravado em agent_traces fora do caminho quente, sem atrasar a resposta
consulta + replay
agent-trace.mjs transforma uma reclamação num trace id que dá para ler
reusado adiante
os mesmos traces alimentam os evals e o escritório 3D ao vivo
O trace virou a peça que o resto do sistema usa. A suíte de provas asserta contra ele pra saber o que o agente fez naquele turno, o escritório 3D desenha a partir dele, e o supervisor do dinheiro confere a resposta contra os resultados de ferramenta que ele registrou. Três consumidores diferentes lendo o mesmo registro.
A parte difícil
A decisão difícil foi o que guardar. Gravando o prompt inteiro em cada turno, a tabela vira um aterro que eu pago todo mês; gravando de menos, justo o trace de que eu preciso fica sem o pedaço que explica. Fiquei com a superfície da decisão: as mensagens, as chamadas de ferramenta e o que elas devolveram, o desfecho.
Aí veio a parte que eu não tinha planejado. Quando o trace ficou limpo o bastante pra depurar, ficou limpo o bastante pra desenhar — e o mesmo dado que encerrava a discussão sobre o que o agente tinha feito virou o escritório ao vivo e o oráculo das provas. O que era ferramenta minha acabou virando parte do produto.
Trade-offs
- Trace custa armazenamento, e cresce com o tráfego. Gravar a superfície da decisão em vez do prompt inteiro segura isso; uma janela de retenção segura o resto.
- Escrever em todo turno é trabalho a mais num caminho quente, então é feito depois que a resposta sai. Aceito o atrasinho entre o turno e o registro dele.
- Trace estruturado é mais código pra manter do que um println. Ele se paga na primeira vez em que o relatório de bug chega como id em vez de print de tela.
O que eu faria diferente
Eu amostraria em vez de guardar tudo. A maioria dos turnos é chata e igual à anterior; o que vale guardar pra sempre é falha e caso de borda. Um amostrador que guardasse 100% de tudo que disparou uma trava e uma fração pequena do resto cortaria o custo com força sem eu perder os traces que de fato são relidos.