Módulo 1: Fundamentos de Prompt Engineering

2. Anatomía de un Prompt

Descripción

Un prompt profesional no es texto libre: tiene componentes identificables que el modelo procesa de forma distinta. En esta cápsula aprenderás los 4 componentes fundamentales (instrucción, contexto, input, output format), cómo el modelo los procesa, y el impacto de la tokenización en los resultados. Al final, podrás descomponer cualquier prompt y diagnosticar qué falta o qué sobra.

Por qué importa: Sin entender la anatomía, no puedes mejorar prompts sistemáticamente. Si un prompt falla, no sabes si el problema está en la instrucción, en el contexto, o en el formato de salida. Con anatomía clara, optimizas por partes.


Los 4 Componentes de un Prompt Profesional

1. Instrucción

Qué es: La tarea que quieres que el modelo ejecute. Debe ser explícita y accionable.

Ejemplo vago:

Haz algo con este texto.

Ejemplo explícito:

Extrae las entidades nombradas (personas, organizaciones, lugares) del siguiente texto.
Devuelve una lista con formato JSON: {"personas": [], "organizaciones": [], "lugares": []}

Regla: La instrucción responde "¿Qué debe hacer el modelo?" con suficiente detalle para que no tenga que adivinar.

Verbos de instrucción útiles:

  • Clasificar, categorizar
  • Extraer, identificar
  • Resumir, condensar
  • Traducir, parafrasear
  • Generar, crear
  • Analizar, evaluar
  • Comparar, contrastar
  • Responder, explicar

2. Contexto

Qué es: Información adicional que el modelo necesita para ejecutar la tarea correctamente. Incluye dominio, restricciones, definiciones, y background.

Ejemplo sin contexto:

Clasifica este ticket.

Ejemplo con contexto:

Eres un clasificador de tickets de soporte. Las categorías son: Billing, Technical, Account, Other.
Solo responde con una de las cuatro categorías, nada más.
Definiciones:
- Billing: problemas de pago, facturas, cargos
- Technical: errores, bugs, problemas de acceso técnico
- Account: cambios de contraseña, configuración, permisos
- Other: cualquier cosa que no encaje en las anteriores

Regla: El contexto responde "¿Qué necesita saber el modelo para hacerlo bien?" y "¿Qué restricciones debe respetar?"

Tipos de contexto:

  • Dominio: "Estás en el contexto de una empresa de seguros"
  • Definiciones: "Un 'incidente crítico' se define como..."
  • Restricciones: "Solo usa información del documento proporcionado"
  • Background: "El usuario ya intentó reiniciar su dispositivo"

3. Input

Qué es: Los datos sobre los que el modelo debe actuar. El contenido variable que cambia en cada llamada.

Ejemplo:

[Instrucción y contexto arriba]

Ticket del usuario:
"Mi factura de marzo no llegó y ya pasaron 2 semanas. Necesito ayuda urgente."

Regla: El input es lo que el usuario o el sistema proporciona en cada request. Debe estar claramente delimitado (por ejemplo, con etiquetas como "Input:" o triple comillas ''').

Cómo delimitar el input:

# Opción 1: Etiqueta
prompt = f"""
Instrucción: Clasifica el sentimiento.

Input: {user_text}
"""

# Opción 2: Comillas triples
prompt = f"""
Clasifica el sentimiento del siguiente texto:

'''{user_text}'''
"""

# Opción 3: XML-style (funciona bien con Claude)
prompt = f"""
Clasifica el sentimiento de este texto:

<texto>
{user_text}
</texto>
"""

La delimitación evita que el modelo "mezcle" el input con la instrucción (especialmente importante si el input puede contener instrucciones).


4. Output Format

Qué es: Cómo debe estructurarse la respuesta. JSON, lista, párrafo, tabla, etc.

Ejemplo sin formato:

Resume este artículo.

Ejemplo con formato:

Resume este artículo en exactamente 3 bullet points.
Cada bullet debe tener máximo 15 palabras.
Formato:
- [punto 1]
- [punto 2]
- [punto 3]

Regla: El output format reduce variabilidad y hace la respuesta parseable por código. En producción, casi siempre necesitas formato estructurado.

Formatos comunes:

FormatoCuándo usar
JSONExtracción de datos, clasificación con metadatos
Lista de bulletsResúmenes, brainstorming
String exactoClasificación simple (POSITIVO/NEGATIVO)
Tabla MarkdownComparaciones
CódigoGeneración de código
Párrafo estructuradoAnálisis narrativo

Ejemplo Completo Integrado

# Prompt con los 4 componentes explícitos y código completo

from openai import OpenAI
import json
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI()

# Componentes del prompt claramente identificados
INSTRUCCION = """
Extrae las entidades nombradas del texto.
Clasifica cada una como PERSONA, ORGANIZACIÓN o LUGAR.
"""

CONTEXTO = """
Reglas:
- Solo incluye entidades que aparezcan explícitamente en el texto
- Si una entidad es ambigua, usa la categoría más probable
- No inventes entidades que no estén en el texto
- Una misma entidad puede aparecer varias veces: inclúyela una sola vez
"""

INPUT = "María García trabaja en Google en Mountain View. Ayer habló con Juan Pérez de Microsoft sobre el proyecto."

OUTPUT_FORMAT = """
Responde con un JSON válido y nada más:
{
  "entidades": [
    {"texto": "...", "tipo": "PERSONA|ORGANIZACIÓN|LUGAR"}
  ]
}
"""

# Prompt ensamblado
prompt = f"""
## Instrucción
{INSTRUCCION}

## Contexto
{CONTEXTO}

## Input
{INPUT}

## Output Format
{OUTPUT_FORMAT}
"""

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}],
    temperature=0  # Determinístico para extracción
)

output = response.choices[0].message.content
print(output)

# Parsear el JSON
data = json.loads(output)
print(f"Entidades encontradas: {len(data['entidades'])}")
for e in data['entidades']:
    print(f"  - {e['texto']} ({e['tipo']})")

Output esperado:

{
  "entidades": [
    {"texto": "María García", "tipo": "PERSONA"},
    {"texto": "Google", "tipo": "ORGANIZACIÓN"},
    {"texto": "Mountain View", "tipo": "LUGAR"},
    {"texto": "Juan Pérez", "tipo": "PERSONA"},
    {"texto": "Microsoft", "tipo": "ORGANIZACIÓN"}
  ]
}
Entidades encontradas: 5
  - María García (PERSONA)
  - Google (ORGANIZACIÓN)
  - Mountain View (LUGAR)
  - Juan Pérez (PERSONA)
  - Microsoft (ORGANIZACIÓN)

Cómo el Modelo Procesa Cada Parte

El modelo no "lee" el prompt como un humano. Lo procesa como secuencia de tokens:

  1. Tokens: El texto se divide en subunidades (palabras, partes de palabras, puntuación). "Extrae" puede ser 1 token, "entidades" puede ser 1-2 tokens.

  2. Orden importa: El modelo procesa de izquierda a derecha. La instrucción al inicio tiene más "peso" que el contexto al final en algunos escenarios. Por eso se recomienda el orden: Instrucción → Contexto → Input → Output Format.

  3. Delimitadores: Usar etiquetas como ## Instrucción o Input: ayuda al modelo a segmentar mentalmente. No es obligatorio, pero mejora consistencia.

  4. Longitud: Más contexto no siempre es mejor. Contexto irrelevante puede "diluir" la instrucción. Solo incluye lo necesario.

  5. Recency bias: Los LLMs suelen dar más peso a lo que está al final del prompt. Por eso colocar el Output Format al final es una buena práctica — es lo último que el modelo "ve" antes de generar.


Tokens y Tokenización: Impacto en Resultados

Qué son los tokens

Los LLMs no procesan caracteres ni palabras completas. Procesan tokens, que son fragmentos de texto (típicamente 3-4 caracteres en inglés, 1-2 en español).

Ejemplo:

  • "Prompt engineering" → ~3-4 tokens
  • "ingeniería de prompts" → ~4-5 tokens

Impacto en resultados

  1. Límite de contexto: Cada modelo tiene un máximo de tokens (ej: 128K para GPT-4o). Si tu prompt + respuesta excede el límite, se trunca.

  2. Costo: La mayoría de APIs cobran por token. Prompt más largo = más costo por llamada.

  3. Latencia: Más tokens = más tiempo de procesamiento. Para aplicaciones en tiempo real, importa.

  4. Calidad: En algunos casos, prompts muy largos con información redundante pueden degradar la calidad. "Signal vs noise".

Verificar token count

import tiktoken
from openai import OpenAI

# Contar tokens antes de llamar
def count_tokens(text: str, model: str = "gpt-4o-mini") -> int:
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

# Ejemplo
prompt = """
Extrae las entidades nombradas del siguiente texto.
Responde con JSON: {"entidades": [{"texto": "...", "tipo": "PERSONA|ORG|LUGAR"}]}

Texto: María García trabaja en Google.
"""

tokens = count_tokens(prompt)
print(f"Tokens del prompt: {tokens}")
# Output: Tokens del prompt: ~42

# Estimación de costo (gpt-4o-mini: $0.15 por millón de tokens de input)
costo_por_llamada = tokens * 0.15 / 1_000_000
print(f"Costo estimado: ${costo_por_llamada:.6f}")

Anatomía vs Roles: La Distinción

Existe una diferencia importante entre anatomía de un prompt (los componentes del contenido) y roles (system/user/assistant que son la estructura de la API):

Anatomía (qué dice el prompt):

  • Instrucción, Contexto, Input, Output Format

Roles (cómo se organiza en la API):

  • system: Instrucción + Contexto (el contrato)
  • user: Input + repetición de Output Format si es necesario
  • assistant: Historial de respuestas
# Mapeo anatomía → roles
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",         # Instrucción + Contexto
            "content": """
            Eres un extractor de entidades nombradas.
            Categorías: PERSONA, ORGANIZACIÓN, LUGAR.
            Responde solo con JSON válido.
            """
        },
        {
            "role": "user",           # Input + Output Format
            "content": """
            Texto: María García trabaja en Google en Mountain View.
            
            Formato: {"entidades": [{"texto": "...", "tipo": "..."}]}
            """
        }
    ],
    temperature=0
)

Comparación: Prompt Sin Anatomía vs Con Anatomía

AspectoSin anatomíaCon anatomía
ReproducibilidadBaja (cada intento es distinto)Alta (misma estructura, resultados consistentes)
DebuggingDifícil (no sabes qué cambiar)Fácil (cambias un componente, mides impacto)
EvaluaciónSubjetiva ("se ve bien")Por componente (¿instrucción clara? ¿formato correcto?)
MantenimientoCaóticoVersionable, documentable
CostoNo optimizadoOptimizable (token count por componente)

Comparación: Órdenes de Componentes

# Orden A: Instrucción primero (recomendado)
prompt_a = """
Clasifica el sentimiento como POSITIVO o NEGATIVO.

Reglas: Solo una palabra. Sin explicaciones.

Texto: "Me encantó el producto"
"""

# Orden B: Input primero (menos efectivo)
prompt_b = """
Texto: "Me encantó el producto"

Clasifica el sentimiento como POSITIVO o NEGATIVO.
Solo una palabra.
"""

# En la mayoría de modelos, orden A es más consistente
# porque la instrucción aparece antes que el input

Conexión con el Proyecto

En el Prompt Analyzer (cápsula 08) usarás la anatomía para:

  • Identificar qué componentes tiene un prompt dado
  • Detectar componentes faltantes (ej: sin output format)
  • Sugerir mejoras específicas por componente
  • Puntuar la "calidad" de un prompt por presencia de componentes

Troubleshooting

Problema 1: El modelo ignora el formato de salida

Causa: El output format está enterrado en mucho texto o no es suficientemente explícito.

Solución: Pon el output format al final, con ejemplos concretos. Usa frases como "Responde ÚNICAMENTE con..." o "Formato obligatorio:" y añade un ejemplo:

Formato obligatorio (no incluyas nada más):
{"resultado": "POSITIVO|NEGATIVO", "confianza": 0.0-1.0}

Ejemplo: {"resultado": "POSITIVO", "confianza": 0.95}

Problema 2: El modelo inventa información no presente en el input

Causa: Falta contexto que restrinja explícitamente la invención.

Solución: Agrega en contexto:

IMPORTANTE: No inventes información.
Si no está en el input, indica "No encontrado" en ese campo.

Problema 3: Respuestas inconsistentes entre llamadas

Causa: Temperature > 0 o instrucción ambigua que permite múltiples interpretaciones.

Solución: Usa temperature=0 para tareas determinísticas. Haz la instrucción más explícita con ejemplos de lo que SÍ y lo que NO quieres.


Problema 4: El modelo mezcla el contexto con el input

Causa: Falta delimitación clara del input.

Solución: Usa delimitadores explícitos:

Instrucción: Clasifica el sentimiento.

Input (texto a clasificar):
'''
Me encantó el producto, lo recomiendo.
'''

Responde solo: POSITIVO, NEGATIVO o NEUTRO

Problema 5: El prompt es demasiado largo y el modelo pierde el hilo

Causa: Contexto excesivo que diluye la instrucción.

Solución: Principio de mínimo contexto útil: incluye solo lo que el modelo NECESITA saber para esta tarea específica. Verifica el token count con tiktoken.


Ejercicios

Ejercicio 1: Identificar componentes

Dado este prompt, identifica instrucción, contexto, input y output format:

Eres un asistente que resume artículos. El resumen debe tener máximo 100 palabras.
Solo incluye hechos del artículo, no opiniones.

Artículo: "La inteligencia artificial está transformando la industria..."

Responde con: RESUMEN: [tu resumen aquí]
Ver solución
  • Instrucción: "Resume artículos" (implícita en el rol)
  • Contexto: Máximo 100 palabras, solo hechos, no opiniones
  • Input: El artículo entre comillas
  • Output Format: "RESUMEN: [tu resumen aquí]"

Análisis: La instrucción está implícita en el rol (no es explícita como acción). Mejorar: "Resume el siguiente artículo en máximo 100 palabras, incluyendo solo hechos."


Ejercicio 2: Completar componentes faltantes

Este prompt falla frecuentemente. ¿Qué componentes faltan?

Traduce esto al inglés: "El prompt engineering es fundamental."
Ver solución

Componentes presentes:

  • Instrucción: ✅ "Traduce... al inglés"
  • Input: ✅ El texto entre comillas

Componentes faltantes:

  • Contexto: No especifica tono (formal/informal), dialecto (UK/US), si hay términos técnicos que no deben traducirse
  • Output Format: ¿Solo la traducción? ¿Con el original? ¿Entre comillas?

Prompt mejorado:

Traduce el siguiente texto al inglés (US). Mantén el tono profesional.
Si hay términos técnicos en español que se usan en inglés (ej: "prompt engineering"), déjalos sin traducir.

Input: "El prompt engineering es fundamental."

Output: Solo la traducción, sin el original ni explicaciones.

Ejercicio 3: Prompt con anatomía completa

Escribe un prompt con los 4 componentes para la siguiente tarea: Extraer el precio, producto y moneda de textos de e-commerce.

Input de ejemplo: "El iPhone 15 Pro está disponible por $1,199 USD"

Ver solución
from openai import OpenAI
import json

client = OpenAI()

INSTRUCCION = "Extrae información de precio de textos de e-commerce."

CONTEXTO = """
Extrae exactamente estos campos:
- producto: nombre del producto
- precio: valor numérico (sin símbolo de moneda)
- moneda: código de 3 letras (USD, EUR, MXN, etc.)

Si algún campo no está presente, usa null.
"""

INPUT = "El iPhone 15 Pro está disponible por $1,199 USD"

OUTPUT_FORMAT = """
JSON válido, sin texto adicional:
{"producto": "...", "precio": 0.0, "moneda": "..."}
"""

prompt = f"""
## Instrucción
{INSTRUCCION}

## Contexto
{CONTEXTO}

## Input
{INPUT}

## Output Format
{OUTPUT_FORMAT}
"""

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}],
    temperature=0
)

result = json.loads(response.choices[0].message.content)
print(result)
# {"producto": "iPhone 15 Pro", "precio": 1199.0, "moneda": "USD"}

Ejercicio 4: Diagnóstico de prompt fallido

Este prompt produce resultados inconsistentes. Identifica el problema y corrígelo:

Eres un experto en marketing. Analiza este tweet y dime si es bueno o malo para la marca.

Tweet: "Nuestro producto cambió mi vida. #Recomendado"
Ver solución

Problemas identificados:

  1. Output Format ausente: "dime si es bueno o malo" es vago. ¿Solo una palabra? ¿Con explicación? ¿Con score?
  2. Contexto insuficiente: ¿Qué criterios definen "bueno para la marca"? ¿Autenticidad? ¿Alcance? ¿Sentimiento?
  3. Instrucción ambigua: "Analiza" no especifica qué aspectos analizar

Prompt corregido:

Eres un experto en marketing de redes sociales.

Evalúa el siguiente tweet según estos criterios:
- Autenticidad: ¿Parece genuino o pagado?
- Sentimiento: ¿Positivo, neutro o negativo para la marca?
- Riesgo reputacional: ¿Hay algún riesgo?

Tweet: "Nuestro producto cambió mi vida. #Recomendado"

Responde con JSON:
{
  "autenticidad": "genuino|pagado|ambiguo",
  "sentimiento": "positivo|neutro|negativo",
  "riesgo_reputacional": true|false,
  "recomendacion": "amplificar|ignorar|responder"
}

Ejercicio 5: Diferencia de orden

Toma este prompt y reorganiza los componentes en el orden recomendado (Instrucción → Contexto → Input → Output):

Input: "La reunión es el martes 15 de julio a las 3pm en la sala B"

Devuelve JSON con los campos: fecha, hora, lugar.

Contexto: Extrae detalles de reuniones de textos en lenguaje natural.

Instrucción: Extrae los detalles de la siguiente reunión.
Ver solución
## Instrucción
Extrae los detalles de la siguiente reunión.

## Contexto
Extrae detalles de reuniones de textos en lenguaje natural.
Si algún campo no está presente, usa null.
Formato de fecha: YYYY-MM-DD. Formato de hora: HH:MM (24h).

## Input
"La reunión es el martes 15 de julio a las 3pm en la sala B"

## Output Format
JSON válido:
{"fecha": "2025-07-15", "hora": "15:00", "lugar": "sala B"}

Mejoras adicionales: Se agregó formato explícito para fecha y hora, y el manejo de campos nulos.


Ejercicio 6 (Avanzado): Prompt con múltiples inputs

Diseña un prompt que pueda procesar múltiples tickets a la vez y devuelva un array de clasificaciones.

Ver solución
from openai import OpenAI
import json

client = OpenAI()

tickets = [
    "No puedo acceder a mi cuenta",
    "¿Cuándo llega mi pedido?",
    "Cobro duplicado en mi factura",
    "Hola, necesito ayuda con algo"
]

# Construir la lista de tickets para el prompt
tickets_formatted = "\n".join([f"{i+1}. {t}" for i, t in enumerate(tickets)])

prompt = f"""
## Instrucción
Clasifica cada ticket de soporte en una categoría.

## Contexto
Categorías disponibles: TECNICO, PEDIDO, BILLING, SALUDO, OTRO
Una categoría por ticket. Solo usa las categorías listadas.

## Input
{tickets_formatted}

## Output Format
JSON con array de objetos:
[
  {{"id": 1, "categoria": "..."}},
  {{"id": 2, "categoria": "..."}}
]
Devuelve exactamente {len(tickets)} objetos.
"""

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}],
    temperature=0
)

results = json.loads(response.choices[0].message.content)
for r in results:
    print(f"Ticket {r['id']}: {r['categoria']}")

# Output esperado:
# Ticket 1: TECNICO
# Ticket 2: PEDIDO
# Ticket 3: BILLING
# Ticket 4: SALUDO

Resumen

  • 4 componentes: Instrucción, Contexto, Input, Output Format
  • Instrucción: Qué hacer (explícita, accionable, con verbo claro)
  • Contexto: Qué saber, qué restricciones, definiciones del dominio
  • Input: Datos variables por llamada, delimitados explícitamente
  • Output Format: Estructura de la respuesta (JSON, string, lista); al final del prompt
  • Tokens: Impactan costo, latencia, límites. Verificar con tiktoken antes de producción
  • Orden recomendado: Instrucción → Contexto → Input → Output Format
  • Roles vs anatomía: Los roles (system/user) son la estructura de la API; la anatomía es el contenido

Recursos adicionales

  1. OpenAI Tokenizer — Herramienta visual para ver cómo se tokeniza texto
  2. tiktoken (Python) — Librería de OpenAI para contar tokens en código
  3. Anthropic Token Counting — Cómo contar tokens para Claude
  4. OpenAI Prompt Engineering Guide — Estrategias recomendadas por OpenAI
  5. Learn Prompting: Prompt Structure — Guía introductoria de estructura de prompts
  6. Anthropic Prompt Design — Cómo Claude procesa los prompts