O Prompt que Compila na Cabeça: Como Escrever Instruções que Geram Código Pronto para Revisão, Não para Descarte
Você pede para a IA implementar um endpoint de paginação. Ela devolve um código que compila, passa nos testes que você tinha (poucos), mas ignora o padrão de cursor que o resto da API já usa, reimplementa uma função de sanitização que já existe em utils/ e assume que o banco é PostgreSQL quando na verdade é MySQL. Você gasta vinte minutos revisando, mais quinze reescrevendo o prompt, mais dez explicando o que já devia estar óbvio. No fim, seria mais rápido ter escrito o código você mesmo.
Esse cenário não é falha do modelo. É falha de especificação. A maioria dos desenvolvedores trata o prompt como uma pergunta rápida — “implementa isso aí” — quando na prática ele funciona como uma interface de contrato entre a sua intenção e o código que sai do outro lado. Quanto mais implícito o contrato, mais espaço a IA tem para preencher lacunas com suposições genéricas, que raramente coincidem com as convenções do seu projeto. Neste artigo, vamos tratar o prompt de código como o que ele realmente é: uma peça de engenharia que precisa de estrutura, contexto e critério de aceite — não um pedido de garçom.
O prompt não é uma pergunta, é uma especificação incompleta por padrão
Todo modelo de linguagem preenche lacunas com o padrão estatístico mais provável do seu treinamento. Se você não diz qual biblioteca de HTTP usar, ele escolhe a mais comum globalmente — não a que está no seu package.json. Se você não diz o padrão de tratamento de erro, ele improvisa um try/catch genérico, mesmo que seu projeto use um padrão de Result tipado. O erro mais comum entre desenvolvedores intermediários é achar que a IA “vai perceber” o contexto do projeto sozinha, sem que ele seja fornecido explicitamente na conversa.
Como observa a Coddy em uma análise sobre o futuro da programação assistida por IA, a habilidade que está se tornando central não é mais só escrever código, mas comunicar intenção com precisão suficiente para que a máquina produza exatamente o que se espera. Isso desloca o esforço: menos tempo digitando sintaxe, mais tempo pensando em requisitos, restrições e casos de borda antes de apertar enter.
Os quatro blocos que faltam na maioria dos prompts
Prompts que geram código ruim costumam ter só uma frase de intenção. Prompts que geram código revisável têm quatro blocos, ainda que curtos:
- Contexto do sistema — stack, versão da linguagem, framework, convenção de nomes, estrutura de pastas relevante.
- Restrição explícita — o que não pode ser feito (não adicionar dependência nova, não alterar assinatura pública, não criar nova camada).
- Critério de aceite — como você vai saber que o resultado está correto (testes que precisam passar, comportamento esperado em casos de borda).
- Formato de saída — código completo? diff? só a função? com ou sem comentários?
Vamos comparar dois prompts para a mesma tarefa e observar a diferença no resultado esperado.
Exemplo prático: prompt fraco versus prompt estruturado
Prompt fraco, típico de quem está começando a usar IA no fluxo de trabalho:
|
1 2 3 |
Cria uma função para validar CPF em TypeScript. |
Esse prompt provavelmente vai gerar uma função de validação de CPF correta matematicamente, mas sem saber se você já tem uma classe ValidationError customizada, se o projeto usa zod para esse tipo de coisa, ou se a função precisa lançar exceção ou retornar um booleano. Agora compare com uma versão estruturada:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Contexto: projeto Node.js + TypeScript, usamos zod para validações de entrada e lançamos AppError (classe em src/errors/AppError.ts) para erros de domínio. Tarefa: crie uma função isValidCPF(cpf: string): boolean que valide o CPF pelo algoritmo padrão dos dígitos verificadores (não use regex apenas para formato). Restrições: - Não instale nenhuma biblioteca nova. - A função deve remover pontuação antes de validar. - CPFs com todos os dígitos iguais (ex: 111.111.111-11) devem retornar false. Critério de aceite: escreva também 6 casos de teste com vitest cobrindo: CPF válido, CPF com pontuação, CPF com dígitos repetidos, CPF com tamanho errado, string vazia e CPF com letras. Formato: só o código da função e dos testes, sem explicação em prosa antes ou depois. |
A diferença de resultado entre os dois prompts não é sutil — é a diferença entre código que você aceita direto e código que você teria que reescrever. O segundo prompt elimina ambiguidade em pontos que normalmente geram retrabalho: biblioteca, formato de retorno, casos de borda e formato de entrega.
💡 Dica do Mestre: segundo uma discussão na comunidade sobre prompts para desenvolvedores no subreddit r/ChatGPTPro, desenvolvedores mais experientes tendem a manter uma biblioteca pessoal de “prompts-base” reutilizáveis por tipo de tarefa — refatoração, revisão de segurança, geração de testes — em vez de reescrever a instrução do zero a cada vez. Vale criar a sua e versionar junto do repositório.
Contexto de projeto: o que realmente precisa entrar no prompt
Um erro comum é achar que “mais contexto é sempre melhor”. Não é. Contexto em excesso dilui o que importa e aumenta a chance do modelo ignorar a instrução principal em favor de detalhes irrelevantes. O objetivo é contexto relevante, não contexto completo.
Priorize convenções que a IA não pode inferir
Existem dois tipos de informação de projeto: a que a IA consegue inferir olhando o código (nomes de variáveis, estilo de indentação) e a que ela só sabe se você disser (decisões arquiteturais, trade-offs já discutidos, motivos históricos de uma escolha estranha). Foque energia no segundo tipo.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
-- Exemplo em Delphi, contexto de um sistema legado -- que precisa manter compatibilidade Contexto: unit legada em Delphi (Object Pascal), FireDAC para acesso a dados, mantemos compatibilidade com Delphi XE7 (não pode usar recursos de sintaxe mais recentes que essa versão, como inline var em qualquer escopo). Tarefa: crie uma função TStringHelper.ToSlug(const AInput: string): string que converta um título em slug de URL (minúsculas, espaços por hífen, remoção de acentos). Restrições: - Sem dependências externas, só RTL padrão. - Deve funcionar com strings vazias (retornar ''). - Compatível com sintaxe do Delphi XE7. Formato: código da function e um bloco de comentário explicando o motivo da não-utilização de regex (se você optar por não usar). |
Esse exemplo mostra algo importante: em stacks menos populares nos dados de treinamento — como versões específicas de Delphi, frameworks internos ou linguagens de nicho — a restrição de versão e ambiente é ainda mais crítica, porque o modelo tem menos exemplos “modernos” para confundir com o que você realmente precisa.
Peça o raciocínio antes do código quando a tarefa for ambígua
Para tarefas de arquitetura, refatoração grande ou qualquer coisa com mais de uma abordagem razoável, pedir o código direto é prematuro. Peça primeiro um plano, revise o plano, depois autorize a implementação.
|
1 2 3 4 5 6 7 8 9 10 11 |
Antes de escrever código, me diga em até 5 bullets: 1. Qual abordagem você usaria para migrar esse serviço de callbacks para async/await sem quebrar os consumidores externos da API pública? 2. Quais funções têm maior risco de regressão? 3. Que testes eu deveria rodar antes e depois da mudança? Não escreva código ainda. Aguarde minha confirmação do plano. |
Esse padrão de duas etapas — plano, depois execução — evita o cenário em que a IA já entregou quinhentas linhas de refatoração antes de você perceber que a abordagem escolhida ignora um detalhe crítico do domínio. Corrigir um plano de cinco linhas é rápido; corrigir quinhentas linhas de código já escrito, não.
💡 Dica do Mestre: como resume um vídeo sobre engenharia de prompt no canal do YouTube dedicado ao tema, prompts “melhores” só parecem melhores quando comunicam melhor — a métrica de qualidade de um prompt não é o quão elaborado ele parece, mas o quanto ele reduz a ambiguidade que o modelo precisaria resolver por conta própria.
Armadilhas comuns e como depurá-las
A alucinação de API: quando o código “parece” certo mas não existe
Um dos problemas mais frequentes em código gerado é a IA inventar métodos que não existem em uma biblioteca — um .paginate() que o ORM não tem, um parâmetro que a função nunca aceitou. Isso acontece porque o modelo generaliza padrões comuns entre bibliotecas parecidas. A defesa prática é sempre colar a assinatura real da função ou trecho da documentação da versão exata que você usa, em vez de confiar que o modelo “sabe” a API de cor.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Aqui está a assinatura exata do método que preciso usar (copiada da documentação da versão 5.2 da lib): async findMany(options: { where?: WhereClause; cursor?: { id: string }; take?: number; }): Promise<Record[]> Use exatamente essa assinatura para implementar a paginação por cursor no endpoint GET /orders. Não invente parâmetros que não estão listados acima. |
Esse tipo de ancoragem elimina boa parte da alucinação porque tira do modelo a tarefa de “lembrar” a API e transforma em uma tarefa de “aplicar” uma especificação que você forneceu.
Diagnosticando por que um prompt está gerando código ruim
Quando o resultado sai errado, resista ao impulso de simplesmente reescrever o prompt do zero. Primeiro, diagnostique a causa, que geralmente cai em uma destas categorias:
- Ambiguidade de escopo — o modelo não sabia se devia alterar um arquivo ou o sistema inteiro. Solução: delimite explicitamente os arquivos envolvidos.
- Falta de exemplo de padrão — o modelo não conhece a convenção do seu time. Solução: cole um trecho de código existente como referência de estilo.
- Critério de aceite ausente — o modelo não sabe quando parar de “melhorar” o código. Solução: defina exatamente o que constitui sucesso.
- Contexto contraditório — você deu instruções que se conflitam ao longo da conversa. Solução: resuma o estado atual antes de pedir a próxima mudança.
Um artigo no Medium sobre a mudança do foco de “escrever código” para “dirigir a saída” descreve bem essa transição: o papel do desenvolvedor passa a ser menos digitar sintaxe e mais funcionar como um revisor técnico que valida, corrige o rumo e refina a instrução — uma posição de direção, não de execução manual.
Usando exemplos de código real como âncora de estilo
Uma técnica subutilizada é colar um trecho de código já existente no seu projeto como referência de padrão, antes de pedir algo novo similar.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Aqui está um controller existente no nosso padrão: class UserController { async create(req: Request, res: Response) { const dto = CreateUserDTO.parse(req.body); const user = await this.userService.create(dto); return res.status(201).json(toUserResponse(user)); } } Siga exatamente esse padrão (DTO com zod, service separado, função toXResponse para serialização) para criar um ProductController com os métodos create e update. |
Esse tipo de instrução por exemplo reduz drasticamente a variância de estilo entre o que a IA gera e o que já existe no repositório — e é praticamente à prova de descrição verbal malfeita, porque o padrão está explícito no próprio código, não em uma tentativa de descrevê-lo em prosa.
Prompts iterativos: refinando em vez de recomeçar
Em conversas longas com ferramentas como Claude Code ou Cursor, o erro comum é tratar cada correção como um novo pedido isolado, sem reconectar com o que já foi decidido. Isso faz o modelo perder o fio da lógica anterior. O padrão mais eficiente é referenciar explicitamente o que já existe e pedir uma modificação incremental, não uma reescrita.
|
1 2 3 4 5 6 |
A função que você gerou está correta, mas o tratamento de erro não segue nosso padrão. Mantenha a lógica de validação exatamente como está, só troque o throw new Error() por throw new AppError('INVALID_CPF', 400). |
Pedidos incrementais como esse preservam o trabalho já validado e reduzem o risco de a IA “corrigir” algo que já estava certo enquanto tenta atender ao novo pedido — um efeito colateral comum quando se pede uma reescrita completa em vez de um ajuste pontual.
💡 Dica do Mestre: conforme mostra uma publicação sobre como criar prompts melhores para programação, a IA pode acelerar bastante o aprendizado e o desenvolvimento, mas o ganho real depende de tratar cada interação como uma iteração sobre um contrato já estabelecido, não como uma pergunta nova e desconectada da anterior.
Um checklist rápido antes de enviar o prompt
Para consolidar o que vimos, um checklist mental de cinco perguntas antes de apertar enter tende a evitar a maior parte dos retrabalhos:
- Eu disse qual stack, versão e convenção de projeto se aplicam aqui?
- Eu disse o que NÃO pode ser feito (dependência nova, mudança de assinatura pública)?
- Eu defini como vou saber se o resultado está correto?
- Para tarefas ambíguas, eu pedi um plano antes do código?
- Eu ancorei a API real (assinatura, exemplo de código) em vez de confiar na memória do modelo?
Nenhuma dessas perguntas exige mais do que uma ou duas frases extras no prompt. O custo de escrevê-las é baixo; o custo de não escrevê-las é o tempo perdido revisando e corrigindo código que nunca deveria ter saído errado.
Leve essa prática para dentro do seu fluxo de trabalho
Escrever prompts melhores não é um talento raro — é uma disciplina que se desenvolve testando estruturas, guardando o que funciona e descartando o que gera retrabalho. Se você quer trocar esses padrões com outros desenvolvedores que já passaram pelas mesmas armadilhas, participar de um grupo dedicado ao assunto acelera muito essa curva de aprendizado.
Convido você a entrar na Comunidade Dev’s AI, onde compartilhamos prompts testados, discutimos falhas reais de projetos e trocamos experiências práticas sobre como usar IA de forma responsável no desenvolvimento de software, em várias linguagens e contextos.
Conclusão
A qualidade do código gerado por IA é, na prática, um espelho da qualidade da especificação que você forneceu. Prompts vagos produzem código genérico; prompts que carregam contexto de projeto, restrições explícitas e critério de aceite produzem código que se aproxima do que um colega sênior, familiarizado com o seu sistema, teria escrito. Isso não elimina a necessidade de revisão — nenhum prompt bem escrito substitui teste e leitura crítica — mas reduz drasticamente a distância entre o que você pediu e o que você recebeu. Trate cada prompt como um contrato: quanto mais explícitas as cláusulas, menos surpresas na entrega.