JSONL dla danych treningowych AI
Kompleksowy przewodnik po przygotowywaniu danych treningowych JSONL dla AI i uczenia maszynowego. Obejmuje fine-tuning OpenAI, Anthropic Claude, zbiory danych HuggingFace, walidacje danych i potoki przetwarzania danych na duza skale.
Ostatnia aktualizacja: luty 2026
Dlaczego JSONL jest standardem dla danych treningowych AI
JSONL (JSON Lines) stal sie de facto standardem dla danych treningowych AI i uczenia maszynowego. Kazdy wazny dostawca AI, od OpenAI przez Anthropic po HuggingFace, uzywa JSONL jako glownego formatu dla zbiorow danych do fine-tuningu. Powod jest prosty: JSONL przechowuje jeden przyklad na linie, co sprawia, ze strumieniowanie danych podczas treningu, losowe mieszanie przykladow, liczenie rekordow, podzial na zbiory treningowe i testowe oraz dodawanie nowych probek bez przepisywania calego pliku jest trywialne.
W przeciwienstwie do pojedynczej tablicy JSON, ktora musi byc w calosci sparsowana przed uzyciem, pliki JSONL moga byc przetwarzane linia po linii. Ma to znaczenie, gdy zbiory danych treningowych rosna do milionow przykladow zajmujacych gigabajty. W tym przewodniku poznasz dokladne formaty JSONL oczekiwane przez OpenAI, Anthropic Claude i HuggingFace, dowiesz sie, jak walidowac i czyscic dane, oraz jak przygotowac zbiory danych na duza skale do produkcyjnych przebiegow treningowych.
Format JSONL do fine-tuningu OpenAI
OpenAI uzywa JSONL zarowno do fine-tuningu, jak i Batch API. Do fine-tuningu modeli czatowych, takich jak GPT-4o-mini, kazda linia musi zawierac tablice messages ze standardowa struktura chat completion. Trzy role - system, user i assistant - definiuja konwersacje, ktora model powinien nauczyc sie odtwarzac.
Kazda linia to jeden przyklad treningowy. Wiadomosc systemowa ustawia zachowanie, wiadomosc uzytkownika to dane wejsciowe, a wiadomosc asystenta to docelowe wyjscie, ktorego model powinien sie nauczyc.
{"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."}]}
W przypadku konwersacji wieloturowych nalezy uwzglednic pelna historie rozmowy. Model uczy sie z kazdej tury asystenta w tablicy messages. W ten sposob uczysz model obslugi pytan uzupelniajacych.
{"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 wymaga co najmniej 10 przykladow treningowych, ale zaleca 50-100 dla zauwazyalnej poprawy. Wszystkie wiadomosci musza miec pola role i content. Wiadomosc systemowa jest opcjonalna, ale zalecana dla spojnego zachowania. Uzyj CLI OpenAI do walidacji pliku przed przeslaniem: openai tools fine_tunes.prepare_data -f training.jsonl
Format treningowy Anthropic Claude
Anthropic uzywa JSONL do fine-tuningu modeli Claude. Format wykorzystuje tury human i assistant w ustrukturyzowanej konwersacji. Chociaz dokladny format zalezy od metody fine-tuningu i wersji API, glowny wzorzec odpowiada strukturze Messages API.
Kazda linia zawiera konwersacje z promptem systemowym i naprzemiennymi wiadomosciami uzytkownika/asystenta. Model uczy sie generowac odpowiedzi asystenta na podstawie kontekstu konwersacji.
{"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."}]}
W przypadku wieloturowych danych treningowych nalezy uwzglednic pelna konwersacje z naprzemiennymi wiadomosciami uzytkownika i asystenta. Model uczy sie przeplywu konwersacji i sposobu utrzymywania kontekstu miedzy turami.
{"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."}]}
Zbiory danych HuggingFace z JSONL
Biblioteka datasets HuggingFace natywnie obsluguje JSONL jako format wejsciowy. Mozesz ladowac lokalne pliki JSONL, strumieniowac zdalne zbiory danych i latwo konwertowac miedzy formatami. JSONL jest zalecanym formatem do udostepniania zbiorow danych na HuggingFace Hub.
Uzyj biblioteki datasets do ladowania plikow JSONL do obiektu Dataset. Zapewnia to wydajny dostep z mapowaniem pamieci, wbudowany podzial train/test oraz bezproblemowa integracje z 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
Konwertuj dowolny zbior danych HuggingFace do formatu JSONL do uzycia z innymi potokami treningowymi. Metoda to_json zapisuje kazdy przyklad jako osobna linie JSON.
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')
Walidacja i czyszczenie danych
Jakosc danych treningowych bezposrednio wplywa na wydajnosc modelu. Nieprawidlowy JSON, brakujace pola, zbyt dlugie przyklady i duplikaty moga pogorszyc wyniki fine-tuningu. Zawsze waliduj i czyscij pliki JSONL przed rozpoczeciem przebiegu treningowego.
Ten skrypt waliduje kazda linie pliku JSONL pod katem typowych problemow: nieprawidlowy JSON, brakujace wymagane pola, pusta tresc i dlugosc tokenow. Uruchom go przed przeslaniem, aby wczesnie wykryc problemy.
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}')
Zduplikowane przyklady treningowe marnuja moc obliczeniowa i moga spowodowac przechylenie modelu w kierunku nadmiernie reprezentowanych wzorcow. Ten skrypt usuwa dokladne duplikaty na podstawie hasha zawartosci kazdej linii.
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')
Przygotowanie danych na duza skale
Produkcyjne zbiory danych treningowych czesto zawieraja setki tysiecy lub miliony przykladow. Na tej skali potrzebujesz zautomatyzowanych potokow do losowego mieszania, podzialu i fragmentacji danych JSONL. Prawidlowe przygotowanie zapobiega problemom treningowym, takim jak katastrofalne zapominanie, i zapewnia powtarzalnosc eksperymentow.
Ten skrypt losowo miesza dane i dzieli je na zbiory treningowe i testowe. Mieszanie jest krytyczne, poniewaz pliki JSONL sa czesto generowane w okreslonym porzadku, a trening na uporzadkowanych danych moze prowadzic do slabej generalizacji.
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)
Gdy zbiory danych sa zbyt duze dla jednego pliku lub musisz rozlozyc trening na wiele GPU, podziel plik JSONL na mniejsze fragmenty. Kazdy fragment moze byc przetwarzany niezaleznie.
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)
Waliduj swoje dane treningowe online
Uzyj naszych darmowych narzedzi przegladarkowych do walidacji, formatowania i konwersji danych treningowych JSONL przed przeslaniem do OpenAI, Anthropic lub HuggingFace.