Как мы запустили сервис вопросов и ответов, получили много хейта, а потом внедрили ML и ускорили процессы в разы
Привет, меня зовут Мария Стефова, и я продакт-менеджер образовательной среды в Нетологии. Сегодня расскажу вам, как мы разрушили барьер между студентом и экспертом и создали сервис для получения живой обратной связи во время выполнения домашнего задания. Сейчас мы получаем в месяц от 2 500 до 4 500 вопросов от студентов, а средний показатель отвеченных вопросов — 95–98%.
Хотя в начале запуска сервиса вопросов и ответов всё было не так радужно: мы словили много хейта от экспертов, и чтобы добиться феноменальных результатов, нам пришлось сильно постараться и отстроить все бизнес-процессы. Немалую роль сыграло и внедрение ML (англ. Machine Learning). Именно оно помогло автоматизировать ответы на львиную долю рутинных вопросов и повысить скорость их обработки. В статье я поделюсь с вами историей о том, как мы размечали данные, искали баланс между порогом вероятности и охватом вопросов, обучали и дообучали модель, а также расскажу об итогах нашей работы.
Мария Стефова
Продакт-менеджер образовательной среды и мотивации студента в Нетологии
В работе со студентами мы в Нетологии каждый день сталкиваемся с ситуацией, когда кому-то что-то непонятно. Иногда это связано с организацией процесса, иногда — с образовательной составляющей. Обратная связь играет ключевую роль в обучении и влияет на результаты. Очень важно вовремя давать студенту ответ на его вопрос.
Обратная связь особенно ценна, когда речь заходит про дистанционный формат. Из-за ограниченного взаимодействие студента с наставником и недостатка живого общения начинают копиться вопросы. В какой-то момент из-за отсутствия информации у студента может сформироваться неправильное восприятие или полное непонимание материала. В результате чего человек не получает ясности в вопросе и не достигает главной цели обучения.
Поэтому мы решили запустить вспомогательный сервис, чтобы студенты могли задавать вопросы и получать живые ответы прямо на платформе во время выполнения домашнего задания.
Почему мы вообще создали сервис вопросов и ответов
Нашей отправной точкой стала задача повысить эффективность домашних заданий. У меня возникла идея добавить к интерфейсу домашних заданий возможность задать вопрос и быстро получить ответ. Ранее вопрос можно было задать только в личных сообщениях координатору. Мы предположили, что решение этой проблемы повысит эффективность обучения. Главной метрикой проекта стала сдаваемость работ, потому что изначально мы решали именно эту задачу.
Во время внутреннего исследования мы увидели такую картину: студент прослушивает лекцию, переходит к домашнему заданию, и иногда на этом этапе у него возникают блоки. В случае, если ученик не понимает, что или как ему надо делать, выполнить домашнее задание он не может. Ему нужна возможность задать вопрос до отправки работы на проверку либо посмотреть чужие вопросы.
Наша гипотеза оправдалась. В результате реализации сервиса мы значительно повысили процент сдаваемости работ. Если до первого ответа он составлял 39,89%, то после первого ответа стал 45,71%. Но это было только начало нашего пути.
С какими сложностями мы столкнулись при реализации сервиса
После внедрения сервиса вопросов и ответов у нас начали копиться вопросы. Студенты стали так активно задавать их, что отвечать на них мы не успевали. Всё это могло привести к тому, что инструментом просто перестали бы пользоваться из-за неудовлетворённости.
Мы так погрузились в решение проблемы студентов, что совсем упустили выстраивание процесса с преподавателями. Это вызвало негативную реакцию, и они просто отказались отвечать на вопросы.
Мы не протестировали интерфейс с преподавателями, поэтому для них он был неудобен и непонятен, а также вызывал много вопросов. Это стало причиной негатива со стороны экспертов.
Промежуточный результат нашей работы над сервисом получился не очень счастливый. Изначально мы предполагали, что координаторы, которые решают организационные вопросы, и эксперты, которые занимаются образовательными задачами, будут самостоятельно разбирать открытую ленту вопросов. Но это не сработало, потому что мы не продумали, как вовлечь их в работу нового инструментария.
Поэтому мы проделали необходимую работу с координаторами и экспертами: со всеми договорились, поставили совместные цели, выстроили процессы по частоте проверки ленты вопросов, проработали возражения. Благодаря этим действиям, замотивировали координаторов передавать вопросы эксперту в личку. С экспертов собрали обратную связь по доработке интерфейса и настройке сортировки. Наша задача состояла в том, чтобы не перегружать эксперта чужими вопросами.
Обработка накопившихся за несколько месяцев более 2 000 вопросов заняла целый квартал. Постепенно нам удалось увеличить скорость ответа до 1 дня.
Изначально мы показывали вопросы всем экспертам курса. Но в ответ на неотстроенные процессы получили недопонимание. Не все эксперты соглашались отвечать на вопросы не по своей теме. Причины были разные: не хотели мешать экспертам из других блоков, не хватало времени.
У нас была гипотеза, что эксперты на одном задании хорошо должны ориентироваться во всех вопросах темы курса в целом. Но это оказалось не так. Поэтому сейчас мы показываем вопросы только тем, кто проверяет конкретные задания.
Первоначальная нагрузка была большая, вопросов было много. Некоторые из них повторялись. Процесс надо было как-то оптимизировать и автоматизировать, чтобы не отнимать много времени у координаторов и преподавателей. Чтобы снять нагрузку при ответах на однотипные вопросы, нужно было обучить сервис давать ответы. Это должно было ускорить весь процесс.
Почему решили внедрить ML
Перед нами стояла задача увеличить скорость реакции на вопросы студентов. На тот момент средняя скорость первого ответа могла доходить до 10,5 часов. Конечно, это не соответствовало ожиданиям студентов. А их ожидания были примерно такие: «Если вопрос лёгкий, готов ждать два-три часа. Если посложнее — желательно в течение рабочего дня».
Установить экспертам SLA (Service Level Agreement, договор внутри компании о том, на каком уровне мы оказываем ту или иную услугу) — отвечать в течение какого-то определённого времени — мы не могли. У нас уже были чаты в Telegram и Discord, где они откликались на вопросы, поэтому новый сервис давал им дополнительную нагрузку.
Когда мы стали внедрять сервис вопросов и ответов, то поняли, что студенты часто задают одни и те же вопросы, их много и большинство из них связаны с организационными моментами. Нужно было разработать стандартизированные ответы, чтобы разгрузить координаторов и преподавателей.
Гипотеза была такая: если мы добавим ML и она будет автоматически обрабатывать часть входящих запросов, то объём вопросов, на которые надо отвечать людям, будет меньше. За счёт этого эксперты смогут быстрее отвечать, а сама нагрузка на них снизится.
Хотели начать с простого — с организационных вопросов. Их легче смоделировать, потому что они общие для всех в Нетологии. А вопросов по домашнему заданию в разы больше, и они уникальны — не просто для каждого курса, но и для каждого отдельного занятия. Именно поэтому мы начали обкатку ML с организационных вопросов. Дальше будем развивать сервис и постепенно добавлять ответы, которые студенты задают по домашнему заданию.
В целом получилось так, что ML стала ответственной за определённую часть вопросов и сняла нагрузку с координаторов.
Как мы внедряли ML и размечали данные
Изначально мы планировали составить список вопросов самостоятельно при поддержке клиентского сервиса, поскольку они работают со студентами и знают, о чём чаще всего спрашивают. Для этого наш Data Scientist предложил собрать базу частых вопросов и проанализировать самые популярные. Далее стали дополнять этот список.
В первую очередь мы опирались на список вопросов, которые составили координаторы, и по нему искали соответствие. Здесь было много ручной работы. Мы анализировали, как модель соотнесла вопрос студента с тем, что у нас было в списке. Много раз видели, что это новый вопрос и его тоже надо внести в список, потому что он часто встречается.
Чтобы обучить модель, сначала мы собирали по 5–10 примеров на каждый вопрос. Всего у нас было 20 организационных вопросов. Важно было собрать реальные примеры — не просто абстрактные формулировки, а такие фразы, какими пишут люди. К этой задаче подключились координаторы. На всё у нас ушло около двух недель. Это был первый этап обучения модели.
Для отдела машинного обучения мы подготовили датасет по 10 примеров на класс. Всего было 25 классов + 1 техническая тема «Частные вопросы». Инженеры обучили на таком датасете модель на предсказание одной из общих тем, с её помощью оценили все вопросы из базы данных. После этого вывели топ-100 примеров по вероятности на каждый класс и на каждый общий вопрос, затем отдали всё на разметку. Разметчику необходимо было всего лишь ставить цифры «1» или «0» возле оценённого моделью вопроса — соответствует ли данный вопрос от студента классу, который предсказала наша модель, или нет. Затем инженеры снова обучили модель на датасете с учётом доразметки и оценили с её помощью все вопросы из базы данных. Так проделали несколько раз.
Модели классификации в машинном обучении не умеют работать с текстами, а умеют работать с числами. Чтобы скормить тексты модели, нужно сначала перевести их в числа. Процесс, который каждому тексту (в нашем случае — вопросу от студента) сопоставляет набор чисел, называется векторизацией — получением векторов или эмбеддингов.
Уже долгое время с 2018 года моделью, которая позволяет получить наилучшие смысловые эмбеддинги из текста, является большая языковая модель на основе архитектуры трансформер (энкодер) — BERT. Она преобразует в числа не весь текст, а токены или отдельные его части. Мы использовали модель BERT, чтобы векторизовать токены из текстов, сопоставив каждому токену 768 чисел, а затем усреднили эти векторы внутри каждого текста (вопроса от студента), чтобы получить эмбеддинги для целых текстов.
Владимир Силкин
Data Scientist отдела машинного обучения в Нетологии
Каждому тексту мы сопоставили 768 чисел, которые являются «признаками». На этих «признаках» мы обучали нашу модель — OVR-логистическую регрессию. OVR (One vs Rest) означает, что была обучена отдельная логистическая регрессия на каждый класс (в нашем случае — каждую тему), а потом это всё было завёрнуто в единую модель. Когда мы обучаем ML-модель на каждый класс, текущий класс помечаем цифрой 1, а все остальные классы (Rest) помечаем цифрой 0. При дефолтном параметре регуляризации мы фиксировали переобучение. В результате усилили регуляризацию (C=1.0 --> C=0.1), чтобы не дать модели переучиваться. Регуляризация не даёт весам модели расти слишком сильно.
Далее разработчики выгрузили тысячи вопросов студентов, которые нужно было проверить в ручном режиме, чтобы понять, правильно ли модель обучилась и корректно ли разметила все вопросы. На основе такой ручной разметки можно было переобучать модель каждый раз. Сама по себе эта задача занимала минимум полторы недели, а всего итераций проверок в ручном режиме было четыре. Вся процедура обучения модели у нас заняла около квартала.
Владимир Силкин
Data Scientist отдела машинного обучения в Нетологии
Код обучения модели мы написали на Python с использованием модуля Scikit-learn. В Kubernetes развернули приложение-сервер, написанное на модуле для Python — Flask. Kubernetes позволяет заново поднимать приложение в случае падения из-за ошибок. Сервер принимает на вход put-запрос с вопросом от студента, а отдаёт номер класса «Общего вопроса» или «Частного вопроса», соответствующий максимальной предсказанной вероятности среди всех классов.
Мы разработали модель и написали API, в который кто угодно может отправлять тексты и получать номер темы. Когда студент пишет вопрос на сайте, вопрос должен автоматически быть отправлен в наш API, а студенту должен быть предоставлен ответ на его вопрос, если наша модель предсказала одну из общих тем.
@app.route('/questions', methods=['PUT'])
def process_questions():
"""
Функция представления для ручки questions.
:input: json с полями id, text
:return: json с полями id, class_probabilities
"""
# 1. Получаем содержимое запроса.
post_data = request.get_json()
# 2. Проверяем, что содержимое запроса ОК
# -- Если нет ключей id и text, то возвращаем ошибку:
...
# -- Если post_data['text'] не int, то возвращаем ошибку:
...
# -- Если post_data['text'] не str, то возвращаем ошибку:
...
# 3. Если запрос ОК, то составляем ответ:
response = {
'id': post_data['id'],
'class_probabilities': netology_questions_model.apply_model(
text=post_data['text'],
bert_model=get_bert(),
tokenizer=get_tokenizer(),
models=get_models_questions()
)}
return json.dumps(response)
Основная сложность была в том, что есть некий порог вероятности. Вот есть ответ от ML, и вероятность, что она угадала, например, 0,7. Чем выше этот порог, тем точнее и скорее она угадала правильно. Но чем выше порог, тем меньше вопросов она охватывает. Надо было искать баланс между порогом вероятности и охватом вопросов.
Когда мы выкатили модель с очень жёстким порогом, охват был не очень большой. То есть она отвечала на очень малое количество вопросов. Но отвечала очень чётко и без ошибок. Сейчас мы этот порог понизили. Модель стала больше ошибаться, но и на большее количество вопросов отвечать. Ещё её дообучили, показатели улучшились, а жалоб от студентов не поступало.
Также мы проводили дополнительные UX-тесты, когда внедряли сервис в интерфейс. Тестировали его на наших студентах. Среди кейсов был такой: «Если вам неправильно ответила машина». Студенты реагировали на это абсолютно спокойно. У них не было никакой негативной реакции.
И, кстати, наша модель — не GPT. В нашей ML есть жёстко заданный ответ, чёткий, который мы согласовали на всех уровнях, чтобы всех устраивало.
Что нам дало внедрение ML в сервис вопросов и ответов
Первоначальная цель сервиса вопросов и ответов была в том, чтобы студенты активнее делали и сдавали домашнее задание. Именно по ним приходило 90% всех вопросов. Работу сервиса мы оценивали по нескольким прокси-метрикам:
количество вопросов;
используемость сервиса;
скорость ответа.
Базовые показатели эффективности складывались на основе количества вопросов и ответов. В начале проекта мы не думали о том, что это будет формат форума, где студенты смогут отвечать друг другу. Потому что тогда на этапе появления реакции одного студента на вопрос другого возникает недопонимание — это ответ по существу вопроса или констатация, что у него такой же вопрос. По нашей статистике порядка 20% студентов отвечают на вопросы по существу.
Мы сейчас идём к тому, чтобы вообще запретить координаторам общаться в личке со студентами. Если они хотят задать вопрос лично, то должны делать это через тикет-систему. То есть это личная переписка, но на платформе. Сейчас мы предлагаем и студентам, и координаторам, и преподавателям общаться именно на платформе. Потому что это удобно, помогает повышать качество и скорость ответов. Все переписки должны быть либо в общем чате, либо через платформу.
В интервью со студентами мы много слышим о том, что они, прежде чем делать задание, смотрят вопросы, которые задали предыдущие студенты — это помогает им выполнить своё задание. Студенты продолжают переписку, не задавая новый вопрос, а продолжают старый. Получился своего рода форум: то есть на стороне студента в грануле задания есть подраздел, где он может задать вопрос. Этот вопрос будут видеть все другие студенты. В зависимости от того, к какому заданию задан вопрос, он отправляется в нужную группу.
На стороне админки есть раздел, в котором все эти вопросы видят координаторы. Вопрос доступен эксперту в его кабинете на платформе.
Как это выглядит: студент пишет вопрос, он отображается в ленте у тех координаторов и экспертов, которые прикреплены к этому курсу или заданию. То есть это видит не вся Нетология, а конкретные люди, которые ответственны за это направление.
Мы решили, что координатор должен видеть все вопросы, потому что он отвечает в целом за то, чтобы студент получил ответ и был доволен коммуникацией. Эксперты видят вопросы в случаях, если студент выбирает тему «Домашнее задание». То есть студент может выбрать тему «Организационный вопрос» или «Домашнее задание».
Получается, что сам студент помогает нам понять, кому этот вопрос релевантнее показать. В грануле задания всегда указано, кому доступна проверка заданий по этому блоку. Этим же самым людям, мы и показываем вопросы.
Возвращаясь к нашей цели — скорость ответа. Вопросы поступают мгновенно, секунды две максимум. Студенты видят, что это ML, так как у ответа нет никакой аватарки пользователя.
Мы предусмотрели, что у нас есть несколько вариаций того, что может сделать студент, когда он увидел ответ:
задать вопрос всё равно;
отметить: «Вопрос решён»;
ничего не делать и покинуть страницу.
Если студент не отправляет вопрос повторно, мы считаем его успешно отвеченным. Сейчас у нас таких вопросов почти 98%. Почти все вопросы, которые модель закрывает, она закрывает нормально. Для нас это подтверждение довольства студентов. Нам достаточно того, что студент не задаёт вопрос повторно.
На данный момент база неотвеченных вопросов пуста, а эксперты регулярно помогают студентам с решением домашек. Мы продолжаем работать над скоростью ответов: внедрили уведомления о новых вопросах, работаем над ML–моделью для замены части ответов автоматическими.
Другие студенты тоже активно включаются в помощь друг другу: они отвечают на 10% вопросов. Лента вопросов и ответов открытая. Это даёт возможность тем, кто уже разобрался с проблемой, помочь другим и проявить экспертность. Это классно работает на мотивацию учиться, помогает образовывать новые социальные связи.
Главный вывод, который мы сделали, внедрив сервис вопросов и ответов, — нужно разделить организационные и учебные вопросы.
Сейчас мы можем взять нашу модель и интегрировать её в уже существующую тикет-систему, чтобы она играла на полную. Это поможет закрывать тикеты быстрее. Также хотим расшириться и сделать такую же функцию для вебинаров.
Продолжаем развивать саму модель. Добавили функцию её дообучения на ответах от студентов, которыми они были удовлетворены. Будем дообучать модель c учётом автоматической доразметки, когда ответов наберётся достаточно много.
Ближайшие курсы по аналитике: