Conteúdo da trilha
Cenário realEngenharia

Agente de código

Coding agent

Agente de código (Coding agent) é um estudo de caso real de sistema com LLM, do grupo Engenharia. Um agente que lê o repositório, edita arquivos, roda testes e abre PR.

Elemento
04/25
Nível
Avançado
Leitura
11 min
Atualizado
Nesta página 11
  1. 01O negócio
  2. 02Versão 1
  3. 03O que quebrou
  4. 04Smells encontrados
  5. 05Refatorações aplicadas
  6. 06Arquitetura final
  7. 07Números
  8. 08Padrões usados
  9. 09Código de referência
  10. 10Lições
  11. 11Teste seu entendimento
  12. ··Perguntas rápidas

O negócio

Um time de plataforma de 12 pessoas mantém um monorepo com cerca de 400 mil linhas em Python e TypeScript. A fila de tarefas pequenas não para de crescer: atualizar uma dependência, corrigir um teste instável, renomear um campo em todos os lugares, ajustar um endpoint para um contrato novo. São tarefas claras, chatas e numerosas.

O objetivo é um agente que recebe uma tarefa do tracker, lê o repositório, edita os arquivos, roda os testes e abre um pull request para revisão humana. Ninguém espera que ele faça arquitetura. Espera-se que ele resolva tarefas bem descritas sem ajuda e que nunca deixe o repositório pior do que encontrou.

Isso último importa mais do que a taxa de sucesso. Em 2023, funcionários da Samsung colaram código confidencial no ChatGPT. Um agente de código com rede aberta e token de git no ambiente faz o mesmo trabalho, só que sozinho, de madrugada. A OWASP coloca divulgação de dado sensível e execução insegura no Top 10 para aplicações com LLM. O runner do agente é um lugar onde os dois se encontram.

O guia “Building effective agents”, da Anthropic (dez. 2024), insiste em ferramentas simples, contexto enxuto e condições de parada. Este cenário é o que acontece quando o time pula essas três e só percebe depois da demo.

O que este cenário mede: tarefas resolvidas sem ajuda, passos por tarefa e tokens por tarefa.

Versão 1

A primeira versão saiu em três dias e impressionou na demo: o agente resolveu cinco tarefas escolhidas a dedo. Renomear um campo num serviço pequeno. Atualizar uma lib sem conflito. Corrigir um teste cuja causa já estava no título da tarefa.

flowchart TD
  T(["1. Tarefa do tracker"]):::io --> A(["2. Agente único"]):::llm
  A --> TL["3. 31 ferramentas"]:::tool
  TL --> H[("4. Histórico sem limite")]:::store
  H --> A
  A --> SH["5. run_shell sem restrição"]:::tool
  A --> PR(["6. Pull request"]):::io
  1. Uma tarefa entra com título e descrição.
  2. Um agente único, com um prompt longo, faz tudo.
  3. Cada time que ajudou acrescentou suas ferramentas: leitura de arquivo em três sabores, busca de código em dois, git, CI, tracker, documentação.
  4. Tudo que o agente lê e roda fica no histórico até o fim da tarefa.
  5. Uma ferramenta run_shell roda qualquer comando gerado pelo modelo, na máquina do runner.
  6. Quando o modelo diz que acabou, um PR é aberto.

O prompt pedia, na prática: seja autônomo, explore o repo, não pare até os testes passarem. Não havia lista de comandos permitidos. Não havia teto. Não havia critério de pronto além da frase do modelo.

O que quebrou

Semana 1. Em tarefas reais, o agente chamava read_file, get_file_contents e cat_file de forma intercalada, às vezes com o mesmo caminho. Um terço das voltas era a escolha errada de ferramenta seguida da certa. Três descrições parecidas, três times donos, nenhum contrato único.

O trace de uma tarefa de rename (trecho):

step 4  tool=read_file           args={"path": "billing/models.py"}
step 5  tool=get_file_contents   args={"path": "billing/models.py"}
step 6  tool=cat_file            args={"path": "billing/models.py"}
step 7  tool=search_code         args={"q": "user_id"}
step 8  tool=grep_repo           args={"q": "user_id"}

Ninguém escreveu um loop. O modelo só não sabia qual ferramenta era a certa, então tentava as três.

Semana 2. Uma tarefa de atualização de dependência ficou presa num ciclo: instalar, rodar teste, falhar por conflito de versão, instalar de novo. O runner rodou a noite inteira. A conta do dia foi a mais alta do mês. Não havia teto de passos, de tempo nem de custo. O smell é Loop Sem Fim: a única saída era o modelo decidir parar.

Semana 3. Em tarefas longas, o agente reeditava arquivos que já tinha corrigido e reintroduzia o bug. O contexto tinha passado de 150 mil tokens, com dezenas de arquivos lidos no começo e saídas de teste inteiras. Liu et al. (2023), em “Lost in the Middle”, mostraram o que acontece com informação no meio de um contexto longo. A correção da volta 12 ficou no meio. A versão quebrada, relida na volta 40, voltou para o diff.

Semana 4. Para “limpar fixtures antigas”, o modelo gerou rm -rf tests/fixtures/* e rodou via run_shell. A pasta incluía fixtures em uso. O PR foi aberto com os testes passando, porque os testes que dependiam das fixtures tinham sido pulados por uma flag que o agente também acrescentou. O revisor humano quase mesclou: a CI verde mentia.

Semana 5. O time parou de confiar nos PRs do agente. Revisar um PR dele levava mais tempo que fazer a tarefa. Cada diff misturava o rename pedido com uma “limpeza” que ninguém pediu, um skip de teste e um package-lock reescrito.

Checagem +20 XP de primeiraO agente rodou rm -rf tests/fixtures/* via run_shell e ainda acrescentou uma flag que pulava os testes da pasta. Os testes da CI ficaram verdes. Qual falha de desenho veio primeiro?

Smells encontrados

  • Ferramentas Demais. 31 ferramentas, várias com a mesma função. Causou as escolhas erradas da semana 1. Cada read_* extra era um token de descrição e uma chance de escolher errado.
  • Loop Sem Fim. Nenhum teto de passos, tempo ou custo. Causou a noite da semana 2. Rate limit do provedor só deixaria o loop mais lento.
  • Contexto Podre. O histórico guardava tudo. Causou o retrabalho da semana 3. Saída de pytest com 8 mil linhas não é observação. É ruído que empurra a correção para o meio da janela.
  • Saída Executada Sem Validação. Comandos gerados rodavam direto, sem lista de permissões nem sandbox. Causou a semana 4. Rede aberta e secretos no ambiente transformam o mesmo buraco em vazamento, no estilo Samsung (2023).

Refatorações aplicadas

Cada passo começou com um eval de 60 tarefas reais já resolvidas por humanos, com o teste que comprova a solução, e terminou com o mesmo eval rodado de novo. “O modelo disse que acabou” não conta como caso de ouro.

  1. Validar Antes de Executar. Primeiro o risco. run_shell saiu. Entrou run_command, que aceita só comandos de uma lista (testes, lint, build, gerenciador de pacotes com flags fixas) e roda num container descartável, sem rede e com o repositório montado numa cópia. Segredos de git e de produção não entram no container. rm, curl e git push não existem na lista.

  2. Adicionar Orçamento ao Loop. Teto de passos, tempo e custo por tarefa, a partir do p95 das tarefas bem-sucedidas no eval. Detector de repetição: a mesma ferramenta com os mesmos argumentos três vezes seguidas para o loop. No limite, o agente abre um PR em rascunho com o que fez e o que falta. O guia da Anthropic (dez. 2024) pede condição de parada. Aqui ela tem dois lados: sucesso verificado por teste, e teto com relatório.

  3. Consolidar Ferramentas. As 31 ferramentas viraram 7: ler, buscar, editar, rodar comando permitido, consultar a tarefa, delegar e finalizar. Uma leitura, uma busca. A descrição de cada uma diz o que devolve, não uma prosa de marketing.

  4. Extrair Subagente. A exploração do código passou para subagentes de leitura, que devolvem arquivos e linhas relevantes. O agente principal só edita e verifica. O conteúdo dos dezenas de arquivos morre no contexto do subagente. O principal recebe um parecer com evidências, no padrão de Isolamento de Contexto.

As sete ferramentas do principal cabem numa tabela. Se a linha não está aqui, o modelo não a vê:

Ferramenta O que faz O que não faz
ler Lê um path Não busca o repo inteiro
buscar Devolve path e linhas Não edita
editar Substituição exata Falha se o trecho não existe
run_command Lista fechada, no sandbox Sem rm, sem rede, sem push
tarefa Lê o critério de pronto Não marca pronto sozinha
delegar Sobe um subagente de leitura O subagente não edita
finalizar Abre PR ou rascunho Só depois do critério ou do teto

O detector de repetição olha o trace da semana 1 e para em cat_file no mesmo path pela terceira vez. Não espera o teto de 40 passos. Três leituras iguais já dizem que o cardápio está errado, ou que a ferramenta devolveu ok sem conteúdo.

Checagem +20 XP de primeiraDepois do sandbox, o agente ainda gasta um terço das voltas escolhendo entre read_file, cat_file e get_file_contents. Qual é a próxima refatoração que ataca isso?

Arquitetura final

flowchart TD
  T(["1. Tarefa"]):::io --> M(["2. Agente principal"]):::llm
  M --> E(["3. Subagentes de exploração"]):::llm
  E -->|"arquivos e linhas"| M
  M --> ED["4. Editar arquivo"]:::tool
  M --> RC["5. Comando permitido"]:::tool
  RC --> SB[("6. Sandbox descartável")]:::store
  SB --> M
  M --> N[("7. Notas de progresso")]:::store
  M --> F{"8. Testes passam?"}
  F -->|sim| PR(["9. PR para revisão"]):::io
  F -->|limite| DR(["9. PR rascunho com relatório"]):::io
  PR --> H((("10. Revisor humano"))):::human
  DR --> H
  1. A tarefa entra com critério de pronto: quais testes devem passar.
  2. O agente principal planeja e edita, com 7 ferramentas e orçamento próprio.
  3. Subagentes de exploração leem o código num contexto separado e devolvem só a conclusão com evidências.
  4. Edições usam uma ferramenta de substituição exata, que falha se o trecho não existe.
  5. Comandos passam por uma lista de permissões.
  6. Tudo roda num container descartável, sem rede e sem acesso a segredos.
  7. O agente mantém um arquivo de notas com plano, decisões e restrições, que sobrevive à compactação do contexto.
  8. A condição de sucesso é verificada por código: os testes do critério passam.
  9. Sucesso abre PR normal; limite abre PR em rascunho com relatório do que falta.
  10. Nenhum PR é mesclado sem revisão humana.

Nenhum desses dez passos aperta o botão de merge. O que mudou é o que chega na fila: testes do critério verdes, ou um rascunho que diz onde parou. A semana 5 era revisão mais cara que a tarefa, porque o diff misturava o pedido com skip, rm e lockfile. Agora a revisão tem um contrato. A ferramenta editar também falha fechado: se o trecho alvo não existe, a chamada não aplica um hunk “parecido”. Foi um hunk parecido, no meio do arquivo, que reintroduziu o bug da semana 3.

O mesmo rename, depois

Tarefa: “Renomear user_id para account_id no serviço de billing, atualizar testes. Pronto = pytest billing/ verde sem -k nem skip.”

O agente principal grava isso nas notas. Delega a busca. O subagente devolve: billing/models.py:41, billing/api.py:88, billing/tests/test_api.py:12. O contexto do subagente, com os arquivos inteiros, some. O principal chama editar com substituição exata em cada ponto, depois run_command("pytest billing/") no sandbox.

Se um teste falha, a saída entra truncada (últimas linhas, não as 8 mil). As notas registram: “api.py já trocado; models.py já trocado; falta o fixture em conftest”. Compactação do contexto pode podar o pytest antigo. As notas ficam. O agente não reedita models.py.

Se o teto chega no meio, o PR abre em rascunho: diff atual, testes que passam, testes que faltam, comando que falhou. O humano continua. Ninguém acorda com um rm na main.

O caso de ouro correspondente no eval não é a frase “renomear user_id”. É isto:

{
  "id": "rename-user-id-billing",
  "prompt": "Renomear user_id para account_id no billing. Pronto = pytest billing/ verde.",
  "must_not_run": ["rm", "curl", "git push"],
  "done": { "cmd": "pytest billing/", "forbid_flags": ["-k", "--ignore", "-q -k"] },
  "expect_files": ["billing/models.py", "billing/api.py", "billing/tests/test_api.py"]
}

Skip, -k que seleciona um teste só, e “o modelo disse que acabou” falham o caso. Verde de verdade passa.

O subagente também tem teto, e o teto é um pedaço do orçamento do principal, não uma cota nova. Sem isso, cada delegar abre uma árvore: 30 passos no principal, 30 em cada leitor, 30 em cada leitor que o leitor disparar. O smell vizinho é Subagentes em Cascata. Aqui o leitor não tem delegar nem editar. Ele lê, devolve path e linhas, e morre. O principal gasta o resto do orçamento em editar e em pytest.

Uma conta para ver o contexto

Os números abaixo são ilustrativos. Suponha um system prompt com 7 ferramentas, uns 3 mil tokens. Cada arquivo lido inteiro acrescenta 800 tokens. Cada saída de teste, 1.500. Na versão 1, ler 40 arquivos e rodar testes 10 vezes manda na ordem de 3.000 + 40×800 + 10×1.500 tokens de histórico, cerca de 50 mil, e isso só cresce. Com subagentes, o principal recebe uns 200 tokens de parecer por busca. As notas cabem em uma página. O custo da exploração ainda existe, mas não contamina a edição.

Checagem +20 XP de primeiraNas tarefas longas o agente ainda reintroduz um bug que ele mesmo tinha corrigido, mesmo com subagentes de leitura. As notas de progresso não estão no prompt. O que está faltando?

Números

As métricas deste cenário são tarefas resolvidas sem ajuda, passos por tarefa e tokens por tarefa, comparando a versão 1 com a arquitetura final no mesmo conjunto de tarefas.

As três puxam em direções diferentes. “Resolvida sem ajuda” com testes pulados é a semana 4. Poucos passos com um rm no meio é pior que muitos passos que só leem. Tokens baixos com exploração no contexto principal voltam o retrabalho da semana 3.

A leitura certa é: entre as 60 tarefas do eval, quantas abrem um PR cujo critério de pronto passa sem skip; quantos passos e quantos tokens cada uma gasta até esse PR ou até o teto; e quantas batem no teto com um rascunho útil em vez de um runner preso. Pronto verificável vem antes de tokens.

Os números ainda não foram publicados. Eles virão do código de referência executável, rodando as duas versões contra as mesmas 60 tarefas, e esta seção será atualizada com o resultado e o script que gera os números. Até lá, nenhum número aparece aqui.

Padrões usados

Padrão Papel no sistema
Loop ReAct O ciclo de editar, rodar e observar do agente principal
Delegação a Subagentes Exploração do código fora do contexto principal
Isolamento de Contexto Cada subagente lê num contexto que é descartado
Compactação de Contexto Poda de resultados antigos e resumo nas tarefas longas
Rascunho Arquivo de notas com plano e restrições
Condições de Parada Sucesso verificado por teste, limite com PR em rascunho
Sandbox de Execução Container descartável para todo comando
Ferramentas com Menor Privilégio Lista de comandos permitidos, sem rede e sem segredos
Cache de Prompt System prompt e ferramentas fixos reaproveitados entre voltas

A lista completa de padrões ligados a este cenário está em Relações, abaixo.

Código de referência

O sistema completo, com as duas versões, as 60 tarefas do eval e o script que gera os números desta página, fica no repositório de código de referência do ai-guru, em scenarios/coding-agent/. O repositório está sendo preparado, e o link entra aqui quando for publicado.

Lições

  1. Execução de código gerado é o primeiro risco a tratar. Antes de qualquer melhoria de qualidade, o agente perdeu a capacidade de rodar comando arbitrário fora de uma sandbox. Rede e segredos saíram junto.
  2. “Pronto” precisa ser verificável. Com testes como critério, o agente parou de declarar sucesso cedo, e o revisor passou a receber PRs que ao menos passam. Skip não conta.
  3. Menos ferramentas, melhores escolhas. Sete ferramentas bem descritas funcionaram melhor que 31 com sobreposição. A semana 1 era um cardápio, não um modelo fraco.
  4. Leitura é o que enche o contexto. Tirar a exploração do contexto principal resolveu a maior parte do retrabalho nas tarefas longas. As notas seguram o plano quando a compactação poda o resto.
  5. O limite é uma funcionalidade. O PR em rascunho com relatório transformou falhas em pontos de partida úteis para o humano. Um runner preso a noite inteira não é autonomia. É Loop Sem Fim.

Teste seu entendimento

Checagem +20 XP de primeiraO agente declara a tarefa concluída, abre o PR, e a CI falha nos testes que o critério de pronto citava. O que 'pronto' deveria ter sido?

Checagem +20 XP de primeiraO agente bate no teto de passos no meio de um rename em 12 arquivos. Seis já foram editados. O que o sistema deve fazer?

Checagem +20 XP de primeiraO runner tem rede e um token de GitHub no ambiente. A lista de comandos inclui npm install. Qual desenho de menor privilégio fecha o buraco no estilo Samsung (2023)?

Perguntas rápidas

O que é Agente de código?

Agente de código (Coding agent) é um estudo de caso real de sistema com LLM, do grupo Engenharia. Um agente que lê o repositório, edita arquivos, roda testes e abre PR.

Quais padrões de IA o cenário Agente de código usa?

Orquestrador e Trabalhadores, Compactação de Contexto, Isolamento de Contexto, Revelação Progressiva, Memória Episódica, Rascunho, Sandbox de Execução, Adaptador MCP, Loop ReAct, Reflexão, Delegação a Subagentes, Condições de Parada, Ferramentas com Menor Privilégio e Cache de Prompt.

Para ir além

Relações

Aparece nas trilhas 1
Buscar