JSONL für KI-Trainingsdaten
Ein umfassender Leitfaden zur Vorbereitung von JSONL-Trainingsdaten für KI und Machine Learning. Umfasst OpenAI Fine-Tuning, Anthropic Claude, HuggingFace-Datensätze, Datenvalidierung und großskalige Datenpipelines.
Letzte Aktualisierung: Februar 2026
Warum JSONL der Standard für KI-Trainingsdaten ist
JSONL (JSON Lines) hat sich zum De-facto-Standard für KI- und Machine-Learning-Trainingsdaten entwickelt. Jeder große KI-Anbieter, von OpenAI über Anthropic bis HuggingFace, verwendet JSONL als primäres Format für Fine-Tuning-Datensätze. Der Grund ist einfach: JSONL speichert ein Beispiel pro Zeile, was es trivial macht, Daten während des Trainings zu streamen, Beispiele zu mischen, Datensätze zu zählen, in Trainings- und Testsets aufzuteilen und neue Proben anzuhängen, ohne die gesamte Datei neu schreiben zu müssen.
Im Gegensatz zu einem einzelnen JSON-Array, das vor der Verwendung vollständig geparst werden muss, können JSONL-Dateien zeilenweise verarbeitet werden. Dies ist entscheidend, wenn Ihre Trainingsdatensätze auf Millionen von Beispielen über Gigabytes anwachsen. In diesem Leitfaden erfahren Sie die genauen JSONL-Formate, die von OpenAI, Anthropic Claude und HuggingFace erwartet werden, wie Sie Ihre Daten validieren und bereinigen, und wie Sie großskalige Datensätze für Produktionstrainingsläufe vorbereiten.
OpenAI Fine-Tuning JSONL-Format
OpenAI verwendet JSONL sowohl für Fine-Tuning als auch für die Batch API. Für das Fine-Tuning von Chat-Modellen wie GPT-4o-mini muss jede Zeile ein messages-Array mit der Standard-Chat-Completion-Struktur enthalten. Die drei Rollen — system, user und assistant — definieren die Konversation, die das Modell reproduzieren soll.
Jede Zeile ist ein Trainingsbeispiel. Die Systemnachricht legt das Verhalten fest, die Benutzernachricht ist die Eingabe, und die Assistentennachricht ist die Zielausgabe, die das Modell lernen soll.
{"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."}]}
Für mehrstufige Konversationen fügen Sie den vollständigen Gesprächsverlauf ein. Das Modell lernt aus jeder assistant-Nachricht im messages-Array. So bringen Sie dem Modell bei, Folgefragen zu bearbeiten.
{"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 erfordert mindestens 10 Trainingsbeispiele, empfiehlt jedoch 50-100 für spürbare Verbesserungen. Alle Nachrichten müssen role- und content-Felder haben. Die Systemnachricht ist optional, wird aber für konsistentes Verhalten empfohlen. Verwenden Sie die OpenAI-CLI, um Ihre Datei vor dem Hochladen zu validieren: openai tools fine_tunes.prepare_data -f training.jsonl
Anthropic Claude Trainingsformat
Anthropic verwendet JSONL für das Fine-Tuning von Claude-Modellen. Das Format verwendet human- und assistant-Runden in einer strukturierten Konversation. Während das genaue Format von der Fine-Tuning-Methode und API-Version abhängt, folgt das Kernmuster der Messages-API-Struktur.
Jede Zeile enthält eine Konversation mit einem System-Prompt und abwechselnden user/assistant-Nachrichten. Das Modell lernt, die Assistentenantworten im gegebenen Konversationskontext zu erzeugen.
{"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."}]}
Für mehrstufige Trainingsdaten fügen Sie die vollständige Konversation mit abwechselnden user- und assistant-Nachrichten ein. Das Modell lernt den Gesprächsfluss und wie es den Kontext über mehrere Runden hinweg beibehält.
{"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."}]}
HuggingFace-Datensätze mit JSONL
Die datasets-Bibliothek von HuggingFace unterstützt JSONL nativ als Eingabeformat. Sie können lokale JSONL-Dateien laden, entfernte Datensätze streamen und einfach zwischen Formaten konvertieren. JSONL ist das empfohlene Format zum Teilen von Datensätzen auf dem HuggingFace Hub.
Verwenden Sie die datasets-Bibliothek, um JSONL-Dateien in ein Dataset-Objekt zu laden. Dies bietet effizienten speicherabgebildeten Zugriff, eingebaute Train/Test-Aufteilung und nahtlose Integration mit der 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
Konvertieren Sie jeden HuggingFace-Datensatz in das JSONL-Format zur Verwendung mit anderen Trainingspipelines. Die to_json-Methode schreibt jedes Beispiel als separate JSON-Zeile.
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')
Datenvalidierung und -bereinigung
Die Qualität der Trainingsdaten wirkt sich direkt auf die Modellleistung aus. Ungültiges JSON, fehlende Felder, übermäßig lange Beispiele und doppelte Einträge können die Fine-Tuning-Ergebnisse verschlechtern. Validieren und bereinigen Sie Ihre JSONL-Dateien immer vor dem Start eines Trainingslaufs.
Dieses Skript validiert jede Zeile Ihrer JSONL-Datei auf häufige Probleme: ungültiges JSON, fehlende Pflichtfelder, leere Inhalte und Token-Länge. Führen Sie es vor dem Hochladen aus, um Probleme frühzeitig zu erkennen.
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}')
Doppelte Trainingsbeispiele verschwenden Rechenleistung und können das Modell in Richtung überrepräsentierter Muster verzerren. Dieses Skript entfernt exakte Duplikate basierend auf dem Inhaltshash jeder Zeile.
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')
Großskalige Datenvorbereitung
Produktionstrainingsdatensätze enthalten oft Hunderttausende oder Millionen von Beispielen. In diesem Maßstab benötigen Sie automatisierte Pipelines zum Mischen, Aufteilen und Sharden Ihrer JSONL-Daten. Eine ordnungsgemäße Vorbereitung verhindert Trainingsprobleme wie katastrophales Vergessen und gewährleistet reproduzierbare Experimente.
Dieses Skript mischt Ihre Daten zufällig und teilt sie in Trainings- und Testsets auf. Das Mischen ist entscheidend, da JSONL-Dateien oft in geordneter Reihenfolge generiert werden und Training mit geordneten Daten zu schlechter Generalisierung führen kann.
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)
Wenn Datensätze für eine einzelne Datei zu groß sind oder Sie das Training auf mehrere GPUs verteilen müssen, teilen Sie die JSONL-Datei in kleinere Teile auf. Jeder Shard kann unabhängig verarbeitet werden.
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)
Validieren Sie Ihre Trainingsdaten online
Verwenden Sie unsere kostenlosen browserbasierten Tools, um Ihre JSONL-Trainingsdaten zu validieren, formatieren und konvertieren, bevor Sie sie bei OpenAI, Anthropic oder HuggingFace hochladen.