Fine-Tuning de LLMs: Cómo Entrenar tu Propio Modelo [Tutorial 2026]
Aprende a hacer fine-tuning de LLMs paso a paso. Tutorial con código Python, datasets, y cómo crear un modelo personalizado para tu negocio.
Fine-Tuning de LLMs: Cómo Entrenar tu Propio Modelo [Tutorial 2026]
El fine-tuning te permite especializar un LLM en tu dominio específico. En lugar de depender de prompts complejos, entrenas el modelo para que entienda tu vocabulario, estilo y casos de uso particulares.
¿Cuándo Hacer Fine-Tuning?
Sí Hacer Fine-Tuning Si:
- Tienes un dominio muy específico (legal, médico, técnico)
- Necesitas un estilo o tono consistente
- El modelo debe seguir un formato específico siempre
- Tienes miles de ejemplos de interacciones ideales
- Los prompts están demasiado largos y costosos
No Hacer Fine-Tuning Si:
- Puedes lograr el resultado con buenos prompts
- Tienes menos de 100 ejemplos
- El conocimiento que necesitas es público y actual
- Necesitas que el modelo acceda a datos en tiempo real
Alternativas al Fine-Tuning
| Método | Cuándo Usarlo |
|---|---|
| Prompt engineering | Primero siempre |
| Few-shot prompting | Ejemplos en el prompt |
| RAG | Datos que cambian frecuentemente |
| Fine-tuning | Comportamiento/estilo consistente |
Opciones de Fine-Tuning en 2026
1. OpenAI Fine-Tuning (GPT-4o, GPT-4o-mini)
| Aspecto | Detalle |
|---|---|
| Modelo base | GPT-4o-mini, GPT-4o |
| Mínimo ejemplos | 10 (recomendado: 50-100) |
| Formato | JSONL con messages |
| Precio training | $25/M tokens (4o-mini) |
| Precio inference | 2x modelo base |
2. Anthropic Fine-Tuning (Claude)
| Aspecto | Detalle |
|---|---|
| Disponibilidad | Solo Enterprise |
| Proceso | Contactar ventas |
| Mínimo ejemplos | 1000+ recomendado |
3. Open Source (Llama, Mistral)
| Aspecto | Detalle |
|---|---|
| Modelos | Llama 3.2, Mistral, Qwen |
| Herramientas | Hugging Face, Axolotl |
| Hardware | GPU 24GB+ (A100, 4090) |
| Técnicas | LoRA, QLoRA, Full fine-tune |
Tutorial: Fine-Tuning con OpenAI
Paso 1: Preparar Dataset
El formato JSONL requiere conversaciones completas:
1{"messages": [{"role": "system", "content": "Eres un asistente de soporte técnico de SoftwareCorp."}, {"role": "user", "content": "No puedo iniciar sesión"}, {"role": "assistant", "content": "Entiendo que tienes problemas para acceder. Vamos a solucionarlo:\n\n1. Verifica que usas el email correcto\n2. Prueba 'Olvidé contraseña'\n3. Limpia cookies del navegador\n\n¿Cuál de estos pasos has intentado?"}]}2{"messages": [{"role": "system", "content": "Eres un asistente de soporte técnico de SoftwareCorp."}, {"role": "user", "content": "La app va muy lenta"}, {"role": "assistant", "content": "Vamos a optimizar el rendimiento:\n\n1. Cierra otras aplicaciones\n2. Actualiza a la última versión\n3. Reinicia el dispositivo\n\n¿Qué versión de la app tienes instalada?"}]}
Paso 2: Validar Dataset
1import json2 3def validate_jsonl(file_path):4 errors = []5 with open(file_path, 'r') as f:6 for i, line in enumerate(f, 1):7 try:8 data = json.loads(line)9 if 'messages' not in data:10 errors.append(f"Línea {i}: Falta 'messages'")11 for msg in data['messages']:12 if 'role' not in msg or 'content' not in msg:13 errors.append(f"Línea {i}: Mensaje mal formado")14 except json.JSONDecodeError:15 errors.append(f"Línea {i}: JSON inválido")16 return errors17 18errors = validate_jsonl('training_data.jsonl')19if errors:20 print("Errores encontrados:")21 for e in errors:22 print(e)23else:24 print("Dataset válido!")
Paso 3: Subir Dataset
1from openai import OpenAI2 3client = OpenAI()4 5# Subir archivo6file = client.files.create(7 file=open("training_data.jsonl", "rb"),8 purpose="fine-tune"9)10 11print(f"Archivo subido: {file.id}")
Paso 4: Crear Fine-Tuning Job
1job = client.fine_tuning.jobs.create(2 training_file=file.id,3 model="gpt-4o-mini-2024-07-18",4 hyperparameters={5 "n_epochs": 3,6 "batch_size": 1,7 "learning_rate_multiplier": 1.88 }9)10 11print(f"Job creado: {job.id}")
Paso 5: Monitorear Progreso
1import time2 3while True:4 job_status = client.fine_tuning.jobs.retrieve(job.id)5 print(f"Status: {job_status.status}")6 7 if job_status.status in ['succeeded', 'failed']:8 break9 10 time.sleep(60)11 12if job_status.status == 'succeeded':13 print(f"Modelo listo: {job_status.fine_tuned_model}")
Paso 6: Usar el Modelo
1response = client.chat.completions.create(2 model=job_status.fine_tuned_model, # ft:gpt-4o-mini-2024-07-18:org:custom:id3 messages=[4 {"role": "system", "content": "Eres un asistente de soporte técnico de SoftwareCorp."},5 {"role": "user", "content": "Mi cuenta está bloqueada"}6 ]7)8 9print(response.choices[0].message.content)
Tutorial: Fine-Tuning Open Source con LoRA
¿Qué es LoRA?
LoRA (Low-Rank Adaptation) entrena solo una pequeña parte del modelo, reduciendo:
- Memoria necesaria: 4-8GB en vez de 80GB
- Tiempo de entrenamiento: horas en vez de días
- Costo: GPU consumer vs cluster
Setup del Entorno
1# Crear entorno2python -m venv llm-finetune3source llm-finetune/bin/activate4 5# Instalar dependencias6pip install torch transformers datasets peft accelerate bitsandbytes7pip install trl wandb
Código de Fine-Tuning con Llama
1import torch2from datasets import load_dataset3from transformers import (4 AutoModelForCausalLM,5 AutoTokenizer,6 BitsAndBytesConfig,7 TrainingArguments8)9from peft import LoraConfig, get_peft_model10from trl import SFTTrainer11 12# Configuración de cuantización (4-bit para ahorrar memoria)13bnb_config = BitsAndBytesConfig(14 load_in_4bit=True,15 bnb_4bit_quant_type="nf4",16 bnb_4bit_compute_dtype=torch.float1617)18 19# Cargar modelo base20model_name = "meta-llama/Llama-3.2-8B-Instruct"21model = AutoModelForCausalLM.from_pretrained(22 model_name,23 quantization_config=bnb_config,24 device_map="auto"25)26 27tokenizer = AutoTokenizer.from_pretrained(model_name)28tokenizer.pad_token = tokenizer.eos_token29 30# Configuración LoRA31lora_config = LoraConfig(32 r=16, # Rank33 lora_alpha=32,34 target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],35 lora_dropout=0.05,36 bias="none",37 task_type="CAUSAL_LM"38)39 40model = get_peft_model(model, lora_config)41 42# Cargar dataset (formato: {"text": "### User: pregunta\n### Assistant: respuesta"})43dataset = load_dataset("json", data_files="training_data.json")44 45# Argumentos de entrenamiento46training_args = TrainingArguments(47 output_dir="./llama-finetuned",48 num_train_epochs=3,49 per_device_train_batch_size=4,50 gradient_accumulation_steps=4,51 learning_rate=2e-4,52 fp16=True,53 logging_steps=10,54 save_strategy="epoch"55)56 57# Trainer58trainer = SFTTrainer(59 model=model,60 train_dataset=dataset["train"],61 tokenizer=tokenizer,62 args=training_args,63 max_seq_length=204864)65 66# Entrenar67trainer.train()68 69# Guardar modelo70trainer.save_model("./llama-finetuned-final")
Usar el Modelo Fine-Tuned
1from peft import PeftModel2 3# Cargar modelo base + adaptador LoRA4base_model = AutoModelForCausalLM.from_pretrained(5 "meta-llama/Llama-3.2-8B-Instruct",6 device_map="auto",7 torch_dtype=torch.float168)9 10model = PeftModel.from_pretrained(base_model, "./llama-finetuned-final")11 12# Generar respuesta13prompt = "### User: ¿Cómo reseteo mi contraseña?\n### Assistant:"14inputs = tokenizer(prompt, return_tensors="pt").to("cuda")15 16outputs = model.generate(**inputs, max_new_tokens=200)17print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Preparar Datasets de Calidad
Estructura de Datos Ideal
1{2 "instruction": "Responde como agente de soporte de SoftwareCorp",3 "input": "Mi factura tiene un error",4 "output": "Lamento el inconveniente con tu factura. Para corregirlo necesito:\n\n1. Número de factura\n2. Descripción del error\n3. Datos correctos\n\n¿Puedes proporcionarme estos datos?"5}
Fuentes de Datos
- Conversaciones reales de tu equipo de soporte
- FAQs convertidas a formato conversacional
- Documentación adaptada a Q&A
- Datos sintéticos generados con GPT-4
Generar Datos Sintéticos
1from openai import OpenAI2 3client = OpenAI()4 5def generate_training_example(topic):6 response = client.chat.completions.create(7 model="gpt-4o",8 messages=[9 {"role": "system", "content": """Genera un ejemplo de conversación10 de soporte técnico para SoftwareCorp sobre el tema dado.11 Formato JSON: {"user": "...", "assistant": "..."}"""},12 {"role": "user", "content": f"Tema: {topic}"}13 ]14 )15 return response.choices[0].message.content16 17topics = [18 "problema de login",19 "facturación incorrecta",20 "app lenta",21 "cancelar suscripción",22 "actualizar plan"23]24 25examples = [generate_training_example(t) for t in topics]
Mejores Prácticas
1. Calidad > Cantidad
- 100 ejemplos excelentes > 1000 ejemplos mediocres
- Revisa manualmente cada ejemplo
- Elimina duplicados y contradicciones
2. Diversidad de Ejemplos
- Cubre todos los casos de uso
- Incluye variaciones de la misma pregunta
- Añade casos edge
3. Consistencia de Formato
- Mismo tono en todas las respuestas
- Estructura similar (saludo, pasos, cierre)
- Longitud consistente
4. Hiperparámetros
| Parámetro | Valor Recomendado | Efecto |
|---|---|---|
| Epochs | 2-4 | Más = overfitting |
| Learning rate | 1e-5 a 2e-4 | Más alto = inestable |
| Batch size | 4-16 | Depende de GPU |
| LoRA rank | 8-64 | Más = más capacidad |
5. Evaluación
1# Métricas a evaluar2test_cases = [3 {"input": "No puedo acceder", "expected_topics": ["login", "contraseña"]},4 {"input": "Cobro incorrecto", "expected_topics": ["factura", "reembolso"]}5]6 7def evaluate_model(model, test_cases):8 results = []9 for case in test_cases:10 response = model.generate(case["input"])11 # Evaluar si cubre los temas esperados12 coverage = sum(1 for t in case["expected_topics"] if t in response.lower())13 results.append(coverage / len(case["expected_topics"]))14 return sum(results) / len(results)
Costos Estimados
OpenAI Fine-Tuning
| Concepto | GPT-4o-mini | GPT-4o |
|---|---|---|
| Training | $25/M tokens | $100/M tokens |
| Inference | $0.60/M input | $6/M input |
| 1000 ejemplos (~500K tokens) | ~$12.50 | ~$50 |
Open Source (Cloud GPU)
| Proveedor | GPU | Precio/hora | Para 8B model |
|---|---|---|---|
| RunPod | A100 40GB | $1.69 | ~$5-10 total |
| Lambda Labs | A100 80GB | $1.29 | ~$4-8 total |
| Vast.ai | 4090 | $0.40 | ~$2-5 total |
Conclusión
El fine-tuning es poderoso pero no siempre necesario. Antes de invertir tiempo y dinero:
- Prueba prompt engineering - A menudo es suficiente
- Considera RAG - Para datos que cambian
- Evalúa el ROI - ¿Justifica el costo?
Si decides hacer fine-tuning:
- Empieza con OpenAI (más fácil)
- Prepara datos de calidad
- Itera basándote en evaluaciones
- Considera open source para escalar
Recursos relacionados:
Posts Relacionados
Cómo Usar Claude Code en Terminal: Tutorial Paso a Paso [2026]
Tutorial completo de Claude Code CLI. Aprende a usar el agente de código de Anthropic en terminal para automatizar desarrollo, refactoring y tareas complejas.
MCP Servers para Claude: Guía de Configuración en Español [2026]
Configura MCP Servers para Claude Code y Claude Desktop. Tutorial en español con ejemplos: filesystem, GitHub, bases de datos, APIs personalizadas.
Gemini 3 Deep Think: Cómo Usar el Modo Razonamiento de Google [2026]
Guía de Gemini 3 Deep Think, el modo de razonamiento avanzado de Google. Cómo activarlo, cuándo usarlo, comparativa con GPT-5.2 Thinking y casos de uso.
Javier Santos Criado
Consultor de IA y Automatización | Fundador de Javadex
Experto en implementación de soluciones de Inteligencia Artificial para empresas. Especializado en automatización con n8n, integración de LLMs, y desarrollo de agentes IA.
¿Quieres más contenido de IA?
Explora nuestras comparativas y guías