Cómo estructurar prompts para obtener código de producción con Claude: guía técnica con ejemplos reales
El problema no es Claude, eres tú escribiendo prompts vagos
Si Claude te devuelve código lleno de TODO, sin manejo de errores y con variables llamadas temp o data, el cuello de botella está en cómo le pides las cosas. Un prompt mal estructurado produce código de prototipo. Un prompt bien diseñado produce código que sobrevive a code review.
Después de miles de interacciones con modelos de lenguaje aplicados a desarrollo, hay un patrón claro: los profesionales que obtienen código usable en producción no son los que tienen mejores conocimientos de programación, sino los que han aprendido a comunicar contexto, restricciones y expectativas de calidad de forma precisa.
Por qué los prompts genéricos producen código de juguete
Claude es un modelo entrenado para ser útil en el contexto más amplio posible. Sin restricciones explícitas, optimiza para claridad didáctica, no para robustez productiva. Esto significa que por defecto tiende a:
- Omitir manejo de excepciones para mantener el ejemplo limpio
- Usar valores hardcodeados en lugar de configuración externalizable
- Ignorar concurrencia, timeouts y casos borde
- Escribir funciones de 80 líneas cuando la situación requiere modularidad
La solución no es un modelo diferente. Es un prompt que define explícitamente el estándar de calidad esperado.
La estructura que funciona: contexto + restricciones + contrato de calidad
1. Define el contexto de producción desde la primera línea
En lugar de:
Escribe una función Python para procesar pagos con Stripe
Usa:
Contexto: API FastAPI en producción, Python 3.11, desplegada en AWS Lambda con timeouts de 29s.
Tarea: función para procesar pagos con Stripe.
Requisitos no negociables:
- Manejo explícito de StripeError, CardError y RateLimitError
- Idempotency key derivada del order_id
- Logging estructurado con correlation_id
- Type hints completos
- Sin dependencias fuera de stripe, boto3 y la stdlib
La diferencia en la calidad del output es inmediata y medible.
2. Especifica el contrato de la función antes del código
Claude genera código mucho más sólido cuando le describes la firma esperada y los casos de error antes de pedir la implementación:
Necesito implementar esta función:
def process_payment(order_id: str, amount_cents: int, customer_id: str) -> PaymentResult:
"""..."""
Donde PaymentResult es un dataclass con campos: success (bool), charge_id (str | None), error_code (str | None).
Casos que debe manejar:
- Tarjeta declinada → success=False, error_code='card_declined'
- Rate limit de Stripe → reintentar con backoff exponencial (máx 3 intentos)
- Timeout de red → success=False, error_code='network_timeout'
- Pago duplicado (mismo order_id) → devolver el charge_id existente sin cobrar de nuevo
3. Ancla el estilo al código que ya existe en tu proyecto
Pegar un fragmento real de tu codebase como referencia de estilo es una de las técnicas más efectivas y menos usadas:
Aquí hay una función existente en nuestro proyecto para que iguales el estilo:
[pega 20-40 líneas de código propio]
Escribe la nueva función siguiendo exactamente el mismo patrón de error handling, logging y estructura de retorno.
Esto elimina el 80% de las iteraciones de ajuste de estilo.
4. Pide primero el plan, luego el código
Para lógica compleja, separar la fase de diseño de la implementación reduce alucinaciones significativamente:
Antes de escribir código, lista los pasos del algoritmo y los edge cases que vas a manejar.
Espera mi confirmación antes de implementar.
Este simple paso hace que Claude explicite sus asunciones, momento en el que puedes corregir el rumbo antes de recibir 150 líneas de código en la dirección equivocada.
5. Incluye la instrucción de revisión en el mismo prompt
Añade al final de cualquier prompt complejo:
Tras escribir el código, revísalo tú mismo contra estos criterios:
[ ] Todos los caminos de error tienen manejo explícito
[ ] No hay valores hardcodeados que deberían ser configuración
[ ] Las funciones tienen un único nivel de abstracción
[ ] Existe al menos un docstring con ejemplo de uso
Si algún criterio no se cumple, corrígelo antes de mostrarme el resultado.
Claude actuará como su propio reviewer, lo que en la práctica reduce errores obvios en el output final.
Un prompt completo de referencia
Rol: Senior Python engineer revisando código antes de merge a main.
Contexto: servicio de notificaciones, asyncio, PostgreSQL con asyncpg, Python 3.12.
Escribe una función async para enviar notificaciones en batch:
- Firma: async def send_notifications(user_ids: list[int], message: NotificationMessage) -> BatchResult
- Procesa en chunks de 100 para no saturar la DB
- Usa asyncio.gather con return_exceptions=True para no fallar el batch completo si un envío falla
- Logging: INFO al inicio con tamaño del batch, WARNING por cada fallo individual, INFO al final con resumen
- Devuelve BatchResult con: sent_count, failed_count, failed_user_ids
Estilo de referencia: [tu código aquí]
Primero muéstrame el diseño. Espera confirmación antes de implementar.
El siguiente paso concreto
Toma el próximo ticket de tu backlog que implique escribir código con IA. Antes de abrir Claude, invierte 5 minutos en escribir el contexto de producción, la firma de la función y los casos de error que debes manejar. Compara el resultado con lo que obtenías antes. La diferencia justifica el tiempo invertido en el prompt, no al revés.
La ingeniería de prompts para código no es un arte esotérico: es comunicación de requisitos técnicos, exactamente lo mismo que hace un buen tech lead al asignar una tarea.