📖 Teoría

Large Language Models (LLMs)

Desde BERT y GPT hasta agentes autónomos: la revolución de los grandes modelos de lenguaje. Arquitecturas encoder-only vs decoder-only, pre-training a escala, tokenización, scaling laws, fine-tuning con PEFT/LoRA, RLHF, DPO, prompting avanzado, modelos de razonamiento, LLMs multimodales, function calling y frameworks de agentes.

De Transformers a LLMs

El Transformer (Vaswani et al., 2017) introdujo una arquitectura basada enteramente en atención que reemplazó a las RNNs. Pero fue la idea de pre-entrenar masivamente un Transformer con texto no etiquetado y luego ajustarlo (fine-tuning) a tareas específicas la que dio lugar a los Large Language Models (LLMs).

Dos filosofías divergentes emergieron casi simultáneamente en 2018:

🎭
BERT (Google)
Encoder-only. Bidireccional. Entiende el lenguaje en contexto completo. Ideal para clasificación, NER, QA extractivo.
🤖
GPT (OpenAI)
Decoder-only. Autoregresivo (izquierda → derecha). Genera texto. Ideal para chatbots, resumen, código, razonamiento.
2017 Transformer Jun 2018 GPT-1 Oct 2018 BERT 2019 GPT-2 2020 GPT-3 2022 ChatGPT 2023+ GPT-4 · LLaMA · Gemini

BERT: Bidirectional Encoder Representations from Transformers

BERT (Devlin et al., 2018) fue el primer modelo en demostrar que un Transformer encoder pre-entrenado bidireccionalmente podía lograr resultados SOTA en 11 tareas de NLP simultáneamente, simplemente añadiendo una capa de clasificación encima.

📄 Paper: "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding"

Devlin, Chang, Lee & Toutanova (2018).
arXiv:1810.04805 · GitHub

Arquitectura del Encoder

BERT usa exclusivamente el encoder del Transformer original:

[CLS] El gato [MASK] sobre la alfombra [SEP] Token + Segment + Position Embeddings Transformer Encoder × L Multi-Head Self-Attention → Add&Norm → FFN → Add&Norm Atención bidireccional: cada token atiende a TODOS los demás MLM Head Predice tokens [MASK] NSP Head ¿Frase B sigue a A? Pre-training objectives (MLM + NSP)

Objetivos de pre-entrenamiento

Se enmascara aleatoriamente el 15% de los tokens de entrada y el modelo debe predecir los tokens originales. De ese 15%:

  • 80% → se reemplaza por [MASK]
  • 10% → se reemplaza por un token aleatorio
  • 10% → se deja sin cambiar

Esta estrategia evita que el modelo dependa del token especial [MASK] (que nunca aparece en fine-tuning/inferencia) y fuerza representaciones robustas.

$$\mathcal{L}_{\text{MLM}} = -\sum_{i \in \mathcal{M}} \log P(x_i \mid \mathbf{x}_{\setminus \mathcal{M}})$$

Donde \(\mathcal{M}\) es el conjunto de posiciones enmascaradas.

Dado un par de frases (A, B), el modelo predice si B es la frase siguiente real de A (IsNext) o una frase aleatoria (NotNext). Se usa la representación del token [CLS] para la clasificación binaria.

Nota: estudios posteriores (RoBERTa, ALBERT) demostraron que NSP tiene un impacto limitado y que eliminar este objetivo no afecta (o mejora) los resultados.

Input Representation

Cada token de entrada es la suma de tres embeddings:

EmbeddingDescripciónEjemplo
TokenWordPiece embedding del subword"play" → "play", "##ing" → "##ing"
SegmentIndica frase A o B (para tareas de pares)[0, 0, 0, 1, 1, 1]
PositionPosición aprendida (no sinusoidal, max 512)[0, 1, 2, ..., 511]

Configuraciones de BERT

ModeloCapas (L)Hidden (H)Heads (A)Parámetros
BERTBASE1276812110M
BERTLARGE24102416340M

Familia y variantes de BERT

Tras el éxito de BERT surgieron numerosas variantes que mejoran aspectos específicos:

Robustly Optimized BERT Approach. Elimina NSP, usa más datos (160 GB vs 16 GB), más batch size, secuencias más largas, y masking dinámico (diferente máscara cada epoch).

Resultados: +2-4 puntos sobre BERT en GLUE, SQuAD y RACE.

arXiv:1907.11692

A Lite BERT. Dos técnicas de reducción de parámetros:

  • Factorized Embedding: separa la dimensión del vocabulario (V×E) de la hidden (E×H)
  • Cross-Layer Parameter Sharing: todas las capas comparten pesos

ALBERT-xxlarge: 235M → 12M parámetros únicos, con rendimiento similar a BERT-large.

arXiv:1909.11942

Knowledge distillation aplicada a BERT. Un modelo "estudiante" de 6 capas que aprende de BERT-base (12 capas) como "profesor".

Resultado: 60% más rápido, 40% menos parámetros (66M), retiene el 97% del rendimiento de BERT.

arXiv:1910.01108

En lugar de MLM, usa un esquema GAN-like: un generador pequeño reemplaza tokens y un discriminador (el modelo principal) predice qué tokens fueron reemplazados (replaced token detection).

Ventaja: cada token recibe una señal de entrenamiento (no solo el 15% enmascarado), lo que lo hace mucho más eficiente computacionalmente.

arXiv:2003.10555

Disentangled attention: separa las representaciones de contenido y posición en la atención. Añade un Enhanced Mask Decoder que usa posición absoluta solo en la capa final.

DeBERTa-v3 fue el primer modelo en superar el rendimiento humano en el benchmark SuperGLUE.

arXiv:2006.03654

ModeloParamsMejora claveGLUE ScoreAño
BERT-base110MMLM + NSP79.62018
RoBERTa-large355MMás datos, sin NSP88.52019
ALBERT-xxlarge235MParameter sharing89.42019
DistilBERT66MDistillation77.02019
ELECTRA-large335MReplaced token detection89.52020
DeBERTa-v3304MDisentangled attention91.42020

Fine-tuning de BERT

El paradigma "pre-train then fine-tune" de BERT revolucionó el NLP. La idea central es simple: tomar el encoder pre-entrenado y añadir una capa de clasificación específica para cada tarea.

📄
Clasificación
Token [CLS] → capa lineal. Sentimiento, spam, categorías.
🏷️
NER / Token cls.
Cada token → capa lineal. Entidades, POS tagging.
QA extractivo
Predecir start/end tokens de la respuesta en el contexto.
🔗
Similitud / NLI
Par de frases → [CLS] → entailment, contradiction, neutral.
# ═══════════════════════════════════════════════════
# Fine-tuning BERT para clasificación de sentimiento
# ═══════════════════════════════════════════════════
from transformers import BertTokenizer, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
from datasets import load_dataset

# 1. Cargar modelo pre-entrenado
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForSequenceClassification.from_pretrained(
    'bert-base-uncased',
    num_labels=2  # positivo / negativo
)

# 2. Dataset
dataset = load_dataset('imdb')

def tokenize(batch):
    return tokenizer(batch['text'], padding='max_length',
                     truncation=True, max_length=512)

tokenized = dataset.map(tokenize, batched=True)

# 3. Training
args = TrainingArguments(
    output_dir='./results',
    num_train_epochs=3,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=64,
    learning_rate=2e-5,        # LR bajo, típico de fine-tuning
    weight_decay=0.01,
    evaluation_strategy='epoch',
    warmup_steps=500,
    fp16=True,                 # Mixed precision
)

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=tokenized['train'],
    eval_dataset=tokenized['test'],
)

trainer.train()  # ~93% accuracy en IMDb

GPT: Generative Pre-trained Transformer

GPT (Radford et al., 2018) tomó el camino opuesto a BERT: usar solo el decoder del Transformer con atención causal (masked) para modelar la probabilidad del siguiente token.

📄 Papers de la serie GPT

  • GPT-1: "Improving Language Understanding by Generative Pre-Training" (Radford et al., 2018) [PDF]
  • GPT-2: "Language Models are Unsupervised Multitask Learners" (Radford et al., 2019) [PDF] · GitHub
  • GPT-3: "Language Models are Few-Shot Learners" (Brown et al., 2020) arXiv:2005.14165
  • GPT-4: "GPT-4 Technical Report" (OpenAI, 2023) arXiv:2303.08774

Modelado autoregresivo

GPT modela la distribución de probabilidad del lenguaje de forma causal (izquierda a derecha):

$$P(x_1, x_2, \ldots, x_n) = \prod_{i=1}^{n} P(x_i \mid x_1, \ldots, x_{i-1})$$

El objetivo de pre-entrenamiento es maximizar la log-verosimilitud:

$$\mathcal{L}_{\text{CLM}} = -\sum_{i=1}^{n} \log P(x_i \mid x_1, \ldots, x_{i-1}; \theta)$$

La máscara causal impide que cada token atienda a tokens futuros, lo que permite la generación autoregresiva token a token.

El gato se sentó sobre la Token Embeddings + Positional Embeddings (aprendido) Transformer Decoder × L Masked Multi-Head Self-Attention → Add&Norm → FFN → Add&Norm Atención causal: token i solo atiende a tokens 1..i Language Model Head Linear(d_model → vocab_size) + Softmax → P("alfombra") = 0.47, P("mesa") = 0.12, ...

Evolución de GPT

ModeloParamsDatosContextInnovación clave
GPT-1117MBookCorpus (5 GB)512Pre-train + fine-tune con decoder-only
GPT-21.5BWebText (40 GB)1024"Zero-shot learning" sin fine-tuning
GPT-3175B300B tokens2048In-context learning, few-shot
GPT-3.5~175BIdem + RLHF4096InstructGPT → ChatGPT
GPT-4~1.8T*~13T tokens*8K-128KMoE, multimodal, razonamiento
GPT-4o128KNatively multimodal (texto+imagen+audio)

* Estimaciones no oficiales (fuentes: análisis independientes, filtraciones).

BERT vs GPT: Comparativa

AspectoBERT (Encoder-only)GPT (Decoder-only)
DirecciónBidireccionalUnidireccional (izq → der)
Pre-trainingMLM + NSPCausal Language Modeling
Uso principalComprensión (clasificación, NER, QA)Generación (texto, código, chat)
Fine-tuningNecesario para cada tareaOpcional (in-context learning)
ContextoVentana completa (fija, 512)Ventana creciente (hasta 128K+)
AtenciónFull attention (O(n²))Causal mask (triangular inferior)
Escalado~340M max (limitado)~1.8T (escala masivamente)
EmbeddingsToken + Segment + Position (aprendido)Token + Position (aprendido/RoPE)
NormalizaciónPost-LayerNormPre-LayerNorm (GPT-2+) → RMSNorm
Activación FFNGELUGELU → SwiGLU (LLaMA+)
VentajaContexto bidireccional ricoGenera texto, escala mejor
💡 ¿Por qué ganó GPT? Aunque BERT domina en benchmarks de comprensión, los modelos decoder-only (GPT-like) han dominado la era de los LLMs porque: (1) generan texto directamente, (2) escalan mejor con datos y compute, (3) el in-context learning elimina la necesidad de fine-tuning, y (4) la generación permite instrucciones y diálogo (ChatGPT).

🔬 Widget: Comparador de tamaño de modelos

Visualiza la escala de diferentes LLMs en términos de parámetros y datos de entrenamiento.

vs

El ecosistema open-source

A partir de 2023, una ola de modelos open-source / open-weight democratizó el acceso a LLMs de alta calidad:

ModeloOrganizaciónParamsLicenciaInnovación
LLaMAMeta7-65BResearchModelos fundacionales eficientes
LLaMA 2Meta7-70BComercialDatos 40% más, GQA en 70B
LLaMA 3Meta8-405BComercial15T tokens, 128K context
Mistral 7BMistral7BApache 2.0Sliding Window Attention, GQA
Mixtral 8×7BMistral46.7B (12.9B activos)Apache 2.0Mixture of Experts (MoE)
Qwen 2.5Alibaba0.5-72BApache 2.0Multilingüe, código, matemáticas
Gemma 2Google2-27BAbiertaDestilación de Gemini
DeepSeek-V3DeepSeek671B (37B activos)MITMoE eficiente, FP8 training
Phi-3Microsoft3.8BMITDatos curados de alta calidad

📚 Repositorios clave

Pre-training de LLMs: el cimiento

El pre-training es la fase donde un LLM aprende la estructura del lenguaje, conocimiento factual y capacidad de razonamiento a partir de billones de tokens de texto no etiquetado. Es la fase más costosa computacionalmente (millones de dólares en GPUs durante semanas o meses).

Datos Web, libros, código ~1-15T tokens Limpieza Dedup, filtrado, calidad, PII Tokenización BPE / SentencePiece 32K-128K vocab Training CLM / next token Miles de GPUs Base Model Completa texto, no sigue instrucciones Pre-training pipeline (semanas-meses, $2M-$100M+)

Datasets de pre-training

La calidad y diversidad de los datos determina en gran medida las capacidades del modelo. Los datasets modernos combinan múltiples fuentes:

DatasetTamañoFuentesUsado por
Common Crawl~250B páginasWeb crawl globalGPT-3, LLaMA, todos
C4~750 GBCommon Crawl filtradoT5, PaLM
The Pile825 GB22 fuentes diversasGPT-NeoX, Pythia
RedPajama1.2T tokensRéplica de LLaMAOpen-source
FineWeb15T tokensCommon Crawl curado por HFOpen-source
The Stack v2~4TBCódigo fuente (GitHub)StarCoder 2
Wikipedia~20 GBEnciclopediaBERT, GPT-3, todos
Books3~100 GBLibrosGPT-3, LLaMA (controversia)
arXiv~85 GBPapers científicosGalactica, LLaMA
1
Language filtering: clasificador fastText para filtrar idiomas deseados.
2
Quality filtering: perplexity scoring con un LM pequeño, heurísticas (longitud, ratio alfanumérico, repeticiones).
3
Deduplication: MinHash LSH para eliminar duplicados cercanos (exact + near-dedup).
4
PII removal: eliminación de emails, teléfonos, IPs, SSNs con regex + NER.
5
Toxicity filtering: clasificador para contenido tóxico/NSFW.
6
Data mixing: proporciones de cada fuente (ej: LLaMA 3 usa 50% web, 25% código, 15% libros, 10% papers).

Ref: Penedo et al. (2024) "The FineWeb Datasets" (arXiv:2406.17557)

Tokenización para LLMs

Los LLMs no procesan texto crudo sino tokens — unidades subword que equilibran la granularidad entre caracteres y palabras.

🔤
BPE
Byte-Pair Encoding. Fusiona pares de bytes/caracteres más frecuentes iterativamente. Usado por GPT-2/3/4.
🔡
WordPiece
Similar a BPE pero maximiza la verosimilitud del corpus. Usado por BERT.
📝
SentencePiece
Unigram o BPE sobre bytes crudos (sin pre-tokenización). Usado por LLaMA, T5, Mistral.
🧬
tiktoken
BPE optimizado de OpenAI. cl100k_base (100K vocab) para GPT-4. GitHub
import tiktoken

# GPT-4 tokenizer
enc = tiktoken.get_encoding("cl100k_base")

text = "Los Large Language Models procesan tokens, no palabras."
tokens = enc.encode(text)
print(f"Texto: {text}")
print(f"Tokens: {tokens}")
print(f"Nº tokens: {len(tokens)}")
print(f"Decodificado: {[enc.decode([t]) for t in tokens]}")

# Output:
# Texto: Los Large Language Models procesan tokens, no palabras.
# Tokens: [30832, 20902, 11688, 27972, 62853, 11, 912, 84113, 13]
# Nº tokens: 9
# Decodificado: ['Los', ' Large', ' Language', ' Models', ' procesan', ' tokens', ',', ' no', ' palabras', '.']

Scaling Laws: las leyes del escalado

Un descubrimiento fundamental de la era LLM es que el rendimiento del modelo sigue leyes de potencia predecibles con respecto al tamaño del modelo, la cantidad de datos y el compute total.

📄 Papers fundamentales

  • Kaplan et al. (2020): "Scaling Laws for Neural Language Models" arXiv:2001.08361
  • Hoffmann et al. (2022): "Training Compute-Optimal Large Language Models" (Chinchilla) arXiv:2203.15556

Leyes de Kaplan (OpenAI, 2020)

La loss del modelo sigue una ley de potencia con tres variables:

$$L(N) \approx \left(\frac{N_c}{N}\right)^{\alpha_N}, \quad L(D) \approx \left(\frac{D_c}{D}\right)^{\alpha_D}, \quad L(C) \approx \left(\frac{C_c}{C}\right)^{\alpha_C}$$

Donde \(N\) = parámetros, \(D\) = tokens, \(C\) = FLOPs. Los exponentes encontrados: \(\alpha_N \approx 0.076\), \(\alpha_D \approx 0.095\), \(\alpha_C \approx 0.050\).

Chinchilla: ratio óptimo de datos/modelo

🐭 La regla Chinchilla: Para un presupuesto de compute fijo, el modelo y los datos deben escalarse en la misma proporción. La regla empírica:
$$D_{\text{optimal}} \approx 20 \times N$$

Es decir, un modelo de 10B parámetros debería entrenarse con ~200B tokens. GPT-3 (175B params, 300B tokens) estaba sub-entrenado según esta regla.

ModeloParams NTokens DRatio D/N¿Chinchilla-optimal?
GPT-3175B300B1.7×❌ Sub-trained
Chinchilla70B1.4T20×✅ Optimal
LLaMA7B1T143×✅ Over-trained (deliberado)
LLaMA 270B2T28.5×≈ Sí
LLaMA 38B15T1875×✅ "Over-trained" para eficiencia en inferencia

💡 Tendencia post-Chinchilla

Modelos recientes (LLaMA 3, Phi-3) intencionalmente sobre-entrenan modelos pequeños con muchos más datos de lo óptimo según Chinchilla. ¿Por qué? Porque el coste de inferencia (que depende de N) domina al de training. Un modelo de 8B con 15T tokens rinde como uno de 70B pero es 10× más barato de servir.

Arquitectura moderna de LLMs

Los LLMs modernos (LLaMA, Mistral, Qwen, etc.) han convergido en un conjunto de mejoras arquitectónicas respecto al Transformer original:

ComponenteTransformer originalLLMs modernosBeneficio
NormalizaciónPost-LayerNormPre-RMSNormTraining más estable
Pos. EncodingSinusoidalRoPE (rotary)Generalización a contextos largos
Activación FFNReLU/GELUSwiGLU+1-2% quality
AttentionMulti-Head (MHA)GQA / MQAKV-cache 8× más pequeño
FFN ratio4×d8/3×d (SwiGLU)Más eficiente
BiasSí (en Linear)No (sin bias)Menos params, misma calidad
TyingA vecesToken embedding = LM headReduce params
Context512-20488K-1M+ (RoPE + YaRN/NTK)Documentos largos

RoPE (Su et al., 2021) codifica posición rotando los vectores query y key en el espacio complejo:

$$f(x_m, m) = x_m e^{im\theta} \quad \text{donde} \quad \theta_j = 10000^{-2j/d}$$

Propiedad clave: el producto punto entre queries/keys solo depende de la distancia relativa entre posiciones, no de la absoluta. Esto permite la extensión de contexto (ej: entrenar en 4K pero inferir en 128K con interpolación NTK/YaRN).

arXiv:2104.09864

En Multi-Head Attention (MHA), cada cabeza tiene su propio K y V, lo que genera un KV-cache enorme. GQA (Ainslie et al., 2023) agrupa varias cabezas de query para compartir un mismo par K/V.

  • MHA: h cabezas, h K/V → KV-cache = 2 × h × d × seq_len
  • GQA: h cabezas query, g grupos K/V (g < h) → KV-cache / (h/g)×
  • MQA: caso extremo con g=1 (un único K/V para todas las cabezas)

LLaMA 2 70B, LLaMA 3, Mistral: usan GQA con 8 grupos KV.

arXiv:2305.13245

Propuesta por Shazeer (2020), SwiGLU combina Swish con un mecanismo de gating:

$$\text{SwiGLU}(x) = \text{Swish}(xW_1) \otimes (xW_2)$$

Donde \(\text{Swish}(x) = x \cdot \sigma(\beta x)\). El FFN con SwiGLU usa dimensión \(\frac{8}{3}d\) (vs 4d con ReLU) para igualar el número de parámetros.

arXiv:2002.05202

Infraestructura de pre-training

Entrenar un LLM a escala requiere paralelismo masivo en miles de GPUs. Las técnicas principales son:

📊
Data Parallelism
Replica el modelo en N GPUs, divide el batch. FSDP (Fully Sharded) fragmenta los parámetros para ahorrar memoria.
🏗️
Tensor Parallelism
Divide cada capa (matrices W) entre GPUs del mismo nodo. Requiere alta conexión (NVLink).
🔗
Pipeline Parallelism
Asigna bloques de capas a distintas GPUs. Micro-batching para evitar burbujas.
🧩
Expert Parallelism
Para MoE (Mixture of Experts): cada experto en una GPU diferente. Usado por Mixtral, DeepSeek, GPT-4.
ModeloGPUsTiempoCoste estimadoFramework
GPT-3 (175B)10,000 V100~14 días~$4.6MCustom (Megatron-LM)
LLaMA (65B)2,048 A100 80GB21 días~$2.4MCustom
LLaMA 3 (405B)16,384 H100~54 días~$100M+Custom (fairscale)
DeepSeek-V32,048 H800~2 meses~$5.6MHAI-LLM (custom)
Mistral 7B~512 A100~días~$500KMegatron-LM

🔧 Frameworks de training distribuido

  • Megatron-LM (NVIDIA) — Estándar para 3D parallelism
  • DeepSpeed (Microsoft) — ZeRO optimizer, pipeline parallelism
  • PyTorch FSDP — Fully Sharded Data Parallel nativo
  • JAX + XLA — TPU-native, usado por Google (PaLM, Gemini)
TécnicaDescripciónAhorro
Mixed Precision (BF16)Forward/backward en BFloat16, master weights en FP322× memoria, ~1.5× velocidad
Gradient CheckpointingRe-computa activaciones en backward en lugar de almacenarlas~60% memoria, +30% tiempo
Flash Attention 2Kernel fusionado GPU para attention, tiling I/O-aware2-4× más rápido, O(n) memoria
Gradient AccumulationAcumula gradientes sobre micro-batchesPermite batches grandes con poca memoria
FP8 trainingForward en FP8 (DeepSeek-V3, Hopper GPUs)2× vs BF16
ZeRO Stage 3Fragmenta params, gradients y optimizer state entre GPUsN× memoria (N = nº GPUs)

Ref: Dao (2023) "FlashAttention-2" (arXiv:2307.08691); Rajbhandari et al. (2020) "ZeRO" (arXiv:1910.02054)

🧮 Widget: Estimador de coste de pre-training

Estima el coste aproximado de pre-entrenar un LLM con la regla de 6ND FLOPs.

Mixture of Experts (MoE)

Los modelos MoE escalan el número de parámetros sin incrementar proporcionalmente el coste computacional. Solo un subconjunto de "expertos" se activa para cada token.

hidden state h Router (softmax) Expert 1 Expert 2 ✓ Expert 3 Expert 5 ✓ Expert 8 output = w₂·E₂(h) + w₅·E₅(h) Top-2 gating (solo 2 de 8 expertos activos)
Modelo MoETotal paramsParams activosExpertosTop-K
Mixtral 8×7B46.7B12.9B82
GPT-4 (estimado)~1.8T~280B162
DeepSeek-V3671B37B2568
DBRX132B36B164
Grok-1314B~80B82

📄 Papers de MoE

  • Shazeer et al. (2017): "Outrageously Large Neural Networks: The Sparsely-Gated MoE Layer" arXiv:1701.06538
  • Fedus et al. (2022): "Switch Transformers: Scaling to Trillion Parameter Models" arXiv:2101.03961
  • Jiang et al. (2024): "Mixtral of Experts" arXiv:2401.04088

De modelo base a chatbot: las 3 fases

Un LLM pre-entrenado (modelo "base") solo sabe completar texto. Para convertirlo en un asistente útil que siga instrucciones se necesitan tres fases adicionales:

1. Pre-training Next-token prediction Trillones de tokens → Base model 2. SFT Supervised Fine-Tuning ~10K-100K instrucciones → Sigue instrucciones 3. RLHF / DPO Aprendizaje por refuerzo con feedback humano → Alineado, seguro, útil ChatBot ChatGPT, Claude... Pipeline: InstructGPT (Ouyang et al., 2022) — arXiv:2203.02155
🔗 Conexión: La fase de RLHF utiliza conceptos de aprendizaje por refuerzo que se cubren en profundidad en el submódulo Aprendizaje por Refuerzo dentro del módulo de Otros Modelos. Allí se explican las bases de policy gradients, reward shaping y PPO que son esenciales para entender RLHF.

Supervised Fine-Tuning (SFT)

El SFT adapta el modelo base a seguir instrucciones entrenándolo con pares (instrucción, respuesta) escritos por humanos o generados sintéticamente.

Formato de datos SFT

# Formato típico de datos SFT (chat template)
data = [
    {
        "messages": [
            {"role": "system", "content": "Eres un asistente experto en ML."},
            {"role": "user", "content": "¿Qué es el dropout?"},
            {"role": "assistant", "content": "El dropout es una técnica de regularización..."}
        ]
    },
    {
        "messages": [
            {"role": "user", "content": "Escribe una función que ordene una lista en Python."},
            {"role": "assistant", "content": "def sort_list(lst):\n    return sorted(lst)"}
        ]
    }
]
# La loss se calcula SOLO sobre los tokens del assistant (no user/system)
Dataset SFTTamañoFuenteNotas
InstructGPT data~13K promptsHumanos (labelers)Dataset original de OpenAI
FLAN v2~1.8K tareas / 15M ej.Datasets NLP reformateadosGoogle, instruction tuning
ShareGPT~90K conversacionesConversaciones con ChatGPTUsado por Vicuna
OpenAssistant~160K mensajesCrowdsourcingMultilingüe, open-source
UltraChat~1.5M diálogosSintéticos (GPT-3.5/4)Usado por Zephyr
Alpaca52KSintéticos (text-davinci-003)Self-instruct de Stanford

Fine-tuning eficiente: PEFT

Fine-tunear todos los parámetros de un LLM de 70B requiere enormes recursos. PEFT (Parameter-Efficient Fine-Tuning) congela la mayoría del modelo y solo entrena un número reducido de parámetros.

🔗
LoRA
Low-Rank Adaptation. Añade matrices de bajo rango a las capas. 0.1-1% de params entrenables.
QLoRA
LoRA + cuantización NF4 del modelo base. Fine-tune un 65B en una sola GPU de 48GB.
🏷️
Prefix Tuning
Añade "soft prompts" aprendibles al inicio del contexto. No modifica el modelo.
🔧
Adapters
Módulos bottleneck insertados entre capas. Houlsby et al. (2019).

LoRA en detalle

LoRA (Hu et al., 2021) es la técnica PEFT más utilizada. En lugar de actualizar la matriz de pesos \(W \in \mathbb{R}^{d \times k}\), LoRA añade una descomposición de bajo rango:

$$W' = W + \Delta W = W + BA \quad \text{donde} \quad B \in \mathbb{R}^{d \times r}, \; A \in \mathbb{R}^{r \times k}, \; r \ll \min(d, k)$$

Con \(r = 16\), una capa de \(4096 \times 4096\) pasa de 16.7M a solo 131K parámetros entrenables (0.8%). El scaling factor \(\alpha / r\) controla la magnitud de la adaptación.

# ═══════════════════════════════════════════════════
# Fine-tuning con LoRA (PEFT library)
# ═══════════════════════════════════════════════════
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer
from datasets import load_dataset

# 1. Modelo base
model_name = "meta-llama/Llama-2-7b-hf"
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# 2. Configurar LoRA
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,                      # Rango de la descomposición
    lora_alpha=32,             # Scaling factor
    lora_dropout=0.05,
    target_modules=[           # Capas donde aplicar LoRA
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj",
    ],
    bias="none",
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# Output: trainable params: 13,631,488 || all params: 6,751,367,168 || 0.20%

# 3. Dataset
dataset = load_dataset("mlabonne/guanaco-llama2-1k")

# 4. Training
training_args = TrainingArguments(
    output_dir="./llama2-lora",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    fp16=True,
    logging_steps=10,
    save_strategy="epoch",
)

trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    dataset_text_field="text",
    max_seq_length=1024,
)

trainer.train()

📄 Papers de PEFT

RLHF: Reinforcement Learning from Human Feedback

RLHF es el proceso que alinea un LLM con las preferencias humanas. Fue la técnica clave detrás de ChatGPT e InstructGPT.

Paso 1: Reward Model Humanos comparan respuestas Resp A ✓ Resp B ✗ A > B → train reward model R(prompt, response) → score ~50K-300K comparaciones Paso 2: RL (PPO) Optimizar policy con reward prompt → LLM → response → R(prompt, resp) → reward → PPO update θ KL penalty vs modelo SFT para evitar reward hacking max R(x,y) - β·KL(π_θ || π_SFT) Modelo Alineado ✅ Sigue instrucciones ✅ Respuestas útiles ✅ Rechaza contenido dañino ✅ Admite ignorancia → ChatGPT, Claude, etc.

El objetivo de RLHF

$$\max_{\pi_\theta} \; \mathbb{E}_{x \sim \mathcal{D}, \; y \sim \pi_\theta(\cdot|x)} \left[ R_\phi(x, y) \right] - \beta \cdot \text{KL}\left(\pi_\theta \| \pi_{\text{SFT}}\right)$$

Donde \(\pi_\theta\) es la policy (el LLM), \(R_\phi\) es el reward model entrenado con preferencias humanas, y el término KL previene que el modelo se desvíe demasiado del modelo SFT (evitando reward hacking).

El reward model se entrena con la loss de Bradley-Terry sobre pares de comparación humana:

$$\mathcal{L}_{\text{RM}} = -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma \left( R_\phi(x, y_w) - R_\phi(x, y_l) \right) \right]$$

Donde \(y_w\) es la respuesta preferida y \(y_l\) la rechazada. El reward model suele ser un LLM más pequeño (ej: 6B) con una cabeza escalar.

📄 Papers de RLHF

  • InstructGPT: Ouyang et al. (2022) "Training language models to follow instructions with human feedback" arXiv:2203.02155
  • RLHF original: Christiano et al. (2017) "Deep RL from Human Preferences" arXiv:1706.03741
  • PPO: Schulman et al. (2017) "Proximal Policy Optimization" arXiv:1707.06347
  • Anthropic RLHF: Bai et al. (2022) "Training a Helpful and Harmless Assistant" arXiv:2204.05862

DPO y alternativas a RLHF

RLHF requiere entrenar un reward model separado y usar PPO (inestable, costoso). DPO simplifica esto drásticamente.

DPO: Direct Preference Optimization

Rafailov et al. (2023) demostraron que se puede optimizar directamente la policy con datos de preferencias, sin un reward model explícito:

$$\mathcal{L}_{\text{DPO}} = -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma \left( \beta \left[ \log \frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \log \frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)} \right] \right) \right]$$

Equivalente a RLHF pero con una simple loss de clasificación binaria. No necesita sampling, es estable, y es 3-10× más barato que PPO.

MétodoReward ModelSamplingEstabilidadCostePaper
RLHF (PPO)Sí (online)InestableAlto (4 modelos en GPU)2203.02155
DPONo (implícito)No (offline)EstableBajo2305.18290
KTONoNoEstableBajo2402.01306
IPONoNoEstableBajo2310.12036
ORPONoNoEstableMuy bajo (SFT+align juntos)2403.07691
GRPONo (rule-based)Sí (online)EstableMedio2402.03300 (DeepSeek)
# ═══════════════════════════════════════════════════
# DPO Training con TRL (Transformer Reinforcement Learning)
# ═══════════════════════════════════════════════════
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import DPOTrainer, DPOConfig
from datasets import load_dataset
from peft import LoraConfig

# 1. Modelo (SFT ya hecho)
model = AutoModelForCausalLM.from_pretrained(
    "my-sft-model",
    torch_dtype="auto",
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained("my-sft-model")

# 2. Dataset de preferencias
# Cada ejemplo: { "prompt": ..., "chosen": ..., "rejected": ... }
dataset = load_dataset("argilla/ultrafeedback-binarized-preferences")

# 3. LoRA para eficiencia
peft_config = LoraConfig(
    r=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj","k_proj","v_proj","o_proj"],
)

# 4. DPO Training
dpo_config = DPOConfig(
    output_dir="./dpo-model",
    beta=0.1,                    # Temperatura (controla desviación de ref)
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=5e-7,          # LR muy bajo para alignment
    num_train_epochs=1,
    fp16=True,
)

trainer = DPOTrainer(
    model=model,
    ref_model=None,              # None → usa modelo inicial como referencia
    args=dpo_config,
    train_dataset=dataset["train"],
    tokenizer=tokenizer,
    peft_config=peft_config,
)

trainer.train()

Datasets de alignment (preferencias)

Los datasets de preferencias son la materia prima del RLHF/DPO:

DatasetTamañoTipoNotas
HH-RLHF170KComparacionesAnthropic. Helpfulness + Harmlessness
UltraFeedback64KRankings (4 respuestas)4 modelos, GPT-4 como juez
Nectar183KRankings (7 respuestas)Starling-LM, GPT-4 ranking
Chatbot Arena~1M+ votosComparaciones humanasLMSYS. ELO ranking real
OASST2~24K rankingsRankings humanosOpen Assistant, crowdsource

Ingeniería de Prompts

Prompt engineering es el arte de diseñar las entradas (prompts) al LLM para obtener las respuestas deseadas sin modificar los pesos del modelo. Con LLMs suficientemente grandes (≥ 100B params), el prompting puede reemplazar al fine-tuning para muchas tareas.

Zero-shot Solo instrucción Few-shot + ejemplos CoT + razonamiento ToT / GoT + exploración Agents + Tools + acciones ← menos esfuerzo · más esfuerzo / capacidad →

Zero-shot y Few-shot Prompting

Zero-shot

El modelo recibe solo la instrucción, sin ejemplos. Funciona sorprendentemente bien con modelos grandes (GPT-3+), especialmente tras SFT/RLHF.

# Zero-shot: solo instrucción
prompt = """Clasifica el siguiente texto como positivo, negativo o neutral.

Texto: "La película fue entretenida pero el final me decepcionó."
Clasificación:"""

# → "Neutral" o "Mixto"

Few-shot (In-Context Learning)

Proporcionar K ejemplos (típicamente 3-8) en el prompt permite al modelo "aprender" el formato y la tarea sin actualizar pesos. Este fenómeno, descubierto con GPT-3, se llama in-context learning (ICL).

# Few-shot: 3 ejemplos + query
prompt = """Clasifica el sentimiento del texto.

Texto: "Me encanta este restaurante, la comida es increíble."
Sentimiento: Positivo

Texto: "El servicio fue pésimo y tardaron una hora."
Sentimiento: Negativo

Texto: "El lugar está bien, nada especial."
Sentimiento: Neutral

Texto: "La película fue entretenida pero el final me decepcionó."
Sentimiento:"""

# → "Mixto" o "Neutral"

📄 Paper clave

Brown et al. (2020) "Language Models are Few-Shot Learners" demostró que GPT-3 con few-shot prompting podía igualar modelos fine-tuneados en muchas tareas. arXiv:2005.14165

Chain-of-Thought (CoT) Prompting

CoT (Wei et al., 2022) mejora dramáticamente el rendimiento en tareas de razonamiento al pedir al modelo que muestre su proceso paso a paso.

🔗
CoT Explícito
Proporcionar ejemplos con razonamiento paso a paso (few-shot CoT).
💭
Zero-shot CoT
Añadir "Let's think step by step" al final del prompt (Kojima et al., 2022).
🗳️
Self-Consistency
Generar múltiples CoT y votar la respuesta más frecuente (Wang et al., 2022).
# ❌ Sin CoT (directo) — falla en problemas complejos
prompt_directo = """Si tengo 3 manzanas y le doy la mitad a Juan,
luego compro 5 más y le doy 2 a María, ¿cuántas tengo?
Respuesta:"""
# → A veces responde mal

# ✅ Con CoT — resuelve correctamente
prompt_cot = """Si tengo 3 manzanas y le doy la mitad a Juan,
luego compro 5 más y le doy 2 a María, ¿cuántas tengo?

Pensemos paso a paso:
1. Empiezo con 3 manzanas
2. Le doy la mitad a Juan: 3/2 = 1.5, pero como son manzanas enteras,
   le doy 1 (me quedo con 2) o redondeamos (1.5)
3. Compro 5 más: 1.5 + 5 = 6.5
4. Le doy 2 a María: 6.5 - 2 = 4.5
Respuesta: 4.5 manzanas

(O con enteros: 2 + 5 - 2 = 5 manzanas)"""

# ✅ Zero-shot CoT — más simple
prompt_zero_cot = """Si tengo 3 manzanas y le doy la mitad a Juan,
luego compro 5 más y le doy 2 a María, ¿cuántas tengo?

Let's think step by step."""

📄 Papers de CoT

  • CoT: Wei et al. (2022) "Chain-of-Thought Prompting Elicits Reasoning in LLMs" arXiv:2201.11903
  • Zero-shot CoT: Kojima et al. (2022) "Large Language Models are Zero-Shot Reasoners" arXiv:2205.11916
  • Self-Consistency: Wang et al. (2022) arXiv:2203.11171

Técnicas avanzadas de prompting

ToT (Yao et al., 2023) generaliza CoT permitiendo al modelo explorar múltiples caminos de razonamiento como un árbol, evaluar cada rama y hacer backtracking. Útil para problemas que requieren planificación (puzzles, código).

arXiv:2305.10601

ReAct (Yao et al., 2022) intercala pasos de razonamiento (Thought) con acciones (Action: buscar en Wikipedia, ejecutar código, etc.) y observaciones (Observation: resultado de la acción).

Patrón: Thought → Action → Observation → Thought → ... → Answer

arXiv:2210.03629

RAG (Lewis et al., 2020) complementa el conocimiento del LLM con información recuperada de una base de documentos. Pipeline:

1
Query: el usuario hace una pregunta
2
Retrieve: buscar documentos relevantes (vector DB: FAISS, Pinecone, Chroma)
3
Augment: añadir contexto recuperado al prompt
4
Generate: el LLM genera respuesta basada en el contexto

arXiv:2005.11401

Forzar al LLM a generar salida estructurada (JSON, XML, tablas) mediante:

  • Prompting: "Responde en formato JSON con los campos: ..."
  • Function calling: schema JSON como herramienta (OpenAI, Anthropic)
  • Constrained decoding: gramáticas formales (Outlines, Guidance, LMQL)
TécnicaCuándo usarMejoraCoste extra
Zero-shotTareas simples, modelos grandesBaselineNinguno
Few-shotFormato específico, tareas de nicho+5-15%Tokens de contexto
CoTMatemáticas, lógica, razonamiento+10-40%Más tokens de output
Self-ConsistencyProblemas con respuesta única+5-15% vs CoTN× llamadas
ToTPuzzles, planificación, códigoVariableAlto (exploración)
RAGConocimiento actualizado, dominio específicoElimina alucinacionesInfra de retrieval
ReActTareas que requieren herramientasAcceso a info realLlamadas a APIs

🛠️ Widget: Constructor de prompt

Selecciona los componentes y genera un prompt template optimizado.

Modelos razonadores: una nueva frontera

Los modelos razonadores representan un salto conceptual: en lugar de generar una respuesta directamente, el modelo "piensa" internamente durante un tiempo variable antes de responder. Usan más compute en tiempo de inferencia (test-time compute) para resolver problemas más difíciles.

💡 La idea central: Los LLMs clásicos usan la misma cantidad de compute para "¿Cuál es la capital de Francia?" que para una demostración matemática compleja. Los modelos razonadores pueden adaptar su esfuerzo computacional a la dificultad del problema.
LLM Clásico (GPT-4) Prompt → [forward pass fijo] → Respuesta Modelo Razonador (o1, DeepSeek-R1, QwQ) Prompt → [thinking tokens ····· variable ·····] → Respuesta

Test-Time Compute: el concepto clave

Test-time compute (TTC) se refiere al compute adicional que un modelo usa durante la inferencia para mejorar su respuesta. Hay dos estrategias principales:

🧠
Internal CoT
El modelo genera tokens de "pensamiento" internos (o1, R1). Más tokens pensados = mejor respuesta. Entrenado con RL.
🗳️
Search / Sampling
Generar N respuestas candidatas y seleccionar la mejor con un verifier/reward model (Best-of-N, MCTS, beam search).

📄 Paper clave

Snell et al. (2024) "Scaling LLM Test-Time Compute Optimally Can Be More Effective Than Scaling Model Parameters". Demostraron que un modelo pequeño (1-3B) con suficiente test-time compute puede superar a un modelo 14× más grande con respuesta directa. arXiv:2408.03314

$$\text{Rendimiento} = f(\underbrace{N_{\text{params}}}_{\text{train-time}}, \; \underbrace{C_{\text{inference}}}_{\text{test-time}})$$

Antes, solo se escalaba \(N\) (más parámetros). Ahora se puede escalar \(C_{\text{inference}}\) (más tokens de pensamiento, más candidatos) para obtener mejores resultados.

OpenAI o1 / o3: la serie de razonamiento

En septiembre de 2024, OpenAI lanzó o1-preview, el primer modelo razonador comercial. Usa chain-of-thought interna (no visible al usuario) entrenada con reinforcement learning a gran escala.

ModeloFechaCapacidad claveBenchmarks notables
o1-previewSep 2024CoT interna, RLAIME: 83.3%, Codeforces: 89th %ile
o1Dic 2024Más training, herramientasAIME: 96.4%, GPQA: 78.8%
o3-miniEne 2025Eficiente, ajuste de esfuerzoCodeforces: 96th %ile
o32025SOTA en razonamientoARC-AGI: 87.5%, Frontier Math

Aunque OpenAI no ha publicado paper, el consenso de la comunidad es:

1
Base model: GPT-4 (o similar) como base
2
SFT con CoT: fine-tuning con cadenas de pensamiento detalladas (posiblemente sintéticas)
3
RL extensivo: PPO/GRPO para optimizar la calidad del razonamiento con reward basado en correctitud verificable (matemáticas, código)
4
Thinking tokens: durante inferencia, genera una cadena larga de "pensamiento" (oculta al usuario) antes de la respuesta final
5
Adaptive compute: problemas fáciles → pocos thinking tokens; problemas difíciles → muchos (hasta ~100K tokens)

DeepSeek-R1: razonamiento open-source

DeepSeek-R1 (DeepSeek AI, enero 2025) fue el primer modelo razonador open-source con rendimiento comparable a o1. Su paper reveló los detalles del entrenamiento que OpenAI no publicó.

📄 Paper

"DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning" arXiv:2501.12948 · GitHub

Proceso de entrenamiento de R1

1
DeepSeek-R1-Zero: RL puro (GRPO) sobre DeepSeek-V3 base, sin ningún SFT previo. El modelo descubrió CoT, self-verification y reflection emergentemente. Pero tenía problemas de formato y legibilidad.
2
Cold start data: generación de miles de ejemplos CoT de alta calidad para SFT inicial (bootstrap).
3
RL con reward mixto: accuracy reward (verificable automáticamente para math/code) + format reward (legibilidad) + language consistency reward.
4
Rejection sampling + SFT: generar muchas respuestas, filtrar las correctas, y hacer SFT final para mejorar formato y generalización.
5
Distillación: destilar R1 a modelos más pequeños (1.5B → 70B). R1-Distill-Qwen-32B supera a o1-mini en varios benchmarks.
🔬 Hallazgo clave: DeepSeek demostró que el razonamiento puede emerger solo con RL (R1-Zero), sin necesidad de datos CoT humanos. El modelo aprendió espontáneamente a "pensar más" en problemas difíciles — un caso de capacidad emergente.

Panorama de modelos razonadores

ModeloOrg.Open?TécnicaBenchmark
o1 / o3OpenAIInternal CoT + RLAIME 96.4%
DeepSeek-R1DeepSeek✅ MITGRPO, cold start, distillAIME 79.8%
QwQ-32BAlibabaRL, thinking tokensAIME 79.5%
Gemini 2.0 Flash ThinkingGoogleThinking tokensGPQA 74%
Claude 3.5 (extended thinking)AnthropicExtended CoT interna
Kimi k1.5MoonshotRL + long CoTAIME 77.5%
Open-Reasoner-ZeroNVIDIAGRPO puro (inspirado en R1-Zero)MATH 86.4%

📚 Papers y recursos

LLMs multimodales: más allá del texto

Los LLMs multimodales (MLLMs) extienden la capacidad de los LLMs para procesar y/o generar múltiples modalidades: texto, imágenes, audio, vídeo. No son modelos separados para cada modalidad, sino un único LLM que integra encoders especializados.

👁️
Visión + Texto
GPT-4V, Gemini, LLaVA, Claude 3. Entienden imágenes y responden preguntas sobre ellas.
🎵
Audio + Texto
GPT-4o, Gemini 2.0. Procesan voz nativa, tonos, música. No solo transcripción.
🎬
Vídeo + Texto
Gemini 1.5 (1M tokens). Analiza vídeos completos frame a frame.
🌐
Any-to-Any
GPT-4o: texto↔imagen↔audio nativo. Genera voz expresiva directamente.

Arquitectura: cómo se integran las modalidades

El patrón dominante para LLMs multimodales sigue una estructura de tres componentes:

Vision Encoder ViT / SigLIP / CLIP Imagen → patch embeddings (normalmente congelado) Audio Encoder Whisper / USM Audio → features Projection MLP / Q-Former / Resampler Alinea al espacio del LLM LLM Backbone LLaMA / Qwen / Gemma [img_tokens] + [text_tokens] → Autoregressive decoding Output: texto (+ imagen/audio) 💬 Arquitectura típica de LLM multimodal (LLaVA, Qwen-VL, InternVL)
ComponenteFunciónEjemplos
Vision EncoderConvierte imagen en secuencia de embeddingsCLIP ViT-L, SigLIP, InternViT
Audio EncoderConvierte audio en embeddingsWhisper encoder, USM
Projection LayerAlinea embeddings visuales al espacio del LLMMLP lineal, Q-Former, Perceiver Resampler
LLM BackboneProcesa tokens multimodales autoregressivamenteLLaMA, Qwen, Gemma, Vicuna

Modelos multimodales clave

CLIP (Contrastive Language-Image Pre-training) aprende un espacio compartido entre imágenes y texto mediante contrastive learning sobre 400M de pares (imagen, caption) de Internet.

$$\mathcal{L}_{\text{CLIP}} = -\frac{1}{N}\sum_{i=1}^{N} \left[ \log \frac{\exp(\text{sim}(v_i, t_i)/\tau)}{\sum_{j=1}^{N}\exp(\text{sim}(v_i, t_j)/\tau)} \right]$$

CLIP no genera texto, pero sus embeddings son la base de muchos modelos multimodales.

arXiv:2103.00020 · GitHub

LLaVA (Liu et al., 2023) conecta CLIP ViT con LLaMA mediante una simple proyección MLP. Es el modelo multimodal open-source más influyente:

  • Pre-training: 595K pares imagen-caption para alinear vision y LLM
  • Instruction tuning: 158K instrucciones visuales generadas por GPT-4
  • LLaVA-1.5: mejoras con MLP proyector + datos mejores → SOTA en 11 benchmarks

arXiv:2304.08485 · GitHub

GPT-4V (2023) fue el primer LLM comercial con capacidad de visión de alta calidad. GPT-4o (2024) va más allá: es natively multimodal, procesando texto, imagen y audio en un único modelo end-to-end, sin pipeline de ASR.

GPT-4o puede generar voz expresiva con emociones, cantar, y entender diagramas complejos.

Gemini (Google, 2023) fue entrenado desde el inicio como modelo multimodal (a diferencia de GPT-4V que añadió visión post-hoc). Gemini 1.5 Pro acepta hasta 1M tokens (1h de vídeo, 11h de audio, 30K líneas de código).

arXiv:2312.11805 (Gemini 1.0) · arXiv:2403.05530 (Gemini 1.5)

ModeloModalidadesVision Enc.LLMOpen?Innovación
LLaVA-1.5Imagen+TextoCLIP ViT-LVicuna 13BSimple MLP projection
InternVL 2.5Imagen+TextoInternViT-6BInternLM2Vision encoder enorme
Qwen-VLImg+Txt+BboxViTQwen 7BGrounding, multi-imagen
GPT-4oTxt+Img+AudioNativoGPT-4Any-to-any nativo
Gemini 1.5Txt+Img+Audio+VideoNativoMoE1M tokens context
Claude 3.5Imagen+TextoClaudeExcelente visión
PixtralImagen+TextoCustom ViTMistralResolución variable

Cómo se entrenan los LLMs multimodales

El entrenamiento típico sigue un proceso en fases:

1
Pre-training visual-lingüístico: entrenar solo la capa de proyección con pares (imagen, caption) manteniendo el LLM y vision encoder congelados. Alinea el espacio visual con el del LLM. (~595K-1M pares)
2
Visual instruction tuning: fine-tuning con instrucciones visuales complejas (VQA, descripción, razonamiento sobre imágenes). Se descongelan el LLM y la proyección. (~150K-1M instrucciones)
3
RLHF / DPO multimodal (opcional): alignment con preferencias humanas específicas de visión (alucinaciones visuales, fidelidad a la imagen).
# ═══════════════════════════════════════════════════
# Inferencia multimodal con LLaVA
# ═══════════════════════════════════════════════════
from transformers import LlavaNextProcessor, LlavaNextForConditionalGeneration
from PIL import Image
import torch

# 1. Cargar modelo
processor = LlavaNextProcessor.from_pretrained("llava-hf/llava-v1.6-mistral-7b-hf")
model = LlavaNextForConditionalGeneration.from_pretrained(
    "llava-hf/llava-v1.6-mistral-7b-hf",
    torch_dtype=torch.float16,
    device_map="auto",
)

# 2. Preparar input multimodal
image = Image.open("mi_imagen.jpg")
prompt = "[INST] \nDescribe esta imagen en detalle. ¿Qué objetos ves y qué relaciones hay entre ellos? [/INST]"

inputs = processor(prompt, image, return_tensors="pt").to("cuda")

# 3. Generar
output = model.generate(**inputs, max_new_tokens=300, do_sample=True, temperature=0.7)
print(processor.decode(output[0], skip_special_tokens=True))

📚 Papers y recursos multimodales

De LLMs a agentes: el salto

Un agente es un LLM que, además de generar texto, puede tomar acciones en el mundo real: ejecutar código, buscar en internet, enviar emails, interactuar con APIs, navegar por webs, etc. El LLM actúa como "cerebro" que decide qué herramienta usar y cuándo.

👤 User Instrucción 🧠 LLM Agent Razonar → Planificar → Decidir acción System prompt + tool schemas 🔍 Web Search 💻 Code Exec 📊 Database 📧 Email API 📋 Observation Resultado → LLM Loop: Thought → Action → Observation → ... → Final Answer

Function Calling: la base del agente

Function calling (o tool use) es la capacidad de un LLM de generar llamadas estructuradas a funciones externas en lugar de texto plano. El LLM no ejecuta la función — genera los parámetros en JSON y el sistema host la ejecuta.

# ═══════════════════════════════════════════════════
# Function Calling con OpenAI API
# ═══════════════════════════════════════════════════
from openai import OpenAI
import json

client = OpenAI()

# 1. Definir herramientas (schema JSON)
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Obtener el clima actual de una ciudad",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "Nombre de la ciudad"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "Buscar información en internet",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "Consulta de búsqueda"}
                },
                "required": ["query"]
            }
        }
    }
]

# 2. Llamar al LLM
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "¿Qué tiempo hace en Madrid?"}],
    tools=tools,
    tool_choice="auto",  # El modelo decide si usar herramienta
)

# 3. El modelo genera una llamada a función (no ejecuta)
tool_call = response.choices[0].message.tool_calls[0]
print(f"Función: {tool_call.function.name}")
print(f"Args: {tool_call.function.arguments}")
# → Función: get_weather
# → Args: {"city": "Madrid", "unit": "celsius"}

# 4. TÚ ejecutas la función y devuelves el resultado
result = get_weather(city="Madrid", unit="celsius")  # Tu implementación
messages.append({"role": "tool", "content": json.dumps(result),
                 "tool_call_id": tool_call.id})

# 5. El LLM genera la respuesta final con el resultado
final = client.chat.completions.create(
    model="gpt-4o", messages=messages
)
print(final.choices[0].message.content)
# → "En Madrid hace 22°C con cielo despejado."

MCP: Model Context Protocol

🔌 MCP (Anthropic, 2024)

El Model Context Protocol es un estándar abierto para conectar LLMs con herramientas y fuentes de datos de forma estandarizada. Define un protocolo cliente-servidor donde:

  • MCP Server: expone herramientas, recursos y prompts
  • MCP Client: el LLM/aplicación que consume las herramientas
  • Transporte: stdio (local) o SSE/HTTP (remoto)

modelcontextprotocol.io · GitHub

Frameworks de agentes

FrameworkOrganizaciónEnfoqueMejor para
LangChainLangChain Inc.Modular, chains/agents/toolsPrototipos, RAG, flujos complejos
LangGraphLangChain Inc.Grafos de estado, ciclosAgentes multi-step con estado
CrewAICrewAIMulti-agente, rolesEquipos de agentes colaborativos
AutoGenMicrosoftMulti-agente conversacionalDebates entre agentes, código
SmolagentsHugging FaceCode agents, minimalistaAgentes que escriben código Python
OpenAI AssistantsOpenAIAPI managed, threadsProducción con OpenAI
Claude CodeAnthropicAgente de código CLIDesarrollo de software autónomo
# ═══════════════════════════════════════════════════
# Agente ReAct con LangGraph
# ═══════════════════════════════════════════════════
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

# 1. Definir herramientas
@tool
def calculate(expression: str) -> str:
    """Evalúa una expresión matemática."""
    return str(eval(expression))

@tool
def search(query: str) -> str:
    """Busca información en una base de conocimiento."""
    # Tu implementación de búsqueda
    return f"Resultado para: {query}"

# 2. Crear agente ReAct
llm = ChatOpenAI(model="gpt-4o", temperature=0)
agent = create_react_agent(llm, tools=[calculate, search])

# 3. Ejecutar
result = agent.invoke({
    "messages": [("user", "¿Cuánto es el PIB de España dividido por su población?")]
})

# El agente internamente:
# Thought: Necesito buscar el PIB y la población de España
# Action: search("PIB España 2024")
# Observation: "El PIB de España en 2024 es ~1.5T EUR"
# Action: search("población España 2024")
# Observation: "La población de España es ~48M"
# Action: calculate("1500000000000 / 48000000")
# Observation: "31250.0"
# Answer: "El PIB per cápita de España es ~31,250 EUR"

Patrones de diseño de agentes

El patrón más popular. El agente alterna entre razonamiento (Thought), acción (Action) y observación (Observation) hasta llegar a la respuesta.

arXiv:2210.03629

Un planificador (LLM) crea un plan de alto nivel (lista de pasos), y un ejecutor (otro LLM o el mismo) ejecuta cada paso. Permite replanning si un paso falla.

Múltiples agentes con roles diferentes (researcher, coder, reviewer) colaboran para resolver una tarea compleja. Pueden debatir, revisar el trabajo de otros, y llegar a consenso. Ejemplos: AutoGen, CrewAI, ChatDev.

arXiv:2308.00352 (MetaGPT)

Reflexion (Shinn et al., 2023): el agente revisa su propia salida, identifica errores, y se corrige. Usa un "critic" o autoevaluación para mejorar iterativamente.

arXiv:2303.11366

En lugar de usar herramientas predefinidas, el agente escribe y ejecuta código Python como su mecanismo de acción principal. Más flexible y composable que function calling.

Usado por: HuggingFace smolagents, OpenAI Code Interpreter, Claude Artifacts. Ref: arXiv:2401.00812 (Executable Code Actions)

Evaluación, limitaciones y futuro

BenchmarkQué evalúaSOTA
SWE-benchResolver issues reales de GitHub~50% (Claude 3.5 + agentic)
WebArenaTareas web (navegar, comprar, buscar)~35%
GAIATareas generales con herramientas~70% (nivel 1)
TAU-benchTool use real (airline, retail)~50%
HumanEvalGeneración de código~95%+ (GPT-4o, Claude 3.5)
⚠️ Limitaciones actuales de los agentes:
  • Reliability: los agentes aún fallan en ~30-70% de tareas complejas
  • Error compounding: cada paso tiene probabilidad de error, que se acumula
  • Cost: muchas llamadas a la API, tokens de reasoning → caro
  • Safety: un agente con acceso a herramientas puede causar daño real
  • Evaluation: difícil medir el progreso sin benchmarks estandarizados

📚 Papers y recursos de agentes

🏗️ Widget: Selector de arquitectura de agente

Según tu caso de uso, te recomendamos el patrón y framework de agente más adecuado.

Recursos y referencias generales

RecursoTipoEnlace
Andrej Karpathy — "Let's build GPT"Video/TutorialYouTube
Lilian Weng — "LLM Powered Autonomous Agents"BlogBlog
Jay Alammar — "The Illustrated Transformer"Blog visualBlog
Sebastian Raschka — "Build an LLM from Scratch"LibroGitHub
Hugging Face NLP CourseCursoHF Course
LMSYS Chatbot ArenaBenchmarkArena
Open LLM LeaderboardRankingsHF Spaces
Awesome LLM — curated listListaGitHub
🏭 Casos de uso