Подготовка датасетов: Форматирование данных для дообучения

45 минут Урок 21

Подготовка датасетов: Фундамент успешного файн-тюнинга

Добро пожаловать в пятый модуль. Если вы добрались сюда, значит, вы уже переросли уровень обычного промпт-инжиниринга и готовы стать архитектором собственных ИИ-решений. Сегодня мы говорим о скучной, но абсолютно критической части работы — о данных.

В мире машинного обучения есть старая поговорка: «Garbage In, Garbage Out» (Мусор на входе — мусор на выходе). Для файн-тюнинга Gemini это не просто поговорка, это закон физики. Вы можете выбрать самую мощную модель (Gemini 1.5 Pro или Ultra), арендовать самые дорогие вычислительные мощности, но если ваш датасет собран «на коленке» и плохо отформатирован, модель просто выучит ваши ошибки.

Цель урока

Мы не просто научимся конвертировать CSV в JSONL. Мы разберем, как структурировать мышление модели через данные. Мы перейдем от хаотичных логов чатов к хирургически точному обучающему набору.

Анатомия формата JSONL для Gemini

В отличие от обычного JSON, где весь файл — это один большой массив объектов, Gemini требует формат JSONL (JSON Lines). Это текстовый файл, где каждая строка — это отдельный, валидный JSON-объект. Это позволяет обрабатывать огромные датасеты потоково, не загружая всё в память.

Каждая строка вашего файла обучения должна представлять собой один пример взаимодействия. Для чат-моделей Gemini стандартная структура выглядит так:

  • messages: Массив сообщений, составляющих диалог.
  • role: Роль участника ('user' или 'model').
  • parts: Содержимое сообщения (текст).

Важно понимать: файн-тюнинг — это не про загрузку энциклопедии в мозг модели (для этого есть RAG и длинный контекст). Файн-тюнинг — это про обучение стилю, формату и логике рассуждений.

json
// Пример одной строки файла dataset.jsonl (разбито на строки для читаемости, в файле это одна строка)
{
  "messages": [
    {
      "role": "system",
      "content": "Ты — помощник технической поддержки, отвечающий кратко и в стиле JSON."
    },
    {
      "role": "user",
      "content": "У меня ошибка 500 на сервере."
    },
    {
      "role": "model",
      "content": "{\"error_type\": \"server\", \"code\": 500, \"action\": \"check_logs\"}"
    }
  ]
}

Стратегия формирования данных: «Золотой стандарт»

Многие новички совершают ошибку, пытаясь взять количеством. «У меня есть 50,000 логов чатов с клиентами, загружу их все!». Остановитесь. Это худшее, что можно сделать.

Реальные логи содержат:

  • Опечатки и грубость операторов.
  • Неверные ответы, которые потом исправляли.
  • Бесконечные «Здравствуйте, подождите минутку».

Если вы скормите это модели, вы получите ИИ, который говорит «подождите минутку» и хамит. Для эффективного дообучения Gemini часто достаточно 100–500 идеальных примеров, чем 10,000 средних. Это называется Curated Dataset (Курированный датасет).

Ключевые принципы подготовки:

  1. Разнообразие (Diversity): Если все примеры выглядят одинаково, модель переобучится (overfit) и не сможет обобщать. Включайте разные формулировки вопросов.
  2. Чистота (Sanitization): Удаляйте PII (персональные данные), служебные теги HTML, лишние пробелы.
  3. Цепочка рассуждений (CoT): Если вы учите модель решать задачи, в ответе model должен быть не просто ответ, а ход решения.

python
# Пример Python-скрипта для подготовки «грязных» данных из CSV в чистый JSONL для Gemini
import csv
import json

# Входной файл: question,answer
input_file = 'raw_support_logs.csv'
output_file = 'training_data.jsonl'

system_prompt = "Ты вежливый помощник банка. Отвечай только на вопросы о тарифах."

def clean_text(text):
    # Простая очистка: удаление лишних пробелов
    return " ".join(text.split())

with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'w', encoding='utf-8') as f_out:
    reader = csv.DictReader(f_in)
    
    for row in reader:
        question = clean_text(row['question'])
        answer = clean_text(row['answer'])
        
        # Фильтруем слишком короткие или пустые диалоги
        if len(question) < 5 or len(answer) < 5:
            continue
            
        # Формируем структуру для Gemini
        data_object = {
            "messages": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": question},
                {"role": "model", "content": answer}
            ]
        }
        
        # Записываем как одну строку JSON
        f_out.write(json.dumps(data_object, ensure_ascii=False) + '\n')

print(f"Готово! Данные сохранены в {output_file}")

Многоходовые диалоги (Multi-turn Chat)

Самые мощные модели создаются не на парах «Вопрос-Ответ», а на полноценных диалогах. Gemini обладает отличным контекстным окном, и вы должны использовать это.

Если вы хотите, чтобы ваш бот умел уточнять детали перед ответом, в вашем датасете должны быть примеры, где:

  1. Пользователь дает неполную информацию.
  2. Модель (в роли model) задает уточняющий вопрос.
  3. Пользователь (в роли user) дополняет информацию.
  4. Модель дает финальный ответ.

Без таких примеров модель будет пытаться «угадать» ответ сразу, галлюцинируя недостающие факты.

json
// Пример многоходового диалога (Multi-turn)
{
  "messages": [
    {"role": "user", "content": "Забронируй мне столик."}, 
    {"role": "model", "content": "С удовольствием! На какой день и на сколько человек вы планируете визит?"},
    {"role": "user", "content": "На эту пятницу, нас будет четверо."}, 
    {"role": "model", "content": "Отлично. Какое время вам подойдет лучше всего?"}
  ]
}

Валидация и разделение данных

Прежде чем отправлять данные на обучение, вы обязаны их проверить. Ошибка валидации на стороне API может стоить вам времени и денег, если обучение упадет на середине из-за одной битой строки JSON.

Checklist перед отправкой:

  • Валидный ли JSON в каждой строке?
  • Соблюдается ли чередование ролей (user -> model -> user -> model)?
  • Нет ли пустых сообщений (empty strings)?
  • Не превышен ли лимит токенов на один пример (обычно 32k или больше, но лучше держать примеры компактными)?

Train / Validation Split: Всегда отделяйте 10-20% данных в файл валидации. Gemini будет использовать этот файл для оценки метрик (Loss) в процессе обучения, но не будет учиться на нем. Это единственный способ понять, начала ли модель действительно понимать задачу или просто зазубрила тренировочные примеры.

Упражнение

Вам дан «грязный» лог диалога из CRM системы. Ваша задача — вручную преобразовать его в валидный JSON-объект для формата JSONL Gemini. <br><br>Исходные данные:<br>Operator: Здравствуйте, чем могу помочь?<br>Client: У меня не работает интернет.<br>Operator: Перезагрузите роутер.<br>Client: Помогло, спасибо.<br><br>Требования:<br>1. Исключите приветствие оператора (начинаем с проблемы клиента).<br>2. Добавьте системный промпт: 'Ты технический помощник'.<br>3. Используйте правильные роли ('user', 'model').

Вопрос

Почему при подготовке датасета для Gemini 3 лучше использовать 500 идеально выверенных примеров, чем 50,000 сырых логов из чата поддержки?