Cómo se entrena un LLM. Parte 3: por dentro del bucle
En la Parte 2 cerramos con una idea aparentemente sencilla: aprender = bajar la loss. Pero si lees ese post con mentalidad de programador, hay tres preguntas naturales que se quedan colgando antes de seguir:
- ¿Dónde se guarda esa loss? ¿En un fichero? ¿En una tabla?
- ¿Cómo son los datos de entrenamiento? ¿Se pueden ver?
- Si los pesos son lo único que «aprende», ¿qué pasa cuando hay información nueva en el mundo? ¿El modelo se va actualizando solo?
Las tres tienen respuestas no obvias y van a aparecer una y otra vez cuando hablemos de RLHF, DPO, fine-tuning, RAG y todo lo demás. Mejor resolverlas ahora, en una entrada autocontenida que sirva de suelo conceptual para el resto de la serie.
Recap mínimo: la orquesta y la loss
Si vienes directamente a esta entrada, lo único que necesitas tener en la cabeza de las dos anteriores es esto:
- Un LLM por dentro es una orquesta enorme de cuerdas afinables (los pesos, en inglés weights). Las respuestas que produce son la sinfonía que toca esa orquesta.
- «Aprender» significa tensar o aflojar las cuerdas hasta que un número llamado función de pérdida (en inglés loss) sea lo más bajo posible. La loss mide cuánto se desvía la sinfonía de la nota objetivo.
- Hay un mecanismo automático (gradient descent + backpropagation) que, dado el valor de la loss, calcula en qué dirección hay que ajustar cada una de los miles de millones de cuerdas.
Si lo tienes claro, sigue. Si no, mejor pasar primero por la Parte 2.
Pregunta 1: ¿cómo se ven los datos de entrenamiento?
Los datos de entrenamiento son ficheros normales y corrientes. Formatos tabulares: JSONL (un objeto JSON por línea), Parquet, TFRecord… nada exótico. Lo único es la escala: a veces son millones, a veces miles de millones de líneas. Pero cada línea es algo que tú podrías abrir con un editor de texto.
Cómo se ven concretamente depende de la fase del entrenamiento. Veamos las tres principales.
Pretraining: solo texto
{"text": "El karst es un tipo de paisaje rocoso formado por la disolución de rocas solubles..."}
{"text": "La función map() en Python aplica una función a cada elemento de un iterable..."}
{"text": "Federico García Lorca nació en Fuente Vaqueros en 1898..."}
Texto crudo, miles de millones de líneas como esas. Aquí no hay «etiqueta» explícita: el propio texto es a la vez entrada y respuesta correcta. El modelo intenta predecir cada palabra a partir de las anteriores, y el dato de «verdad» es la siguiente palabra real del texto.
SFT (Supervised Fine-Tuning, ajuste fino supervisado): pares prompt-respuesta
{"prompt": "Explícame qué es el karst de forma sencilla",
"completion": "El karst es un paisaje formado cuando el agua de lluvia, ligeramente ácida, va disolviendo poco a poco rocas como la caliza..."}
{"prompt": "Tradúceme «buenos días» al alemán",
"completion": "«Guten Morgen»."}
Cada línea es un par (prompt, respuesta_modelo) escrito por humanos. La respuesta es la nota objetivo explícita: el modelo va a intentar imitarla token a token y la loss mide cuánto se desvía de ella. Veremos SFT con más detalle en la próxima entrega.
RLHF (datos de preferencia): trios
{"prompt": "Explícame qué es el karst",
"response_a": "El karst es un tipo de paisaje rocoso formado por la disolución de rocas solubles, principalmente caliza...",
"response_b": "Es cuando el agua se come las piedras lol",
"preferred": "a"}
Cada línea es un trio: el mismo prompt, dos respuestas distintas que un humano ha visto, y la indicación de cuál ha preferido. No hay puntuación absoluta, solo una comparación binaria. Veremos en la Parte 4 por qué esa elección de formato (comparar pares en lugar de puntuar del 1 al 10) no es estética: es la pieza que hace que RLHF (Reinforcement Learning from Human Feedback, aprendizaje por refuerzo a partir de feedback humano) funcione.
El detalle no obvio
Lo importante de los tres ejemplos: son ficheros estáticos. Se preparan, se guardan en disco y de ahí se leen durante el entrenamiento. No «se generan al vuelo» ni «se actualizan dinámicamente». Cuando un lab grande entrena un modelo nuevo, decide a priori el corpus, lo congela y entrena contra ese corpus. Si más adelante quiere meter datos nuevos, tiene que re-entrenar, y eso lo veremos al final del post.
Pregunta 2: ¿dónde se guarda la loss?
Aquí está el malentendido más común y más útil de aclarar.
Una intuición razonable, viniendo de programación, sería pensar que en algún sitio hay una tabla así:
{
"la música de moda es el": {
"jazz": { "loss": 2.3 },
"rock": { "loss": 1.8 },
"pop": { "loss": 1.5 },
"reggaeton": { "loss": 1.4 }
}
}
…una especie de base de datos donde cada frase tiene su loss «actualizándose» cuando llega información nueva. No funciona así.
La loss es efímera: se calcula, se usa una vez para ajustar los pesos y se descarta. Mira el bucle, en pseudocódigo:
for batch in dataset:
prediccion = modelo(batch.prompt) # la orquesta toca
loss = comparar(prediccion, batch.target) # mide la desviación
gradientes = backprop(loss) # calcula cómo afinar las cuerdas
modelo.pesos -= learning_rate * gradientes # afina las cuerdas
# ← aquí la loss se descarta. Solo queda su efecto, ya disuelto en los pesos.
Después de la línea de modelo.pesos -= ..., la loss desaparece. Lo único que queda son los pesos modificados un pelín.
El otro JSON: trazas para humanos
Hay un sitio donde sí se guardan las loss, pero es otro fichero distinto, y es para los ingenieros, no para el modelo:
{"step": 12500, "loss": 1.834, "learning_rate": 1e-5, "tokens_seen": 1.6e9}
{"step": 12501, "loss": 1.829, "learning_rate": 1e-5, "tokens_seen": 1.6e9}
{"step": 12502, "loss": 1.821, "learning_rate": 1e-5, "tokens_seen": 1.6e9}
Esto se llama logging de entrenamiento y se sube a herramientas como Weights & Biases o TensorBoard. Los ingenieros lo miran en gráficas para ver si la loss baja, si converge o si explota. Es monitorización para humanos, no memoria del modelo. El modelo no consulta este fichero. Si lo borraras, el entrenamiento seguiría exactamente igual.
Resumen de la pregunta 2: los datos de entrada se guardan; la loss no. La loss es un número intermedio que se calcula, se usa para mover los pesos un pelín y se tira. Lo que persiste no es el número, sino el efecto que tuvo en los pesos.
El ejemplo trazado: «la música de moda es el ___»
Vamos a trazar paso a paso qué pasa con una frase ambigua, porque es donde se ven más claramente las consecuencias de lo anterior.
Imagina que el corpus de entrenamiento contiene, repartidas entre miles de millones de frases, ocurrencias del patrón «la música de moda es el ___»:
- En un blog de los 60s: «la música de moda es el rock».
- En una hemeroteca de los 90s: «la música de moda es el grunge».
- En un foro de 2010: «la música de moda es el reggaeton».
- En Twitter de 2020: «la música de moda es el trap».
El entrenamiento se las va comiendo una a una, en orden aleatorio. Cada vez que se topa con una de ellas:
PASO 12.503 del entrenamiento
---
Input al modelo: "la música de moda es el"
Target (real): "rock"
Predicción del modelo (distribución sobre 50.000 palabras posibles):
pop: 0,18
rock: 0,05 ← le asigna baja probabilidad
reggaeton: 0,14
jazz: 0,04
...
Loss = -log(0,05) ≈ 3,0 → "te has equivocado bastante"
Gradientes calculados → ajustar pesos para que, en este contexto,
suba un poquito la probabilidad de "rock".
Pesos actualizados. Loss descartada. Siguiente paso.
Y mucho más adelante, con los pesos ya un poco distintos:
PASO 47.812 del entrenamiento
---
Input: "la música de moda es el"
Target: "reggaeton"
Predicción ahora (los pesos ya han cambiado un pelín):
pop: 0,17
rock: 0,09 ← subió un pelín por aquel paso anterior
reggaeton: 0,14
...
Loss = -log(0,14) ≈ 2,0
Gradientes → subir un poquito "reggaeton".
Loss descartada.
El resultado final
Cuando termina todo el entrenamiento y le preguntas al modelo «la música de moda es el ___», no te da una respuesta única. Lo que te da, internamente, es una distribución de probabilidad que refleja la frecuencia relativa de cada continuación que vio en su corpus:
pop: 0,18
rock: 0,15
reggaeton: 0,14
trap: 0,11
jazz: 0,05
grunge: 0,04
techno: 0,03
... (resto con probabilidades más bajas)
No hay una «verdad correcta» almacenada. Hay un mapa de plausibilidad. En el momento de generar la respuesta, el modelo samplea de ahí (con un parámetro llamado temperatura que se puede subir para que arriesgue más, o bajar para que vaya a lo más probable).
Idea clave: el modelo no aprende «la respuesta es X». Aprende una distribución sobre todas las palabras posibles, calibrada para imitar las frecuencias del corpus.
Pregunta 3: ¿dónde queda lo aprendido?
Hemos visto que los datos sí se guardan y que la loss no. ¿Y «lo que aprende» el modelo? Está en sus pesos. Y aquí viene la propiedad más rara y más importante de la «memoria» de un LLM: no es declarativa, no es consultable, no se puede inspeccionar.
Una vez terminado el entrenamiento, podrías borrar el dataset entero y el modelo seguiría funcionando exactamente igual. No «consulta» los datos en runtime. Los datos pasaron por él durante el entrenamiento, dejaron huella en los pesos, y se acabó la relación.
Lo aprendido está disuelto en miles de millones de números. Si abrieras el fichero del modelo (que es esencialmente una matriz gigante), no encontrarías «el dato del karst aquí» o «lo del reggaeton allá». Verías ruido aparente, números entre -1 y 1 sin estructura legible. Y sin embargo, ese conjunto de números, cuando se aplica a una frase de entrada, produce respuestas coherentes.
La analogía: memoria muscular del guitarrista
Imagina que aprendes a tocar la guitarra practicando 1.000 canciones. Al final lo que sabes está en tus dedos (memoria muscular = pesos del modelo), no en una libreta donde tengas apuntado «error en compás 14 de la canción 47, corregí inclinando el dedo así». La libreta podría haber existido durante la práctica (las trazas de loss), pero al final lo que tocas se sostiene solo, sin libreta.
Si te tocara explicarle a otra persona «qué» sabes y «cómo» lo sabes, no podrías. Solo podrías tocar. El conocimiento es procedural, no declarativo. Lo mismo le pasa al modelo: sabe responder, pero no tiene un índice consultable de «lo que sabe».
Consecuencia práctica importante: no se puede «borrar» un hecho concreto de un LLM una vez entrenado. Si entrenaste el modelo con un texto que contenía un dato erróneo, no hay un sitio donde localizar ese dato y eliminarlo. El dato está repartido, fragmentado, mezclado con todo lo demás. Esto hace que el «derecho al olvido» sea un problema técnico abierto y muy difícil. Es uno de los motivos por los que los grandes labs son cuidadosos con qué meten en los corpus de entrenamiento.
El cuadro mental: persistido vs efímero, estático vs dinámico
Vamos a poner orden con una tabla, porque es el bloque conceptual del que va a colgar todo lo que viene en la serie:
| Cosa | Persistencia | Forma |
|---|---|---|
| Datos de entrenamiento | Almacenados en disco | JSONL, Parquet… con (input, target) o (prompt, resp_a, resp_b, preferred) |
| Loss durante el entrenamiento | Efímera (se descarta cada paso) | Un float por paso |
| Logs de entrenamiento (para humanos) | Almacenados (Weights & Biases, TensorBoard) | {step, loss, learning_rate, ...} |
| Lo aprendido | Persistido pero no consultable | Disuelto en los pesos |
| Distribución de salida | Computada en runtime a partir de los pesos | Vector de probabilidades sobre el vocabulario |
| Pesos | Estáticos tras el entrenamiento | Matriz gigante, congelada |
| Prompt / contexto de inferencia | Dinámico, distinto en cada llamada | Texto que el usuario pasa al modelo |
Las dos últimas filas son la pieza más importante para entender lo que viene. Los pesos son estáticos una vez termina el entrenamiento. El prompt es lo único dinámico en cada interacción. Cualquier «actualización» tiene que tocar uno de los dos.
¿Cómo se le mete información nueva a un modelo?
Si los pesos están congelados y la loss no se guarda, ¿cómo aprende un LLM cosas nuevas?
La respuesta corta es que no aprende solo. Cualquier «actualización» es una operación explícita y discreta, no continua. Hay tres formas, ordenadas de la más cara y profunda a la más barata y superficial.
1. Re-entrenamiento (continued pretraining)
Es lo más bestia: vuelves a someter el modelo al bucle de pretraining, pero esta vez con un corpus ampliado que incluye texto reciente. Los pesos vuelven a moverse. Todos.
- Coste: astronómico. Miles de GPUs durante días o semanas. Decenas o cientos de miles de euros.
- Frecuencia: baja. Es lo que hacen los labs grandes cuando sacan una versión nueva (Llama 3 → Llama 3.1, GPT-4 → GPT-4-turbo). No es algo continuo.
2. Fine-tuning (ajuste fino)
Misma idea pero a escala mucho menor. En lugar de pasar el modelo por billones de tokens, lo afinas con un dataset pequeño y específico (de unos miles a unos millones de ejemplos). A menudo no se tocan todos los pesos: existen técnicas como LoRA (Low-Rank Adaptation, adaptación de bajo rango) que congelan la mayoría del modelo y solo entrenan un puñado de capas extra muy ligeras.
- Coste: moderado. Horas o días en GPUs accesibles. Cientos o pocos miles de euros.
- Casos típicos: adaptar el modelo a un dominio (médico, legal), a un estilo (la voz de tu marca) o a una tarea concreta (clasificar tickets, extraer datos de facturas).
- Detalle importante: RLHF, técnicamente, es una forma de fine-tuning. El bucle es el mismo; lo que cambia es de dónde sale la loss.
3. RAG (Retrieval Augmented Generation, generación aumentada con recuperación)
Aquí cambia radicalmente la filosofía. Los pesos no se tocan. Lo que se hace es enchufarle al modelo, en runtime, una pieza externa que busca información actualizada en una base de datos y se la inyecta en el prompt como contexto extra.
Usuario: "¿Cuál es la política de devoluciones de la empresa?"
↓
Retriever: busca en la base de datos los párrafos más relevantes
de los documentos internos.
↓
Sistema construye el prompt aumentado:
[CONTEXTO]
"Política de devoluciones (rev. abril 2026): los productos
pueden devolverse en un plazo de 30 días desde la entrega..."
[PREGUNTA]
¿Cuál es la política de devoluciones de la empresa?
↓
Modelo: responde basándose en el contexto recuperado.
- Coste: bajísimo. No reentrenas nada. Solo necesitas indexar tus documentos una vez (y reindexar cuando cambian).
- Ventajas: información fresca, auditable (el modelo puede citar las fuentes), barata, y un único modelo puede atender a 1.000 clientes con 1.000 bases de conocimiento separadas.
- Limitaciones: el modelo no «interioriza» la información, la lee cada vez. La calidad de la respuesta depende mucho del retriever. El contexto tiene un límite (la «ventana de contexto» del modelo).
El cuadro resumen
| Método | Qué cambia | Coste | Frecuencia | Para qué sirve |
|---|---|---|---|---|
| Re-entrenamiento | Todos los pesos | Altísimo | Cada meses/años | Versión nueva del modelo base |
| Fine-tuning | Algunos pesos | Moderado | Por proyecto | Adaptar a dominio/tarea/estilo |
| RAG | Solo el prompt | Mínimo | Cada consulta | Información fresca y auditable |
El cambio de mentalidad importante: «el modelo», en sí, va a ser siempre estático. La pregunta operativa interesante no es «¿cómo aprende el modelo en vivo?» (no aprende), sino «¿qué le pongo delante en cada llamada para que actúe como si supiera lo último?». Esa pregunta es la que han pasado a hacerse las arquitecturas modernas de aplicaciones con LLMs y la veremos a fondo en la última entrega de la serie.
Resumen
- Los datos de entrenamiento son ficheros normales (JSONL, Parquet) y sí se almacenan. Su forma cambia según la fase: texto crudo en pretraining, pares
(prompt, completion)en SFT, trios(prompt, resp_a, resp_b, preferred)en RLHF. - La loss es efímera: se calcula, mueve los pesos un pelín y se descarta. Lo que sí se guarda son las trazas de loss para que los ingenieros monitoricen el entrenamiento.
- Lo aprendido queda disuelto en los pesos. No es consultable. No se puede borrar un hecho concreto. La memoria del modelo es procedural (como la de un guitarrista), no declarativa.
- Para un input ambiguo, el modelo no aprende «la respuesta correcta» sino una distribución de probabilidad sobre todas las continuaciones plausibles.
- Los pesos son estáticos tras el entrenamiento. Lo único dinámico en cada llamada es el prompt.
- Para meter información nueva: re-entrenamiento (caro, mueve todos los pesos), fine-tuning (moderado, mueve algunos) o RAG (mínimo, no toca pesos, solo aumenta el prompt).
Próxima entrega
Con todo esto en la cabeza, ya puedes meterte en la Parte 4: RLHF, la maquinaria, la primera de las técnicas serias de alineamiento. RLHF (Reinforcement Learning from Human Feedback, aprendizaje por refuerzo a partir de feedback humano) es la pieza que convirtió un GPT-3 brillante pero impenetrable en el ChatGPT de noviembre de 2022 que cualquiera podía usar. En coloquial: se afina el modelo a base de que humanos comparen pares de respuestas y digan cuál suena mejor. En esa entrega veremos por qué comparar es radicalmente más fiable que puntuar, qué es un modelo de recompensa, cómo se cierra el bucle con PPO y por qué noviembre de 2022 marcó un antes y un después en la industria.
En entregas posteriores cubriremos las grietas de RLHF (sí, las tiene, y serias) y las técnicas que se inventaron para esquivarlas: RLAIF, DPO y RLVR.
