Módulo 1: Fundamentos de Prompt Engineering

4. Temperature y Parámetros de Generación

Descripción

Los parámetros de generación (temperature, top_p, max_tokens, frequency_penalty, presence_penalty) controlan cómo el modelo produce texto. Elegir mal estos valores puede hacer que un prompt "perfecto" falle en producción. En esta cápsula aprenderás qué hace cada parámetro, cuándo usar temperature 0 vs 1, y configuraciones recomendadas por caso de uso.

Por qué importa: Un clasificador con temperature=0.9 dará resultados inconsistentes aunque el prompt sea excelente. Un generador creativo con temperature=0 sonará robótico y repetitivo. Los parámetros son parte del diseño del prompt: no son secundarios.


Temperature

Qué hace: Controla la aleatoriedad en la selección del siguiente token. Modifica la distribución de probabilidad de los tokens candidatos antes de muestrear.

  • temperature=0: El modelo elige siempre el token más probable. Determinístico.
  • temperature=1: Muestrea según las probabilidades originales del modelo.
  • temperature>1: Aplana la distribución (tokens menos probables tienen más chance). Más aleatorio.

Rango típico: 0.0 a 2.0 (OpenAI). 0.0 a 1.0 (Anthropic).

Cuándo usar cada valor

TemperatureCasos de usoEjemplo de tarea
0Clasificación, extracción, código, respuesta con una correctaClasificar sentimiento, extraer entidades, generar SQL
0.1-0.3QA sobre documentos, resúmenes factualesResponder preguntas sobre un PDF, resumir un informe
0.3-0.5Balance: consistencia con algo de fluidezRespuestas de soporte, análisis, traducción profesional
0.7-0.9Creatividad, brainstorming, copyGenerar slogan, ideas de nombres, variaciones de texto
1.0+Máxima creatividad / exploraciónArte generativo, juegos de rol, escritura experimental

Ejemplo Práctico: Comparando Temperature

from openai import OpenAI

client = OpenAI()

prompt_clasificacion = "Clasifica el sentimiento: 'Me encantó el producto, lo recomiendo'"
prompt_creativo = "Escribe un eslogan de 5 palabras para una cafetería artesanal."

# Temperatura 0: mismo resultado siempre
print("=== Clasificación (temperature=0) ===")
for i in range(3):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "Clasifica sentimiento. Solo: POSITIVO, NEGATIVO o NEUTRO."},
            {"role": "user", "content": prompt_clasificacion}
        ],
        temperature=0,
        max_tokens=5
    )
    print(f"  Intento {i+1}: {response.choices[0].message.content.strip()}")
# Output: POSITIVO / POSITIVO / POSITIVO (siempre igual)

# Temperatura 0.8: creatividad, variación
print("\n=== Creativo (temperature=0.8) ===")
for i in range(3):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt_creativo}],
        temperature=0.8,
        max_tokens=20
    )
    print(f"  Intento {i+1}: {response.choices[0].message.content.strip()}")
# Output varía:
#   Intento 1: "Tu café, tu momento perfecto."
#   Intento 2: "Sabores que abrazan el alma."
#   Intento 3: "Cada sorbo, una historia única."

top_p (Nucleus Sampling)

Qué hace: Limita el conjunto de tokens candidatos a los que acumulan el top_p de probabilidad. Ej: top_p=0.1 considera solo los tokens más probables hasta sumar 10% de probabilidad.

Relación con temperature: Ambos controlan aleatoriedad, pero de forma diferente:

  • temperature escala la distribución entera
  • top_p corta la distribución después de cierto umbral

Recomendación de OpenAI: Cambia solo temperature o top_p, no ambos simultáneamente.

# top_p bajo = más determinismo (diferente mecanismo al temperature)
response_low_p = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Dame una palabra que describa el océano"}],
    temperature=1.0,  # Sin restricción por temperature
    top_p=0.1         # Pero solo tokens top 10% de probabilidad
)

# top_p alto = más variedad
response_high_p = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Dame una palabra que describa el océano"}],
    temperature=1.0,
    top_p=0.95  # Permite tokens menos probables
)

Valores típicos:

  • 1.0: Sin filtro (todos los tokens considerados)
  • 0.9: Variedad con coherencia
  • 0.1-0.5: Más determinismo que con temperature pero sin llegar a 0

max_tokens

Qué hace: Límite máximo de tokens en la respuesta del modelo. No incluye los tokens del prompt.

Cuándo ajustar:

Tipo de respuestamax_tokens recomendadoEjemplo
Clasificación simple5-20"POSITIVO", "Billing", "Error 404"
Extracción de datos50-200JSON con 3-5 campos
Resumen corto100-3003 bullet points
Análisis moderado300-600Evaluación con criterios
Análisis extenso / código800-2000Función completa, análisis detallado
# max_tokens bajo para clasificación
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "Clasifica el ticket en: TECNICO, BILLING, CUENTA. Una sola palabra."},
        {"role": "user", "content": "No puedo entrar a mi cuenta"}
    ],
    temperature=0,
    max_tokens=5  # "CUENTA" cabe en 1-2 tokens
)
print(response.choices[0].message.content)  # CUENTA

# Verificar si la respuesta fue truncada
finish_reason = response.choices[0].finish_reason
print(f"Finish reason: {finish_reason}")
# "stop" = respuesta completa
# "length" = truncada por max_tokens

Importante: Si finish_reason == "length", la respuesta fue cortada. Aumenta max_tokens o pide una respuesta más concisa en el prompt.


frequency_penalty y presence_penalty

frequency_penalty

Qué hace: Penaliza tokens en proporción a cuántas veces ya aparecieron. Reduce repetición de las mismas palabras.

  • 0: Sin penalización (default)
  • 0.5-1.0: Reduce repetición moderadamente
  • 2.0: Penalización máxima (puede degradar calidad)

presence_penalty

Qué hace: Penaliza tokens que ya aparecieron, independientemente de la frecuencia. Fomenta hablar de nuevos temas.

  • 0: Sin penalización (default)
  • 0.3-0.6: Incentiva variedad de temas
  • 2.0: Penalización máxima
# Ejemplo: generación de lista sin repetición
prompt_lista = "Lista 10 adjetivos para describir un buen liderazgo:"

# Sin penalización: puede repetir conceptos
response_sin = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt_lista}],
    temperature=0.7,
    frequency_penalty=0,
    presence_penalty=0,
    max_tokens=150
)

# Con penalización: más diversidad
response_con = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt_lista}],
    temperature=0.7,
    frequency_penalty=0.5,   # Reduce repetición de mismas palabras
    presence_penalty=0.3,    # Fomenta nuevos conceptos
    max_tokens=150
)

Casos donde NO usar penalización:

  • Código: términos técnicos deben repetirse (ej: def, return, nombre de variables)
  • Extracción: si el mismo término aparece varias veces en el texto, debes incluirlo
  • Respuestas técnicas donde la precisión del vocabulario importa

seed: Reproducibilidad en OpenAI

OpenAI ofrece el parámetro seed para reproducibilidad aproximada (no garantizada pero muy consistente):

# Con seed: mayor reproducibilidad
responses = []
for i in range(3):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Dame un nombre para una startup de IA"}],
        temperature=0.9,  # Alta temperatura
        seed=42           # Pero con seed fijo
    )
    responses.append(response.choices[0].message.content)

print("Respuestas con seed=42:")
for r in responses:
    print(f"  - {r}")
# Las 3 respuestas serán muy similares o idénticas

Nota: seed es útil para reproducibilidad en testing y debugging, pero no es 100% garantizado entre versiones del modelo.


Configuraciones por Caso de Uso

from openai import OpenAI
from dataclasses import dataclass

client = OpenAI()

@dataclass
class ModelConfig:
    temperature: float
    max_tokens: int
    frequency_penalty: float = 0.0
    presence_penalty: float = 0.0
    top_p: float = 1.0

# Configuraciones predefinidas
CONFIGS = {
    "clasificacion": ModelConfig(
        temperature=0,
        max_tokens=20,
        frequency_penalty=0
    ),
    "extraccion": ModelConfig(
        temperature=0,
        max_tokens=200,
        frequency_penalty=0
    ),
    "resumen": ModelConfig(
        temperature=0.3,
        max_tokens=300,
        frequency_penalty=0.3
    ),
    "qa_documental": ModelConfig(
        temperature=0.3,
        max_tokens=500
    ),
    "brainstorming": ModelConfig(
        temperature=0.8,
        max_tokens=400,
        frequency_penalty=0.5,
        presence_penalty=0.3
    ),
    "copy_creativo": ModelConfig(
        temperature=0.7,
        max_tokens=200,
        frequency_penalty=0.4
    ),
    "codigo": ModelConfig(
        temperature=0,
        max_tokens=1500,
        frequency_penalty=0
    ),
}

def call_with_config(system: str, user: str, config_name: str) -> str:
    config = CONFIGS[config_name]
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": user}
        ],
        temperature=config.temperature,
        max_tokens=config.max_tokens,
        frequency_penalty=config.frequency_penalty,
        presence_penalty=config.presence_penalty,
        top_p=config.top_p
    )
    return response.choices[0].message.content

# Uso
result = call_with_config(
    system="Clasifica el sentimiento. Solo: POSITIVO, NEGATIVO, NEUTRO.",
    user="El producto llegó rápido pero la calidad es mediocre.",
    config_name="clasificacion"
)
print(result)  # NEGATIVO o NEUTRO

Tabla Resumen

Caso de usotemperaturemax_tokensfreq_penaltypresence_penalty
Clasificación05-2000
Extracción (NER, JSON)050-20000
Resumen factual0.3150-3000.20
QA sobre documentos0.3200-50000
Análisis y evaluación0.4300-6000.20.1
Generación de ideas0.8200-4000.50.3
Copy creativo0.7100-3000.40.2
Generación de código0500-150000
Traducción0.2igual al original00

Conexión con el Proyecto

En el Prompt Analyzer (cápsula 08) podrías detectar si un prompt usa parámetros apropiados:

  • ¿Temperature 0 para tareas determinísticas (clasificación, extracción)?
  • ¿max_tokens adecuado al tipo de respuesta esperada?
  • ¿frequency_penalty activado para generaciones largas?

Troubleshooting

Problema 1: Respuestas truncadas

Síntoma: La respuesta se corta a mitad de una oración o antes del cierre del JSON.

Diagnóstico:

# Verificar el finish_reason
finish_reason = response.choices[0].finish_reason
print(f"Finish reason: {finish_reason}")  # "length" = truncado

Solución:

  • Aumentar max_tokens gradualmente (usa +200 hasta que finish_reason == "stop")
  • O reducir la longitud esperada en el prompt: "Responde en máximo 50 palabras"

Problema 2: Respuestas inconsistentes en clasificación

Síntoma: El mismo texto clasifica como POSITIVO a veces y NEUTRO en otras.

Causa: temperature > 0 en tarea determinística.

Solución:

# ✅ Correcto para clasificación
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[...],
    temperature=0  # Determinístico
)

# ❌ Problemático
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[...],
    temperature=0.7  # Introduce variabilidad innecesaria
)

Problema 3: Respuestas muy repetitivas

Síntoma: El modelo repite las mismas frases o ideas.

Solución:

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Describe 5 beneficios del ejercicio"}],
    temperature=0.7,
    frequency_penalty=0.8,  # Penaliza repetición de palabras
    presence_penalty=0.3,   # Incentiva nuevos conceptos
    max_tokens=300
)

Problema 4: Respuestas demasiado conservadoras o genéricas

Síntoma: Para brainstorming, el modelo da respuestas obvias y repetitivas.

Causa: Temperature demasiado baja para una tarea creativa.

Solución: Aumenta temperature a 0.7-0.9 para tareas creativas. Verifica que no tengas top_p bajo.


Ejercicios

Ejercicio 1: Elegir parámetros

Para cada tarea, elige temperature y max_tokens apropiados y justifica:

  • (a) Extraer emails de un texto
  • (b) Generar 10 ideas para nombres de producto
  • (c) Responder preguntas sobre un documento técnico
  • (d) Generar código Python para una función de ordenamiento
Ver solución

(a) Extraer emails:

  • temperature=0: Solo hay una respuesta correcta (los emails presentes)
  • max_tokens=100-200: Lista de emails en JSON

(b) 10 ideas de nombres:

  • temperature=0.7-0.9: Necesitamos creatividad y variedad
  • max_tokens=150-300: 10 nombres con una palabra o frase cada uno
  • frequency_penalty=0.5: Para que los nombres sean variados

(c) QA sobre documento:

  • temperature=0.2-0.3: Factual pero fluido
  • max_tokens=300-500: Respuesta explicativa

(d) Código Python:

  • temperature=0: Código debe ser correcto, no creativo
  • max_tokens=500-1500: Dependiendo de la complejidad
  • frequency_penalty=0: El código repite palabras clave por necesidad

Ejercicio 2: Experimento con temperature

Ejecuta el mismo prompt 3 veces con temperature=0 y 3 veces con temperature=0.9. Compara variabilidad.

Ver solución
from openai import OpenAI

client = OpenAI()

prompt = "Dame una analogía para explicar qué es machine learning."

for temp in [0, 0.9]:
    print(f"\n=== Temperature={temp} ===")
    for i in range(3):
        r = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": prompt}],
            temperature=temp,
            max_tokens=80
        )
        print(f"  {i+1}: {r.choices[0].message.content.strip()[:100]}...")

# Con temp=0: Las 3 respuestas serán muy similares o idénticas
# Con temp=0.9: Las 3 respuestas serán distintas (analogías diferentes)

Observación esperada: Con temperature=0 las respuestas son prácticamente idénticas. Con 0.9 cada intento produce una analogía distinta.


Ejercicio 3: Detectar respuesta truncada

Escribe código que: (1) haga una llamada con max_tokens=10, (2) detecte si fue truncada, (3) reintente con max_tokens más alto automáticamente.

Ver solución
from openai import OpenAI

client = OpenAI()

def call_with_retry(system: str, user: str, initial_max_tokens: int = 50) -> str:
    """
    Llama al modelo y reintenta con más tokens si la respuesta fue truncada.
    """
    max_tokens = initial_max_tokens
    max_retries = 3
    
    for attempt in range(max_retries):
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": user}
            ],
            temperature=0,
            max_tokens=max_tokens
        )
        
        finish_reason = response.choices[0].finish_reason
        content = response.choices[0].message.content
        
        if finish_reason == "stop":
            print(f"Completado en intento {attempt+1} con max_tokens={max_tokens}")
            return content
        elif finish_reason == "length":
            print(f"Truncado con max_tokens={max_tokens}, reintentando con {max_tokens * 2}...")
            max_tokens *= 2  # Doblar tokens y reintentar
        else:
            break
    
    return content  # Devolver lo que tenemos

# Test
result = call_with_retry(
    system="Explica en detalle qué es un transformer en IA.",
    user="Dame una explicación completa",
    initial_max_tokens=10  # Muy bajo, se truncará
)
print(f"\nResultado final:\n{result[:200]}...")

Ejercicio 4 (Avanzado): Benchmark de temperature

Implementa un benchmark que prueba una tarea de clasificación con temperature 0, 0.3, 0.5, 0.7 y mide la consistencia (% de respuestas idénticas en 5 intentos).

Ver solución
from openai import OpenAI
from collections import Counter

client = OpenAI()

def benchmark_temperature(
    system: str,
    user: str,
    temperatures: list[float],
    n_tries: int = 5
) -> dict:
    """
    Prueba diferentes temperaturas y mide consistencia.
    """
    results = {}
    
    for temp in temperatures:
        responses = []
        for _ in range(n_tries):
            r = client.chat.completions.create(
                model="gpt-4o-mini",
                messages=[
                    {"role": "system", "content": system},
                    {"role": "user", "content": user}
                ],
                temperature=temp,
                max_tokens=10
            )
            responses.append(r.choices[0].message.content.strip())
        
        counts = Counter(responses)
        most_common = counts.most_common(1)[0]
        consistency = most_common[1] / n_tries * 100
        
        results[temp] = {
            "responses": responses,
            "most_common": most_common[0],
            "consistency_pct": consistency
        }
    
    return results

# Ejecutar benchmark
results = benchmark_temperature(
    system="Clasifica el sentimiento. Una sola palabra: POSITIVO, NEGATIVO o NEUTRO.",
    user="El producto llegó tarde pero estaba en perfectas condiciones.",
    temperatures=[0, 0.3, 0.5, 0.7, 1.0],
    n_tries=5
)

print("Temperature | Consistencia | Respuesta más común")
print("-" * 50)
for temp, data in results.items():
    print(f"    {temp:.1f}    |    {data['consistency_pct']:3.0f}%      | {data['most_common']}")

# Output esperado (aproximado):
# Temperature | Consistencia | Respuesta más común
# --------------------------------------------------
#     0.0    |    100%      | NEUTRO
#     0.3    |     80%      | NEUTRO
#     0.5    |     60%      | NEUTRO
#     0.7    |     60%      | NEUTRO
#     1.0    |     40%      | NEUTRO

Resumen

  • temperature=0: Clasificación, extracción, código — cualquier tarea con respuesta correcta
  • temperature 0.2-0.4: QA factual, resúmenes, análisis — balance de precisión y fluidez
  • temperature 0.7-0.9: Creatividad, brainstorming, copy — variedad intencional
  • max_tokens: Ajustar al tipo de respuesta. Verificar finish_reason para detectar truncados.
  • top_p: Alternativa a temperature. No combinar ambos.
  • frequency_penalty: Reducir repetición de palabras en generación larga.
  • presence_penalty: Fomentar diversidad de conceptos.
  • seed: Para reproducibilidad aproximada en testing (OpenAI).

Recursos adicionales

  1. OpenAI API Parameters — Documentación completa de todos los parámetros disponibles
  2. OpenAI Prompt Engineering - Temperature — Recomendaciones de OpenAI para cada parámetro
  3. Anthropic Generation Parameters — Parámetros disponibles en la API de Claude
  4. Temperature in LLMs (Explained) — Explicación técnica de cómo funciona temperature
  5. tiktoken — Para calcular tokens y dimensionar max_tokens correctamente antes de llamar