Módulo 2: OpenAI API - Introducción

Parameters Avanzados de OpenAI API

Descripción de la cápsula

Has visto el uso básico de OpenAI API. Ahora aprenderás a controlar las respuestas con parameters avanzados:

  • temperature (creatividad)
  • max_tokens (longitud)
  • top_p (sampling)
  • frequency_penalty y presence_penalty

Estos parameters te dan control fino sobre cómo GPT genera texto.

Tiempo: 25 minutos
Dificultad: Media


🎯 Objetivos

  • ✅ Dominar temperature (determinismo vs creatividad)
  • ✅ Controlar longitud con max_tokens
  • ✅ Entender top_p, penalties
  • ✅ Elegir parameters según use case

🌡️ Parameter 1: Temperature

¿Qué es?

Controla la aleatoriedad de las respuestas:

  • temperature=0: Determinista (siempre igual)
  • temperature=1: Balanceado (default)
  • temperature=2: Muy creativo (máximo)

Rango: 0.0 - 2.0


Ejemplo visual:

Prompt: "Dame un nombre para una startup de AI"

Temperature 0 (determinista):

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    temperature=0,
    messages=[{"role": "user", "content": "Dame un nombre para una startup de AI"}]
)

Output (siempre igual):

IntelliCore

Ejecuta 10 veces → Siempre "IntelliCore"


Temperature 1 (balanceado):

temperature=1

Output (varía):

Run 1: NeuralPath
Run 2: CogniSphere
Run 3: ThinkBot AI

Temperature 2 (muy creativo):

temperature=2

Output (muy variado, a veces extraño):

Run 1: QuantumMindGlow
Run 2: BrainyPixelForge
Run 3: ZephyrCogniVerse

Cuándo usar cada valor:

TemperatureUse CaseEjemplo
0.0-0.3Respuestas consistentes, factualFAQs, soporte técnico, clasificación
0.7-1.0Balance creatividad/consistenciaChatbots general, recomendaciones
1.5-2.0Máxima creatividadEscritura creativa, brainstorming

Código de prueba:

from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def test_temperature(temp: float):
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        temperature=temp,
        messages=[{"role": "user", "content": "Dame un nombre para una startup de AI"}]
    )
    return response.choices[0].message.content

# Test 3 temperaturas, 3 veces cada una
for temp in [0, 1, 2]:
    print(f"\n=== TEMPERATURE {temp} ===")
    for i in range(3):
        result = test_temperature(temp)
        print(f"  Run {i+1}: {result}")

Ejecuta y observa diferencias.


🔢 Parameter 2: Max Tokens

¿Qué es?

Límite máximo de tokens en la respuesta generada.

Importante:

  • 1 token ≈ 0.75 palabras (inglés)
  • 1 token ≈ 0.5 palabras (español, más largo)

Ejemplo:

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    max_tokens=50,  # Máximo 50 tokens
    messages=[{"role": "user", "content": "Explica qué es Python"}]
)

Output (truncado a ~50 tokens):

Python es un lenguaje de programación interpretado, 
de alto nivel, conocido por su sintaxis clara y 
legibilidad. Es ampliamente usado en...

Nota: Respuesta se corta si excede 50 tokens.


Sin max_tokens:

max_tokens=None  # Default (sin límite explícito)

GPT decide cuándo parar (usualmente termina respuesta completa).


Cuándo usar:

ValorUse Case
10-50Respuestas muy cortas (sí/no, clasificación)
100-300Respuestas moderadas (FAQs)
500-1000Respuestas largas (explicaciones)
NoneDejar que GPT decida

⚠️ Costo vs Max Tokens:

Ejemplo:

  • Prompt: 20 tokens
  • max_tokens=100 → GPT genera 80 tokens
  • Costo: (20 input + 80 output) × pricing

Si max_tokens=1000 pero GPT solo genera 80:

  • Costo: (20 + 80) × pricing (mismo costo)
  • max_tokens NO afecta costo si GPT termina antes

Benefit: Previene respuestas infinitas por bug.


🎲 Parameter 3: Top-p (Nucleus Sampling)

¿Qué es?

Alternativa a temperature. Controla cuántas palabras GPT considera al generar texto.

  • top_p=0.1: Solo considera 10% palabras más probables (determinista)
  • top_p=1.0: Considera todas las palabras (creativo)

Rango: 0.0 - 1.0


Temperature vs Top-p:

Regla: Usa UNO, no ambos.

# Opción 1: Solo temperature
temperature=0.7, top_p=1.0  # Default top_p

# Opción 2: Solo top_p
temperature=1.0, top_p=0.9  # Default temperature

Recomendación: Usa temperature (más intuitivo).


🚫 Parameters 4 y 5: Penalties

Frequency Penalty (penaliza repetición):

Reduce probabilidad de repetir palabras/frases ya usadas.

  • frequency_penalty=0: Sin penalización (default)
  • frequency_penalty=1: Máxima penalización
  • frequency_penalty=2: Muy agresivo (evita casi toda repetición)

Rango: -2.0 a 2.0


Ejemplo:

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    frequency_penalty=1.5,
    messages=[{"role": "user", "content": "Escribe 5 razones para aprender Python"}]
)

Sin penalty (repetitivo):

1. Python es fácil
2. Python es versátil
3. Python es popular
4. Python es poderoso
5. Python es útil

Con penalty (más variado):

1. Sintaxis clara y legible
2. Gran ecosistema de bibliotecas
3. Comunidad activa y soporte
4. Aplicable en múltiples dominios
5. Curva de aprendizaje suave

Presence Penalty (penaliza temas repetidos):

Incentiva a GPT a hablar de temas nuevos.

  • presence_penalty=0: Sin penalización (default)
  • presence_penalty=1: Máxima penalización

Rango: -2.0 a 2.0


Ejemplo:

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    presence_penalty=1.0,
    messages=[{"role": "user", "content": "Háblame de Python"}]
)

Sin penalty: Habla solo de Python
Con penalty: Menciona Python pero también compara con otros lenguajes


Cuándo usar penalties:

PenaltyUse Case
FrequencyEscritura creativa, evitar repeticiones
PresenceBrainstorming, explorar temas diversos
Ambos 0Respuestas factuales (default)

🧪 Experimentos Combinados

Experimento 1: Chatbot determinista (FAQs):

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    temperature=0,
    max_tokens=100,
    messages=[
        {"role": "system", "content": "Eres un bot de soporte. Responde conciso y consistente."},
        {"role": "user", "content": "¿Cómo reseteo mi contraseña?"}
    ]
)

Resultado: Siempre misma respuesta (predecible para usuarios).


Experimento 2: Escritura creativa:

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    temperature=1.5,
    max_tokens=500,
    frequency_penalty=1.2,
    presence_penalty=0.8,
    messages=[
        {"role": "system", "content": "Eres un escritor creativo."},
        {"role": "user", "content": "Escribe inicio de cuento sci-fi"}
    ]
)

Resultado: Muy creativo, variado, sin repeticiones.


Experimento 3: Clasificación (sí/no):

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    temperature=0,
    max_tokens=1,  # Solo "Sí" o "No"
    messages=[
        {"role": "system", "content": "Responde solo 'Sí' o 'No'."},
        {"role": "user", "content": "¿Python es un lenguaje interpretado?"}
    ]
)

Resultado: "Sí" (determinista, mínimo costo).


📊 Tabla Resumen de Parameters

ParameterDefaultRangoControlaCuándo usar
temperature1.00.0-2.0AleatoriedadSiempre (principal knob)
max_tokensNone1-∞Longitud máximaLimitar costo/longitud
top_p1.00.0-1.0SamplingAlternativa a temperature
frequency_penalty0-2 a 2Repetición palabrasEscritura creativa
presence_penalty0-2 a 2Repetición temasBrainstorming

🎯 Guía de Decisión: Qué Parameters Usar

Use Case 1: FAQ Bot / Soporte Técnico

temperature=0.0          # Determinista
max_tokens=150           # Respuestas cortas
frequency_penalty=0      # Default
presence_penalty=0       # Default

Por qué: Consistencia es crítica (misma respuesta siempre).


Use Case 2: Chatbot General

temperature=0.7          # Ligeramente creativo
max_tokens=None          # GPT decide
frequency_penalty=0      # Default
presence_penalty=0       # Default

Por qué: Balance naturalidad/consistencia.


Use Case 3: Escritura Creativa

temperature=1.5          # Muy creativo
max_tokens=1000          # Respuestas largas
frequency_penalty=1.0    # Evita repeticiones
presence_penalty=0.8     # Explora temas diversos

Por qué: Maximiza creatividad y variedad.


Use Case 4: Clasificación (ML labeling)

temperature=0.0          # Determinista
max_tokens=5             # Solo label
frequency_penalty=0      # Default
presence_penalty=0       # Default

Por qué: Necesitas respuesta exacta y consistente.


🏭 Código Educativo vs Producción

Versión educativa (para aprender):

from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# Código simple para entender el concepto
def generate_response(prompt: str, temp: float = 0.7) -> str:
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        temperature=temp,
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

Explicación: Esta versión enfoca en entender cómo funcionan los parameters básicos sin distracciones.


Versión producción (para proyectos reales):

from openai import OpenAI
import os
import time
import logging
from typing import Optional, Dict, Any
from dotenv import load_dotenv

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def generate_response_production(
    prompt: str,
    temperature: float = 0.7,
    max_tokens: Optional[int] = None,
    max_retries: int = 3,
    timeout: int = 30
) -> Dict[str, Any]:
    """
    Genera respuesta con OpenAI API con manejo robusto de errores.
    
    Args:
        prompt: Texto del prompt
        temperature: Controla aleatoriedad (0-2)
        max_tokens: Límite de tokens (None = sin límite)
        max_retries: Intentos máximos si falla
        timeout: Timeout en segundos
    
    Returns:
        Dict con response, metadata (tokens, cost, latency)
    """
    
    # Validación de inputs
    if not prompt or not isinstance(prompt, str):
        raise ValueError("Prompt debe ser string no vacío")
    
    if not 0 <= temperature <= 2:
        raise ValueError("Temperature debe estar entre 0 y 2")
    
    if max_tokens is not None and max_tokens < 1:
        raise ValueError("max_tokens debe ser >= 1")
    
    # Retry logic con exponential backoff
    for attempt in range(max_retries):
        try:
            start_time = time.time()
            
            response = client.chat.completions.create(
                model="gpt-3.5-turbo",
                temperature=temperature,
                max_tokens=max_tokens,
                messages=[{"role": "user", "content": prompt}],
                timeout=timeout
            )
            
            latency = time.time() - start_time
            
            # Validación de response
            if not response.choices:
                raise ValueError("API retornó respuesta vacía")
            
            # Calcular costo (precios Febrero 2026)
            input_tokens = response.usage.prompt_tokens
            output_tokens = response.usage.completion_tokens
            cost = (input_tokens * 0.0015 / 1000) + (output_tokens * 0.002 / 1000)
            
            # Metadata completa
            result = {
                "content": response.choices[0].message.content,
                "metadata": {
                    "model": response.model,
                    "tokens": {
                        "input": input_tokens,
                        "output": output_tokens,
                        "total": response.usage.total_tokens
                    },
                    "cost_usd": round(cost, 6),
                    "latency_seconds": round(latency, 2),
                    "finish_reason": response.choices[0].finish_reason,
                    "temperature": temperature
                }
            }
            
            logger.info(
                f"OpenAI request successful | "
                f"tokens={response.usage.total_tokens} | "
                f"latency={latency:.2f}s | "
                f"cost=${cost:.6f}"
            )
            
            return result
            
        except Exception as e:
            logger.error(
                f"Attempt {attempt + 1}/{max_retries} failed: {type(e).__name__}: {e}"
            )
            
            # Si es el último intento, propaga el error
            if attempt == max_retries - 1:
                raise RuntimeError(
                    f"Failed after {max_retries} attempts: {e}"
                ) from e
            
            # Exponential backoff: 2^attempt segundos
            wait_time = 2 ** attempt
            logger.info(f"Retrying in {wait_time}s...")
            time.sleep(wait_time)
    
    # No debería llegar aquí
    raise RuntimeError("Unexpected error in retry logic")

# Ejemplo de uso en producción
if __name__ == "__main__":
    try:
        result = generate_response_production(
            prompt="Explica qué es FastAPI",
            temperature=0.7,
            max_tokens=300
        )
        
        print(f"Respuesta: {result['content']}\n")
        print(f"Tokens usados: {result['metadata']['tokens']['total']}")
        print(f"Costo: ${result['metadata']['cost_usd']}")
        print(f"Latencia: {result['metadata']['latency_seconds']}s")
        
    except Exception as e:
        logger.error(f"Error fatal: {e}")
        # Aquí podrías enviar alerta a Sentry, Datadog, etc.

Diferencias clave:

AspectoEducativaProducción
Validación❌ Ninguna✅ Inputs + outputs
Error handling❌ Sin retries✅ Retries con backoff
Logging❌ Sin logs✅ Logging estructurado
Timeout❌ Default (infinito)✅ 30s configurable
Metadata❌ Solo content✅ Tokens, cost, latency
Type hints⚠️ Básico✅ Completo + docstring
Cost tracking❌ No calcula✅ Cálculo preciso

Cuándo usar cada una:

  • Educativa: Para aprender el concepto, prototipos rápidos, scripts one-off
  • Producción: Para APIs, aplicaciones con usuarios reales, sistemas críticos

Nota importante: En Módulos 7-8 usarás patterns de la versión producción para el proyecto final.


🏋️ Ejercicios Prácticos

Ejercicio 1: Temperature básico (Fácil)

Modifica el código para probar 3 temperaturas (0, 0.7, 1.5) con el prompt "Dame 3 nombres de productos tech".

Ver solución
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

for temp in [0, 0.7, 1.5]:
    print(f"\n=== Temperature {temp} ===")
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        temperature=temp,
        messages=[{"role": "user", "content": "Dame 3 nombres de productos tech"}]
    )
    print(response.choices[0].message.content)

Explicación: Con temp=0 verás consistencia, con 1.5 verás creatividad máxima.


Ejercicio 2: Max tokens (Fácil)

Crea función que retorne respuestas de exactamente 50 tokens.

Ver solución
def short_response(prompt: str) -> str:
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        max_tokens=50,  # Límite estricto
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

# Test
result = short_response("Explica qué es Python")
print(result)
print(f"Tokens usados: {len(result.split())}")  # Aproximado

Explicación: max_tokens=50 fuerza respuesta corta. Útil para resúmenes o clasificación.


Ejercicio 3: Penalties (Medio)

Crea función que genere 10 ideas únicas (sin repetir conceptos) usando penalties.

Ver solución
def generate_unique_ideas(topic: str, count: int = 10) -> list:
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        temperature=1.2,  # Creativo
        frequency_penalty=1.5,  # Evita repetir palabras
        presence_penalty=1.0,  # Explora temas diversos
        messages=[{
            "role": "user",
            "content": f"Lista {count} ideas únicas sobre: {topic}"
        }]
    )
    return response.choices[0].message.content

# Test
ideas = generate_unique_ideas("apps AI para productividad", 10)
print(ideas)

Explicación: Penalties altos evitan repetición de palabras y temas, generando ideas más diversas.


Ejercicio 4: Use case específico (Medio)

Configura parameters para chatbot de soporte técnico (respuestas consistentes, cortas, sin creatividad).

Ver solución
def support_bot(question: str) -> str:
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        temperature=0.0,  # Determinista
        max_tokens=150,  # Respuestas cortas
        frequency_penalty=0,  # Default
        presence_penalty=0,  # Default
        messages=[
            {"role": "system", "content": "Eres un bot de soporte técnico. Responde conciso y consistente."},
            {"role": "user", "content": question}
        ]
    )
    return response.choices[0].message.content

# Test
print(support_bot("¿Cómo cambio mi contraseña?"))
print(support_bot("¿Cómo cambio mi contraseña?"))  # Misma respuesta

Explicación: temperature=0 garantiza respuestas idénticas para mismas preguntas. Crítico para FAQs.


Ejercicio 5: Clasificación optimizada (Avanzado)

Crea clasificador de sentimiento (Positivo/Negativo/Neutral) optimizado para costo y velocidad.

Ver solución
def classify_sentiment(text: str) -> str:
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        temperature=0.0,  # Determinista
        max_tokens=1,  # Solo 1 palabra
        messages=[
            {
                "role": "system",
                "content": "Clasifica sentimiento. Responde solo: Positivo, Negativo o Neutral"
            },
            {
                "role": "user",
                "content": text
            }
        ]
    )
    return response.choices[0].message.content

# Test
texts = [
    "Me encanta este producto!",
    "Pésimo servicio, no lo recomiendo",
    "Es un producto normal"
]

for text in texts:
    sentiment = classify_sentiment(text)
    print(f"{text[:30]:30}{sentiment}")

Explicación:

  • max_tokens=1 = costo mínimo (1 token output)
  • temperature=0 = consistencia en clasificación
  • Total: ~$0.00001 por clasificación

Ejercicio 6: Comparación A/B (Avanzado)

Compara cost y quality entre 2 configuraciones: temp=0 vs temp=1.5.

Ver solución
import time

def compare_configs(prompt: str):
    configs = [
        {"name": "Determinista", "temperature": 0.0},
        {"name": "Creativo", "temperature": 1.5}
    ]
    
    results = []
    
    for config in configs:
        start = time.time()
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            temperature=config["temperature"],
            messages=[{"role": "user", "content": prompt}]
        )
        latency = time.time() - start
        
        tokens = response.usage.total_tokens
        cost = (tokens * 0.002 / 1000)  # Aproximado
        
        results.append({
            "config": config["name"],
            "temperature": config["temperature"],
            "response": response.choices[0].message.content[:100] + "...",
            "tokens": tokens,
            "cost": f"${cost:.6f}",
            "latency": f"{latency:.2f}s"
        })
    
    # Print results
    for r in results:
        print(f"\n{'='*60}")
        print(f"Config: {r['config']} (temp={r['temperature']})")
        print(f"Response: {r['response']}")
        print(f"Tokens: {r['tokens']} | Cost: {r['cost']} | Latency: {r['latency']}")

# Test
compare_configs("Escribe un eslogan para startup AI")

Explicación: Mismo prompt, diferentes configs. Observa diferencias en calidad, variabilidad y costo.


🔗 Recursos adicionales

  1. OpenAI API Parameters - Reference completo oficial
  2. Prompt Engineering Guide - Best practices OpenAI
  3. Temperature Playground - Test interactivo de parameters
  4. OpenAI Cookbook - Parameters - Ejemplos avanzados
  5. Rate Limits & Optimization - Guía oficial
  6. Cost Calculator - Calculadora de costos
  7. Error Handling Best Practices - Guía de errores
  8. Community Examples - Discusiones community

➡️ Próximo paso

Siguiente cápsula: 06-pricing-rate-limits.md

Ahora que dominas los parameters, aprenderás:

  • Cómo calcular costos exactos
  • Rate limits y quotas
  • Optimización de costos
  • Monitoreo de usage

Tiempo: 25 minutos


Tiempo estimado: 25 minutos
Siguiente: 06-pricing-rate-limits.md