Рекомендательные системы для видео: как устроены

Автор: Николай СапуновОбновлено: август 202621 мин чтения
Содержание статьи +

TL;DR

Рекомендательная система для видео отвечает на два разных вопроса – что зритель в принципе может посмотреть в каталоге, который слишком велик, чтобы оценивать по одному тайтлу, и что показать первым – и почти каждый реальный рекомендер делится на эти два этапа: candidate generation (генерация кандидатов) и ranking (ранжирование). Что считать релевантным, система решает одним из трёх способов: по тому, что смотрели похожие зрители (collaborative filtering), по тому, из чего состоит сам тайтл (content-based filtering, работающий на метаданных), или комбинируя их (гибрид) – и каждый способ по-своему ведёт себя с новым зрителем или совсем новым тайтлом, это и есть проблема холодного старта (cold start). Эта статья объясняет, как устроена эта механика на уровне продукта, опираясь на публичные инженерные отчёты YouTube, Netflix и Amazon, чтобы вы могли спроектировать, укомплектовать и измерить рекомендер, не обучая модели самостоятельно. Главное проектное решение инженеры YouTube формулируют прямо: ранжируйте по ожидаемому watch time, а не по кликам, потому что система, настроенная на клики, учится продвигать тайтлы, на которые нажимают и тут же бросают.

Почему это важно

Если вы запускаете стриминговый сервис или строите его, рекомендации – это движок, который превращает оплаченный каталог в реально просмотренные часы: на большом каталоге Netflix сообщает, что рекомендер даёт около 80% часов просмотра (Gomez-Uribe & Hunt, 2015). Сами модели вы обучать не будете – это вы наймёте или купите. Но именно вы решаете, что система оптимизирует, какие данные ей нужны, как она ведёт себя в день первый, когда о зрителе ничего не известно, и как вы будете доказывать, что изменение помогло. Эта статья – про продуктовую обвязку: про те части, которые основатель, продакт-менеджер или первый стриминговый CTO обязаны понимать, чтобы принимать эти решения и говорить с инженерами и вендорами, делающими остальное. Математику внутри моделей мы выносим в внутренности рекомендательных моделей в разделе AI for Video Engineering, а не выводим здесь.

«Потому что вы смотрели» – это два вопроса, а не один

Начнём с ряда, который есть в каждом стриминговом приложении: Потому что вы смотрели [что-то], вот десять тайтлов. Выглядит как одно решение. На самом деле их два, и разделение этих двух – ключ ко всему остальному.

Первый вопрос: что этот зритель в принципе может посмотреть? В каталоге могут быть десятки тысяч тайтлов. Аккуратно оценить каждый для каждого зрителя при каждой загрузке главного экрана невозможно – на это нет времени в тех нескольких сотнях миллисекунд, что у вас есть до отрисовки экрана. Поэтому первый этап забрасывает широкую дешёвую сеть и вытягивает несколько сотен тайтлов, которые вероятно релевантны. Этот этап называется candidate generation (генерация кандидатов, иногда «retrieval»).

Второй вопрос: из этих нескольких сотен – что показать первым и в каком порядке? Теперь чисел достаточно мало, чтобы потратить на каждое настоящие усилия, оценив его более богатой моделью и куда большим объёмом деталей о зрителе и тайтле. Этот этап называется ranking (ранжирование).

Это разделение на два этапа – не причуда одной компании; по словам инженеров YouTube, опубликовавших свою архитектуру, это «классическая двухэтапная дихотомия информационного поиска» (Covington, Adams & Sargin, Deep Neural Networks for YouTube Recommendations, ACM RecSys 2016). Представьте это как наём. Вы не проводите трёхчасовое собеседование с каждым кандидатом. Вы быстро просматриваете тысячи резюме, чтобы получить шорт-лист из пары десятков (candidate generation), а потом подробно собеседуете этот шорт-лист (ranking). Просмотр быстрый и приблизительный; собеседование медленное и точное. Рекомендер работает так же и по той же причине: дорогой шаг нельзя позволить себе на всём пуле.

Рисунок 1. Воронка рекомендаций. Candidate generation забрасывает широкую дешёвую сеть по всему каталогу (миллионы → сотни); ranking оценивает этот шорт-лист вглубь и упорядочивает те несколько десятков, что зритель действительно видит (сотни → десятки). Именно это разделение позволяет рекомендеру оставаться быстрым на большом каталоге.

Почему разделение важно вам как владельцу продукта, а не только инженеру? Потому что оно показывает, где живут две ваши самые трудные проблемы. Покрытие – чтобы хорошие, но неочевидные тайтлы вообще получали шанс всплыть – это проблема candidate generation. Качество – чтобы первые три ряда были действительно лучшим из шорт-листа – это проблема ranking. Когда кто-то жалуется «рекомендации затёртые», он обычно имеет в виду, что candidate generation слишком узкий. Когда жалуется «рекомендации очевидные» – что ranking играет слишком безопасно. Другой этап – другое лечение.

Три способа, которыми система решает, что «релевантно»

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

Первая стратегия – collaborative filtering (коллаборативная фильтрация): решать, что рекомендовать, по поведению множества зрителей, а не по чему-либо в самом тайтле. На простом языке это «те, кто смотрел то же, что и вы, ещё смотрели вот это». Классический производственный пример – Amazon, чьи инженеры описали подход под названием item-to-item collaborative filtering: вместо поиска похожих на вас зрителей (что дорого и нестабильно) он заранее вычисляет для каждого тайтла те, что чаще всего смотрят те же люди, и рекомендует от уже просмотренного вами (Linden, Smith & York, Amazon.com Recommendations: Item-to-Item Collaborative Filtering, IEEE Internet Computing, 2003). Его сила в том, что о содержании знать ничего не нужно – он работает чисто на паттерне «кто-что-смотрел» и потому находит связь, которую не придумал бы ни один разметчик. Его слабость – он беспомощен с тайтлом, который пока никто не смотрел.

Вторая стратегия – content-based filtering (контентная фильтрация): рекомендовать тайтлы, похожие на уже понравившиеся, по атрибутам самих тайтлов – жанр, актёры, режиссёр, язык, тон, тема. На простом языке это «похоже на то, что вы смотрели». Топливо для этого подхода – метаданные: структурированное описание каждого тайтла. Контентная система может рекомендовать совсем новый тайтл сразу после добавления, потому что видит: новый триллер делит режиссёра и жанр с тремя триллерами, которые вы досмотрели. Слабость – зеркальное отражение силы коллаборативной фильтрации: она склонна рекомендовать то же самое и редко удивляет, и она ровно настолько хороша, насколько хороши метаданные за ней – поэтому чистый пайплайн метаданных и есть неприметное ядро discovery.

Третья стратегия – гибрид, то есть просто использование обеих, потому что каждая проваливается ровно там, где другая сильна. Коллаборативная фильтрация слепа к новым тайтлам; контентная их видит. Контентная повторяется; коллаборативная находит неожиданное. Почти каждый серьёзный стриминговый рекомендер – гибрид, и современное направление – свернуть оба типа сигнала в одно обученное представление: отчёт Netflix 2025 года об их унифицированном рекомендере описывает объединение выученных поведенческих паттернов с контентными метаданными в одной foundation-модели, чтобы одна и та же система хорошо справлялась и с известными, и с новыми тайтлами (Netflix Technology Blog, Foundation Model for Personalized Recommendation, 2025).

Рисунок 2. Три стратегии релевантности с одного взгляда. Collaborative filtering работает на поведении и находит неожиданное, но не видит новый тайтл; content-based работает на метаданных и тянет новые, но повторяет; гибрид смешивает оба. Нижняя строка – «тянет новый тайтл?» – это вопрос cold start, который определяет большинство продуктовых решений.

В таблице ниже добавлен режим отказа каждого подхода – то, за чем следить, – чтобы вы могли это обойти.

ПодходИдея простыми словамиГлавный входСюрприз?Новый тайтл?За чем следить
Collaborative filtering«Те, кто смотрел как вы, смотрели это»Поведение всех зрителейДа – находит связиНет – нужна историяCold start; перекос в популярное
Content-based filtering«Похоже на то, что вы смотрели»Метаданные тайтла (жанр, актёры, тема)Редко – повторДа – судит по атрибутамПузырь; не лучше метаданных
Гибрид (большинство систем)Оба, закрывают слепые зоны друг другаПоведение + метаданныеДа, под контролемДа – контент тянет новыеБольше частей собирать и настраивать

Таблица 1. Три способа, которыми рекомендер решает, что релевантно, с режимом отказа каждого. Столбец «Новый тайтл?» – может ли подход рекомендовать тайтл, который никто ещё не смотрел – больше всего определяет реальный продукт, потому что это и есть замаскированная проблема холодного старта.

Математика, превращающая «кто-что-смотрел» в рекомендацию – матричная факторизация, эмбеддинги, нейросетевые модели ранжирования – относится к слою машинного обучения, и мы намеренно оставляем её статье про внутренности рекомендательных моделей в AI for Video Engineering. Продуктовый вывод стоит и без математики: настраивайте сбор данных под гибрид, потому что в итоге понадобится именно гибрид.

Проблема холодного старта: день, когда система не знает ничего

У каждого рекомендера есть неловкий первый день. Это и есть проблема холодного старта (cold start): система не может дать хорошие рекомендации, когда у неё нет истории, на которой учиться. Она проявляется в трёх разных формах, и у них разные решения, поэтому их стоит называть по отдельности.

Холодный старт нового зрителя ощущается острее всего. Подписчик регистрируется, главный экран загружается, а система ни разу не видела, что он смотрел. Коллаборативной фильтрации не с чем работать – она живёт на поведении, а его нет. Обычные решения практичны, а не хитры: задать пару вопросов о вкусах при регистрации (шаг онбординга «выберите три шоу, которые вам нравятся»), опереться на то, что сейчас широко популярно, как на безопасный дефолт, и использовать тот контекст, что есть – страну, язык, устройство, время суток – чтобы не показать ребёнку лишнего. Как только зритель посмотрит хотя бы два-три тайтла, поведение появляется, и система быстро прогревается.

Холодный старт нового тайтла тише, но дороже, потому что прямо тратит контент, за лицензию которого вы заплатили. У тайтла, который никто не смотрел, нет паттерна со-просмотров, поэтому коллаборативная фильтрация его не всплывёт, и он может лежать в каталоге невидимым. Именно здесь зарабатывает своё место контентная фильтрация: судя о тайтле по метаданным, она может рекомендовать новый триллер любителям триллеров в день первый. Инженеры YouTube решали смежную проблему «свежего контента» отдельным сигналом, который назвали «example age», чтобы модель активно предпочитала недавно загруженные видео, а не сползала к затёртому бэк-каталогу (Covington et al., 2016). Продуктовый урок прямой: без контентного сигнала и чистых метаданных ваши новейшие, активнее всего продвигаемые тайтлы – те, что рекомендер показывает хуже всего.

Холодный старт новой платформы недооценивают основатели. В день запуска у вас нет ни истории зрителей, ни данных со-просмотров вообще для чего-либо. Чистой коллаборативной системе не на чем стоять. Поэтому новый сервис сначала опирается на контентные рекомендации и редакторскую кураторскую подборку, и только смещает вес к коллаборативной фильтрации по мере накопления данных просмотра за первые недели и месяцы. Планируйте это явно: рекомендер, с которым вы запускаетесь, – не тот, что вы будете крутить через год.

Рисунок 3. Три лица холодного старта и что реально лечит каждое. Нового зрителя греют онбордингом, популярностью и контекстом; новый тайтл тянут контентные метаданные; новая платформа опирается на редактуру и content-based, пока не накопится поведение. Коллаборативная фильтрация слабее всего в каждом холодном случае – поэтому в каждой реальной системе держат контентный запасной вариант.

Паттерн, который даёт масштаб: candidate generation, затем ranking

Теперь соберём воронку и стратегии вместе, потому что именно эту архитектуру вы будете задавать. Причина, по которой двухэтапное разделение вообще существует, – жёсткое ограничение, которое чувствуется в арифметике, так что давайте проговорим её вслух.

Допустим, в каталоге 50 000 тайтлов, а главный экран должен отрисоваться примерно за 200 миллисекунд, чтобы казаться мгновенным. Представьте, что хорошая модель ranking тратит 1 миллисекунду на оценку одного тайтла для одного зрителя со всеми нужными признаками. Оценить весь каталог заняло бы 50 000 × 1 мс = 50 000 мс, то есть 50 секунд. Это не медленный главный экран; это сломанный – в 250 раз сверх бюджета. Даже распараллеленная по серверам, дорогая поштучная цена на всём каталоге для каждого зрителя при каждой загрузке экономически и физически недостижима. (У YouTube корпус в миллионы, а бюджет задержки – «десятки миллисекунд», то же самое на несколько порядков труднее; Covington et al., 2016.)

Поэтому работу делят. Candidate generation использует дешёвую операцию – не аккуратную поштучную оценку, а быстрый поиск – чтобы вытянуть, скажем, 500 самых правдоподобных тайтлов из 50 000. Современный способ сделать этот поиск быстрым – превратить каждого зрителя и каждый тайтл в список чисел («эмбеддинг»), устроенный так, что похожие вещи лежат рядом, а затем спросить у специального индекса ближайшие к этому зрителю тайтлы. Этот поиск ближайших соседей работает заметно меньше миллисекунды независимо от размера каталога, потому что индекс не проверяет каждый тайтл по одному. YouTube описывает ровно это: на этапе выдачи оценка «сводится к поиску ближайшего соседа в пространстве скалярного произведения» (Covington et al., 2016), и тот же паттерн «two-tower плюс ближайшие соседи» теперь стандартная практика крупномасштабного retrieval (Google Cloud, Implement two-tower retrieval for large-scale candidate generation, 2024).

Затем ranking делает дорогую работу только над этими 500. По 1 мс на каждый это 500 мс – всё ещё сверх бюджета, так что на практике шорт-лист – несколько сотен, а ранкер подстроен под бюджет, но суть в том, что математика теперь в диапазоне, который можно довести до ваших 200 мс. Дорогая модель видит только шорт-лист, никогда – весь каталог. В этом весь фокус, и поэтому «candidate generation, затем ranking» встречается практически в каждом производственном видео-рекомендере, от статьи YouTube 2016 года до foundation-модели Netflix 2025-го, которая всё ещё производит эмбеддинги, используемые «для candidate generation», питающего нижестоящий ranking (Netflix Technology Blog, 2025).

Ещё одно практическое следствие: поскольку candidate generation может смешивать несколько источников, вы можете слить персональный коллаборативный retriever, контентный retriever (для новых тайтлов) и редакторский список (для того, что хотите продвинуть) в один шорт-лист, а ranking пусть разбирается. В статье YouTube отмечается, что дизайн «позволяет смешивать кандидатов, сгенерированных другими источниками» (Covington et al., 2016). Так гибрид и устроен в продакшене: не одна умная модель, а несколько retriever'ов, питающих один ранкер.

Что ранкер должен оптимизировать: watch time, а не клики

Вот самое важное решение во всей системе, и это продуктовое решение, а не техническое: что для ранкера значит «хорошо»? Что вы прикажете максимизировать, то он и будет максимизировать – в том числе так, как вы не задумывали.

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

Инженеры, которые держат крупнейший в мире видео-рекомендер, говорят это прямо, и это стоит процитировать, потому что это закрывает спор. На этапе ranking цель YouTube «обычно простая функция ожидаемого watch time на показ. Ранжирование по click-through rate часто продвигает обманные видео, которые пользователь не досматривает ("clickbait"), тогда как watch time лучше отражает вовлечённость» (Covington et al., 2016). Они идут дальше и отказываются даже обучаться только на кликах: положительные примеры взвешиваются по тому, сколько видео реально смотрели, так что тайтл, на который нажали и бросили, почти ничего не весит.

Это в точности совпадает с тезисом якорной статьи блока – что discovery нужно мерить по watch time и возврату, а не по кликам – и с тем, как Netflix описывает настройку рекомендера на удержание подписчика, а не на тапы (Gomez-Uribe & Hunt, 2015). Практическая инструкция вашей команде коротка: определите успех как вовлечённость, предсказывающую возврат зрителя – watch time, досмотренные сессии, возврат на следующей неделе – и заставьте ранкер оптимизировать именно это, пусть это и труднее измерить и медленнее двигать, чем клики. Затем доказывайте каждое изменение против этой цели настоящим экспериментом – это тема статьи про A/B-тестирование и эксперименты.

Рекомендер – это продуктовая система, а не модель

Рекомендательную систему легко представить как «модель». В продакшене это в основном всё вокруг модели: входящие события, питающие её метаданные и судящие её эксперименты. Увидеть весь цикл – вот что позволяет реалистично планировать бюджет и команду.

Цикл начинается с событий: каждый запуск, пауза, досмотр, поиск и пропуск логируется как сигнал того, что зритель реально сделал. Эти неявные сигналы – что люди смотрят – куда обильнее и честнее явных, вроде лайка, поэтому YouTube обучается на просмотрах, а не на оценках (Covington et al., 2016). Эти события текут в пайплайн данных персонализации, который чистит их, соединяет с метаданными тайтлов и складывает результат туда, где модели могут им пользоваться. Модели – candidate generation и ranking – производят ряды, которые затем складываются в персональный главный экран из рядов и обложек, который видит зритель. Зритель реагирует, порождая новые события, и цикл замыкается. Рекомендер становится лучше не потому, что модель переобучают в вакууме, а потому что цикл продолжает крутиться.

Две границы этого цикла важны владельцу продукта. Первая: цикл работает на данных просмотра, а они чувствительны; что можно собирать и возвращать в систему, ограничено правилами приватности, и пайплайн должен уважать эту границу согласия – приватность данных просмотра это проектный вход, а не довесок. Вторая: цикл настолько надёжен, насколько надёжно ваше измерение: идеальная рекомендация, спрятанная за медленно грузящимся плеером, всё равно теряет зрителя, поэтому метрики качества опыта – startup time и rebuffering нужно смотреть рядом с метриками рекомендаций, иначе каждую будут винить в провале другой.

Рисунок 4. Рекомендер как цикл, а не модель. События (просмотры, досмотры) питают пайплайн данных и хранилище метаданных; те питают candidate generation и ranking; получившиеся ряды дают watch time и новые события. Метаданные – топливо, пайплайн – обвязка, эксперименты – судья, а модель – лишь один из многих блоков.

Разобранный пример: прогрев нового подписчика

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

В день первый регистрируется новый подписчик. Поведения для него нет – холодный старт нового зрителя. Онбординг просит выбрать три понравившихся тайтла; он выбирает два триллера и документалку. У candidate generation теперь есть зерно: контентный retriever вытягивает тайтлы, чьи метаданные похожи на эти три, retriever популярного добавляет то, что широко в тренде на этой неделе, и два списка сливаются в шорт-лист из нескольких сотен. Ranking упорядочивает их по доступному скудному контексту – устройство, страна, час вечера – и главный экран отрисовывается меньше чем за 200 мс. Он ещё не персональный, но и не пустой.

К дню третьему он досмотрел два триллера и бросил комедию через пять минут. Эти события прошли через пайплайн. Теперь у коллаборативной фильтрации что-то есть: другие зрители, досмотревшие те же два триллера, ещё досмотрели определённый мини-сериал, который не связало бы ни одно контентное правило. Этот сериал входит в набор кандидатов. Брошенная комедия, взвешенная по почти нулевому watch time, учит ранкер понижать похожие комедии – ровно то взвешивание по watch time, что описывают инженеры YouTube.

К дню седьмому главный экран ощутимо персональный: ряд «Потому что вы смотрели» из реальных досмотров, коллаборативный ряд, всплывающий неожиданный сериал, и контентный ряд, тянущий два недавно добавленных триллера, которые никто ещё не смотрел, но чьи метаданные подходят. Тот же зритель, тот же каталог – но система прогрелась от «популярное-плюс-онбординг» до настоящего гибрида за неделю, потому что цикл продолжал крутиться. Эта дуга, от холодного к тёплому, – то, под что нужно проектировать, и поэтому стартовый рекомендер и зрелый – разные системы.

Частая ошибка: одна гигантская модель, оценивающая весь каталог

Самая дорогая архитектурная ошибка команд – пропустить воронку, построить одну модель, которая пытается оценить каждый тайтл для каждого зрителя при каждой загрузке. Это интуитивно («просто отранжируем весь каталог») и работает в демо с 200 тайтлами. Это рушится в момент роста каталога и аудитории по причине, которую показала арифметика выше: дорогая поштучная оценка не может пройти по всему каталогу в бюджете 200 мс, а счёт за попытку растёт как каталог × зрители × загрузки. Лечение – двухэтапная воронка: дешёвый retrieval для шорт-листа, затем дорогой ranking только по шорт-листу.

Вторая, более тонкая версия ошибки – оптимизировать не то: выкатить рекомендер, настроенный на клики, и праздновать рост тапов, пока watch time и удержание тихо падают. Лечение – дисциплина, на которой настаивают эта статья и её якорь: ранжировать по ожидаемому watch time и возврату, и доказывать каждое изменение экспериментом по удержанию, а не по тапам. Третья версия – пренебречь холодными случаями: запуститься на одной коллаборативной фильтрации, а потом удивляться, почему новые тайтлы не всплывают, а новые подписчики видят дженерик-стену. Лечение – держать контентный retriever и чистые метаданные в системе с первого дня. Пропустите воронку – не отмасштабируется; пропустите watch time – будет вводить в заблуждение; пропустите cold start – ваш новейший контент останется невидимым.

Чем здесь полезен Фора Софт

Рекомендательная система – это в основном обвязка: поток событий из запусков и досмотров, чистый пайплайн метаданных, быстрый индекс candidate generation и шаг ranking, привязанный к watch time, а не к кликам – и бóльшая часть инженерной стоимости в этой обвязке, а не в модели сверху. Фора Софт строит видеостриминговые и OTT/Internet-TV платформы с 2005 года, по 250+ выпущенным проектам для 400+ клиентов, а значит, мы прокладывали пайплайны событий просмотра и хранилища метаданных, питающие discovery, интегрировали сервисы рекомендаций и поиска в реальные приложения на web, mobile и TV и инструментировали метрики watch time и удержания, которые говорят, работает ли всё это. Наш подход – scalability-first и vendor-neutral: мы стартуем от размера вашего каталога, конкуренции за одновременных зрителей и вовлечённости, нужной для удержания подписчиков, а затем строим слой candidate-generation-и-ranking – или интегрируем сервис рекомендаций – который реально требует ваш масштаб, оставляя внутренности модели специализированному слою и владея продуктовой обвязкой вокруг них.

Ключевые выводы

  • Рекомендер отвечает на два вопроса: что вы могли бы смотреть (candidate generation) и что первым (ranking).
  • Двухэтапная воронка существует потому, что оценка всего каталога на зрителя на загрузку не влезает в бюджет задержки.
  • Релевантность даётся тремя путями: collaborative filtering, content-based filtering и гибрид, нужный большинству.
  • У cold start три формы – новый зритель, новый тайтл, новая платформа – у каждой своё решение.
  • Ранжируйте по ожидаемому watch time, а не по кликам; клики учат систему продвигать кликбейт.
  • Рекомендер – это цикл (события, пайплайн, метаданные, модель, эксперимент), а не одна модель.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.