JSONL per Dati di Addestramento IA
Una guida completa alla preparazione dei dati di addestramento JSONL per l'intelligenza artificiale e il machine learning. Copre il fine-tuning di OpenAI, Anthropic Claude, dataset HuggingFace, validazione dei dati e pipeline di dati su larga scala.
Ultimo aggiornamento: Febbraio 2026
Perché JSONL è lo Standard per i Dati di Addestramento IA
JSONL (JSON Lines) è diventato lo standard de facto per i dati di addestramento di intelligenza artificiale e machine learning. Ogni grande fornitore di IA, da OpenAI ad Anthropic a HuggingFace, utilizza JSONL come formato principale per i dataset di fine-tuning. Il motivo è semplice: JSONL memorizza un esempio per riga, rendendo banale lo streaming dei dati durante l'addestramento, il mescolamento degli esempi, il conteggio dei record, la suddivisione in set di train e test e l'aggiunta di nuovi campioni senza riscrivere l'intero file.
A differenza di un singolo array JSON che deve essere completamente analizzato prima dell'uso, i file JSONL possono essere elaborati riga per riga. Questo è importante quando i dataset di addestramento crescono fino a milioni di esempi che occupano gigabyte. In questa guida imparerai i formati JSONL esatti previsti da OpenAI, Anthropic Claude e HuggingFace, come validare e pulire i tuoi dati e come preparare dataset su larga scala per esecuzioni di addestramento in produzione.
Formato JSONL per il Fine-tuning di OpenAI
OpenAI utilizza JSONL sia per il fine-tuning che per la Batch API. Per il fine-tuning di modelli chat come GPT-4o-mini, ogni riga deve contenere un array messages con la struttura standard di chat completion. I tre ruoli, system, user e assistant, definiscono la conversazione che il modello deve imparare a riprodurre.
Ogni riga è un esempio di addestramento. Il messaggio system imposta il comportamento, il messaggio user è l'input e il messaggio assistant è l'output target che il modello deve imparare.
{"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."}]}
Per conversazioni multi-turno, includi l'intera cronologia della conversazione. Il modello impara da ogni turno assistant nell'array messages. Questo è il modo per insegnare al modello a gestire le domande di follow-up.
{"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 richiede almeno 10 esempi di addestramento, ma ne raccomanda 50-100 per miglioramenti evidenti. Tutti i messaggi devono avere i campi role e content. Il messaggio system è opzionale ma raccomandato per un comportamento coerente. Usa la CLI di OpenAI per validare il tuo file prima del caricamento: openai tools fine_tunes.prepare_data -f training.jsonl
Formato di Addestramento Anthropic Claude
Anthropic utilizza JSONL per il fine-tuning dei modelli Claude. Il formato usa turni human e assistant in una conversazione strutturata. Mentre il formato esatto dipende dal metodo di fine-tuning e dalla versione dell'API, il pattern principale segue la struttura della Messages API.
Ogni riga contiene una conversazione con un prompt di sistema e messaggi alternati user/assistant. Il modello impara a produrre le risposte assistant dato il contesto della conversazione.
{"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."}]}
Per dati di addestramento multi-turno, includi la conversazione completa con messaggi alternati user e assistant. Il modello impara il flusso della conversazione e come mantenere il contesto attraverso i turni.
{"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."}]}
Dataset HuggingFace con JSONL
La libreria datasets di HuggingFace supporta nativamente JSONL come formato di input. Puoi caricare file JSONL locali, fare streaming di dataset remoti e convertire tra formati facilmente. JSONL è il formato raccomandato per condividere dataset su HuggingFace Hub.
Usa la libreria datasets per caricare file JSONL in un oggetto Dataset. Questo fornisce accesso efficiente con memory-mapping, suddivisione train/test integrata e integrazione senza soluzione di continuità con la Trainer API.
from datasets import load_dataset# Load a local JSONL filedataset = load_dataset('json', data_files='training.jsonl')print(dataset)# DatasetDict({# train: Dataset({# features: ['messages', 'system'],# num_rows: 5000# })# })# Load with train/test splitdataset = load_dataset('json', data_files={'train': 'train.jsonl','test': 'test.jsonl'})# Stream a large remote datasetdataset = load_dataset('json',data_files='https://example.com/large_dataset.jsonl',streaming=True)for example in dataset['train']:print(example)break
Converti qualsiasi dataset HuggingFace in formato JSONL per l'uso con altre pipeline di addestramento. Il metodo to_json scrive ogni esempio come una riga JSON separata.
from datasets import load_dataset# Load a dataset from the Hubdataset = load_dataset('squad', split='train')# Export to JSONLdataset.to_json('squad_train.jsonl')print(f'Exported {len(dataset)} examples')# Export with specific columnsdataset.select_columns(['question', 'context', 'answers']).to_json('squad_filtered.jsonl')# Process and exportdef 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')
Validazione e Pulizia dei Dati
La qualità dei dati di addestramento influisce direttamente sulle prestazioni del modello. JSON non valido, campi mancanti, esempi eccessivamente lunghi e voci duplicate possono tutti degradare i risultati del fine-tuning. Valida e pulisci sempre i tuoi file JSONL prima di avviare un'esecuzione di addestramento.
Questo script valida ogni riga del tuo file JSONL contro problemi comuni: JSON non valido, campi obbligatori mancanti, contenuto vuoto e lunghezza dei token. Eseguilo prima del caricamento per individuare i problemi in anticipo.
import jsonimport sysfrom collections import Counterdef 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:continuestats['total'] += 1# Check valid JSONtry:data = json.loads(line)except json.JSONDecodeError as e:errors.append(f'Line {line_num}: Invalid JSON - {e}')stats['invalid_json'] += 1continue# Check messages field existsif 'messages' not in data:errors.append(f'Line {line_num}: Missing "messages" field')stats['missing_messages'] += 1continuemessages = data['messages']# Check message structurefor i, msg in enumerate(messages):if 'role' not in msg:errors.append(f'Line {line_num}, msg {i}: Missing "role"')stats['missing_role'] += 1if 'content' not in msg:errors.append(f'Line {line_num}, msg {i}: Missing "content"')stats['missing_content'] += 1elif not msg['content'].strip():errors.append(f'Line {line_num}, msg {i}: Empty content')stats['empty_content'] += 1# Check has at least one assistant messageroles = [m.get('role') for m in messages]if 'assistant' not in roles:errors.append(f'Line {line_num}: No assistant message')stats['no_assistant'] += 1stats['valid'] += 1return {'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}')
Esempi di addestramento duplicati sprecano risorse computazionali e possono introdurre bias nel modello verso pattern sovra-rappresentati. Questo script rimuove i duplicati esatti basandosi sull'hash del contenuto di ogni riga.
import jsonimport hashlibdef deduplicate_jsonl(input_path: str, output_path: str) -> dict:"""Remove duplicate training examples from a JSONL file."""seen_hashes = set()total = 0unique = 0with open(input_path, 'r') as fin, open(output_path, 'w') as fout:for line in fin:line = line.strip()if not line:continuetotal += 1# Hash the normalized JSON to catch formatting differencesdata = 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 += 1duplicates = total - uniqueprint(f'Total: {total}, Unique: {unique}, Removed: {duplicates}')return {'total': total, 'unique': unique, 'duplicates': duplicates}deduplicate_jsonl('training.jsonl', 'training_deduped.jsonl')
Preparazione Dati su Larga Scala
I dataset di addestramento in produzione contengono spesso centinaia di migliaia o milioni di esempi. A questa scala, hai bisogno di pipeline automatizzate per il mescolamento, la suddivisione e lo sharding dei tuoi dati JSONL. Una preparazione adeguata previene problemi di addestramento come il catastrophic forgetting e garantisce esperimenti riproducibili.
Questo script mescola i tuoi dati in modo casuale e li suddivide in set di train e test. Il mescolamento è fondamentale perché i file JSONL sono spesso generati in ordine, e addestrare su dati ordinati può portare a una scarsa generalizzazione.
import jsonimport randomfrom pathlib import Pathdef 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 examplesexamples = []with open(input_path, 'r') as f:for line in f:line = line.strip()if line:examples.append(json.loads(line))# Shufflerandom.shuffle(examples)# Splitsplit_idx = int(len(examples) * (1 - test_ratio))train_data = examples[:split_idx]test_data = examples[split_idx:]# Write output filestrain_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)
Quando i dataset sono troppo grandi per un singolo file o hai bisogno di distribuire l'addestramento su più GPU, suddividi il file JSONL in blocchi più piccoli. Ogni shard può essere elaborato indipendentemente.
import jsonfrom pathlib import Pathdef 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 = 0line_count = 0current_file = Nonewith open(input_path, 'r') as fin:for line in fin:line = line.strip()if not line:continueif 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 += 1current_file.write(line + '\n')line_count += 1if current_file:current_file.close()print(f'Created {shard_num} shards from {line_count} examples')return shard_numshard_jsonl('large_dataset.jsonl', './shards/', shard_size=50000)
Valida i Tuoi Dati di Addestramento Online
Usa i nostri strumenti gratuiti basati su browser per validare, formattare e convertire i tuoi dati di addestramento JSONL prima di caricarli su OpenAI, Anthropic o HuggingFace.