Disclaimer
Este texto foi inicialmente concebido pela IA Generativa em função da transcrição de um vídeo do canal Dev Eficiente, apresentado por Alberto Souza. Se preferir acompanhar por vídeo, é só dar o play.
Introdução
Uma pergunta que aparece com frequência quando falamos de agentes de código é qual o nível de desconfiança que devemos ter de um código gerado por um modelo. Não um modelo qualquer, mas os modelos de ponta que usamos no dia a dia. A resposta costuma vir carregada de intuição, e intuição raramente é um bom instrumento de decisão técnica.
Neste post eu reviso um artigo científico que tenta responder isso com dados: "Human written versus AI generated code: a large scale study of defects, vulnerabilities and complexities". O estudo compara código escrito inteiramente por pessoas com código escrito inteiramente por LLMs, em três dimensões de qualidade: defeitos, vulnerabilidades de segurança e complexidade estrutural.
Vale um recorte temporal honesto antes de qualquer conclusão. O artigo é de 2025, e este vídeo foi gravado em junho de 2026. Em um cenário de evolução acelerada dos modelos e dos agentes construídos sobre eles, um ano é bastante tempo. Então trate os números como uma fotografia de um momento que já passou, e preste atenção principalmente na direção que eles apontam.
Como o estudo foi feito
O ponto de partida foi um dataset com centenas de milhares de funções, algo em torno de 200 e poucas mil em Python e um número parecido em Java, mineradas de dezessete a dezoito mil repositórios do GitHub. Todas escritas por seres humanos.
O dataset pronto não trazia a documentação das funções. Então os autores executaram um processo para casar cada função de volta ao seu repositório original e recuperar a documentação. A partir dessa documentação, rodaram prompts contra três famílias de modelos para gerar implementações equivalentes: um modelo da OpenAI, o GPT-3.5, um modelo da família Qwen e um modelo da família DeepSeek. Foram quatro implementações de cada função, para poder comparar.
Um detalhe importante sobre a metodologia, porque ele muda a leitura de tudo o que vem depois: não havia agente, não havia contexto adicional, não havia harness. Era um prompt direto contra a documentação, pedindo a implementação naquela linguagem. Um cenário muito mais pobre do que qualquer fluxo sério de geração de código hoje.
O estudo se organiza em torno de três perguntas:
- Os tipos e a frequência de defeitos diferem entre código humano e código gerado, e isso muda conforme a linguagem?
- Existe diferença nas vulnerabilidades de segurança entre código humano e código gerado?
- As métricas de complexidade estrutural variam entre um e outro?
O que conta como defeito aqui
Antes dos resultados, é preciso alinhar o vocabulário, porque a palavra defeito carrega mais peso do que o estudo lhe atribui. A classificação usou o framework Orthogonal Defect Classification, bem aceito na literatura, com regras aplicadas por ferramentas de análise estática tanto para Python quanto para Java.
Defeito, nesse contexto, não é sinônimo de código que não funciona. É uma categoria ampla que inclui desde erros que impedem a execução até práticas desencorajadas. Alguns tipos, para dar concretude:
- Assignment: erros de inicialização ou de binding de variável, por exemplo usar uma variável que não foi inicializada. Esse tende a quebrar de fato.
- Algoritmo: problemas de lógica. Aqui entra também algo como blocos aninhados demais, que não afeta a corretude, mas é considerado um defeito de estrutura.
- Interface: problemas de comunicação entre módulos, como um parâmetro sem valor definido.
- Checking: validação de falhas e tratamento de erro faltando, como a ausência de checagem de timeout ou um bloco de catch vazio.
- Timing e serialização: questões de concorrência, ordenação e sincronização.
- Function, class e object: problemas estruturais de design.
Guarde isso: quando o estudo diz que um código tem mais defeitos, boa parte disso é prática ruim capturada por regra estática, não é, necessariamente, código que não roda.
Resultado 1: defeitos
O resultado dos defeitos surpreende quem chega com a intuição pronta. O código que saiu com menos defeitos foi o gerado pelo GPT-3.5, um modelo antigo se comparado ao que temos hoje e, lembrando, sem agente e sem contexto. Ainda assim, com menos defeitos.
Em Python, o código humano foi menos ruim do que parte dos modelos, mas ainda perdeu. Em Java a disputa ficou mais equilibrada, com o código humano em uma posição intermediária. No total acumulado de defeitos, no entanto, o código humano saiu pior nas duas linguagens.
O que eu achei mais curioso não foi o número, foi a conclusão que os autores tiraram dele. Eles escrevem que os achados reforçam a necessidade de avaliar o código gerado por IA, não apenas quanto à corretude, mas também quanto ao design. Pela leitura dos dados, porém, o que precisou de mais revisão foi o código humano, não o da máquina. A necessidade de revisão é real e vale para todos, porque todos apresentaram defeitos. Mas o dado não aponta especificamente para o código gerado.
Resultado 2: vulnerabilidades
Aqui a história se inverte, e essa é a parte que merece mais atenção. Em ambas as linguagens, o código humano foi o que apresentou menos vulnerabilidades de segurança. Todos os modelos, de forma consistente, geraram código com mais problemas de segurança do que o escrito por pessoas.
E não é só uma questão de quantidade. Os autores registram que o código gerado por IA difere do humano também na natureza e na distribuição das vulnerabilidades, ficando mais suscetível a problemas de alta severidade.
Esse é o ponto onde o balanço fica interessante. Se cada dimensão do estudo tivesse o mesmo peso, o código humano perderia no geral. Mas as dimensões não têm o mesmo peso. Uma falha de segurança de alta severidade tende a ser mais crítica do que um bloco aninhado a mais, que é um defeito de prática e não de corretude. Peso não é algo que o estudo decide por você. É julgamento de engenharia, e depende do que está em jogo no seu sistema.
Resultado 3: complexidade estrutural
A terceira dimensão avaliou complexidade a partir de um conjunto de métricas: número de linhas, complexidade ciclomática, número de tokens, tamanho dos nomes de funções como proxy para semântica e tokens únicos como proxy para o vocabulário da linguagem utilizado.
O resultado foi consistente nas duas linguagens: o código humano é estruturalmente mais complexo, tanto em tamanho quanto em estrutura lógica. O código gerado, sobretudo pelos modelos DeepSeek e Qwen, favorece brevidade e complexidade reduzida, com menos linhas, menor complexidade ciclomática e menos tokens.
Vale uma ressalva sobre a metodologia, porque ela ensina algo mais valioso do que o resultado em si. Escolher tamanho de nome como proxy para semântica é uma decisão defensável, mas o mesmo número maior também poderia indicar prolixidade, alguém que escreve nomes gigantes sem ganho real de clareza. Ou seja, a métrica não é neutra.
O que eu tiro disso não é qual métrica é a certa. É que medir complexidade importa mais do que acertar de primeira o conjunto de métricas. Quando você tem um conjunto de métricas que, combinadas, produzem uma avaliação, você ganha a capacidade de iterar sobre esse processo avaliativo e descobrir se aquelas métricas de fato trazem a perspectiva que você quer. Sem medir, você fica preso na intuição.
Quem é o assistente de quem
Feita a revisão, a pergunta que fica é o que fazer com isso na prática. O artigo, como boa parte da literatura, termina em revisão, revisão, revisão. Eu não discordo que revisão importa. Mas, pela minha experiência, ela tende a ser cada vez menos necessária quando o input é bem feito, o contexto é adequado e existe um mecanismo mínimo de revisão no fluxo. Com isso, a saída costuma vir correta. Isso depende do seu contexto, da sua stack e do seu domínio, então defina por conta própria o que correto e o que suficiente significam no seu caso.
Antes de qualquer discussão sobre revisão, existe uma questão de responsabilidade que não muda. Eu sou o responsável por tudo o que gero através dos agentes. Se um bug entra na plataforma, a pessoa cobrada sou eu. Se um conteúdo sai com informação incorreta, quem responde sou eu. Não dá para responsabilizar a máquina. O responsável continua sendo a pessoa, sem qualquer dúvida.
Existe uma ideia comum entre quem lidera que ajuda a enquadrar isso: uma habilidade importante é contratar pessoas melhores do que você para determinados tipos de trabalho. É assim que eu enxergo os agentes hoje. Eu sou o chefe, e o agente é alguém que eu contratei, com capacidade de execução geralmente melhor do que a minha para a maioria das tarefas.
A questão então é onde eu entro. Eu entro no pedaço de conhecimento em que o modelo por baixo do agente não foi tão bem treinado, ou foi treinado em uma linha que não é a que eu quero seguir. Quando o assunto é design de código, as práticas mais estabelecidas nos modelos tendem para múltiplas camadas e para tratar acoplamento com frameworks como algo sempre ruim. Não é a linha que eu defendo há alguns anos, então ali eu preciso fazer o ajuste fino.
Em contrapartida, quando eu preciso escrever queries eu não faço ajuste nenhum, porque o modelo tem mais repertório do que eu nisso. Em testes, os modelos são capazes, mas tendem a produzir testes superficiais quando não são direcionados, então ali eu direciono. Em segurança por design, eu diria que o modelo já é mais bem treinado do que eu.
Levando a ideia ao limite, eu me vejo menos como quem tem um assistente e mais como o assistente do assistente. Meu papel, nesse momento, é atrapalhar o mínimo possível o agente. Isso passa por engenharia de contexto: entender o que de fato é necessário, dar a autonomia adequada e ser sucinto. Passa também pelo harness, e aqui ferramentas como Claude Code e Codex ajudam bastante, porque já trazem guardrails sobre até onde o agente pode ir, como avaliar se a geração atendeu ao requisito e até onde vai o loop de autonomia.
Conclusão
Se o estudo já apontava, mesmo com modelos antigos e sem agente, que o código gerado tende a ter menos defeitos e menor complexidade estrutural, é razoável imaginar que a distância aumente com os modelos e agentes atuais. Na dimensão de segurança, onde o código humano ainda levava vantagem, é plausível que o cenário se aproxime ou até se inverta conforme os modelos amadurecem nesse eixo. Isso é leitura de tendência, não afirmação fechada.
O que não muda é a divisão de trabalho. A capacidade de execução migra cada vez mais para o agente. O que fica em primeiro plano do lado humano é o julgamento: definir peso entre dimensões que competem, cravar a linha de design que você acredita, direcionar onde o modelo tende ao superficial e responder pelo resultado. Não é sobre digitar código. É sobre decidir e responder por estar certo.
Dev + Eficiente
Desenvolva software de alta qualidade e domine Engenharia de IA com o Dev + Eficiente. Cursos práticos, acesso vitalício, comunidade ativa e acesso a vagas remotas exclusivas em diversas empresas de tecnologia. Sua jornada para se tornar um dev mais eficiente pode começar agora.
Top comments (0)