Menu

Prompts de code review: revisar código com IA

Um bom prompt de code review diz o que procurar, pede uma gravidade para cada problema, exige uma entrada concreta que o dispare e um diff, e manda o modelo ignorar o estilo. Depois você confere cada apontamento, porque alguns vão estar errados.

Você pode editar cada prompt desta página e depois abri-lo no ChatGPT, no Claude ou em outro app de IA.

Um prompt de code review deve dizer ao modelo o que procurar, qual a gravidade de cada problema e que prova apresentar. "Revise este código" traz uma lista simpática de sugestões em que uma falha de segurança fica entre uma dica de docstring e uma preferência de nome. Um prompt de revisão com checklist, níveis de gravidade e pedido de diffs traz um relatório sobre o qual você pode agir, um apontamento por vez.

De "revise isto" a um checklist com gravidade

O código das duas abas tem dois bugs reais. Compare como cada resposta os apresenta.

Você pode revisar este código? def get_user(conn, username): cur = conn.cursor() cur.execute(f"SELECT id, email FROM users WHERE name = '{username}'") row = cur.fetchone() return {"id": row[0], "email": row[1]}
Try it
Example replyReplies vary between models and runs.

No geral, a função é curta e fácil de acompanhar. Algumas sugestões:

  • Acrescente anotações de tipo, por exemplo username: str, para deixar a assinatura mais clara.
  • Acrescente uma docstring explicando o que a função retorna.
  • Use consultas parametrizadas. Montar SQL com f-strings pode levar a SQL injection.
  • Trate usuários inexistentes. fetchone() pode retornar None.
  • Nomes: fetch_user talvez descreva melhor o acesso ao banco.

A primeira resposta encontrou os dois bugs, e esse é o problema de julgar uma revisão pelo que ela menciona. A injection está em terceiro lugar em uma lista de cinco, amenizada como "pode levar a", sem correção, ao lado de uma dica de docstring. Quem passasse o olho acrescentaria anotações de tipo e seguiria em frente.

O segundo prompt mudou quatro coisas:

  • Escopo. "Só bugs, segurança e tratamento de erros. Ignore estilo" tira o ruído. Estilo é trabalho de um linter e de um formatador, que são mais rápidos e nunca discordam de si mesmos.
  • Gravidade. Obriga o modelo a ordenar, e uma lista ordenada diz por onde começar.
  • Uma entrada que dispare o problema. "x' OR '1'='1" transforma um risco vago em uma demonstração que você pode rodar. É também o seu melhor filtro contra falsos positivos, como mostra a última seção.
  • Diffs. Um diff pequeno por apontamento pode ser aplicado ou rejeitado sozinho. Uma função reescrita mistura cada correção com mudanças que ninguém pediu.

"Se não houver nada em um nível de gravidade, não invente" importa mais do que parece. Quando alguém pede uma revisão, o modelo tende a produzir apontamentos mesmo quando há pouco a encontrar, e os mais fracos incham a lista. Uma permissão explícita para não relatar nada em um nível corta esse enchimento.

O contexto de que o revisor precisa

Um revisor humano sabe para que serve o código e de onde vêm as entradas. O modelo sabe só o que você cola. "username vem direto de um formulário de login" é a frase que transforma SQL injection em um apontamento de gravidade alta, e não em um risco teórico. Contexto útil para uma revisão:

  • De onde vêm as entradas: usuários, outro serviço interno, um arquivo de configuração que você controla.
  • O que chama o código e o que espera receber de volta.
  • O ambiente de execução: versão da linguagem, framework, driver do banco. A correção da injection acima usa ? porque esse é o marcador do sqlite3; alguns outros drivers usam %s.
  • O que mais importa para você nesta mudança: correção, segurança, desempenho ou os três.

Um prompt de revisão reutilizável

Este bloco transforma o checklist em um template. Mude a linguagem, o foco e o código e mantenha as regras. Desligar a parte de restrições é um jeito rápido de ver quanto ruído volta sem ela.

Template de code review
Fill in
Parts
Você é um revisor sênior de JavaScript. Você relata problemas reais e nada mais.
Revise o código abaixo, com foco em bugs e tratamento de erros.
Isto roda no navegador. `ids` é um array de ids numéricos vindos da nossa própria API.
async function loadAll(ids) { const results = []; ids.forEach(async (id) => { const res = await fetch(`/api/items/${id}`); results.push(await res.json()); }); return results; }
Para cada apontamento: gravidade (alta, média ou baixa), a linha, uma entrada ou situação que o dispare e um diff mínimo. Do mais grave para o menos grave.
Nenhum comentário sobre estilo, nomes ou formatação. Se não tiver certeza de que um apontamento é real, diga isso e diga o que o confirmaria. Se não encontrar nada, diga "Nenhum apontamento".
Try it
Example replyReplies vary between models and runs.

1. Alta: a função retorna antes de qualquer requisição terminar (linha 3) O forEach não espera callbacks async. O loadAll retorna o array results vazio na hora, e os push acontecem depois. Quem chama sempre recebe [].

2. Média: requisições com falha são tratadas como dados (linha 5) Uma resposta 404 ou 500 não é uma exceção no fetch. Um corpo de erro em JSON é lido e colocado no array como se fosse um item, e um corpo que não é JSON faz o res.json() gerar um erro dentro de um callback que ninguém espera.

Correção para os dois, que também mantém os resultados na mesma ordem de ids:

 async function loadAll(ids) {
-  const results = [];
-  ids.forEach(async (id) => {
-    const res = await fetch(`/api/items/${id}`);
-    results.push(await res.json());
-  });
-  return results;
+  return Promise.all(
+    ids.map(async (id) => {
+      const res = await fetch(`/api/items/${id}`);
+      if (!res.ok) throw new Error(`Item ${id}: HTTP ${res.status}`);
+      return res.json();
+    })
+  );
 }

A linha de papel define um padrão ("problemas reais e nada mais"), que é onde o prompt de papel mais ajuda. Se um programa lê a revisão, por exemplo um script que publica os apontamentos como comentários em um pull request, peça JSON com campos fixos em vez de texto corrido; saída estruturada mostra como.

Como lidar com falsos positivos

Alguns apontamentos vão estar errados. O modelo não vê quem chama a função e valida a entrada, a restrição do banco que torna um caso impossível ou o motivo de uma linha estranha ser intencional. Ele também pode errar sobre como uma biblioteca se comporta; alucinação de IA explica por que uma afirmação confiante não é uma afirmação verificada.

Teste cada apontamento com a entrada que o dispara. Se você não consegue produzir uma entrada que chegue ao problema no seu sistema, conteste com o contexto que faltava em vez de aceitar a correção:

Contestar um apontamento
Você apontou esta função porque `cents` poderia ser undefined ou uma string: function formatPrice(cents) { return `$${(cents / 100).toFixed(2)}`; } Ela só é chamada por `renderCart`, que retorna antes se `Number.isInteger(cents)` não for verdadeiro. Isso ainda é um problema? Se não for, retire o apontamento.
Try it
Example replyReplies vary between models and runs.

Com essa verificação, não: o formatPrice só recebe inteiros, então o apontamento não se aplica e eu o retiro.

Uma coisa que a verificação não cobre: inteiros negativos passam em Number.isInteger, e formatPrice(-500) retorna "$-5.00". Se reembolsos ou descontos puderem chegar a esta função, talvez você queira "-$5.00". Se não puderem, não há nada a mudar.

Um modelo que recebe uma evidência nova deve retirar o apontamento ou explicar por que ele continua valendo com essa evidência em vista. As duas coisas são úteis. Um modelo que simplesmente concorda com toda contestação não está revisando, então julgue a resposta pelos motivos, não por ter concordado ou não. Para código que o próprio modelo escreveu, faça a revisão em uma conversa nova, para que ela não seja feita pelo mesmo raciocínio que produziu o código. Os mesmos hábitos de escopo, contexto e testes deixam o código melhor desde o início; veja prompts para escrever código.

Perguntas frequentes

Qual é um bom prompt para code review?

Diga o que revisar (bugs, segurança, tratamento de erros), peça uma gravidade para cada apontamento e exija uma entrada concreta que dispare o problema, mais um diff que o corrija. Mande o modelo ignorar formatação e nomes, a não ser que você peça. Dê a ele o contexto que um revisor humano teria: para que serve o código e o que o chama.

A IA pode substituir o code review humano?

Não, mas é uma primeira passada útil. Ela é rápida e boa em padrões comuns de bugs, como None não tratado, await esquecido e SQL montado com strings. Ela não conhece as regras do seu produto, o resto da base de código ou o motivo de uma decisão, e alguns apontamentos dela vão estar errados. Use antes de uma revisão humana, não no lugar dela.

Por que um code review de IA aponta problemas que não existem?

O modelo vê só o código que você colou. Se um valor é validado por quem chama a função, ou se um caso nunca pode acontecer no seu sistema, o modelo não tem como saber, então aponta o risco mesmo assim. Pedir uma entrada concreta que cause a falha filtra muitos desses casos: um apontamento sem nenhuma entrada realista que o dispare costuma ser um falso positivo.

Devo pedir à IA que reescreva o meu código durante a revisão?

Peça diffs pequenos, um por apontamento, em vez de um arquivo reescrito. Uma reescrita completa mistura as correções com mudanças que ninguém pediu, e você teria de revisar a reescrita também. Os diffs deixam você aceitar ou rejeitar cada apontamento separadamente.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR