Как вы подготовите датасет для fine-tuning, если у вас только неструктурированные диалоги с клиентами?
Краткий тезис
Подготовка датасета из неструктурированных диалогов — это многоэтапный процесс: от парсинга сырых логов до форматирования в инструкционные пары. Ключевые шаги: очистка от PII, фильтрация шума, балансировка, аугментация для разнообразия и автоматическая оценка качества через LLM-as-a-judge. Цель — получить чистый, сбалансированный датасет в формате, пригодном для fine-tuning (например, ChatML), с контролем утечек и смещений.
1. Понимание задачи: что такое неструктурированные диалоги
Неструктурированные диалоги — это сырые записи общения между оператором поддержки и клиентом, часто в виде текстовых логов без явных меток ролей, с временными метками, опечатками, вставками системных сообщений (например, «Перевод звонка…»). Fine-tuning на таких данных требует преобразования их в инструкционные пары (instruction‑response), чтобы модель научилась отвечать как оператор.
Основные риски: утечка PII (персональные данные), дисбаланс тематик, короткие или неполные диалоги, повторяющиеся паттерны.
2. Парсинг логов: извлечение сообщений и ролей
- Определяем источники: JSON-логи, CSV, текстовые файлы, базы данных CRM.
- Извлекаем каждое сообщение: временная метка, идентификатор оператора/клиента, текст.
- Размечаем роли: оператор →
assistant, клиент →user. Если лог содержит системные сообщения (например, «бота подключили»), их либо удаляем, либо помечаем как system. - Группируем в диалоги: по session_id или временному окну (обычно до 30 мин бездействия — новый диалог).
import pandas as pd
def parse_logs(filepath):
df = pd.read_json(filepath)
df['role'] = df['sender'].apply(lambda x: 'user' if x == 'client' else 'assistant')
dialogs = df.groupby('session_id').apply(lambda g: g[['role', 'message']].to_dict('records'))
return dialogs
Термин session_id — уникальный идентификатор сессии диалога, по которому можно собрать все сообщения одного разговора.
3. Очистка данных: удаление PII, шума и стандартизация
- Удаление PII: имена, номера телефонов, email, адреса. Используем регулярные выражения или библиотеки типа presidio‑analyzer.
- Удаление шума: лишние пробелы, HTML-теги, нечитаемые символы, повторяющиеся фразы («Алло?», «Вы меня слышите?»).
- Стандартизация: приведение к нижнему регистру (кроме имён собственных), исправление распространённых опечаток (словарь замен).
- Маскирование: заменить конкретные имена на
[NAME], номера на[PHONE]— сохраняет структуру, не нарушая приватность.
Пример маскирования:
import re
def mask_pii(text):
text = re.sub(r'\b\d{10,15}\b', '[PHONE]', text) # номера телефонов
text = re.sub(r'\b[A-Za-z0-[[9. Как вы обновляете документы в существующей RAG-системе|9]]._%+-]+@[A-Za-z0-[[9. Как вы обновляете документы в существующей RAG-системе|9]].-]+\.[A-Z|a-z]{[[2 Как вы решаете проблему lost in the middle при работе с длинными контекстами|2]],}\b', '[EMAIL]', text)
return text
4. Форматирование в инструкционные пары
Для fine-tuning необходимо представить диалог как последовательность сообщений с явными ролями. Популярные форматы:
| Формат | Пример |
|---|---|
| ChatML | `< |
| Alpaca | {"instruction": "Ответь как оператор поддержки", "input": "Текст клиента", "output": "Текст оператора"} |
Выбор зависит от модели: Llama fine-tuning чаще использует ChatML, для меньших моделей (GPT‑2) — Alpaca.
Каждый диалог может быть разбит на несколько пар user → assistant (каждая реплика оператора — отдельный пример). Важно сохранять контекст предыдущих реплик (включать в input всю историю до текущего ответа).
5. Фильтрация и балансировка датасета
- Удаление коротких диалогов: диалоги, где суммарная длина сообщений < 10 слов или где ответ оператора < 3 слов — они не несут обучающей информации.
- Балансировка по длине: слишком длинные диалоги (более 2048 токенов) обрезать или разбивать на части.
- Балансировка по тематикам: если 80% диалогов — возврат товара, а 20% — консультация, модель будет плохо отвечать на редкие запросы. Используем стратифицированную выборку или оверсэмплинг меньших классов.
- Удаление дубликатов: одинаковые запросы клиента могут свидетельствовать о ботах или копипастах.
6. Аугментация данных для разнообразия
Даже если у вас много диалогов, они могут быть однотипны. Аугментация помогает модели лучше обобщать:
- Перефразирование через LLM: для каждого запроса клиента сгенерировать 1–3 варианта перефразирования (с помощью GPT‑4 или другой сильной модели), сохраняя ту же реплику оператора.
- Обратный перевод: перевести клиентский запрос на другой язык и обратно (напр., русский → английский → русский) — порождает лексические вариации.
- Синонимическая замена: замена ключевых слов (например, «проблема» → «неполадка») с помощью WordNet или BERT‑маскировки.
Важно аугментация не должна менять intent (намерение) клиента, иначе модель выучит неверные паттерны.
7. Разметка качества и автоматическая оценка
Не все диалоги одинаково полезны. Часть может содержать грубые ошибки оператора или неразрешённые проблемы. Применяем LLM-as-a-judge:
- Отправляем диалог мощной LLM с промптом: «Оцени качество ответа оператора от 1 до 5 по шкале: полезность, полнота, корректность».
- Отбрасываем диалоги с оценкой < 3.
- Можно дополнительно использовать метрики BLEU, ROUGE, BERTScore для сравнения ответов оператора с эталоном (если он есть), но в сырых диалогах эталона нет — только субъективная оценка.
Пример промпта для LLM-as-a-judge:
Система: Ты — эксперт по качеству поддержки. Оцени ответ оператора по шкале 1-5.
Пользователь: {запрос клиента}
Ассистент: {ответ оператора}
Оценка (только число):
8. Токенизация и подготовка к fine-tuning
После очистки данных необходимо преобразовать текст в токены:
- Выбираем токенизатор, соответствующий базовой модели (например, bert‑base‑uncased или tokenizer из transformers для Llama).
- Обрезаем по max_length (обычно 512–2048 токенов).
- Применяем padding до фиксированной длины внутри батча.
- Для instruction‑tuning важно, чтобы токены ответа (assistant) были замаскированы при подсчёте loss — используется маска attention_mask и labels (set labels =
-100для токенов промпта).
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
def tokenize_pair(user_input, assistant_output):
# Формат ChatML
prompt = f"<|im_start|>user\n{user_input}<|im_end|>\n<|im_start|>assistant\n"
full_text = prompt + assistant_output + "<|im_end|>"
tokenized = tokenizer(full_text, truncation=True, max_length=1024, padding="max_length")
return tokenized
9. Проверка на утечки и смещения (bias)
- Разделение train/val/test: по времени (более старые диалоги — train, новые — val/test) или по session_id, чтобы избежать пересечения контекста.
- Стратификация: сохранять пропорции тематик в каждой выборке.
- Проверка на утечки: убедиться, что один и тот же запрос не попал одновременно в train и test (например, через хэширование фраз).
- Детекция смещений (bias): если модель будет учиться на диалогах, где операторы всегда женского пола, это может привести к гендерным стереотипам. Анализировать распределение атрибутов.
Пет-проект для закрепления
Задача Разработать пайплайн подготовки датасета из 10 000 неструктурированных чат-логов (файлы JSON) для fine-tuning небольшой модели (например, TinyLlama-1.1B).
Инструменты Python, pandas, transformers, presidio-analyzer, OpenAI API (для аугментации и оценки), Hugging Face Datasets.
Шаги:
- Загрузить 10 000 JSON-логов (можно синтезировать с помощью GPT).
- Распарсить в диалоги, назначить роли.
- Очистить от PII (регулярки + presidio).
- Отфильтровать короткие (< 5 реплик) и дублирующиеся диалоги.
- Преобразовать в формат ChatML.
- Сбалансировать по темам (определить темы через TF-IDF + KMeans).
- Аугментировать 20% запросов через перефразирование (GPT-4o-mini).
- Оценить качество ответов (LLM-as-a-judge), отбросить нижний квартиль.
- Токенизировать и сохранить в формате Hugging Face Dataset.
- Обучить TinyLlama на полученном датасете, сравнить с baseline (исходная модель) по метрикам ROUGE и BERTScore.
Ожидаемый результат Работающий пайплайн, который из сырых логов создаёт готовый датасет для fine-tuning; обученная модель, дающая осмысленные ответы в стиле поддержки.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 31 | Какие методы fine-tuning существуют (full, LoRA, QLoRA)? |
| 33 | Как выбрать базовую модель под задачу fine-tuning? |
| 34 | Как оценить качество fine-tuned модели? |
| 35 | Data augmentation для fine-tuning: стратегии и риски. |
| 40 | Обработка персональных данных (PII) в обучающих датасетах. |
| 45 | Форматы instruction tuning (ChatML, Alpaca, ShareGPT) – сравнение. |
Навигация
- Предыдущий: 31
- Следующий: 33
- Индекс: 00. Индекс разборов