> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-es/entrenamiento/trl.md).

# TRL (entrenamiento RLHF/DPO)

**TRL** (Transformer Reinforcement Learning) es la biblioteca oficial de HuggingFace para entrenar modelos de lenguaje con técnicas de aprendizaje por refuerzo. Con más de 10 mil estrellas en GitHub, proporciona implementaciones de última generación de RLHF, DPO, PPO, GRPO y otros algoritmos de alineación para LLMs.

{% hint style="success" %}
Todos los ejemplos se pueden ejecutar en servidores GPU alquilados a través de [Marketplace de CLORE.AI](https://clore.ai/marketplace).
{% endhint %}

***

## ¿Qué es TRL?

TRL es la biblioteca detrás de muchos de los mejores modelos de lenguaje alineados de hoy. Proporciona:

* **SFT (Fine-Tuning Supervisado)** — ajuste estándar de instrucciones con formato ChatML
* **RLHF/PPO** — optimización clásica de política proximal con un modelo de recompensa
* **DPO** — Optimización Directa de Preferencias (¡no se necesita modelo de recompensa!)
* **GRPO** — Optimización de Política Relativa en Grupo (método de DeepSeek-R1)
* **KTO** — Optimización de Kahneman-Tversky (funciona con preferencias no emparejadas)
* **Modelado de Recompensas** — entrenar un modelo de recompensa a partir de datos de preferencias humanas
* **IterativeSFT** — RL en línea con una configuración más sencilla
* **ORPO** — Optimización de Preferencias de Odds Ratio

TRL se integra de forma nativa con el ecosistema de HuggingFace: `transformers`, `peft`, `datasets`, `accelerate`, y `bitsandbytes`.

{% hint style="info" %}
**¿Qué algoritmo deberías usar?**

* **DPO** — el más simple y estable. Úsalo cuando tengas datos de preferencias emparejadas (elegido/rechazado).
* **PPO** — el más potente pero complejo. Úsalo cuando tengas un modelo de recompensa o una función de puntuación.
* **GRPO** — excelente para tareas de razonamiento/matemáticas. Método de entrenamiento de DeepSeek-R1.
* **SFT** — siempre empieza aquí antes de aplicar cualquier método de RL.
  {% endhint %}

***

## Requisitos del servidor

| Componente     | Mínimo                    | Recomendado                     |
| -------------- | ------------------------- | ------------------------------- |
| GPU            | RTX 3090 (24 GB)          | A100 80 GB / H100               |
| VRAM           | 16 GB (SFT/DPO 7B + LoRA) | 80 GB (fine-tuning completo 7B) |
| RAM            | 32 GB                     | 64 GB+                          |
| CPU            | 8 núcleos                 | 16+ núcleos                     |
| Almacenamiento | 100 GB                    | 300 GB+                         |
| SO             | Ubuntu 20.04+             | Ubuntu 22.04                    |
| Python         | 3.9+                      | 3.11                            |
| CUDA           | 12.8+                     | 12.8+                           |

### VRAM por tarea

| Tarea | Modelo      | Método      | VRAM             |
| ----- | ----------- | ----------- | ---------------- |
| SFT   | Llama 3 8B  | QLoRA 4-bit | \~8 GB           |
| DPO   | Llama 3 8B  | LoRA        | \~20 GB          |
| PPO   | Llama 3 8B  | Completo    | \~80 GB (2×A100) |
| GRPO  | Qwen 7B     | LoRA        | \~24 GB          |
| SFT   | Llama 3 70B | QLoRA 4-bit | \~48 GB          |
| DPO   | Llama 3 70B | LoRA        | \~80 GB          |

***

## Puertos

| Puerto | Servicio | Notas                                                   |
| ------ | -------- | ------------------------------------------------------- |
| 22     | SSH      | Acceso a terminal, transferencia de archivos, monitoreo |

TRL es una biblioteca de entrenamiento: se ejecuta como un script CLI/Python, no requiere servidor web.

***

## Instalación en Clore.ai

### Paso 1 — Alquilar un servidor

1. Ve a [Marketplace de Clore.ai](https://clore.ai/marketplace)
2. Filtrar por **VRAM ≥ 24 GB** (RTX 3090, A100 o H100)
3. Elige una imagen base de **PyTorch** o **CUDA 12.8** base
4. Selecciona **Almacenamiento ≥ 200 GB** para modelos y conjuntos de datos
5. Abre el puerto **22** para acceso SSH

### Paso 2 — Conectarse vía SSH

```bash
ssh root@<ip-del-servidor> -p <puerto-ssh>
```

### Paso 3 — Instalar TRL

```bash
# Crear un entorno virtual de Python
python3 -m venv /opt/trl
source /opt/trl/bin/activate

# Instalar TRL con todas las dependencias
pip install trl

# Instalar dependencias adicionales para flujos de trabajo completos
pip install \
    transformers \
    datasets \
    peft \
    accelerate \
    bitsandbytes \
    wandb \
    scipy \
    sentencepiece \
    protobuf

# Verificar soporte de GPU
python3 -c "import torch; print(f'CUDA: {torch.cuda.is_available()}, GPU: {torch.cuda.get_device_name(0)}')"
```

### Paso 4 — Autenticación de HuggingFace

```bash
# Inicia sesión para acceder a modelos restringidos (Llama, Gemma)
huggingface-cli login
# Introduce tu token de HF desde https://huggingface.co/settings/tokens

# O establece la variable de entorno
export HF_TOKEN=hf_your-token-here
```

### Paso 5 — Opcional: seguimiento con Weights & Biases

```bash
# Configura el seguimiento de experimentos (altamente recomendado)
pip install wandb
wandb login  # Introduce tu clave API de W&B desde https://wandb.ai/settings

# O desactiva W&B
export WANDB_DISABLED=true
```

***

## Fine-Tuning Supervisado (SFT)

SFT siempre es el primer paso antes de cualquier técnica de RL.

### Prepara tu conjunto de datos

```python
# Formato: la biblioteca datasets con columna 'messages' o 'text'
# Formato ChatML (recomendado)
from datasets import Dataset

data = [
    {
        "messages": [
            {"role": "system", "content": "Eres un asistente útil de nube GPU."},
            {"role": "user", "content": "¿Cómo alquilo una GPU en Clore.ai?"},
            {"role": "assistant", "content": "Visita clore.ai/marketplace, filtra por especificaciones de GPU, selecciona un servidor y haz clic en Alquilar. El acceso SSH se proporciona inmediatamente después del pago."}
        ]
    },
    # ... más ejemplos
]

dataset = Dataset.from_list(data)
dataset.save_to_disk("data/sft_dataset")
dataset.push_to_hub("tu-usuario/mi-sft-dataset")  # opcional
```

### Script de entrenamiento SFT

```python
# sft_train.py
from trl import SFTTrainer, SFTConfig
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
import torch

# Configuración del modelo
model_name = "meta-llama/Llama-3.2-8B-Instruct"

# QLoRA: configuración de cuantización de 4 bits
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

# Cargar modelo
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
)

# Cargar tokenizador
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# Configuración de LoRA
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# Cargar conjunto de datos
dataset = load_dataset("trl-lib/ultrachat_200k", split="train_sft[:10%]")

# Configuración de entrenamiento
training_config = SFTConfig(
    output_dir="./sft_output",
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    warmup_ratio=0.05,
    lr_scheduler_type="cosine",
    fp16=False,
    bf16=True,
    max_seq_length=2048,
    dataset_text_field="messages",
    logging_steps=10,
    save_steps=100,
    save_total_limit=3,
    push_to_hub=False,
    report_to="wandb",  # o "none"
)

# Inicializar el entrenador
trainer = SFTTrainer(
    model=model,
    args=training_config,
    train_dataset=dataset,
    peft_config=lora_config,
    tokenizer=tokenizer,
)

# Entrena
trainer.train()
trainer.save_model("./sft_final")
```

```bash
# Ejecutar entrenamiento
python3 sft_train.py
```

***

## DPO (Optimización Directa de Preferencias)

DPO es el método de alineación más popular: no necesita modelo de recompensa, solo pares de preferencias.

### Prepara el conjunto de datos DPO

```python
# Formato: cada ejemplo tiene 'prompt', 'chosen', 'rejected'
from datasets import Dataset

data = [
    {
        "prompt": "Explica cómo optimizar el uso de la GPU",
        "chosen": "Para optimizar el uso de la GPU: 1) Usa tamaños de lote más grandes para maximizar la ocupación, 2) Activa precisión mixta (bf16/fp16), 3) Perfila con nvidia-smi para identificar cuellos de botella, 4) Usa streams de CUDA para operaciones paralelas.",
        "rejected": "Simplemente usa más GPUs."
    },
    # ... más pares de preferencias
]

dataset = Dataset.from_list(data)
```

### Script de entrenamiento DPO

```python
# dpo_train.py
from trl import DPOTrainer, DPOConfig
from transformers import AutoTokenizer, AutoModelForCausalLM
from datasets import load_dataset
import torch

model_name = "./sft_final"  # ¡Empieza desde tu modelo SFT!

# Cargar modelo SFT (la política a alinear)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

# Modelo de referencia (copia congelada del modelo SFT)
ref_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# Cargar conjunto de datos de preferencias
dataset = load_dataset("trl-lib/ultrafeedback_binarized", split="train[:5%]")

# Configuración de DPO
dpo_config = DPOConfig(
    output_dir="./dpo_output",
    num_train_epochs=1,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    learning_rate=5e-7,           # Mucho más bajo que SFT
    beta=0.1,                     # Coeficiente de penalización KL
    loss_type="sigmoid",          # Pérdida estándar de DPO
    max_length=2048,
    max_prompt_length=512,
    bf16=True,
    logging_steps=10,
    save_steps=50,
    report_to="wandb",
)

trainer = DPOTrainer(
    model=model,
    ref_model=ref_model,
    args=dpo_config,
    train_dataset=dataset,
    tokenizer=tokenizer,
)

trainer.train()
trainer.save_model("./dpo_final")
```

***

## PPO (Optimización de Política Proximal)

PPO es el enfoque clásico de RLHF: úsalo cuando tengas una señal de recompensa:

```python
# ppo_train.py
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
from transformers import AutoTokenizer, pipeline
from datasets import load_dataset
import torch

model_name = "./sft_final"

# Modelo de política (con cabeza de valor para PPO)
model = AutoModelForCausalLMWithValueHead.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
)

tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# Modelo de recompensa (puede ser cualquier función de puntuación)
sentiment_pipe = pipeline(
    "sentiment-analysis",
    model="distilbert/distilbert-base-uncased-finetuned-sst-2-english",
    device=0,
)

def reward_fn(texts):
    """Puntúa cada respuesta. Devuelve una lista de tensores de recompensa."""
    results = sentiment_pipe(texts)
    rewards = []
    for result in results:
        score = result["score"] if result["label"] == "POSITIVE" else -result["score"]
        rewards.append(torch.tensor(score))
    return rewards

ppo_config = PPOConfig(
    output_dir="./ppo_output",
    learning_rate=1.41e-5,
    mini_batch_size=1,
    batch_size=4,
    gradient_accumulation_steps=4,
    kl_penalty="kl",
    target_kl=6.0,
    cliprange=0.2,
    vf_coef=0.1,
)

trainer = PPOTrainer(
    config=ppo_config,
    model=model,
    ref_model=None,  # Copia automáticamente el modelo inicial como referencia
    tokenizer=tokenizer,
)

# Bucle de entrenamiento
dataset = load_dataset("imdb", split="train[:1000]")
for epoch in range(3):
    for batch in trainer.dataloader:
        queries = batch["input_ids"]
        
        # Generar respuestas
        responses = trainer.generate(queries, max_new_tokens=100)
        
        # Puntuar respuestas
        texts = tokenizer.batch_decode(responses, skip_special_tokens=True)
        rewards = reward_fn(texts)
        
        # Actualización PPO
        stats = trainer.step(queries, responses, rewards)
        trainer.log_stats(stats, batch, rewards)
```

***

## GRPO (Optimización de Política Relativa en Grupo)

GRPO se usa en DeepSeek-R1 para entrenamiento de razonamiento:

```python
# grpo_train.py
from trl import GRPOTrainer, GRPOConfig
from transformers import AutoTokenizer, AutoModelForCausalLM
from datasets import Dataset
import re, torch

model_name = "Qwen/Qwen2.5-7B-Instruct"

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Conjunto de datos de matemáticas
def make_math_dataset():
    examples = [
        {"prompt": "¿Cuánto es 2+2?", "answer": "4"},
        {"prompt": "¿Cuánto es 15 * 7?", "answer": "105"},
        # ... más problemas de matemáticas
    ]
    return Dataset.from_list(examples)

dataset = make_math_dataset()

def correctness_reward(completions, answer, **kwargs):
    """Da una recompensa de 1.0 si la respuesta es correcta, 0.0 en caso contrario."""
    rewards = []
    for completion in completions:
        # Extraer el número final de la respuesta
        numbers = re.findall(r'\d+', completion[-1]["content"])
        if numbers and numbers[-1] == answer:
            rewards.append(1.0)
        else:
            rewards.append(0.0)
    return rewards

grpo_config = GRPOConfig(
    output_dir="./grpo_output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    num_generations=8,       # GRPO genera G respuestas por prompt
    learning_rate=5e-7,
    bf16=True,
    logging_steps=10,
)

trainer = GRPOTrainer(
    model=model,
    args=grpo_config,
    train_dataset=dataset,
    reward_funcs=correctness_reward,
    tokenizer=tokenizer,
)

trainer.train()
```

***

## Entrenamiento multi-GPU

Usa `accelerate` para entrenamiento distribuido:

```bash
# Configura accelerate para múltiples GPUs
accelerate config

# Ejemplo de configuración para 4 GPUs:
# - compute_environment: LOCAL_MACHINE
# - distributed_type: MULTI_GPU
# - num_processes: 4
# - mixed_precision: bf16

# Inicia el entrenamiento en todas las GPUs
accelerate launch sft_train.py
accelerate launch dpo_train.py

# O especifica las GPUs explícitamente
CUDA_VISIBLE_DEVICES=0,1,2,3 accelerate launch \
  --num_processes 4 \
  --mixed_precision bf16 \
  sft_train.py
```

***

## Usando la CLI de TRL

TRL proporciona comandos CLI prácticos:

```bash
# SFT mediante CLI
trl sft \
  --model_name_or_path meta-llama/Llama-3.2-8B-Instruct \
  --dataset_name trl-lib/ultrachat_200k \
  --dataset_text_field messages \
  --output_dir ./cli_sft_output \
  --num_train_epochs 3 \
  --per_device_train_batch_size 2 \
  --gradient_accumulation_steps 4 \
  --learning_rate 2e-4 \
  --bf16 \
  --use_peft \
  --lora_r 16 \
  --lora_alpha 32

# DPO mediante CLI
trl dpo \
  --model_name_or_path ./cli_sft_output \
  --dataset_name trl-lib/ultrafeedback_binarized \
  --output_dir ./cli_dpo_output \
  --num_train_epochs 1 \
  --beta 0.1 \
  --bf16
```

***

## Monitoreo del entrenamiento

```bash
# Vigila la utilización de la GPU
watch -n 1 nvidia-smi

# Monitorea la pérdida de entrenamiento (si usas W&B)
# Abre https://wandb.ai/your-username en el navegador

# Comprueba el directorio de salida para los checkpoints
ls -lh sft_output/checkpoint-*/

# Reanuda desde un checkpoint
python3 sft_train.py --resume_from_checkpoint sft_output/checkpoint-500/
```

***

## Recomendaciones de GPU para Clore.ai

{% hint style="warning" %}
**Los equipos multinodo de clase 80GB no aparecen listados en el marketplace de Clore.ai.** Los equipos más grandes listados hoy son 4× RTX PRO 6000 Blackwell (96GB cada una, 380GB en total) y 8–11× RTX 5090 (32GB cada una). La capacidad A100 / H200 / B200 se vende como [bare metal](https://clore.ai/bare-metal) bajo pedido. Consulta [Precios y disponibilidad de GPU](/guides/guides_v2-es/primeros-pasos/pricing.md) antes de dimensionar un despliegue.
{% endhint %}

El entrenamiento con TRL es una de las cargas de trabajo que más VRAM consume. Elige tu GPU según el tamaño del modelo y el método:

| Tarea                                                      | GPU                | Notas                                                                                                |
| ---------------------------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------- |
| SFT / DPO en 7–8B (QLoRA)                                  | **RTX 3090** 24 GB | \~8 GB para QLoRA de 4 bits; cabe cómodamente; $0.07–0.21/h en Clore.ai                              |
| SFT / DPO en 7–8B (LoRA bf16)                              | **RTX 4090** 24 GB | La misma VRAM que la 3090, pero un 30% más rápido en cómputo; excelente para iterar rápidamente      |
| SFT completo en 7B o DPO en 13B                            | **A100 40 GB**     | 40 GB caben para entrenamiento en precisión completa de 7B; la memoria ECC evita errores silenciosos |
| PPO / ajuste fino completo de 7B, o cualquier QLoRA de 70B | **A100 80 GB**     | PPO necesita 2× modelo policy+ref en VRAM; 80 GB ejecuta ambos sin OOM                               |

**Consejo práctico:** Empieza en una RTX 3090 con QLoRA para experimentar: entrena Llama 3 8B en \~2 h con 10K ejemplos. Una vez que hayas validado el pipeline, pasa a una A100 de 80 GB para ejecuciones en precisión completa o modelos de 70B.

**Números de velocidad (Llama 3 8B SFT, QLoRA, batch=4, seq=2048):**

* RTX 3090: \~1.100 tokens/s de rendimiento de entrenamiento
* RTX 4090: \~1.450 tokens/s
* A100 80 GB: \~2.800 tokens/s (bf16 completo, sin cuantización)

***

## Solución de problemas

### CUDA sin memoria

```bash
# Reduce el tamaño del lote
per_device_train_batch_size=1
gradient_accumulation_steps=16  # Mantén el tamaño efectivo del lote igual

# Usa cuantización de 4 bits (QLoRA)
# Añade BitsAndBytesConfig con load_in_4bit=True

# Habilita gradient checkpointing
gradient_checkpointing=True

# Reduce la longitud de secuencia
max_seq_length=1024  # en lugar de 2048+

# Comprueba la memoria de la GPU
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
```

### La pérdida es NaN

```bash
# Causa común: la tasa de aprendizaje es demasiado alta
learning_rate=1e-5  # Prueba una más baja

# Causa común: datos defectuosos (cadenas vacías, valores None)
# Valida el dataset:
python3 -c "
from datasets import load_from_disk
ds = load_from_disk('data/sft_dataset')
print(ds[0])
print(f'Longitud: {len(ds)}')
# Comprueba None
none_count = sum(1 for x in ds if x.get('messages') is None)
print(f'Cantidad de None: {none_count}')
"

# Habilita bf16 en lugar de fp16 (más estable)
bf16=True
fp16=False
```

### DPO: `chosen_rewards > rejected_rewards` es Falso

```bash
# Esto significa que el modelo prefiere las respuestas rechazadas — sobreajuste o datos defectuosos
# Soluciones:
# 1. Comprueba la calidad de tu dataset
# 2. Reduce beta (menor penalización KL)
# 3. Reduce la tasa de aprendizaje
# 4. Añade más entrenamiento SFT antes de DPO
beta=0.05  # Prueba valores más pequeños
```

### El entrenamiento es muy lento

```bash
# Habilita Flash Attention 2
pip install flash-attn --no-build-isolation

# En tu código:
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    attn_implementation="flash_attention_2",
    torch_dtype=torch.bfloat16,
)

# Usa bf16 en lugar de fp16 en GPUs Ampere+ (A100, RTX 3000+)
bf16=True

# Aumenta los workers de DataLoader
dataloader_num_workers=4

# Comprueba si realmente se está usando la GPU
nvidia-smi  # Debería mostrar una alta utilización de la GPU
```

### `tokenizer.pad_token` advertencia

```bash
# Solución estándar para tokenizadores Llama/Mistral
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"  # Importante para la estabilidad del entrenamiento
```

### Permiso denegado / HuggingFace 401

```bash
# Vuelve a iniciar sesión
huggingface-cli login

# Establece el token en el entorno
export HF_TOKEN=hf_your-token

# Para modelos/datasets privados, asegúrate de tener acceso:
# Ve a https://huggingface.co/meta-llama/Llama-3.2-8B-Instruct
# Haz clic en "Request access" y acepta la licencia
```

***

## Guardar y compartir tu modelo

```bash
# Fusiona los pesos de LoRA en el modelo base
python3 << 'EOF'
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

base_model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-8B-Instruct",
    torch_dtype=torch.bfloat16,
    device_map="auto"
)
model = PeftModel.from_pretrained(base_model, "./sft_final")
merged = model.merge_and_unload()
merged.save_pretrained("./merged_model")

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-8B-Instruct")
tokenizer.save_pretrained("./merged_model")
print("¡Modelo fusionado guardado!")
EOF

# Súbelo a HuggingFace
huggingface-cli upload your-username/my-trl-model ./merged_model
```

***

## Enlaces útiles

* **GitHub**: <https://github.com/huggingface/trl> ⭐ 10K+
* **Documentación**: <https://huggingface.co/docs/trl>
* **Artículo sobre DPO**: <https://arxiv.org/abs/2305.18290>
* **GRPO / DeepSeek-R1**: <https://arxiv.org/abs/2501.12599>
* **Artículo sobre PPO (RLHF)**: <https://arxiv.org/abs/2203.02155>
* **HuggingFace PEFT**: <https://github.com/huggingface/peft>
* **Weights & Biases**: <https://wandb.ai>
* **Flash Attention**: <https://github.com/Dao-AILab/flash-attention>
* **Marketplace de Clore.ai**: <https://clore.ai/marketplace>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-es/entrenamiento/trl.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
