Eu sei que essa questão da observabilidade ainda não é o tema mais quente. A maior parte dos times está numa etapa anterior, em que os agentes mal estão conseguindo chegar em produção. A discussão hoje é sobre prototipação, ajuste de prompt, definição de arquitetura. Talvez esse artigo não pegue muita gente que ainda está construindo o conhecimento de como levar agentes pra produção.
Mas pra quem já está operando múltiplos agentes, como é o nosso caso aqui, a dor da observabilidade nasce e bate forte, com uma clareza muito grande. Muitas vezes a discussão de observabilidade de agentes se resume a logs, poucos, ou mesmo a LLMs adjudicando as respostas dos LLMs. A gente também usa esse tipo de abordagem e é bastante útil em algumas situações, mas não é suficiente pra você dizer que tem observabilidade.
Sobre LLM como juiz
Não é que LLM-as-judge não ajude. A gente usa e ajuda em vários cenários. Mas o próprio trabalho de você treinar um agente julgador é grande, porque cada agente executa uma microtarefa muito personalizada dentro do contexto empresarial. Do mesmo jeito que não existem templates de agentes prontos que você possa fazer um transplante de uma empresa pra outra, também não existem templates de prompt prontos capazes de julgar a qualidade dos outputs, porque os critérios vão ser muito contextuais.
Então você tem que ter clareza: quando escolher o LLM pra julgar, depois de ter tido um tempo de treinamento do seu agente que executa a tarefa, agora vai ter que dedicar um tempo pro seu agente que monitora a tarefa. O que vou compartilhar aqui são algumas sugestões pra quem precisa lançar o seu agente em produção, ter algumas formas de monitorar que não dependam do treinamento de um agente julgador. Não anula, mas são formas de você não ficar sem nenhuma visibilidade do que está acontecendo.
Métricas simples que podem ajudar
Quando você leva um agente pra produção, quanto melhor ele tá, mais o uso cresce, e cresce rápido. Então fica muito difícil você fazer monitoramento sem alguns critérios pré-definidos de pelo menos quais outputs colocar uma lupa. Aqui tem uma lista de métricas bem simples mas que podem te ajudar:
- Tamanho do output
- Taxa de aprovação/reprovação em pontos de aprovação humana
- Taxa de fricções detectadas em agentes conversacionais
- Taxa de uso
- Falhas e erros em produção
Tamanho do output
Essa talvez seja a forma mais simples e que mais ajuda a pegar erros grosseiros. Quando um agente dentro de um fluxo grande simplesmente para de produzir, ou começa a produzir diferente. Pode ser que ele não produza simplesmente vazio — ele vai produzir alguma coisa, porque é um LLM, a natureza dele é generativa. Mas essa resposta pode ter uma disparidade de tamanho muito grande. Por exemplo, muito pequena, porque ele está só informando que não consegue gerar o output.
É o tipo de coisa que, com monitoramento utilizando média e desvio padrão dos outputs dentro de ciclos pré-definidos, que você prepara com cuidado e que a gente vai falar mais adiante, você consegue ser avisado de uma forma muito rápida e barata. Porque é literalmente um count e cálculos que não são custosos do ponto de vista estatístico, que são média e desvio padrão.
O lado oposto também ajuda: você pode detectar situações em que o output sai muito grande, fora do padrão. Pode te ajudar a detectar cenários de anomalia que estão aumentando seu custo, dado que o custo de output é mais caro. Pode estar entrando ali um input inadequado, muito maior, que está provocando uma resposta muito maior do que o padrão. Você consegue ver isso rápido pra atuar rápido na questão de custo.
Taxas
O desafio fica um pouquinho maior quando a métrica não envolve média, que era o caso do exemplo anterior. As taxas envolvem um pouco mais de dificuldade. Trago aqui um exemplo: a taxa de atritos detectados.
Você pode criar um indicador de atritos. Se o seu agente é conversacional, você detecta automaticamente fricções nas interações. Se o seu agente é do tipo analítico, que executa uma tarefa analítica e tem no meio do fluxo pontos de aprovação humana, você pode detectar o aumento da taxa de reprovação ou mesmo o sumiço da taxa de aprovação. Você vê que o fluxo está ficando engasgado.
A taxa de reprovação da tarefa e a detecção de atrito em conversa são relativamente fáceis de implementar, mesmo sem você ter um sistema sofisticado de coleta de feedbacks. Você contabiliza esses sinais — eles não são feedbacks diretos, mas funcionam mesmo que você ainda não esteja organizado pra capturar feedbacks de uma forma estruturada. Tem um desafio de mensuração, que é a questão da janela de tempo, sobre o qual a gente vai falar um pouco.
Welford
Antes de chegar no desafio da janela, vale apresentar uma técnica antiga, às vezes pouco conhecida, que resolve uma parte do problema. Os agentes em produção acabam fazendo muitas execuções quando você automatiza processos sérios e centrais. Isso vira um desafio operacional — guardar histórico bruto de tudo pra recalcular estatística é caro.
O algoritmo de Welford é de 1962. Ele calcula média e desvio padrão de forma incremental: cada valor novo atualiza três numerinhos guardados numa única linha (a contagem, a média atual, e um auxiliar que carrega a variação acumulada). Sem precisar guardar a lista dos valores individuais, sem revisitar nada, em operação O(1) por evento. É numericamente estável e funciona bem em escala.
Pra o caso de monitorar média de uma grandeza pontual (como o tamanho do output), Welford resolve direto. Cada execução nova atualiza os três números, e você sempre tem média e desvio padrão atualizados, sem precisar montar série temporal nem pipeline de agregação.
Como definir ciclos sem enviesar o baseline
Pra taxa, a primeira coisa que vem na cabeça é média móvel. Você define uma janela (últimos 7 dias, por exemplo), conta quantos eventos caíram na janela, e compara com o histórico. Parece intuitivo, mas tem uma limitação séria.
A média móvel sobrepõe janelas: cada nova observação reaproveita eventos antigos da janela anterior. Se você alimenta o baseline a cada evento, está adicionando ao histórico observações redundantes que reforçam o estado atual. Quando o agente está em transição (era bom, começou a piorar), as janelas vão capturando o estado degradado progressivamente, e o baseline acompanha junto. Antes da degradação ser anômala pelo critério estatístico, o novo “normal” já incorporou a piora. A anomalia que deveria aparecer nunca aparece.
A alternativa é trabalhar com ciclos fechados sequenciais. Cada ciclo tem data de início e fim bem definidos, e não se sobrepõe ao anterior. Durante o ciclo, você só conta os eventos. Quando o ciclo fecha, a contagem final daquele ciclo vira uma única observação que entra no baseline. O próximo ciclo começa do zero. Cada ciclo é uma observação independente.
A implementação não é mais complicada que a média móvel. Como a gente não tem job rodando o tempo todo pra “fechar ciclos”, a verificação é feita de forma preguiçosa: quando chega um evento novo, o sistema verifica se ainda está dentro do ciclo aberto (e só incrementa o contador), ou se o ciclo já passou (e nesse caso consolida a contagem do ciclo anterior, decide se virou anomalia ou se alimenta o baseline, e abre ciclo novo). Cada evento é o gatilho, mas o baseline só é alimentado uma vez por ciclo. Isso resolve a contaminação sem precisar de infraestrutura extra.
Uma decisão que veio junto: o tamanho do ciclo precisa ser configurável por agente, porque cada um tem ritmo próprio. Um agente conversacional pode ter ciclo curto (recebe muita interação), outro pode ter ciclo de 30 dias (executa uma vez por mês). E quando o usuário muda o tamanho do ciclo, o baseline antigo, construído com o tamanho anterior, não pode ser descartado. Na nossa implementação, a gente mantém uma linha separada de baseline pra cada tamanho de ciclo, e ativa a que bate com a configuração atual. Se o usuário volta atrás, recupera o aprendizado.