Как устроена структура обучающего датасета для задачи чат-бота
Что проверяют
Понимаете ли вы, что структура датасета зависит от типа бота: классификатор намерений, поиск по базе знаний или генеративная модель. Следом обычно спрашивают, как вы делите данные на обучение и тест и как убеждаетесь, что модель не видела тест.
Как отвечать
Сначала уточните тип бота, потом опишите структуру под него:
- бот на намерениях: реплики с меткой интента и размеченными сущностями (дата, город, номер заказа). Плюс класс «вне тематики», иначе бот уверенно отнесёт любой вопрос к ближайшему интенту;
- поиск по базе знаний (RAG): пары «запрос, релевантный фрагмент» и трудные негативы, то есть похожие, но неверные фрагменты. На них дообучают эмбеддинги и ранжировщик, на них же считают recall@k;
- генеративный бот, SFT: JSONL, где строка это диалог списком
messagesс ролямиsystem,user,assistant, при необходимости с вызовами инструментов. В токены диалог превращают тем же шаблоном, что и на инференсе (apply_chat_templateв transformers), а лосс обычно считают только по ответам ассистента; - обучение на предпочтениях: для DPO тройки
prompt,chosen,rejected, где из двух ответов на один запрос один помечен лучшим.
Дальше подготовка: удаление точных и почти точных дублей (MinHash), вычистка персональных данных, баланс тем и длины диалогов, отдельный набор реальных запросов для оценки. Несколько тысяч проверенных вручную диалогов обычно полезнее сотен тысяч сгенерированных без контроля.
Где спотыкаются
Делят данные случайно по строкам. Перефразы одного вопроса и реплики одного диалога попадают и в обучение, и в тест, метрики завышены. Делить надо по диалогам, а лучше по пользователям или по времени.
Обучают в одном формате, а запускают в другом: теряют системный промпт или специальные токены шаблона, и модель начинает дописывать реплики за пользователя.
Считают, что синтетика заменит реальные данные. Сгенерированные диалоги закрывают редкие сценарии, но без выборки живых запросов вы не узнаете, о чём пользователи спрашивают на самом деле.