Pular para o conteúdo
Categoria: Desenvolvendo com IA14 min de leitura

O padrão ReAct: raciocínio e ação em agentes de IA

Por Lucas Andrade ·

Entenda como o ciclo de pensar, agir e observar do padrão ReAct permite que LLMs resolvam tarefas complexas passo a passo usando ferramentas externas — com exemplos e armadilhas.

O padrão ReAct: raciocínio e ação em agentes de IA

ReAct é um dos padrões mais influentes na construção de agentes de IA modernos. Seu nome combina Reasoning (raciocínio) e Acting (ação), e sua ideia central é elegante: em vez de fazer o modelo pensar OU agir, faça-o intercalar os dois em um ciclo. Neste artigo você vai entender como esse loop funciona, por que ele é tão eficaz, como implementá-lo na prática e quais armadilhas evitar.

O problema que o ReAct resolve

Um LLM puro tem duas limitações sérias. Primeiro, ele raciocina apenas sobre o que está no seu contexto — não pode buscar informação nova nem verificar fatos no mundo. Segundo, quando tenta resolver problemas complexos "de cabeça", acumula erros e alucinações sem oportunidade de se corrigir.

Pense em um modelo a quem você pergunta a cotação atual do dólar ou o status de um pedido no seu banco de dados. Por melhor que ele seja, a resposta correta simplesmente não está nos pesos da rede: é um dado externo, dinâmico, que muda a cada minuto. Sem uma forma de agir sobre o mundo, o modelo só pode adivinhar — e adivinhar com confiança é exatamente o que chamamos de alucinação.

A técnica de Chain-of-Thought, de Wei e colegas (2022), melhorou o raciocínio ao fazer o modelo pensar em voz alta, passo a passo — algo aprofundado em Chain-of-Thought: fazendo a IA pensar passo a passo. Mas o Chain-of-Thought sozinho ainda é um monólogo fechado: o modelo não consulta o mundo externo durante o raciocínio.

ReAct, proposto por Yao e colegas (2023), une as duas capacidades. O modelo raciocina E age, usando o resultado de cada ação para informar o próximo passo do raciocínio. Assim ele pode buscar dados reais, corrigir suposições erradas e fundamentar suas conclusões.

O ciclo: Thought, Action, Observation

O coração do ReAct é um loop de três etapas que se repete até a tarefa terminar:

  1. Thought (Pensamento): o modelo raciocina sobre o estado atual e decide o que fazer a seguir.
  2. Action (Ação): o modelo escolhe uma ferramenta e seus argumentos.
  3. Observation (Observação): o sistema executa a ferramenta e devolve o resultado ao modelo.

O resultado da observação volta para o contexto, e o ciclo recomeça. O modelo pode então pensar de novo, agir de novo, observar de novo — até concluir que tem a resposta final.

Veja um traço simplificado de execução para a pergunta "Qual a população da capital do Japão?":

Thought: Preciso descobrir qual é a capital do Japão.
Action: buscar("capital do Japão")
Observation: A capital do Japão é Tóquio.

Thought: Agora preciso da população de Tóquio.
Action: buscar("população de Tóquio")
Observation: Tóquio tem cerca de 14 milhões de habitantes.

Thought: Já tenho a resposta.
Final Answer: A capital do Japão é Tóquio, com cerca de 14 milhões de habitantes.

Repare como cada observação alimenta o próximo pensamento. O modelo não adivinhou — ele consultou, observou e raciocinou sobre fatos reais.

Por que a observação é o ingrediente secreto

A grande diferença em relação ao Chain-of-Thought está na linha Observation. No Chain-of-Thought, o modelo escreveria algo como "a população de Tóquio é provavelmente uns 13 ou 14 milhões" — um chute educado. No ReAct, esse número vem de fora, de uma fonte real, e o modelo apenas o incorpora. É a diferença entre lembrar e consultar. Quando o modelo erra uma suposição no primeiro passo, a observação do passo seguinte frequentemente revela o erro, dando a chance de corrigir o rumo.

Por que intercalar raciocínio e ação funciona tão bem

Yao e colegas (2023) demonstraram que essa sinergia traz benefícios concretos:

  • Menos alucinação: como o modelo verifica fatos via ferramentas, ele se ancora em informação real em vez de inventar.
  • Raciocínio guiado por evidência: cada passo é informado pelo resultado anterior, reduzindo desvios.
  • Recuperação de erros: se uma ação retorna algo inesperado, o pensamento seguinte pode ajustar a estratégia.
  • Interpretabilidade: o traço de pensamentos e ações é legível, o que facilita depurar o comportamento do agente.

Em outras palavras, o raciocínio torna as ações mais inteligentes, e as ações tornam o raciocínio mais fundamentado. É um ciclo virtuoso.

No artigo original, ReAct superou tanto o Chain-of-Thought puro (que alucinava mais por não ter como verificar) quanto agentes que só agiam sem raciocinar (que se perdiam por não planejar). A combinação venceu em benchmarks de pergunta-e-resposta com busca (HotpotQA) e em ambientes interativos de texto (ALFWorld, WebShop). A lição é que nenhuma das duas metades sozinha basta.

ReAct e function calling

Na implementação prática, a etapa de "Action" depende de o modelo conseguir invocar ferramentas de forma estruturada. É aqui que entra o function calling: como dar ferramentas ao seu LLM. Em vez de o modelo escrever uma string como buscar("Tóquio") em texto livre, os provedores modernos oferecem uma saída estruturada em que o modelo retorna o nome da função e os argumentos em formato parseável.

Essa evolução é importante. Na formulação original do ReAct, a "Action" era texto livre que o sistema precisava parsear com expressões regulares frágeis — qualquer variação na forma como o modelo escrevia quebrava o parser. Com function calling nativo, o provedor garante uma estrutura JSON validada, eliminando boa parte dessa fragilidade.

Um esqueleto de loop ReAct com function calling fica assim:

def agente_react(pergunta, ferramentas, max_passos=10):
    mensagens = [{"role": "user", "content": pergunta}]
    for _ in range(max_passos):
        resposta = modelo.chamar(mensagens, tools=ferramentas)
        if resposta.tem_chamada_de_ferramenta():
            ferramenta = resposta.chamada_de_ferramenta
            observacao = executar(ferramenta.nome, ferramenta.args)
            mensagens.append(resposta)            # o "Thought + Action"
            mensagens.append(observacao_como_msg(observacao))  # a "Observation"
        else:
            return resposta.texto                 # resposta final
    return "Limite de passos atingido."

O max_passos é importante: ele evita loops infinitos quando o modelo não converge para uma resposta.

Definindo boas ferramentas

A qualidade de um agente ReAct depende menos do prompt e mais das ferramentas que você oferece. Uma boa definição de ferramenta tem:

  • Nome claro e descritivo (buscar_pedido_por_id, não func1).
  • Descrição que diz quando usar. O modelo escolhe a ferramenta lendo essa descrição.
  • Parâmetros tipados e documentados, idealmente com um schema JSON.
  • Mensagens de erro úteis. Se a ferramenta falha, a observação deve explicar por quê, para o modelo se ajustar.
ferramenta_clima = {
    "name": "obter_clima",
    "description": "Retorna o clima atual de uma cidade. "
                   "Use quando o usuário perguntar sobre temperatura ou tempo.",
    "parameters": {
        "type": "object",
        "properties": {
            "cidade": {"type": "string", "description": "Nome da cidade"}
        },
        "required": ["cidade"]
    }
}

Uma descrição vaga é a causa número um de um agente escolher a ferramenta errada. Trate as descrições como parte do prompt: elas são o que o modelo lê para decidir.

Onde o ReAct se encaixa na construção de agentes

ReAct é, em essência, o motor de decisão dentro de um agente. Em como construir um agente de IA que executa tarefas e em o que é um agente de IA? Definição e exemplos, o ciclo pensar-agir-observar é exatamente o que dá ao agente sua autonomia: a capacidade de decidir os próprios passos em vez de seguir um roteiro fixo.

Praticamente todos os frameworks de agentes — LangChain, LlamaIndex, AutoGPT e similares — implementam alguma variante do ReAct sob o capô. Entender o padrão ajuda a depurar e a otimizar qualquer um deles.

ReAct versus fluxos fixos

Nem toda tarefa precisa de um loop ReAct. Se o caminho é conhecido e linear — "extraia estes campos, valide, salve no banco" — um fluxo fixo (uma sequência codificada de chamadas) é mais barato, mais rápido e mais previsível. O ReAct brilha quando o caminho não é conhecido de antemão: o modelo precisa decidir, a cada passo, qual a próxima ação com base no que descobriu. Essa é a regra prática: use ReAct quando há genuína incerteza sobre a sequência de passos; use um fluxo fixo quando a sequência é determinística.

Limitações e cuidados

ReAct é poderoso, mas não é mágico. Alguns pontos de atenção:

  • Custo e latência: cada passo é uma chamada ao modelo. Tarefas longas ficam caras e lentas.
  • Loops improdutivos: o modelo pode repetir a mesma ação sem progredir. Limite de passos e detecção de repetição ajudam.
  • Qualidade das ferramentas: observações ruins levam a raciocínio ruim. Ferramentas confiáveis e mensagens de erro claras são essenciais.
  • Segurança: dar ferramentas a um agente amplia a superfície de ataque — atenção a entradas maliciosas que podem desviar o ciclo.
  • Janela de contexto: a cada passo, o histórico de pensamentos e observações cresce. Tarefas longas podem estourar o contexto, exigindo sumarização ou descarte de passos antigos.

Estratégias para os loops improdutivos

O loop improdutivo é a falha mais comum em produção. O modelo chama buscar("X"), recebe uma observação que não resolve, e chama buscar("X") de novo, repetindo indefinidamente. Mitigações práticas:

  • Detecção de repetição: se a mesma ação com os mesmos argumentos aparecer duas vezes seguidas, intervenha (force uma resposta ou injete uma dica).
  • Orçamento de passos: além do teto duro de max_passos, avise o modelo no prompt quantos passos restam, para ele priorizar.
  • Observações que reconhecem o impasse: se uma ferramenta não tem resultado, a observação deve dizer "nenhum resultado encontrado; tente outra abordagem", em vez de devolver vazio silenciosamente.

Variações do padrão

Desde 2023, surgiram extensões do ReAct que vale conhecer:

  • Reflexão: o agente, ao terminar (ou falhar), gera uma autocrítica que é injetada na próxima tentativa, aprendendo com o erro entre execuções.
  • Plan-and-Execute: separa uma fase de planejamento (gerar a lista de passos) de uma fase de execução, reduzindo o número de chamadas caras ao modelo grande.
  • Árvores de raciocínio: em vez de um único caminho linear, o agente explora múltiplos ramos e escolhe o melhor.

Todas mantêm o núcleo do ReAct — pensar, agir, observar — e adicionam camadas por cima.

Um exemplo de implementação mais concreta

O esqueleto anterior esconde detalhes que importam na prática. Veja uma versão um pouco mais completa, com tratamento de erro na execução da ferramenta e uma mensagem de sistema que estabelece o comportamento do agente:

SISTEMA = """Você é um agente que resolve tarefas usando ferramentas.
Pense passo a passo. Use uma ferramenta de cada vez. Quando tiver a
resposta final, responda em texto sem chamar nenhuma ferramenta."""

def executar_ferramenta(nome, args, registro):
    fn = registro.get(nome)
    if fn is None:
        return f"Erro: ferramenta '{nome}' não existe."
    try:
        return str(fn(**args))
    except Exception as e:
        # A observação descreve a falha; o modelo pode se ajustar.
        return f"Erro ao executar {nome}: {e}"

def agente_react(pergunta, ferramentas, registro, max_passos=12):
    mensagens = [
        {"role": "system", "content": SISTEMA},
        {"role": "user", "content": pergunta},
    ]
    ultima_acao = None
    for passo in range(max_passos):
        resposta = modelo.chamar(mensagens, tools=ferramentas)
        if not resposta.tem_chamada_de_ferramenta():
            return resposta.texto

        chamada = resposta.chamada_de_ferramenta
        assinatura = (chamada.nome, str(chamada.args))
        if assinatura == ultima_acao:
            # Repetição detectada: força o modelo a mudar de estratégia.
            obs = "Você repetiu a mesma ação. Tente uma abordagem diferente."
        else:
            obs = executar_ferramenta(chamada.nome, chamada.args, registro)
        ultima_acao = assinatura

        mensagens.append(resposta)
        mensagens.append(observacao_como_msg(obs))
    return "Limite de passos atingido sem resposta final."

Repare em três decisões de projeto: a mensagem de sistema deixa explícito como terminar (texto sem ferramenta), a execução nunca derruba o loop por uma exceção (o erro vira observação), e a detecção de repetição quebra o loop improdutivo mais comum. Esses três detalhes resolvem a maioria dos problemas que você encontra ao colocar um agente ReAct em produção.

Depurando um agente ReAct

Quando um agente se comporta mal, o traço de Thought/Action/Observation é o seu melhor amigo. Imprima ou registre cada passo e procure por padrões:

  • A observação não responde à ação? A ferramenta está com bug ou recebendo argumentos errados. Olhe os args que o modelo gerou.
  • O modelo escolhe a ferramenta errada repetidamente? A descrição da ferramenta está vaga ou ambígua. Melhore o texto que descreve quando usá-la.
  • O raciocínio está correto mas a resposta final ignora as observações? O contexto pode estar grande demais e as observações antigas "se perderam" — considere sumarizar.
  • O agente desiste cedo? O modelo pode estar interpretando uma observação de erro como impasse final. Ajuste a mensagem de erro para sugerir alternativas.

A regra geral: quase todo problema de um agente ReAct se manifesta de forma visível no traço. Resista à tentação de só olhar a resposta final; o valor está no caminho.

Além do ReAct: rumo a múltiplos agentes

Quando uma tarefa fica grande demais para um único loop ReAct gerenciar, uma alternativa é dividir o trabalho entre agentes especializados que colaboram — tema explorado em sistemas multi-agentes com LLMs: quando vários modelos colaboram. Cada agente pode rodar seu próprio ciclo ReAct, e um orquestrador coordena o conjunto.

Um exemplo realista de ponta a ponta

Para fixar, imagine um agente de suporte que responde "Meu pedido 4821 já foi enviado?". Ele tem duas ferramentas: buscar_pedido(id) e consultar_rastreio(codigo). Um traço possível:

Thought: O usuário quer saber o status de envio do pedido 4821.
         Primeiro preciso buscar os dados do pedido.
Action: buscar_pedido(id="4821")
Observation: {"id": "4821", "status": "enviado", "rastreio": "BR9912"}

Thought: O pedido foi enviado e tem código de rastreio BR9912.
         Vou consultar o rastreio para dar uma resposta mais útil.
Action: consultar_rastreio(codigo="BR9912")
Observation: {"situacao": "em trânsito", "previsao": "2026-07-02"}

Thought: Tenho status e previsão. Posso responder.
Final Answer: Sim! O pedido 4821 foi enviado (código BR9912) e está em
              trânsito, com previsão de entrega para 02/07/2026.

Note como o agente não respondeu na primeira observação, embora já soubesse que o pedido fora enviado. O raciocínio decidiu que valia a pena enriquecer a resposta com o rastreio — uma decisão que um fluxo fixo não tomaria sozinho. É exatamente essa capacidade de decidir o próximo passo com base no que descobriu que justifica o ReAct para tarefas com incerteza.

Repare também que as observações são JSON estruturado. Devolver dados estruturados em vez de prosa livre ajuda o modelo a extrair os campos certos sem ambiguidade, e é uma boa prática geral no design de ferramentas.

Perguntas frequentes

ReAct e Chain-of-Thought são a mesma coisa? Não. Chain-of-Thought é só a parte do raciocínio em voz alta. ReAct adiciona ações e observações: o modelo pode consultar o mundo durante o raciocínio, não só pensar isoladamente.

Preciso de um framework para usar ReAct? Não. O loop é simples o bastante para você escrever à mão em algumas dezenas de linhas, como no exemplo acima. Frameworks ajudam com tooling, mas entender o loop cru é o que permite depurar quando algo dá errado.

Quantos passos um agente ReAct costuma levar? Depende da tarefa. Consultas simples resolvem em 1 a 3 passos; tarefas de pesquisa multietapa podem levar 5 a 10. Definir um teto entre 8 e 15 costuma ser um bom ponto de partida.

ReAct funciona com qualquer modelo? Funciona melhor com modelos capazes de seguir instruções e de usar ferramentas de forma estruturada. Modelos menores ou antigos podem ter dificuldade em manter o formato e em decidir bem entre ferramentas.

Conclusão

O padrão ReAct resolveu um problema fundamental dos LLMs ao unir raciocínio e ação em um único ciclo iterativo. Em vez de pensar isoladamente (como no Chain-of-Thought de Wei et al., 2022) ou agir cegamente, o agente pensa, age, observa o resultado e recomeça — fundamentando cada decisão em evidência real (Yao et al., 2023). Esse loop simples é o coração da maioria dos agentes de IA atuais. As variações modernas — reflexão, plan-and-execute, multi-agente — apenas estendem esse núcleo. Compreendê-lo bem, incluindo suas armadilhas de custo, loops e contexto, é o que separa quem apenas usa um framework de quem entende, depura e estende o comportamento de um agente.

Referências

  • Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K., Cao, Y. (2023). ReAct: Synergizing Reasoning and Acting in Language Models. ICLR.
  • Wei, J., Wang, X., Schuurmans, D., Bosma, M., Ichter, B., Xia, F., Chi, E., Le, Q., Zhou, D. (2022). Chain-of-Thought Prompting Elicits Reasoning in Large Language Models. NeurIPS.
  • Shinn, N., Cassano, F., Gopinath, A., Narasimhan, K., Yao, S. (2023). Reflexion: Language Agents with Verbal Reinforcement Learning. NeurIPS.

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly