JSONL para datos de entrenamiento IA

Una guía completa para preparar datos de entrenamiento JSONL para IA y aprendizaje automático. Cubre fine-tuning de OpenAI, Anthropic Claude, datasets de HuggingFace, validación de datos y pipelines de datos a gran escala.

Última actualización: febrero de 2026

Por qué JSONL es el estándar para datos de entrenamiento IA

JSONL (JSON Lines) se ha convertido en el estándar de facto para datos de entrenamiento de IA y aprendizaje automático. Todos los principales proveedores de IA, desde OpenAI hasta Anthropic y HuggingFace, utilizan JSONL como su formato principal para datasets de fine-tuning. La razón es simple: JSONL almacena un ejemplo por línea, lo que hace trivial transmitir datos durante el entrenamiento, mezclar ejemplos, contar registros, dividir en conjuntos de entrenamiento y prueba, y agregar nuevas muestras sin reescribir todo el archivo.

A diferencia de un único arreglo JSON que debe parsearse completamente antes de usarse, los archivos JSONL se pueden procesar línea por línea. Esto importa cuando tus datasets de entrenamiento crecen a millones de ejemplos que abarcan gigabytes. En esta guía, aprenderás los formatos JSONL exactos esperados por OpenAI, Anthropic Claude y HuggingFace, cómo validar y limpiar tus datos, y cómo preparar datasets a gran escala para ejecuciones de entrenamiento en producción.

Formato JSONL para fine-tuning de OpenAI

OpenAI usa JSONL tanto para fine-tuning como para la Batch API. Para hacer fine-tuning de modelos de chat como GPT-4o-mini, cada línea debe contener un arreglo messages con la estructura estándar de completado de chat. Los tres roles, system, user y assistant, definen la conversación que el modelo debe aprender a reproducir.

Cada línea es un ejemplo de entrenamiento. El mensaje system establece el comportamiento, el mensaje user es la entrada y el mensaje assistant es la salida objetivo que el modelo debe aprender.

Formato de entrenamiento de Chat Completion
{"messages": [{"role": "system", "content": "You are a helpful customer support agent for an e-commerce platform."}, {"role": "user", "content": "Where is my order #12345?"}, {"role": "assistant", "content": "I can see that order #12345 was shipped on February 10th via FedEx. The tracking number is FX987654321. Based on the latest update, it should arrive by February 14th."}]}
{"messages": [{"role": "system", "content": "You are a helpful customer support agent for an e-commerce platform."}, {"role": "user", "content": "I want to return my purchase."}, {"role": "assistant", "content": "I would be happy to help with your return. Could you please provide the order number and the reason for the return? Our return policy allows returns within 30 days of delivery for most items."}]}

Para conversaciones multi-turno, incluye el historial completo de la conversación. El modelo aprende de cada turno del assistant en el arreglo messages. Así es como enseñas al modelo a manejar preguntas de seguimiento.

Entrenamiento de conversaciones multi-turno
{"messages": [{"role": "system", "content": "You are a Python programming tutor."}, {"role": "user", "content": "What is a list comprehension?"}, {"role": "assistant", "content": "A list comprehension is a concise way to create lists in Python. Instead of writing a for loop to build a list, you can write it in one line: [expression for item in iterable if condition]."}, {"role": "user", "content": "Can you show me an example?"}, {"role": "assistant", "content": "Sure! Here is an example that creates a list of squares for even numbers:\n\nsquares = [x**2 for x in range(10) if x % 2 == 0]\n# Result: [0, 4, 16, 36, 64]\n\nThis is equivalent to:\nsquares = []\nfor x in range(10):\n if x % 2 == 0:\n squares.append(x**2)"}]}

OpenAI requiere al menos 10 ejemplos de entrenamiento, pero recomienda 50-100 para mejoras notables. Todos los mensajes deben tener los campos role y content. El mensaje system es opcional pero recomendado para un comportamiento consistente. Usa la CLI de OpenAI para validar tu archivo antes de subirlo: openai tools fine_tunes.prepare_data -f training.jsonl

Formato de entrenamiento de Anthropic Claude

Anthropic usa JSONL para hacer fine-tuning de modelos Claude. El formato utiliza turnos human y assistant en una conversación estructurada. Aunque el formato exacto depende del método de fine-tuning y la versión de la API, el patrón central sigue la estructura de la Messages API.

Cada línea contiene una conversación con un prompt de sistema y mensajes alternados user/assistant. El modelo aprende a producir las respuestas del assistant dado el contexto de la conversación.

Formato Messages de Claude
{"system": "You are a medical information assistant. Provide accurate, general health information while always recommending consulting a healthcare professional.", "messages": [{"role": "user", "content": "What are the symptoms of vitamin D deficiency?"}, {"role": "assistant", "content": "Common symptoms of vitamin D deficiency include fatigue and tiredness, bone pain and muscle weakness, mood changes including depression, slow wound healing, and frequent infections. However, many people with mild deficiency may not notice symptoms. A blood test is the only way to confirm your vitamin D levels. I recommend speaking with your doctor who can order the appropriate test and recommend supplementation if needed."}]}
{"system": "You are a medical information assistant. Provide accurate, general health information while always recommending consulting a healthcare professional.", "messages": [{"role": "user", "content": "Is it safe to take ibuprofen daily?"}, {"role": "assistant", "content": "Taking ibuprofen daily for extended periods can carry risks including stomach ulcers and gastrointestinal bleeding, increased risk of heart attack and stroke, kidney problems with long-term use, and potential interactions with other medications. For occasional pain relief, short-term use at recommended doses is generally considered safe for most adults. However, if you find yourself needing daily pain relief, please consult your doctor. They can evaluate the underlying cause and recommend a safer long-term treatment plan."}]}

Para datos de entrenamiento multi-turno, incluye la conversación completa con mensajes alternados de user y assistant. El modelo aprende el flujo de conversación y cómo mantener el contexto a través de los turnos.

Conversaciones multi-turno de Claude
{"system": "You are a cooking assistant specializing in Italian cuisine.", "messages": [{"role": "user", "content": "How do I make carbonara?"}, {"role": "assistant", "content": "Authentic carbonara uses just five ingredients: spaghetti, guanciale (cured pork cheek), eggs, Pecorino Romano cheese, and black pepper. The key technique is tempering the egg mixture with the hot pasta water so it creates a creamy sauce without scrambling."}, {"role": "user", "content": "Can I use bacon instead of guanciale?"}, {"role": "assistant", "content": "While guanciale gives the most authentic flavor, pancetta is a closer substitute. Bacon works in a pinch but its smoky flavor changes the dish significantly. If using bacon, choose an unsmoked variety. Whichever you use, cut it into small pieces and render the fat slowly over medium-low heat until crispy."}]}

Datasets de HuggingFace con JSONL

La biblioteca datasets de HuggingFace soporta nativamente JSONL como formato de entrada. Puedes cargar archivos JSONL locales, transmitir datasets remotos y convertir entre formatos fácilmente. JSONL es el formato recomendado para compartir datasets en el HuggingFace Hub.

Usa la biblioteca datasets para cargar archivos JSONL en un objeto Dataset. Esto proporciona acceso eficiente con mapeo en memoria, división train/test integrada e integración perfecta con la Trainer API.

Carga de datasets JSONL
from datasets import load_dataset
# Load a local JSONL file
dataset = load_dataset('json', data_files='training.jsonl')
print(dataset)
# DatasetDict({
# train: Dataset({
# features: ['messages', 'system'],
# num_rows: 5000
# })
# })
# Load with train/test split
dataset = load_dataset('json', data_files={
'train': 'train.jsonl',
'test': 'test.jsonl'
})
# Stream a large remote dataset
dataset = load_dataset(
'json',
data_files='https://example.com/large_dataset.jsonl',
streaming=True
)
for example in dataset['train']:
print(example)
break

Convierte cualquier dataset de HuggingFace a formato JSONL para usarlo con otros pipelines de entrenamiento. El método to_json escribe cada ejemplo como una línea JSON separada.

Exportación a JSONL
from datasets import load_dataset
# Load a dataset from the Hub
dataset = load_dataset('squad', split='train')
# Export to JSONL
dataset.to_json('squad_train.jsonl')
print(f'Exported {len(dataset)} examples')
# Export with specific columns
dataset.select_columns(['question', 'context', 'answers']).to_json(
'squad_filtered.jsonl'
)
# Process and export
def format_for_finetuning(example):
return {
'messages': [
{'role': 'user', 'content': example['question']},
{'role': 'assistant', 'content': example['answers']['text'][0]}
]
}
formatted = dataset.map(format_for_finetuning, remove_columns=dataset.column_names)
formatted.to_json('squad_chat_format.jsonl')

Validación y limpieza de datos

La calidad de los datos de entrenamiento impacta directamente en el rendimiento del modelo. JSON inválido, campos faltantes, ejemplos excesivamente largos y entradas duplicadas pueden degradar los resultados del fine-tuning. Siempre valida y limpia tus archivos JSONL antes de iniciar una ejecución de entrenamiento.

Este script valida cada línea de tu archivo JSONL contra problemas comunes: JSON inválido, campos requeridos faltantes, contenido vacío y longitud de tokens. Ejecútalo antes de subir el archivo para detectar problemas temprano.

Validador de datos de entrenamiento JSONL
import json
import sys
from collections import Counter
def validate_training_data(path: str) -> dict:
"""Validate a JSONL file for AI fine-tuning."""
stats = Counter()
errors = []
with open(path, 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
stats['total'] += 1
# Check valid JSON
try:
data = json.loads(line)
except json.JSONDecodeError as e:
errors.append(f'Line {line_num}: Invalid JSON - {e}')
stats['invalid_json'] += 1
continue
# Check messages field exists
if 'messages' not in data:
errors.append(f'Line {line_num}: Missing "messages" field')
stats['missing_messages'] += 1
continue
messages = data['messages']
# Check message structure
for i, msg in enumerate(messages):
if 'role' not in msg:
errors.append(f'Line {line_num}, msg {i}: Missing "role"')
stats['missing_role'] += 1
if 'content' not in msg:
errors.append(f'Line {line_num}, msg {i}: Missing "content"')
stats['missing_content'] += 1
elif not msg['content'].strip():
errors.append(f'Line {line_num}, msg {i}: Empty content')
stats['empty_content'] += 1
# Check has at least one assistant message
roles = [m.get('role') for m in messages]
if 'assistant' not in roles:
errors.append(f'Line {line_num}: No assistant message')
stats['no_assistant'] += 1
stats['valid'] += 1
return {'stats': dict(stats), 'errors': errors[:50]}
result = validate_training_data('training.jsonl')
print(f"Total: {result['stats'].get('total', 0)}")
print(f"Valid: {result['stats'].get('valid', 0)}")
if result['errors']:
print(f"\nFirst {len(result['errors'])} errors:")
for err in result['errors']:
print(f' {err}')

Los ejemplos de entrenamiento duplicados desperdician cómputo y pueden sesgar el modelo hacia patrones sobrerrepresentados. Este script elimina duplicados exactos basándose en el hash del contenido de cada línea.

Script de deduplicación
import json
import hashlib
def deduplicate_jsonl(input_path: str, output_path: str) -> dict:
"""Remove duplicate training examples from a JSONL file."""
seen_hashes = set()
total = 0
unique = 0
with open(input_path, 'r') as fin, open(output_path, 'w') as fout:
for line in fin:
line = line.strip()
if not line:
continue
total += 1
# Hash the normalized JSON to catch formatting differences
data = json.loads(line)
canonical = json.dumps(data, sort_keys=True)
content_hash = hashlib.sha256(canonical.encode()).hexdigest()
if content_hash not in seen_hashes:
seen_hashes.add(content_hash)
fout.write(json.dumps(data) + '\n')
unique += 1
duplicates = total - unique
print(f'Total: {total}, Unique: {unique}, Removed: {duplicates}')
return {'total': total, 'unique': unique, 'duplicates': duplicates}
deduplicate_jsonl('training.jsonl', 'training_deduped.jsonl')

Preparación de datos a gran escala

Los datasets de entrenamiento en producción a menudo contienen cientos de miles o millones de ejemplos. A esta escala, necesitas pipelines automatizados para mezclar, dividir y fragmentar tus datos JSONL. Una preparación adecuada previene problemas de entrenamiento como el olvido catastrófico y garantiza experimentos reproducibles.

Este script mezcla tus datos aleatoriamente y los divide en conjuntos de entrenamiento y prueba. La mezcla es crítica porque los archivos JSONL a menudo se generan en orden, y entrenar con datos ordenados puede llevar a una mala generalización.

Pipeline de división Train/Test y mezcla
import json
import random
from pathlib import Path
def prepare_training_data(
input_path: str,
output_dir: str,
test_ratio: float = 0.1,
seed: int = 42
) -> dict:
"""Shuffle and split JSONL into train/test sets."""
random.seed(seed)
output = Path(output_dir)
output.mkdir(parents=True, exist_ok=True)
# Load all examples
examples = []
with open(input_path, 'r') as f:
for line in f:
line = line.strip()
if line:
examples.append(json.loads(line))
# Shuffle
random.shuffle(examples)
# Split
split_idx = int(len(examples) * (1 - test_ratio))
train_data = examples[:split_idx]
test_data = examples[split_idx:]
# Write output files
train_path = output / 'train.jsonl'
test_path = output / 'test.jsonl'
for data, path in [(train_data, train_path), (test_data, test_path)]:
with open(path, 'w') as f:
for example in data:
f.write(json.dumps(example) + '\n')
print(f'Train: {len(train_data)} examples -> {train_path}')
print(f'Test: {len(test_data)} examples -> {test_path}')
return {'train': len(train_data), 'test': len(test_data)}
prepare_training_data(
'all_examples.jsonl',
'./prepared_data/',
test_ratio=0.1,
seed=42
)

Cuando los datasets son demasiado grandes para un solo archivo o necesitas distribuir el entrenamiento entre múltiples GPUs, fragmenta el archivo JSONL en partes más pequeñas. Cada fragmento puede procesarse de forma independiente.

Fragmentación de archivos para entrenamiento distribuido
import json
from pathlib import Path
def shard_jsonl(
input_path: str,
output_dir: str,
shard_size: int = 50000
) -> int:
"""Split a large JSONL file into smaller shards."""
output = Path(output_dir)
output.mkdir(parents=True, exist_ok=True)
shard_num = 0
line_count = 0
current_file = None
with open(input_path, 'r') as fin:
for line in fin:
line = line.strip()
if not line:
continue
if line_count % shard_size == 0:
if current_file:
current_file.close()
shard_path = output / f'shard_{shard_num:04d}.jsonl'
current_file = open(shard_path, 'w')
shard_num += 1
current_file.write(line + '\n')
line_count += 1
if current_file:
current_file.close()
print(f'Created {shard_num} shards from {line_count} examples')
return shard_num
shard_jsonl('large_dataset.jsonl', './shards/', shard_size=50000)

Valida tus datos de entrenamiento online

Usa nuestras herramientas gratuitas en el navegador para validar, formatear y convertir tus datos de entrenamiento JSONL antes de subirlos a OpenAI, Anthropic o HuggingFace.

¿Listo para preparar tus datos de entrenamiento?

Valida, formatea e inspecciona tus archivos de entrenamiento JSONL directamente en tu navegador. Sin subidas, sin registros, 100% privado.

Preguntas frecuentes

Datos de entrenamiento JSONL — Formatos de OpenAI, Claude...