< BACK Engenharia de Prompts para Código em Produção: Lições Difíceis -- ilustração em arte linear

Engenharia de Prompts para Código em Produção: Lições Difíceis

Era 23h43 de uma quinta-feira e eu estava olhando para 340 linhas de código React que o GPT-4 tinha gerado com total confiança. Limpo. Bem comentado. Completamente quebrado em produção. O custom hook estava gerenciando estado de um jeito que causava silent re-render loops, aquele tipo que não lança erros, só mata sua performance discretamente até um cliente te ligar numa sexta de manhã perguntando por que a página de checkout demora nove segundos para carregar.

Aquela noite me ensinou mais sobre engenharia de prompts do que qualquer tutorial do YouTube ou thread do Twitter jamais ensinaria. E tive muitas outras noites assim desde então.

Estou construindo na web há nove anos. Na Seahawk Media fizemos deploy de bem mais de 12.000 sites, WordPress, headless builds, apps React customizadas, lojas WooCommerce processando volume sério de transações. AI coding assistants entraram meu workflow de verdade por volta de início de 2023, e oscilei entre achar que são milagrosas e querer jogar meu laptop no Tâmisa.

Aqui está o que realmente aprendi. Do jeito difícil.

---

O Modelo Não Conhece Sua Base de Código. Você Tem que Contar a Ele.

Isso parece óbvio. Não é, não na prática.

O maior erro que vejo developers cometerem, inclusive eu mesmo pelos primeiros seis meses, é tratar um LLM como um senior engineer que já leu todo seu código. Você pede "escreva uma função para lidar com autenticação de usuário" e ele escreve algo tecnicamente correto no vácuo. Mas seu projeto usa Supabase, não Firebase. Seus tokens vivem em httpOnly cookies, não localStorage. Seu formato de erro é { status, message, data }, não o que quer que o modelo tenha defaultado.

O modelo não está errado. Ele só não te conhece.

Dê a Ele um Preâmbulo de Projeto, Toda Maldita Vez

Agora começo cada sessão de codificação significativa com o que chamo de "bloco de contexto." Leva cerca de 90 segundos para escrever. Parece algo assim:

  • Stack: Next.js 14 (App Router), TypeScript, Supabase, Tailwind CSS 3.4
  • State: Zustand, sem Redux em lugar nenhum
  • Auth: Supabase Auth com cookies httpOnly via middleware
  • Error shape: { success: boolean, error?: string, data?: unknown }
  • Convenção de estilo: utility-first, sem arquivos CSS customizados a menos que absolutamente necessário

Cole isso antes de qualquer requisição não-trivial. Eu faço isso no Cursor mantendo um arquivo _context.md na raiz do projeto. Dois atalhos para colar. A qualidade do output salta visivelmente, menos suposições, menos coisas que tenho que arrancar.

---

Especificidade é o Jogo Todo

Lá em 2022, antes de usar IA pesadamente, um cliente me entregou um brief que tinha literalmente duas frases: "Construa um sistema de agendamento. Faça bem feito." Passamos três semanas indo e vindo sobre o escopo. Essa experiência ficou comigo e molda diretamente como escrevo prompts agora.

Prompt vago → código vago. Toda vez.

"Escreva uma função que busca pedidos" vai te dar algo. "Escreva uma função async TypeScript chamada fetchOrdersByUser que aceita um userId: string, consulta a tabela orders no Supabase onde user_id corresponde e status não é cancelled, ordena resultados por created_at descendente e retorna Order[] ou lança um erro tipado" vai te dar algo que você realmente consegue colocar em produção.

A diferença não é a capacidade do modelo. É a especificidade do prompt.

O que Incluir em um Prompt de Código

  1. Nome da função e assinatura, não deixe o modelo inventar convenções de naming
  2. Tipos de entrada e tipos de saída, TypeScript generics se relevante
  3. A fonte de dados, qual tabela, qual endpoint de API, qual camada de cache
  4. Edge cases que você já conhece, "lidar com o caso onde o array está vazio"
  5. O que NÃO fazer, "não use useEffect para isso, use uma server action"

Esse último ponto importa mais do que as pessoas percebem. Dizer ao modelo o que evitar economiza tempo enorme. Comecei a manter uma pequena nota de "anti-patterns" por projeto, coisas como "nenhum client component a menos que a interação do usuário exija", e incluo linhas relevantes nos prompts daquele projeto.

---

Encadeie Seus Prompts. Não Peça por Tudo de Uma Vez.

Seahawk tinha um cliente fintech no final de 2023, não vou dizer quem, onde estávamos construindo um fluxo KYC multi-etapa. Coisa complexa. Upload de documentos, integração de liveness check, polling de status. Cometi o erro no início de pedir ao GPT-4 para "construir o componente de fluxo KYC completo." Produziu 600 linhas de lixo de aparência heroica. Lógica emaranhada, preocupações misturadas, nenhuma separação real entre estado de UI e lógica de negócio.

Então descartei e comecei de novo com uma cadeia.

Primeiro prompt: "Projete a máquina de estado para um fluxo KYC de 4 etapas. Etapas: identidade, upload de documento, verificação de vivacidade, revisão. Me dê apenas o tipo de estado e as transições, nenhuma UI."

Segundo prompt: "Dado esta máquina de estados [cole], escreva a store Zustand."

Terceiro prompt: "Dada esta store [cole], escreva o componente StepIdentity. Apenas este step."

O output da abordagem encadeada era usável. Não perfeito, ainda reescrevi uns 30%, mas usável. A abordagem monolítica não me deu nada.

A própria orientação da Anthropic sobre prompting fala sobre quebrar tarefas complexas em subtarefas, e honestamente, isso se alinha exatamente com o que descobri por tentativa e erro. Quebre o problema antes de quebrar sua base de código.

---

Faça Ele Argumentar Consigo Mesmo

Aqui está um que encontrei completamente por acaso. Eu estava revisando uma função utilitária gerada e em vez de apenas executá-la, adicionei um prompt de acompanhamento: "Quais são os possíveis bugs ou casos extremos no código que você acabou de escrever?"

O modelo encontrou três problemas que não havia contabilizado. Um deles era um problema genuíno, uma race condition em um loop assíncrono que seria um pesadelo para debugar em produção.

Agora faço isso rotineiramente. Escrevo o código, depois peço para ele criticar o código. Depois peço para ele corrigir a crítica. Parece levemente absurdo, pedir ao modelo para revisar seu próprio trabalho, mas consistentemente traz à tona coisas que eu só teria pegado depois de uma sessão de debugging dolorosa.

Você pode ir além. Depois de obter uma função funcional, tente: "Reescreva isso com foco em performance" ou "Como isso se comportaria sob alta concorrência?" As respostas nem sempre são aplicáveis, mas cerca de 40% das vezes surfam algo que vale a pena agir.

---

O Frame "Role + Constraint"

Existe um padrão de prompt que uso constantemente agora e gostaria de ter descoberto no primeiro ano. Funciona assim: "Você é um [tipo específico de engenheiro]. Sua restrição é [regra rígida]. Agora [tarefa]."

Exemplo: "Você é um engenheiro backend que se importa profundamente com eficiência de consultas de banco de dados. Sua restrição é que você não pode buscar mais do que o necessário para este render, nada de over-fetching. Escreva uma query Supabase para o dashboard admin que retorne contagem de pedidos, receita total, e os cinco pedidos mais recentes."

Esse enquadramento faz duas coisas. Alinha a "persona" do modelo com o que eu realmente preciso. E a restrição funciona como um guardrail, algo que o modelo explicitamente verifica a si mesmo enquanto gera.

As melhores práticas de prompting da OpenAI descrevem uma ideia similar sobre dar ao modelo uma persona com instruções explícitas. Vale a pena ler se você ainda não leu, embora eu diga que a parte de constraint é subenfattizada na documentação deles.

Compare a saída desse prompt enquadrado com "escreva uma query Supabase para o painel de administração." Dia e noite. Genuinamente.

---

Quando Parar de Fazer Prompts e Apenas Escrever o Código

Esta é a parte que ninguém quer dizer em voz alta.

Ferramentas de IA para código são brilhantes em: boilerplate, operações CRUD, funções utilitárias, escrever testes para código que você já escreveu, traduzir entre formatos (esquema JSON para tipo TypeScript, SQL para query Supabase, etc.), e primeiras versões de coisas que você vai modificar pesadamente.

Elas são genuinamente fracas em: entender a arquitetura real do seu app, saber qual trade-off importa para sua escala específica, escrever qualquer coisa que toque uma interação stateful complicada sem orientação pesada, e qualquer coisa onde a spec é fundamentalmente ambígua.

Tenho uma regra pessoal agora: se enviei mais de quatro prompts de acompanhamento tentando acertar um pedaço de código, fecho o chat e escrevo eu mesmo. O custo de tempo do debug de prompts pode exceder o custo de tempo de simplesmente escrever, especialmente para qualquer coisa com menos de uns 50 linhas.

O Stack Overflow Developer Survey 2024 descobriu que 76% dos desenvolvedores estão usando ou planejam usar ferramentas de IA, mas os mesmos dados mostraram confiança relativamente baixa em acurácia. Essa lacuna entre uso e confiança é exatamente onde a boa engenharia de prompt vive.

---

Versione Seus Prompts Como Você Versiona Seu Código

No ano passado comecei a manter uma pasta prompts/ em projetos onde a assistência de IA é significativa. Arquivos Markdown. Um por área de feature major. Quando um prompt produz output particularmente bom, eu salvo. Quando encontro uma versão melhor, atualizo o arquivo.

Parece obsessivo. Economizou pra mim provavelmente seis horas no último projeto grande, um build headless WooCommerce para um varejista migrando de Shopify. Reaproveitei um prompt de product query (com edições menores) em quatro componentes diferentes em vez de re-engenheirar o contexto do zero cada vez.

Versione no Git. Sério. A qualidade dos prompts é reproduzível se você tratar prompts como artefatos em vez de inputs descartáveis. Os templates de prompt do LangChain formalizam essa ideia em um contexto de framework, mas você não precisa de nenhum framework, uma pasta de arquivos Markdown é suficiente para a maioria dos workflows de agência.

---

FAQ

Engenharia de prompts é realmente uma habilidade transferível ou apenas específica do modelo?

Principalmente transferível. Os princípios centrais, especificidade, definição de contexto, encadeamento, loops de crítica, aplicam-se entre GPT-4, Claude 3.5 Sonnet, Gemini, o que vier a seguir. A sintaxe varia um pouco e alguns modelos respondem melhor a certos enquadramentos, mas a lógica subjacente se mantém. Descobri que Claude tende a responder bem a restrições explícitas; GPT-4 responde bem a exemplos. Diferenças menores, mesmos fundamentos.

Como você lida com código gerado por IA em code review?

Igual a qualquer outro código. Se está indo para produção, passa por revisão. Ponto final. Parei de sinalizar "isso foi gerado por IA" em PRs na Seahawk porque virou uma herança falsa, os revisores escrutinizariam diferente, às vezes injustamente, às vezes não o suficiente. O código se sustenta ou cai pelos seus próprios méritos. O que eu sinalizo: qualquer seção onde a lógica não é óbvia e eu não adicionei comentários inline explicando o raciocínio.

Você usa system prompts ou apenas chat prompts?

Ambos. No Cursor eu dependo do arquivo .cursorrules para instruções persistentes em nível de projeto, coisas que eu teria que colar toda vez. Para tarefas pontuais na web UI do ChatGPT ou Claude, é tudo no chat. A abordagem .cursorrules reduziu significativamente a repetição e o modelo mantém mais consistência ao longo de uma sessão longa.

Qual é sua opinião honesta sobre IA substituindo desenvolvedores?

Está substituindo certas tarefas, não desenvolvedores. Os julgamentos, o que construir, como arquitetar, qual trade-off se encaixa na situação real desse cliente, isso está longe de ser automatizado. Se houver algo, os desenvolvedores sendo pressionados são aqueles que eram puramente orientados à execução, não orientados a design ou arquitetura. Aguçar a camada de julgamento. Isso é a parte defensável.

---

Nove anos construindo coisas na web, e a lição fundamental se repete constantemente: a qualidade do seu output é determinada pela qualidade dos seus inputs. Isso era verdade quando eram briefings de clientes. É verdade agora com prompts.

O modelo é um desenvolvedor júnior rápido, ocasionalmente brilhante, frequentemente excessivamente confiante. Gerencie-o de acordo.

Leitura relacionada: Building a Real-Time Auction Site with Next.js & Supabase, How to Cost Custom Software in 2026: A Working Estimator for, e desenvolvimento web personalizado.

< BACK