Pular para o conteúdo
mnzes

Como funciona o loop de um agente de IA?

PorDiógenes MenezesAprendendo IA em público

12 min de leitura

O loop de um agente de IA tem quatro etapas por volta. O contexto inteiro vai ao modelo; o modelo devolve um raciocínio e um pedido de ferramenta; o seu código valida e executa esse pedido; o resultado entra no contexto como uma mensagem nova. Aí começa a volta seguinte, com um contexto maior. Só a segunda etapa roda no modelo.

Essa assimetria é o que mais importa e é a que menos aparece nos diagramas. Três das quatro etapas são código seu, e nelas você decide o que o modelo vai ler adiante. O formato de intercalar raciocínio e ação numa mesma sequência veio do padrão ReAct, de 2022, e permaneceu praticamente inalterado desde então1.

As duas consequências que aparecem primeiro em produção também vêm daí. O contexto cresce a cada volta e é reenviado inteiro, o que faz o custo subir de forma superlinear. E, como tudo compartilha a mesma janela, uma tarefa longa acaba precisando de algum tipo de isolamento para não misturar o que não deveria estar junto.

contexto: system prompt,pedido e históricomodelo devolvepensamento + açãoseu código validae executaresultado entra comomensagem de ferramentacontexto maior≈ 3.100 tokens na volta 1+ 700 tokens por volta
Figura 1Só uma das quatro etapas roda no modelo. As outras três são código seu, e é nelas que você decide o que ele vai ler na volta seguinte.

Uma volta, com o conteúdo real

Vale seguir uma volta concreta, num agente que investiga por que um lote de cobranças recorrentes falhou na madrugada.

Etapa 1: o contexto sai daqui. Na primeira volta ele tem quatro partes: as instruções de sistema, a descrição das ferramentas disponíveis, o pedido do usuário e nada mais. Algo perto de 3.100 tokens. É importante ver que isso é uma lista de mensagens, não uma string: cada item tem um papel, e o papel muda como o modelo trata o conteúdo.

Etapa 2: o modelo responde com dois tipos de bloco. Um é texto, o raciocínio. O outro é estruturado: nome da ferramenta, argumentos e um identificador daquela chamada. O identificador existe porque a resposta precisa ser casada com o pedido certo quando várias chamadas saem juntas.

Etapa 3: o seu código executa. Aqui acontece tudo o que não é modelo. Você confere se a ferramenta existe, valida os argumentos contra o schema, aplica a permissão daquele usuário, roda a operação e captura o erro. Uma volta pode morrer inteira nessa etapa, sem que o modelo seja chamado de novo, se a validação recusar.

Etapa 4: o resultado volta como mensagem de ferramenta. Não como texto do usuário. A distinção é real e tem efeito: o modelo trata mensagem de usuário como instrução e resultado de ferramenta como observação. Devolver um erro de API no papel de usuário é uma forma discreta de dizer ao modelo que o usuário pediu aquilo.

A ordem dessas mensagens é rígida. Cada resultado precisa aparecer logo depois do pedido que o originou, casado pelo identificador, e a maioria das APIs recusa o histórico quando falta o par. Isso importa muito na hora de truncar ou resumir: descartar um pedido de ferramenta sem descartar o resultado dele deixa o histórico inválido, e o erro que volta é de formato, não de conteúdo, o que costuma levar meia hora para ser diagnosticado.

E aí a volta 2 começa com um contexto que agora tem 3.800 tokens, porque o pedido de ferramenta e o resultado ficaram no histórico. Ninguém removeu nada.

Perceber, decidir e agir é um nome emprestado

O ciclo perceber, decidir e agir vem da robótica e da literatura de agentes anterior aos LLMs, onde havia sensor de verdade. O nome pegou porque o formato é mesmo o mesmo, e ele engana num ponto.

Num agente de LLM não existe percepção. O que o modelo “percebe” é o texto que o seu código escreveu no contexto, na ordem em que o seu código escolheu escrever. Se ler_log devolve 3.000 linhas e você entrega as 3.000, essa é a percepção. Se você entrega as 20 linhas em volta do erro, essa é a percepção. Não há um mundo por trás disso que o modelo possa consultar por conta própria.

Isso muda o lugar onde se trabalha. Boa parte do esforço de melhorar um agente não está no prompt nem no modelo: está em decidir o que cada ferramenta devolve, com que forma e com quanto detalhe. É a etapa 4 do loop, e é a mais barata de mexer.

Explica também uma falha que parece teimosia. Um agente que consulta a mesma tabela quatro vezes muitas vezes está sendo informado de nada por ela. Um resultado vazio serializado como [] e o mesmo resultado como nenhuma linha com status 'pendente' entre 02:00 e 04:00 são o mesmo fato e produzem voltas seguintes bem diferentes.

O contexto cresce em toda volta

volta 13,1 milvolta 68,5 milvolta 1216 milvolta 1823 miljanela cheia
Figura 2Nada é removido entre as voltas. O contexto da volta 18 contém tudo o que passou pelas 17 anteriores, e a janela enche por acúmulo, não por uma resposta grande.

Com 3.100 tokens fixos e cerca de 1.100 acrescentados por volta entre pedido e resultado, a volta 18 chega perto de 23 mil tokens de entrada. Não é um número alarmante em si. O problema é o formato do crescimento e o que ele faz com a atenção do modelo.

Um trabalho de 2023 mediu como o desempenho varia conforme a posição da informação relevante dentro do contexto. O resultado foi um U: modelos vão melhor quando o que importa está no começo ou no fim, e caem de forma significativa quando está no meio, inclusive em modelos anunciados como de contexto longo2. Num loop de agente, o começo é a instrução original e o fim é o último resultado de ferramenta. O meio é a história inteira da investigação.

Duas coisas seguem disso, e as duas são práticas. A restrição que precisa valer até a última volta não pode ficar só na primeira mensagem: ou é reinjetada perto do fim, ou vira validação dentro da ferramenta. E o resultado que mais importa deve ser o último a entrar, o que na maior parte dos loops acontece de graça.

Vale desconfiar da solução mais óbvia, que é resumir o histórico quando ele fica grande. Resumo é uma chamada a mais, custa tokens, e o que ele descarta é decidido por um modelo que não sabe qual detalhe você vai precisar na volta 22. Funciona, mas é uma troca, não uma correção.

Quantas voltas são normais

A faixa útil vai de três a quarenta, com a maioria das tarefas que funcionam bem ficando abaixo de quinze.

Abaixo de três, o loop não está pagando por si: se a tarefa resolve em duas chamadas com ordem conhecida, um workflow entrega o mesmo mais barato e mais rápido. Acima de quarenta, o padrão quase nunca é progresso lento. É repetição: as mesmas três ações alternando, ou a mesma consulta com um argumento levemente diferente, quatro vezes seguidas.

Existe uma aritmética simples por trás disso. Se cada volta tem 95% de chance de sair certa e os erros não se corrigem, quinze voltas em série terminam com 46% de chance de estar tudo certo. Trinta voltas caem para 21%. Encurtar a tarefa costuma render mais que aumentar o teto.

Quanto tempo leva uma volta

Ordem de grandeza, com as premissas na mesa. Uma chamada ao modelo com 8 mil tokens de entrada e 300 de saída leva entre 3 e 8 segundos, e o tempo cresce mais com o tamanho da saída do que com o da entrada. A ferramenta leva o que ela leva: uma consulta indexada responde em 50 ms, uma varredura de log de um dia inteiro leva alguns segundos, uma chamada a serviço externo com nova tentativa pode passar de vinte.

Quinze voltas a 5 segundos de modelo mais 2 de ferramenta dão perto de dois minutos. Nada disso é paralelizável no eixo principal, porque cada volta depende do resultado da anterior. O que paraleliza é dentro da volta, quando o modelo pede três leituras independentes de uma vez, e o ganho aí é real mas limitado ao trecho sem dependência.

Duas coisas mexem nesse número mais do que o modelo escolhido: quantas voltas a tarefa precisa, que você controla cortando escopo, e quanto leva a ferramenta mais lenta, que costuma ser um índice faltando em algum lugar.

Os quatro critérios de parada

teto de passos20 para começarteto de tokens150 mil de janelatempo de parede10 minutosrepetição detectada3 ações iguaisverificados pelo seu código, não pelo modelonenhum deles existe: o loop rodaaté o limite de gasto da conta
Figura 3Os quatro são verificados fora do modelo, por comparação de número. O modelo declarar que terminou é um quinto sinal, e é o único que pode mentir sem saber.

Teto de passos. O mais simples e o mais eficaz. Vinte é um começo razoável e você ajusta com dado, olhando a distribuição de voltas das execuções bem-sucedidas.

Teto de tokens. Necessário porque passos não têm tamanho fixo. Uma única ferramenta que devolve um arquivo grande pode gastar em uma volta o que dez voltas normais gastariam.

Tempo de parede. É o que protege o usuário e a fila. Uma tarefa que passa de dez minutos raramente vai terminar bem, e enquanto ela roda ocupa recurso.

Repetição detectada. O mais barato de implementar e o menos usado: guarde o nome da ferramenta e os argumentos das últimas três chamadas; se as três forem idênticas, o agente não está progredindo, está insistindo. Parar ali economiza a maior parte do desperdício.

O quinto sinal é o modelo declarar que terminou, e ele é o único que pode estar errado sem que ninguém perceba. Um trabalho de 2023 examinou a autocorreção intrínseca, sem feedback externo, e encontrou que o desempenho em raciocínio não melhora depois da revisão e em alguns arranjos piora, porque o modelo não tem como saber que errou3. Se ele não consegue avaliar de forma confiável a própria resposta, também não consegue avaliar de forma confiável se a tarefa acabou.

A saída não é abandonar o sinal, é acompanhá-lo de verificação. Reflexão sobre a falha, escrita em linguagem natural e guardada para a tentativa seguinte, melhora resultado quando existe algum sinal externo dizendo que a tentativa anterior deu errado4. O que muda de figura é a origem do sinal: teste que roda, comparação com estado esperado, validação de schema. Não a opinião do modelo sobre si mesmo.

Onde o loop quebra

Nenhum critério existe. É a falha da caixa âmbar da figura. “Continue até resolver”, sem teto, diante de um erro permanente, roda até alguém olhar a conta.

A janela enche e o começo some. Quando o histórico passa do limite, alguma coisa é descartada, e o que estava no começo vai primeiro. A instrução dita na volta 1 não existe mais na volta 18, e o modelo não avisa que esqueceu.

A mensagem de erro não diz nada. Falha ao consultar faz o modelo repetir a mesma chamada. Argumento data precisa estar em ISO 8601, recebi "ontem" faz ele corrigir. Texto de erro de ferramenta é prompt, com todos os efeitos de prompt, e quase sempre é escrito como se fosse para um arquivo de log.

A ferramenta devolve demais. Uma resposta de 3.000 linhas enche a janela em seis voltas. Cortar na ferramenta é quase sempre a edição de maior retorno num agente que se perde.

O paralelismo esconde uma dependência. Disparar três chamadas juntas corta latência quando elas são independentes. Quando a segunda precisava do resultado da primeira, o modelo recebe duas observações que não se encaixam e a volta seguinte começa de um estado inconsistente.

Como instrumentar

  1. Registre a trajetória inteira, com cada requisição enviada e cada resultado exatamente como o modelo o recebeu. Não a resposta final, não o que o terminal mostrou.
  2. Conte tokens por volta e guarde a série. É uma linha de código e é o que mostra qual ferramenta está enchendo a janela.
  3. Meça a distribuição de voltas das execuções que deram certo. O teto sai desse número, não de um palpite.
  4. Detecte repetição desde o primeiro dia. Três ações idênticas seguidas é uma condição de parada de cinco linhas.
  5. Devolva erro de ferramenta escrito para leitura. O que aconteceu, o que era esperado e o que fazer em seguida, em uma frase.
  6. Rode a mesma tarefa oito vezes e compare as trajetórias. Duas execuções que divergem na volta 4 dizem exatamente qual observação está sendo lida de dois jeitos.

O item 1 é o que quase ninguém tem no começo e é o primeiro que todo mundo procura no primeiro incidente.

Footnotes

  1. Yao et al. (2022) propuseram intercalar raciocínio e ação numa mesma sequência de geração, com o resultado da ação voltando como observação, que é a estrutura do loop usada até hoje.

  2. Liu et al. (2023) mediram uma curva em U: o desempenho é maior quando a informação relevante está no começo ou no fim do contexto e cai de forma significativa quando ela está no meio.

  3. Huang et al. (2023) encontraram que, sem feedback externo, revisar a própria resposta não melhora raciocínio e em alguns arranjos piora o resultado.

  4. Shinn et al. (2023) mostraram ganho ao transformar a falha em texto de reflexão guardado para a tentativa seguinte, num arranjo que depende de um sinal externo indicando que a tentativa anterior falhou.

Perguntas frequentes

Como funciona o loop de um agente?
Em quatro etapas por volta. O contexto inteiro vai ao modelo, o modelo devolve um texto de raciocínio e um pedido de ferramenta, o seu código valida e executa esse pedido, e o resultado é acrescentado ao contexto como uma nova mensagem. Aí a volta recomeça, com o contexto maior.
O que é o ciclo perceber, decidir e agir?
É o nome antigo, vindo de robótica, para o mesmo formato. Num agente de LLM perceber é ler o contexto, decidir é gerar o pedido de ferramenta e agir é o seu código executá-lo. A diferença é que não há sensor: a percepção é o texto que você mesmo escreveu no contexto.
Quantas iterações um agente costuma fazer?
Entre três e quarenta, com a maior parte das tarefas úteis abaixo de quinze. Abaixo de três o loop não está pagando por si. Acima de quarenta, o padrão quase sempre é repetição, não progresso, e vale olhar a trajetória antes de aumentar o teto.
Por que um agente entra em loop infinito?
Porque a condição de parada depende de um julgamento que só o modelo faz, e diante de um erro permanente ele nunca conclui que terminou. Sem teto de passos, de tokens e de tempo no seu código, o ciclo só para quando alguém percebe o gasto.
O que volta ao modelo depois de uma ferramenta?
Uma mensagem marcada como resultado de ferramenta, ligada ao identificador do pedido que a originou. Ela não é texto de usuário e não deve ser montada como se fosse. O que você escreve nela é o que o modelo vai ler, e o tamanho dela decide em qual volta a janela enche.
Dá para chamar várias ferramentas na mesma volta?
Dá, quando a API suporta e as chamadas são independentes entre si. Três consultas de leitura sem relação podem sair juntas e voltar juntas, o que corta latência. O que não dá é paralelizar chamadas em que a segunda depende do resultado da primeira.
O que acontece quando a janela enche no meio do loop?
Depende do que o seu código faz, porque o modelo não faz nada. Ou você trunca, ou resume o trecho antigo, ou move parte para fora do contexto. Em todas as opções some primeiro o que estava no começo, que costuma ser justamente a instrução original.

Referências

  1. Yao, S. et al.. ReAct: Synergizing Reasoning and Acting in Language Models (2022)arXiv:2210.03629
  2. Liu, N. F. et al.. Lost in the Middle: How Language Models Use Long Contexts (2023)arXiv:2307.03172
  3. Huang, J. et al.. Large Language Models Cannot Self-Correct Reasoning Yet (2023)arXiv:2310.01798
  4. Shinn, N. et al.. Reflexion: Language Agents with Verbal Reinforcement Learning (2023)arXiv:2303.11366