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

Обычные подборки, жанровые фильтры и списки “что посмотреть вечером” помогают только до определённого момента.
Они работают как витрина, но плохо работают как персональная рекомендация, потому что почти не учитывают зрительский опыт, индивидуальные предпочтения и то, какие фильмы человек вообще уже видел.

Именно с этой задачи я и подошёл к своему проекту NextFilm: не как к каталогу фильмов, а как к рекомендательной системе.
Основной вопрос звучал так: как выдать полезную рекомендацию новому пользователю, если на старте о нём почти ничего не известно.

По сути, в моём контексте это и есть cold start.
Не абстрактная проблема “мало данных”, а вполне прикладная ситуация: пользователь уже хочет получить рекомендацию, а система пока не знает, что он смотрел, насколько у него большая зрительская база и какие паттерны вкуса у него вообще есть.

Почему жанров недостаточно

Наивный способ рекомендовать фильмы — опираться на жанры, популярность и общие рейтинги.
Но жанр — слишком грубый признак.

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

То же самое происходит с универсальными подборками.
Они могут давать неплохой средний результат, но почти не решают задачу персонализации, особенно если пользователь уже много смотрел и плохо реагирует на слишком очевидные рекомендации.

Из этого для меня следовал простой вывод:
если рекомендательная система хочет быть полезной, она должна сначала понять не только “что нравится”, но и какой у пользователя зрительский опыт.

Этап 1. Сбор стартовых сигналов

Первый этап в моём пайплайне — не выдача рекомендаций, а сбор стартового профиля.
На этом шаге для меня важнее всего понять, какие фильмы пользователь уже видел и как он к ним относится.

Это критично по двум причинам.

Во-первых, нужно отделить “фильм не нравится” от “пользователь его просто не смотрел”.
Если этого не сделать, модель начинает делать ложные выводы на пустом месте.

Во-вторых, у пользователей очень разная база просмотра.
Один человек знает в основном самые популярные фильмы последних лет, другой — классику и авторское кино, третий вообще редкий зритель и узнаёт только самые громкие названия.

Если все эти сценарии одинаково обработать на старте, модель быстро начинает шуметь.
Поэтому первый полезный шаг — собрать набор уже просмотренных фильмов и получить по ним первичные оценки.

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

Этап 2. Построение вектора вкуса

Когда стартовых оценок становится достаточно, можно переходить от “карты просмотренного” к более содержательной модели предпочтений.

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

Именно здесь оценки начинают превращаться во внутренний вектор предпочтений.
Идея не в том, чтобы сказать “пользователь любит драму”, а в том, чтобы описать, какой тип фильма для него обычно оказывается релевантным.

Такой подход лучше работает на практике, чем грубая жанровая сегментация.
Он позволяет объяснить, почему два фильма из одного жанра могут оказаться очень далеко друг от друга с точки зрения конкретного зрителя.

На этом этапе рекомендательная модель уже может делать первые осмысленные выводы.
Но опираться только на локальные оценки одного пользователя всё ещё рискованно: данных мало, а случайные совпадения могут слишком сильно влиять на выдачу.

Этап 3. Коллективный сигнал

Чтобы не замыкаться только на локальном профиле, я добавляю внешний слой коллективных оценок.
Для этого я использую MovieLens 25M от GroupLens — открытый датасет, в котором собрано 25 млн оценок по более чем 62 тысячам фильмов.

Здесь для меня важна не абстрактная “математика поверх математики”, а вполне прикладная логика.
Если пользователю понравился определённый набор фильмов, можно посмотреть, какие ещё фильмы систематически нравятся людям с похожими паттернами.

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

На практике это уже похоже на гибридную схему:
часть сигнала идёт от внутреннего профиля пользователя, часть — от collaborative filtering по похожим оценочным паттернам.

Этап 4. Дообучение на новых сигналах

Важный момент: такая модель не должна оставаться статичной.
Если после первого онбординга зафиксировать профиль навсегда, качество рекомендаций быстро упрётся в потолок.

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

Это особенно важно в кино.
Вкусы не только различаются между людьми, но и меняются со временем: пользователь может уставать от одних типов фильмов и начинать лучше реагировать на другие.

Поэтому для меня рекомендательная система — это не “один раз посчитанная формула”, а постоянно уточняемая модель.
Каждая новая оценка должна не просто сохраняться, а менять дальнейшую траекторию выдачи.

Этап 5. Зачем здесь GPT

Даже если предыдущие этапы уже дают неплохой пул кандидатов, остаётся ещё одна проблема: как превратить технически релевантную выдачу в результат, который человеку удобно воспринимать.

Базовая модель может подобрать формально хорошие варианты, но список всё равно может выглядеть странно.
Например, быть плохо упорядоченным, недостаточно объяснимым или слишком “машинным” по подаче.

Поэтому GPT в моём пайплайне не заменяет рекомендательную модель.
Он стоит поверх неё как финальный слой интерпретации и re-ranking.

Сначала система собирает кандидатов на основе пользовательских оценок, вектора вкуса и коллективных сигналов.
Затем LLM помогает более осмысленно отсортировать кандидатов, сгруппировать выдачу и сделать результат понятнее для пользователя.

Для меня здесь принципиально важно не подменять модель LLM-магией.
GPT хорош в интерпретации, объяснении и финальной подаче, но базовая релевантность всё равно должна рождаться раньше — на уровне данных, сигналов и ранжирования.

Что получается в итоге

Если упростить пайплайн, он выглядит так:

  1. Собрать стартовые оценки и понять, что пользователь уже видел.

  2. Построить начальный профиль предпочтений.

  3. Превратить набор оценок в более устойчивый вектор вкуса.

  4. Сопоставить сильные сигналы с коллективными паттернами из MovieLens 25M.

  5. Отранжировать кандидатов.

  6. Поверх этого применить GPT как слой интерпретации и финальной сборки выдачи.

С инженерной точки зрения для меня это попытка уменьшить долю случайных рекомендаций.
Не советовать “что-то популярное”, а пройти от слабых сигналов к более устойчивой модели пользователя.

Где у подхода ограничения

Понятно, что такая схема не решает всё автоматически.

Во‑первых, cold start остаётся самым чувствительным этапом: чтобы получить приличное качество рекомендаций, системе приходится просить пользователя сделать достаточно заметный первый шаг — поставить оценки ряду фильмов. И если пользователь не готов тратить на это время, система получает слишком мало сигнала и начинает работать хуже.

Во-вторых, в рекомендательных системах всегда есть риск переобучиться на популярных фильмах.
Чем сильнее в данных выражены массовые паттерны, тем выше шанс, что модель будет чаще возвращаться к очевидным вариантам.

В-третьих, LLM-слой тоже нельзя переоценивать.
Он помогает сделать выдачу понятнее, но не исправляет фундаментальные ошибки, если базовый ранжирующий слой собран слабо.

То есть главный интерес для меня сейчас не в “идеальной модели”, а в качестве пайплайна целиком: какие сигналы собирать на старте, как уменьшать шум, как дообучать систему и где правильно ставить границу между классическим рекомендателем и LLM.

Почему мне это интересно

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

Поэтому мне и интересно строить систему именно как рекомендательный пайплайн:
с cold start, пользовательским профилем, коллективным сигналом, дообучением и финальным слоем интерпретации.

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

Если у вас есть опыт построения рекомендательных систем — особенно в части cold start, гибридных моделей или интеграции LLM в пайплайн, — буду рад любым замечаниям и альтернативным подходам в комментариях.

Сервис, о котором шла речь в статье: NextFilm

Комментарии (6)


  1. Kot_na_klaviature
    28.04.2026 20:53

    Сервис спрашивает в основном про шедевры, которые выбрал, как "обожаю". Интересно как он из этого будет делать выводы. Но выводы сделал - опять выдал в предложке шедевры, которые уже видел. Один, который не видел, но его смотреть не хочется - что-то проходное и неинтересное. В общем, смысл зачем мне это надо не уловил. Выглядит, как рандом. Если захочется пересмотреть что-то из шедевров можно для начала открыть ТОП250 Кинопоиска или IMDB. Там же по оценке можно фильтровать по жанрам / режиссерам / темам.
    ПС На карточках не хватает ссылок на тот же Кинопоиск, чтобы не нужно было гуглить (а мне пришлось).


    1. Pegiy Автор
      28.04.2026 20:53

      Спасибо, что так подробно расписали впечатления — это очень помогает понять, где сервис сейчас не дотягивает. Про “одни шедевры” и ощущение рандома. На старте моя задача — за минимум оценок получить максимум сигналов, поэтому в онбординге я сознательно опираюсь на самые известные фильмы: вероятность, что вы их видели и сможете честно отметить “обожаю / нормально / не моё”, сильно выше, чем у нишевых картин. Для людей с большой насмотренностью это действительно может ощущаться как “ещё один ТОП‑250”, и ваш комментарий хорошо подсвечивает, что дальше алгоритм должен агрессивнее скрывать уже просмотренное и сильнее смещаться к новому, а не просто пересобирать классику. Про ссылки на Кинопоиск и другие площадки. Идея правда лежит на поверхности — открыть карточку, сразу перейти смотреть, а не гуглить. Но у КиноПоиска, Иви и крупных онлайн‑кинотеатров нет простого официального API с полным каталогом, который можно просто подключить и получить гарантированно корректные ссылки, поэтому это не одна кнопка в интерфейсе, а полноценная интеграционная задача: навести мостики между каталогами, аккуратно матчить фильмы и следить, чтобы ничего не ломалось при изменениях на их стороне. Эта история уже в бэклоге, до неё нужно просто добраться после базовых вещей с рекомендациями.


      1. Kot_na_klaviature
        28.04.2026 20:53

        Многие могут не помнить названий и гуглить каждую карточку не будут. Как минимум постеры нужны. И нужно не по одному предлагать, а выдать 100 фильмов - постеров сразу на странице, чтобы пользователь отметил какие ему нравятся и какие категорически не нравятся (10 фильмов хотя бы пускай отметит). А в предложке выдать относительные новинки (выпуск до 3-5 лет) ну и парочку из старых шедевров для красоты, с кнопкой "ещё", которая выдаст ещё фильмов если пользователю не подойдут предыдущие. Так гораздо больше шансов предложить, что пользователь ещё не видел. Нужно, чтобы это быстро было и полезно, тогда есть хоть какой-то смысл.


        1. Pegiy Автор
          28.04.2026 20:53

          Постеры уже есть, но видимо не всегда подгружаются, планирую загрузить их на сервер. Для быстрой оценки тоже уже есть дополнительна ветка "Оценить", где процесс оценки проходит быстрее. Рассмотрю, чтобы сделать онбординг аналогично. Про быстро, что только в этом смысл, не соглашусь. Оценку нужно пройти только один раз, занимает это максимум 10 митнут, дальше для повторных рекомендаций уже проходить не надо. Но нужно зарегистрироваться, чтобы не потерять настройки профиля


  1. morginalium8
    28.04.2026 20:53

    Зашел на сайт, потыкал, посмотрел. Все просто супер! Есть мелкие проблемы в UI, но сейчас не про это. Хотелось бы вставить свои 3 копейки про алгоритм рекомендаций.

    1. Ручные фичи на втором этапе. Для базовой проверки подойдет, но мне кажется лучше реализовать это через линейные слои с расширением (а может и через depthwise-свертку). Можно подавать на вход фильмы, а на выходе получать готовый вектор пользователя.

    2. На третьем этапе какая-то несогласованность. Вроде как идея началась с того, что система вообще не будет подсматривать в у других людей, а будет работать индивидуально. А тут ты берешь и вместе в предпочтениями пользователя наваливаешь чужих данных.

    3. Дообучение online штука классная, но дорогая. Это надо оптимизировать: либо хранить модель на компе пользователя и там-же дообучать, или использовать свои мощности (что долго и дорого).

    Кстати, было бы еще классно исходники на гите увидеть )


    1. Pegiy Автор
      28.04.2026 20:53

      Спасибо, что дошли до сайта и потыкали живой прототип — это очень помогает.

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

      2. Согласен, в статье формулировка местами звучит так, будто я вообще не хочу смотреть на других пользователей. Скорее идея такая: на самом старте не опираться только на чужие паттерны, потому что данных по человеку мало (из 50 фильмов в онбординге хорошо, если он реально видел 20, а заставить на входе оценить хотя бы сто фильмов - это утопия). Поэтому локальный профиль задаёт направление вкуса, а MovieLens‑слой использую как priors: он расширяет пространство кандидатов, но не подменяет собой профиль конкретного пользователя.

      3. Согласен, полноценный online‑training в проде был бы тяжёлым. У меня сейчас речь скорее про лёгкие обновления (пересчёт весов/структур по новым оценкам), а не про backprop на каждом клике. Формулировку в статье, видимо, стоит сделать точнее, чтобы не выглядело как “мы постоянно доучиваем большую модель в онлайне”.

      Исходники — тоже в планах; как только приведу код в приемлемый вид, хочу выложить хотя бы MVP‑версию пайплайна на гит и уже от неё отталкиваться.