Fine-tuning и веса · Fine-tuning and weights · урок 3 · 13 мин

Данные для SFT: форматы, chat template, чистка

SFT data: formats, chat templates, cleaning

ТемыFine-tuningНаборы данных

Зачем

После урока ты соберёшь набор данных для SFT в правильном формате, поймёшь, что делает chat template и почему из-за него модель «не умеет остановиться», и опишешь чистку данных до обучения. На собеседовании это вопрос «walk me through the data pipeline», а на работе — та часть проекта, которая съедает больше всего времени и решает качество.

Набор данных — главный актив

SFT (supervised fine-tuning, обучение на парах «запрос → эталонный ответ») учит модель подражать примерам, включая их ошибки. Если в наборе половина ответов неудачна, модель выучит и неудачи. Авторы LIMA получили сильную модель всего на 1 000 тщательно отобранных пар. Отсюда правило: 500 ответов, написанных или вычитанных лучшими операторами, ценнее 50 000 сырых журналов чата. Для стиля и формата обычно хватает сотен – низких тысяч хороших пар. Adapter (обученную добавку) можно переобучить за час, а потерянные или грязные данные быстро не восстановишь, поэтому версионируют в первую очередь данные.

Форматы, которые понимает TRL

Библиотека TRL (Hugging Face, post-training; документация v1.15.0, открыта 10.10.2026) принимает четыре вида примеров: - language modeling, сырой текст: {"text": "..."} — для continued pretraining; - conversational: {"messages": [{"role": "user", ...}, {"role": "assistant", ...}]} — диалог с ролями; - prompt-completion: {"prompt": "...", "completion": "..."}; - conversational prompt-completion: те же поля, но в каждом список сообщений.

Для tool calling (вызова инструментов) в сообщениях есть tool_calls и роль tool, а в отдельной колонке tools лежат JSON-схемы доступных функций. Файл обычно JSONL: один пример на строку. Пример строки для ассистента банка:

{"messages": [
 {"role": "system", "content": "Ты ассистент банка. Сначала ответ, потом условия."},
 {"role": "user", "content": "Сколько стоит перевод на карту другого банка?"},
 {"role": "assistant", "content": "Сейчас проверю действующий тариф.", "tool_calls": [{"type": "function", "function": {"name": "get_fee", "arguments": {"product": "card_transfer_external"}}}]}
]}

Обрати внимание: в эталоне нет цифры тарифа, есть вызов tool. Иначе модель выучит сегодняшнюю комиссию как часть стиля и будет называть её через год.

Chat template: как роли превращаются в tokens

Модель не видит ролей, она видит последовательность tokens (кусочков текста). Chat template (шаблон диалога) превращает список сообщений в строку со служебными special tokens (зарезервированными tokens разметки). У Qwen это формат ChatML: каждая реплика начинается с <|im_start|>user или <|im_start|>assistant и заканчивается <|im_end|>. У других семейств свои маркеры. Документация Transformers предупреждает: с чужими маркерами модели работают «drastically worse».

Четыре правила, на которых ломаются новички: 1. Один шаблон в обучении и в inference (работе модели на запросах). Сервер вроде vLLM применяет шаблон из tokenizer модели; если ты учил на другом, поведение поплывёт. 2. При подготовке обучающих данных add_generation_prompt=False: маркер «теперь отвечает ассистент» нужен только при генерации. 3. Не дублировать special tokens. Если ты сделал apply_chat_template(..., tokenize=False), а потом сам переводишь строку в tokens, ставь add_special_tokens=False, иначе в начале окажутся два служебных tokens. 4. EOS-token (token конца последовательности) должен совпадать с концом реплики в шаблоне. Если модель учили, что реплика кончается <|im_end|>, а trainer считает концом другой token, модель не научится останавливаться и будет писать бесконечно. Документация TRL прямо пишет: для базовой Qwen/Qwen2.5-1.5B задать eos_token="<|im_end|>".

Loss только на ответе

Loss (ошибка, которую минимизирует обучение) в SFT — token-level cross-entropy: насколько модель «удивлена» каждым следующим token эталона. Считать её нужно на ответе ассистента, а не на вопросе пользователя и не на system prompt: иначе модель учится сочинять вопросы клиентов и заучивает повторяющийся system prompt. В TRL для prompt-completion так и сделано по умолчанию (completion_only_loss). Для диалогов нужно assistant_only_loss=True; это требует в шаблоне маркеров {% generation %}, и для известных семейств вроде Qwen3 TRL дописывает их сам. Гайд Unsloth отмечает, что обучение только на ответах может поднять точность на несколько процентных пунктов, особенно в многоходовых диалогах.

Чистка до обучения

Разбиение, разметка и синтетика

Три части: train, validation (для выбора момента остановки) и test, который открывают один раз. Test — это новые обращения, пришедшие после сбора train, разбитые по клиенту или теме, а не по случайным строкам: иначе почти одинаковые диалоги одного клиента попадут и туда, и туда, и ты измеришь память вместо обобщения. Разметке нужны письменные правила с пограничными случаями и два разметчика на общей части; их согласие меряют Cohen's κ (каппа Коэна, согласие с поправкой на случайность). Синтетика от сильной модели быстра, но однообразна, содержит непроверенные ошибки и предубеждения модели-учителя, а лицензия учителя может ограничивать такое использование. Человек проверяет выборку, а test собирают только из реальных данных.

Схема

Термины · Key terms

SFT (supervised fine-tuning)
обучение на парах «запрос → эталонный ответ»
chat template
шаблон, превращающий сообщения с ролями в строку tokens
special tokens
служебные tokens разметки диалога, например <|im_end|>
EOS token
token конца последовательности, по которому модель останавливается
assistant-only loss
ошибка считается только на ответах ассистента
JSONL
файл, где каждая строка — отдельный JSON-пример
dedup
удаление точных и почти точных дублей
PII redaction
замена персональных данных метками до обучения
held-out test
запечатанный набор новых примеров для итоговой оценки
Cohen's kappa
согласие двух разметчиков с поправкой на случайность

Сделай сам

Напиши в заметке две строки JSONL в формате messages для ассистента банка с правилом «сначала ответ, потом условия». В первой — обычный ответ без цифр. Во второй — вопрос про комиссию, где ассистент вызывает tool вместо того, чтобы назвать сумму. Под строками перечисли три проверки, которые ты запустишь по всему набору до обучения.

Обсуди с тьютором: покажи свои строки и спроси, на какой из них модель скорее выучит что-то нежелательное и почему; попроси тьютора найти в твоих примерах скрытую PII или изменчивый факт.

Проверь себя · ответ под вопросом

1Почему после SFT модель может не останавливаться и писать бесконечно?
Скорее всего, EOS-token в настройках обучения не совпал с концом реплики в chat template. Модель не видела в примерах того token, на котором её потом останавливают. Лечится явным eos_token, например <|im_end|> для Qwen, и одним шаблоном в обучении и inference.
2Зачем считать loss только на ответе ассистента?
Иначе модель учится генерировать вопросы пользователей и заучивает повторяющийся system prompt. Цель SFT — научить отвечать, поэтому градиент должен идти от tokens ответа. В TRL это completion_only_loss для prompt-completion и assistant_only_loss=True для диалогов.
3Почему test нельзя делить случайными строками из того же журнала?
Почти одинаковые диалоги одного клиента попадут и в train, и в test, и оценка покажет память, а не обобщение. Test собирают из новых обращений после сбора train и делят по клиенту или теме. Так оценка ближе к тому, что будет в production.

Interview questions · US / UK

1We want to fine-tune on 18 months of chat transcripts. Walk me through the data pipeline.
Strong answer: Keep only reviewed, uncorrected, well-rated replies; replace volatile facts like fees with tool calls; redact PII before training with consistent placeholders and measure recall on our own names; dedup and normalise like production; split by customer and time with the latest months sealed as test.
2After fine-tuning, the model never stops generating. What went wrong?
Strong answer: EOS token not aligned with the chat template's end-of-turn token; different templates in training and serving; duplicated special tokens; fix with an explicit eos_token, one template end to end, and a check of the tokenized training examples.
3Security asks how you guarantee the model won't repeat a customer's account number. What do you say?
Strong answer: Models memorise, even text seen once, and larger models more so; redact before training and measure redaction recall on our data; probe after training with canary strings and prefix completions; the real guarantee is an output filter in code, not the weights.

Ключевые фразы · Say it aloud

Материалы