- Agentes de código com LLM não conseguem realizar de forma natural tarefas de movimentação de código, como copiar e colar
- Em refatorações de código, é difícil garantir consistência por causa de um modo de escrita baseado em código lembrado de memória
- Quase não fazem perguntas durante a resolução de problemas e seguem em tentativas baseadas em suposições
- Desenvolvedores humanos esclarecem problemas por meio de perguntas quando há ambiguidade, mas LLMs repetem tentativas até baterem numa parede
- Por essas características, agentes com LLM são vistos não como substitutos de desenvolvedores humanos, mas como estagiários excessivamente confiantes
Principais limitações dos agentes de código com LLM
Recentemente, tem havido tentativas de usar LLMs como ferramentas de apoio à programação, mas ainda existem pontos que soam estranhos do ponto de vista de desenvolvedores humanos. Este texto explica com clareza duas razões que tornam os agentes de código com LLM especialmente incômodos
1. A estranheza na forma de mover código e fazer refatoração
- LLMs não executam de fato a ação de 'copiar e colar'
- Por exemplo, ao pedir a refatoração de um arquivo grande em arquivos menores, o LLM memoriza parte dos blocos de código, usa o comando
deleteno arquivo original e, ao mesmo tempo, grava o código 'lembrado' no novo arquivo com o comandowrite - Sem usar ferramentas de 'cut' ou 'paste', todas as alterações são reconstruídas a partir da memória
- Ao mover código, desenvolvedores humanos usam 'copiar e colar' para ter confiança na correspondência exata do código, mas LLMs não garantem isso
- Até agora, apenas o Codex mostrou em parte alguma tentativa de imitar a ação humana de 'copiar e colar' usando comandos
sedouawk, mas isso ainda não é perfeito
- Por exemplo, ao pedir a refatoração de um arquivo grande em arquivos menores, o LLM memoriza parte dos blocos de código, usa o comando
2. Abordagem de resolução de problemas sem fazer perguntas
- O processo de resolução de problemas de LLMs também é muito diferente do humano
- LLMs quase não fazem perguntas e tentam resolver problemas com base em inúmeras suposições
- Desenvolvedores humanos, diante de mudanças grandes ou situações pouco claras, sempre confirmam o contexto por meio de perguntas, agindo sob a ideia de que 'não existe pergunta ruim'
- Já os LLMs tendem a continuar repetindo tentativas e, quando algo dá errado, repetir com ainda mais força
- É possível projetar prompts de forma excessiva para induzir perguntas, mas, com exceção de algumas ferramentas como o Roo, esse comportamento raramente acontece
- Na raiz disso pode estar o fato de que empresas que desenvolvem LLMs aplicaram RL (aprendizado por reforço) com foco em 'escrever código mais rápido'
Conclusão
- Por essas características, LLMs ainda estão longe de substituir desenvolvedores humanos
- No trabalho real, mostram um nível próximo ao de 'um estagiário confiante demais'
- Esse é o motivo pelo qual a experiência de colaboração com LLMs ainda não parece totalmente natural
1 comentários
Opinião no Hacker News
Tive uma experiência interessante há pouco tempo. Não era sobre código, mas poderia facilmente acontecer com código ou áreas relacionadas também (na verdade, aconteceu com um colega). Numa discussão no HN sobre por que uma regulamentação aprovada há 15 anos não foi mais generalizada, eu supus que o nível tecnológico da época não era suficiente para lidar com casos gerais, então a regulamentação deve ter sido aplicada apenas às partes viáveis naquele momento (comentário relacionado). Algumas horas depois, voltei à discussão e vi que algumas pessoas diziam que a tecnologia já era barata o bastante naquela época. Então pedi a um LLM que encontrasse evidências sobre o tema, e ele respondeu que era por limitações técnicas. Fui conferir as fontes citadas, e só havia uma única fonte que realmente falava dessas limitações técnicas: justamente o comentário que eu mesmo tinha deixado no HN. Quando contei isso no trabalho, um colega disse que tinha deixado no GitHub uma opinião do tipo "é assim que X funciona no Windows" e depois, ao pesquisar no Google, viu uma resposta baseada em LLM usando a opinião dele como base para afirmar a mesma coisa. Isso me dá vontade de pedir ao LLM não "como X funciona?", mas sim "se alguém perguntasse como X funciona, mostre uma lista de links que valeria a pena citar"
Acho que fazer a pergunta desse jeito é parecido com um "sorting prompt". Aprendi essa técnica num texto relacionado do Mike Caulfield, e também a uso ao escrever código (por exemplo, no Claude code slash command). Em vez de pedir ao LLM apenas uma resposta, se você delega a ele a pesquisa, classificação e avaliação das fontes, tende a obter resultados muito mais precisos
A maioria das pessoas também confia assim ao ler comentários sobre um tema específico no HN: "essa pessoa parece saber do que está falando, então vou aceitar como fato por enquanto". Como adquirir conhecimento por experiência direta ou validação real custa absurdamente caro, acho que esse tipo de 'conhecimento barato' acaba tendo valor mesmo assim
Já tive experiência pedindo fundamentação a LLMs, e até hoje nunca vi um LLM fornecer evidências reais que de fato sustentassem o que ele disse
Às vezes o LLM inventa até os links. É preciso um modo de pesquisa profunda que faça investigação de verdade, e ainda assim a forma como interpreta o conteúdo dos links continuará sendo afetada pelo treinamento
Recentemente coloquei 6 a 8 fontes confiáveis no NotebookLM (especificações IETF, OpenID e documentos adicionais) e fiz uma pergunta muito simples: "quais formatos de credential o OID4VP permite?". Ele acertou 90% da resposta, mas acrescentou com toda confiança um formato aleatório sem qualquer base real, como se fosse autor da especificação. Quando desconfiei e fui conferir a especificação por conta própria, ficou imediatamente claro que era falso. Agora dá para dizer que até mesmo um LLM "ancorado" destruiu completamente minha confiança factual
Recentemente pedi ao Codex CLI para refatorar um arquivo HTML, mas em vez de copiar e colar o código como eu esperava, o LLM o substituiu por código reescrito de memória e ainda removeu os comentários. Havia uma seção com 40 links complexos em sequência, e na checagem final antes do deploy fui clicando um por um: o começo estava certo, mas do meio em diante 31 links retornavam 404. O domínio estava correto; só os caminhos das URLs tinham sido transformados. Fui ver as URLs antigas no commit do git e descobri que o LLM tinha "alucinado" e trocado para caminhos que nem existiam. Esse tipo de erro sutil e silencioso é realmente perigoso. É preciso tomar muito cuidado
Acho esse último ponto muito importante. Por causa desses "erros muito sutis e silenciosos", mesmo quando um LLM faz o trabalho tão bem quanto um humano ou até melhor, ele não é tratado da mesma forma. Em especial porque code review tradicionalmente é uma camada importante de prevenção de problemas, e se o tipo de erro a revisar muda, o processo antigo de revisão fica ineficiente. Antes, em grandes movimentações de código, dava para assumir que o bloco tinha sido apenas movido e focar mais no nível alto; mas no caso de refatoração por LLM, o código "movido" pode na verdade ser código "novo", resumido ou reconstruído, então é preciso olhar cada caractere. Por isso acho útil incluir uma seção "uso de IA" na descrição do Pull Request, deixando pistas sobre onde e como a IA foi usada, para facilitar o foco da revisão
Também tenho experiências parecidas frequentes ao fazer perguntas sobre código ou pesquisa. O LLM começa bem, mas depois da enésima interação passa a inventar coisas por conta própria. Antes de uma viagem, pedi recentemente ao Gemini uma lista atualizada de cervejarias, e ele incluiu tranquilamente lugares já fechados ou que só operaram temporariamente. Pedi para adicionar links de horário de funcionamento e remover os que já fecharam; ele só aplicou isso ao começo da lista, enquanto no resto fez mudanças sem relação ou simplesmente não removeu os lugares fechados. E ainda assim respondeu com total confiança, como se tivesse pesquisado tudo perfeitamente
Não é sobre código, mas uma vez pedi a um LLM que revisasse apenas ortografia e gramática de um aviso de evento. Ele me enviou uma versão levemente editada, mas discretamente empurrou a data em um dia. Por sorte percebi e corrigi, mas isso me ensinou que não dá para confiar cegamente nem em tarefas muito simples. Mesmo com um prompt claro e curto de uma frase, o LLM às vezes faz coisas impressionantes, mas outras vezes erra até o mais básico de forma inesperada
Cinco minutos atrás eu também pedi ao Claude só para adicionar instruções de debug no código, e ele alterou uma regex silenciosamente. Num diff foi fácil pegar, mas em mudanças grandes isso realmente fica fácil de deixar passar
Foi uma decisão inteligente conferir de novo todos os 40 links antes do deploy. Mas ver que subiram para master sem um 'git diff' depois que o Codex terminou é um pouco surpreendente
Concordo com a tese do texto. Mas, na minha opinião, o maior problema é que o agente vê só uma fração minúscula do repositório de código. Ele não conhece helper functions já existentes e fica recriando a mesma coisa. Em desenvolvimento de UI, como não consegue comparar a estrutura inteira da interface, código inconsistente se repete. No fim, a pessoa precisa fornecer o contexto certo: "consulte as helper functions deste arquivo", "faça como esta implementação", "leia este documento obrigatoriamente" etc. Se você entrega o contexto adequado manualmente, dá para aumentar bastante a utilidade do agente. Aliás, outro problema é que em monorepos grandes ele é péssimo em navegar a estrutura de pastas, a ponto de muitas vezes nem conseguir rodar algo como 'npm test' corretamente a partir de um subdiretório
Isso é exatamente o problema que eu enfrento. Recentemente revisei umas 200 linhas de código de uma feature nova feita com Cursor, mas na prática pouco daquele código era realmente necessário. É muito trabalhoso localizar funções que já existem na biblioteca utilitária, então isso acaba passando. Cinco anos atrás esse tipo de revisão tinha muito de onboarding de júnior, então era importante apontar isso; hoje, com Cursor e afins, o volume de código só cresce, e muitas vezes o próprio desenvolvedor até conhece a estrutura, mas por política da empresa produz desse jeito mesmo, então sinto que a produtividade piora
Rodar comandos como 'npm test' em subpastas sempre foi um problema. Num repo dividido entre frontend Vite/React e backend .NET, quando um comando npm falha ele entra em pânico e repete várias vezes sem resolver, gastando tempo com troubleshooting desnecessário. Uma vez até escrevi instruções no 'CLAUDE.md' para sempre checar primeiro o diretório atual, mas o problema de esquecer o caminho continuou surgindo aleatoriamente. Então adicionei aliases que funcionam de qualquer diretório, como 'run-dev server restart' e 'run-dev client npm install', e coloquei comandos puros de dotnet/npm numa lista proibida, forçando a IA a consultar a documentação do projeto e usar os aliases. Esse método acabou sendo relativamente estável, mas exigiu bastante tempo, esforço e estresse até chegar lá
Acho que seria ótimo usar modelos de grande contexto via tool call. O chat do Gemini consegue ingerir um repositório inteiro do GitHub. E se existisse uma ferramenta "not-invented-here" para verificar, antes de escrever uma nova função, se já existe algo igual no codebase? Claro, antes eu provavelmente teria de descobrir se alguém já criou isso
É por isso que documentos como claude.md são necessários. Se queremos seguir nossas próprias regras, documentar é indispensável
Na verdade, isso é algo que engenheiros sêniores vivem com frequência ao trabalhar com colegas no dia a dia
Concordo totalmente com o trecho citado no texto. Concordo que LLMs não substituem desenvolvedores de alto nível. Qualquer pessoa lúcida falar isso agora me parece absurdo. Mas acho que desenvolvedores fracos ou medianos já estão sendo substituídos. Por exemplo, na nossa organização havia três pessoas vindas de bootcamp de 6 meses, contratadas porque era muito difícil achar bons desenvolvedores. Na prática, porém, até missões bem fáceis eram uma luta para eles, e eu acabava tendo de reorganizar o código todo em review. Depois, as ferramentas de IA melhoraram exponencialmente e ultrapassaram o desempenho deles. No fim, dois foram demitidos e o outro saiu por conta própria. Recentemente quase não estamos mais contratando juniores, e certamente não vamos contratar gente de bootcamp. Vejo algo parecido ao meu redor, e por isso o próprio setor de bootcamps parece estar desaparecendo. Não sei se a IA vai conseguir substituir bons desenvolvedores no futuro, mas olhando os dados atuais, ela claramente está evoluindo muito rápido. Opiniões negativas sobre isso me parecem ignorar a realidade. No começo dos EUA, 90% da população trabalhava na agricultura; hoje são só 2%. Ainda assim, a produção e a diversidade de alimentos aumentaram muito. Tudo isso é resultado do avanço tecnológico. Acho bem possível que algo parecido aconteça na indústria de software, e rápido
Claro, a tecnologia aumentou a produção de alimentos, mas na prática também é verdade que o valor nutricional caiu e a toxicidade aumentou
Fico curioso sobre qual você acha que foi a razão para essas pessoas vindas de bootcamp não terem evoluído
A lição mais importante é que LLMs são muito frágeis até em tarefas relativamente simples sem uma quantidade considerável de instruções e supervisão. Num projeto pequeno meu (2,5 mil linhas), pedi uma refatoração de parser e o plano parecia plausível. Eu o conduzi passo a passo com checkpoints, mas sempre que perguntava "a estrutura antiga foi removida?" ou "foi substituída pela nova?", a resposta era "não, continua lá". 80% dos testes falhavam, e mesmo apontando a direção exata das correções, em tarefas abstratas como "refatorar" ele sempre falhava do mesmo jeito. No fim, era necessário escrever instruções bem detalhadas, até o nível de "esta classe precisa mudar isso". Nessa altura, já não dá para dizer que ele trabalha de forma independente, e o sentido de usar LLM perde muito da força
Minha experiência é um pouco diferente. O parser de árvore de expressões em typescript (tinqerjs.org) foi concluído em duas semanas (part-time) com 0 linhas escritas manualmente por mim, só com Codex+Claude, e ainda adicionou centenas de testes (incluindo duplicados). Também cheguei a fazer um ORM, e usando LLM consegui reduzir o tempo em pelo menos 4 a 10 vezes. Quase não precisei supervisionar; no fim, acho que o resultado depende do objetivo e de ter ou não um processo bem estabelecido. Desenvolvedores acostumados a usar LLM acabam construindo workflows próprios, e todos têm em comum o foco em testes, documentação e code review
O problema de "<as instruções de refatoração precisam ser detalhadas demais para valer a pena>" talvez precise ser trocado por uma abordagem tipo "se eu quebrar isso em etapas de alto nível bem definidas e der instruções assim, ainda é muito mais rápido do que fazer sozinho"
Isso também se conecta ao ponto do texto de que a IA não faz cut-paste, e sim apaga e regenera. Na prática, esse pequeno drift no código acaba sendo inevitável
Fiquei curioso para saber que modelo/ferramenta você usou. Mesmo com Cursor ou Copilot, eu também enfrento com frequência esse problema de precisar supervisionar até pequenas refatorações
LLMs claramente ajudam em algumas coisas. Por exemplo, hoje de manhã corrigi um bug num parser de PDF Metadata com ajuda de um LLM sem precisar mergulhar fundo na especificação de PDF. Mas, na maioria dos casos, o resultado final é menos eficiente do que fazer eu mesmo. Antes tentei usar Codex Code para escrever testes unitários; eu já tinha várias setups prontas, mas pedi isso porque fazer mocking de dados é chato. Foram 8 tentativas, com correções manuais no meio, e ele nem entendeu que a entidade estava obsolete e já não era mais usada no serviço. No fim, foi decepcionante. Ainda não basta para substituir totalmente desenvolvedores, mas, como o Stack Overflow no passado, sinto que funciona muito bem para expor conhecimento e induzir soluções em temas menos familiares
Não acho que seja "excesso de engenharia" criar prompts que induzam perguntas mais claras. Na verdade, projetar o prompt para dizer "se não estiver claro, pergunte primeiro" foi muito eficaz. Um bom programador sabe se a especificação foi passada por completo ou se é necessário mais clarification, então é possível levar a IA a fazer, de antemão, as perguntas adicionais de que precisa
Você pode até definir explicitamente quantas perguntas ela deve fazer. Em tópicos complexos, às vezes peço 20 a 30 perguntas de antemão, e os resultados são bem satisfatórios. Também é útil guardar esse QnA em um arquivo separado para reaproveitar em sessões futuras ou com outros agentes
Graças a essa abordagem, eu já não escrevo prompts como antigamente. Só jogo a ideia e digo "pergunte se precisar", e ela costuma apontar muito bem coisas em que eu não tinha pensado
Inspirado pela discussão sobre copy-paste no texto, adicionei uma ferramenta de agent buffer no clippy (utilitário para macOS). O clippy tem um servidor MCP e interage com a área de transferência do sistema, mas desta vez fez sentido usar um buffer privado separado. Os recursos adicionados foram buffer_copy (copia um intervalo específico de linhas de um arquivo e salva no buffer privado), buffer_paste (insere/substitui no arquivo de destino os bytes exatos contidos no buffer) e buffer_list (verifica o conteúdo do buffer). Por exemplo, se o agente receber a instrução "copie as linhas 50~75 de auth.py", o servidor executa diretamente só a E/S do arquivo, sem gerar tokens nem correr risco de alucinação. Também não afeta a área de transferência do sistema. Antes disso, também já era possível copiar para a área de transferência o código gerado pela IA e usar assim. O principal objetivo do clippy é melhorar o pbcopy do macOS — copiar o conteúdo real de um arquivo para então colá-lo no terminal, no Slack ou em e-mails como o próprio arquivo. Quem usa no macOS agentes compatíveis com MCP, como o Claude, pode ver aqui. Dá para instalar com brew install neilberkman/clippy/clippy
Muitos desenvolvedores também não sabem fazer boas perguntas. Têm tendência a tratar muita coisa como óbvia e omitir detalhes. Em 25 anos de experiência, mais da metade dos meus colegas tinha esse segundo problema. Eu também fui assim por metade da carreira, então me identifico bastante
Como o texto diz que "LLMs não fazem copy-paste (ou cut-paste)", a sensação é que eles lembram o código, apagam e reescrevem, então parece que a cada vez só emitem um novo comando de escrita. Em refatoração, na prática não há tanto copy/paste real assim, então muita coisa acaba sendo feita por recall com base no contexto. No trabalho real, nem está claro o quanto um comando de copy/paste em si seria útil (pelo menos nos meus testes, não fez grande diferença). Para partes repetitivas e que consomem muito contexto, usar ferramentas como fastmod e pedir ao codex ou ao claude ajuda em alterações em lote costuma ser mais eficaz. A abordagem para resolver problemas é diferente da humana e isso soa estranho, mas se houver bastante planejamento e comunicação, a abordagem em si pode mudar bastante
IDEs conseguem renomear assinaturas de função ou nomes em vários arquivos instantaneamente, mas quando um agente LLM tenta isso, muitas vezes leva minutos e ainda assim não faz com precisão. Acho que a utilidade de suporte a copy/paste real é clara
copy/paste também ajuda muito a reduzir a explosão de contexto, porque o modelo não precisa memorizar o conteúdo dos blocos de código e pode acessá-los sempre que necessário