El mismo prompt, dos respuestas distintas
Lanzas la misma petición dos veces y el modelo contesta cosas diferentes. La primera reacción es pensar que algo falla. No falla: es que un LLM no elige la siguiente palabra, la sortea. En cada paso calcula una probabilidad para cada token posible y saca uno de esa lotería. Quien controla las reglas de la lotería eres tú, con tres parámetros que la mayoría deja en su valor por defecto sin saber qué hacen: temperatura, top-p y top-k.
Entender esas tres perillas es la diferencia entre un modelo que inventa cuando necesitas precisión y uno que repite lo mismo cuando le pides ideas. No es ajuste fino de experto; es higiene básica de cualquiera que sirva un LLM en producción.
De logits a probabilidades
Antes de elegir, el modelo produce un vector de puntuaciones crudas, una por cada
token de su vocabulario: los logits. Esos números no suman uno ni son
probabilidades todavía. La función softmax los convierte en una distribución:
exponencia cada logit y lo normaliza para que el total sea uno. El token con
mayor logit se lleva la mayor probabilidad, pero el resto también recibe su parte.
La clave está en ese paso de exponenciar, porque es justo donde entra la temperatura. Todo lo demás (top-k, top-p) actúa después, recortando la lista de candidatos antes de tirar el dado.
Temperatura: cuánto arriesga el modelo
La temperatura divide los logits antes del softmax. Con temperatura baja, las
diferencias entre logits se agrandan: el token favorito se dispara y el modelo
casi siempre elige lo más probable. Con temperatura alta, las diferencias se
aplanan y tokens improbables ganan opciones reales de salir.
import numpy as np
logits = np.array([2.0, 1.0, 0.1]) # tres tokens candidatos
def softmax_con_temperatura(logits, t):
z = logits / t # la temperatura escala los logits
e = np.exp(z - z.max()) # -max por estabilidad numérica
return e / e.sum()
print(softmax_con_temperatura(logits, 0.5)) # [0.87 0.12 0.02] -> conservador
print(softmax_con_temperatura(logits, 1.0)) # [0.66 0.24 0.10] -> por defecto
print(softmax_con_temperatura(logits, 1.5)) # [0.55 0.28 0.16] -> arriesgado
Fíjate en la primera columna: a temperatura 0,5 el token favorito acapara el 87 % de la probabilidad; a 1,5 baja al 55 % y los demás respiran. Temperatura 0 es el caso límite: elegir siempre el token más probable, sin azar. Ahí el modelo se vuelve determinista y repetible, que es justo lo que quieres cuando extraes un JSON o clasificas un ticket.
Top-k y top-p: recortar la lista antes de sortear
La temperatura reparte probabilidad, pero no impide que un token absurdo con una probabilidad diminuta acabe saliendo de vez en cuando. Para eso están los métodos de truncado, que descartan la cola larga de candidatos malos antes del sorteo.
Top-k se queda con los k tokens más probables y tira el resto. Sencillo,
pero rígido: k = 40 puede ser demasiado generoso cuando solo hay una
continuación sensata y demasiado corto cuando hay muchas igual de válidas.
Top-p (o nucleus sampling) es más listo: ordena los tokens por
probabilidad y se queda con los que suman, acumulados, hasta p. Con p = 0,9,
el modelo considera el conjunto mínimo de tokens que cubre el 90 % de la
probabilidad. Si un token domina, la lista se queda en dos o tres; si hay muchos
plausibles, se ensancha sola. Se adapta al contexto, y por eso es hoy el método
por defecto en casi todas las APIs.
| Parámetro | Qué hace | Sube el valor → | Rango típico |
|---|---|---|---|
| Temperatura | Escala los logits | Más aleatorio y creativo | 0 – 1,2 |
| Top-k | Deja los k mejores | Más candidatos, más ruido | 20 – 100 |
| Top-p | Deja el núcleo del p % | Más candidatos, más ruido | 0,8 – 0,95 |
No los toques todos a la vez
El error más común es mover temperatura y top-p al mismo tiempo buscando “más creatividad” y acabar con salidas incoherentes. Los dos regulan lo mismo desde ángulos distintos, así que interactúan de forma poco intuitiva. La regla práctica que a mí me funciona: fija uno y mueve el otro.
Para tareas donde importa el acierto (extracción de datos, clasificación, llamadas a herramientas, código), baja la temperatura a cerca de cero y olvídate de top-p. Quieres el token más probable, no una interpretación artística del esquema. Para tareas donde importa la variedad (ideas, borradores, títulos alternativos), sube la temperatura a un rango de 0,7 a 1,0 y deja top-p en torno a 0,9. Y si generas varias opciones de una tirada, súbela un poco más: preferible tres candidatos distintos que tres clones.
# Determinista: para JSON, clasificación, tool calling
resp = client.chat.completions.create(
model="gpt-4o",
messages=mensajes,
temperature=0, # sin azar; misma entrada, misma salida
)
# Creativo: para brainstorming, variantes de copy
resp = client.chat.completions.create(
model="gpt-4o",
messages=mensajes,
temperature=0.9, # arriesga
top_p=0.9, # pero sin candidatos absurdos
n=3, # tres alternativas de una vez
)
La letra pequeña: determinista no es garantía
Temperatura 0 acerca la salida a lo determinista, pero no siempre la clava al
cien por cien. En hardware paralelo el orden de las operaciones en coma flotante
puede variar entre ejecuciones, y una diferencia mínima en los logits basta para
que, en un empate, salga otro token. Si necesitas reproducibilidad estricta para
depurar o para tests, fija también la semilla (seed) cuando la API la exponga y
registra la respuesta del modelo. No te fíes de que “temperatura 0” signifique
“idéntico siempre”.
Cómo empezar mañana
Antes de tocar el prompt por enésima vez, comprueba con qué parámetros de muestreo estás llamando al modelo. Si los tienes por defecto, muy probablemente estás pidiendo creatividad a una tarea que necesita precisión, o al revés.
Separa tus llamadas en dos perfiles y trátalos distinto: uno determinista a temperatura cero para todo lo que deba ser fiable y verificable, y otro creativo con temperatura alta y top-p sobre 0,9 para lo que deba ser variado. Cambia un parámetro cada vez y mide el efecto sobre casos reales, no sobre una impresión. La aleatoriedad de un LLM no es un defecto que aguantar; es una perilla, y ahora sabes en qué dirección girarla.