Sem o loop, não existe agent
Todo o segredo do Claude Code cabe em uma linha: while stop_reason == "tool_use"
O que um agent faz, de verdade?
Quando você roda o Claude Code no terminal e pede para ele "organizar todos os comentários TODO em uma lista", você vê: ele decide por conta própria fazer grep, depois cat em alguns arquivos e então gerar Markdown. O modelo não executa código diretamente — ele apenas solicita que seja executado. O que o faz parecer "ter mãos e pés" são as cerca de 30 linhas de código de cola ao redor dele.
Esta lição desmonta essa cola e a examina de perto. Ela se chama agent loop (laço do agente), e sua estrutura é:
while response.stop_reason == "tool_use": response = LLM(messages, tools) # 1. ask the model execute_tools(response.tool_calls) # 2. run what it asked for messages.append(tool_results) # 3. feed results back
Só isso. Nada mais. O Claude Code em produção empilha permissões, hooks, sub-agents, isolamento com worktree e compressão de memória em cima disso — mas o núcleo ainda são essas quatro linhas.
Intuição-chave: toda resposta do modelo é ou "quero chamar uma ferramenta" ou "terminei de falar". Enquanto estiver no primeiro estado, o loop continua; assim que entra no segundo, o loop sai. O critério é o campo stop_reason da resposta.
Veja o messages[] crescer passo a passo
O loop abaixo simula a tarefa: "Quais arquivos existem no diretório atual? Depois leia o package.json". Clique em Step; a cada clique você avança uma ação dentro do ciclo. À esquerda está a visão em bolhas de conversa, à direita está o array messages[] real enviado ao modelo — observe como ele cresce.
Os resultados das ferramentas precisam voltar ao histórico de mensagens
O erro mais comum de iniciantes é tratar "executar a ferramenta" como um efeito colateral — executou, acabou. Mas o modelo só vê messages[] na próxima rodada de inferência. O que não está lá, para o modelo nunca aconteceu. Esquecer o append quebra o loop inteiro.
Os erros não são todos iguais. Dois tipos comuns:
- Esquecer o append: o modelo não vê o resultado na próxima rodada, então repete o mesmo tool_use — e você tem um loop infinito.
- Fazer o append mas perder o
tool_use_id: a API da Anthropic retorna diretamente o errotool_result must have tool_use_id, e o loop trava na chamada de API.
A mesma tarefa: "Contar quantos arquivos Python existem no projeto". Dois versões lado a lado — veja a diferença no resultado final.
Interpretando o stop_reason
Toda resposta do modelo traz um stop_reason. Para decidir se o loop continua, basta olhar esse campo:
tool_use— o modelo quer chamar uma ferramenta, continue o loop.end_turn— o modelo considera que terminou, saia do loop.max_tokens— atingiu o limite de tokens e foi truncado, saia do loop (trate como exceção e informe o usuário que a saída está incompleta).stop_sequence— encontrou uma sequência de parada personalizada, saia do loop.
Escrever "continuar enquanto não for tool_use", ou ignorar max_tokens tratando-o como end_turn normal, são bugs frequentes.
Rode você mesmo
Clone localmente shareAI-lab/learn-claude-code:
git clone https://github.com/shareAI-lab/learn-claude-code cd learn-claude-code pip install -r requirements.txt cp .env.example .env # fill in ANTHROPIC_API_KEY python agents/s01_agent_loop.py
Depois peça para ele fazer algo real: Conta quantos arquivos .py tem neste repositório. Você verá ele enviar um ls -R, ver a saída, enviar um find . -name "*.py" | wc -l e então dar a resposta. Todo esse processo é esse loop em ação.