Как Яндекс Браузер извлекает контент веб-страниц для пересказа? Часть I

Представьте, что вам нужно быстро проанализировать текст с десятка веб-страниц. На помощь придет функция краткого пересказа в Яндекс Браузере. Здесь — и не только здесь — работает суммаризация текста. Но возникает вопрос: что попадает в качестве входных данных в LLM, занимающуюся суммаризацией? На него в двух постах ответит Михаил Катунькин, старший ML-разработчик в Яндекс Браузере. В первой части речь пойдёт об общей идее и реализации, а во второй — об обучении модели.

Общая идея

Самое очевидное решение — взять HTML-код страницы. Его проблема в том, что верстка содержит в себе много лишней текстовой информации, которая «засорит» и сильно увеличит контекст модели: теги, скрипты, стили. Всё это приведёт к ухудшению качества пересказа, большему времени работы модели и удорожанию инференса.

Значит, следующий шаг — извлечь только текстовую информацию. Это улучшит ситуацию, но в контекст модели по-прежнему будет проникать много лишнего: реклама, меню, комментарии. А из-за того, что модель потеряет информацию о структуре страницы, в пересказ начнёт попадать, например, содержание статей из блока рекомендаций похожего контента.

Можно использовать разные эвристики, чтобы извлекать не весь текст страницы, а только полезный. Такой подход, например, используется в режиме чтения в браузере Однако из-за разнообразия верстки сайтов эта техника не является универсальной, нуждается в переподборе эвристик с течением времени, даёт плохое качество извлечения текста на определённых доменах.

Мы решили извлекать основной контент страницы при помощи ML-модели. А затем использовать информацию из HTML-кода для задания структуры текста: заголовков, подзаголовков, ссылок, выделений.

Важный нюанс: пересказ должен работать быстро даже при медленном интернете. Передавать тяжелые HTML-страницы целиком на серверы Яндекса было бы плохим решением. Поэтому модель следовало сделать легковесной, чтобы она работала непосредственно на устройстве пользователей.

Реализация

HTML представляет собой дерево тегов. Блоки с текстом на странице — это листья в дереве. Будем для каждого листа принимать решение: брать его или нет в конечный текст. В качестве бинарного классификатора возьмем Catboost.

Классификация осуществляется на основе множества статистик, посчитанных при обходе дерева: по тегам, атрибутам тегов, текстам. Существенное улучшение качества даёт следующий трюк: блоки с текстом классифицируется не независимо, а группами с одинаковым путём из тегов и атрибутов от блока до корня. При этом для хорошего качества извлечения текста модели достаточно информации о структуре разметки и базовых статистик по текстам.

Использование семантических вектор-признаков, посчитанных по текстам, заметного улучшения качества суммаризации не даёт. Поэтому в продакшен-версии от них решили отказаться ради скорости работы модели.

Было важно оптимизировать код подсчёта признаков для модели, из-за того, что деревья тегов могут содержать сотни тысяч узлов. В итоговой версии код реализовали на C++. Он работает 40 мс на одно извлечение в 90 перцентили. Для сравнения, код на JS с эвристиками из режима чтения в Mozilla работает 1,125 с в 90 перцентили. Для достижения этого результата, в частности, мы оптимизировали динамические выделения памяти, а также удалили из набора признаков сложные в вычислении, но не столь значимые.

Из HTML-дерева с проклассифицироваными листьями уже можно получить очищенный текст в формате markdown. Для этого по дереву идёт обход в глубину, собирающий текст из листьев, прошедших порог классификации, и учитывающий наличие тегов с заголовками, ссылками, выделениями и прочим.

ML Underhood