Кеш кандидатов в рекомендательных системах VK: меньше железа при том же качестве выдачи
Команда AI VK рассказала о механизме кеширования кандидатов, который снижает нагрузку на инфраструктуру рекомендаций без потери качества. Подход уже применяется в VK Видео и VK Клипах. Инженеры предлагают переиспользовать часть кандидатов между соседними запросами одного пользователя.
Инженер команды AI VK Николай Анохин опубликовал разбор подхода под названием «кеш кандидатов», который позволяет заметно снизить требования рекомендательной системы к вычислительным ресурсам. Речь идёт о внутренней инфраструктуре рекомендаций, где каждый пользовательский запрос запускает сбор кандидатов и их последующее ранжирование. По словам автора, механизм уже внедрён в продакшене VK Видео и VK Клипов, то есть применяется не в эксперименте, а в реальных сервисах с большим потоком запросов. Публикация появилась на фоне общего интереса к инженерным оптимизациям ИИ-инфраструктуры: отраслевые опросы фиксируют высокий уровень доверия к ИИ-инструментам при сохранении осторожности к их результатам, а значит, решения, не затрагивающие качество выдачи, воспринимаются как наиболее безопасный путь развития.
Проблема, которую решает кеш, связана с архитектурой ранжирования. Модель считает скор для каждого кандидата по отдельности, поэтому стоимость этапа растёт линейно вместе с числом объектов на входе. Сто лишних кандидатов в одном запросе означают сто дополнительных проходов модели, умноженных на весь поток обращений сервиса. При этом в итоговую выдачу попадают единицы, а остальные кандидаты нужны лишь для того, чтобы модель могла выбрать из них лучших. Отсюда и возникает естественный вопрос: можно ли сократить число кандидатов на входе в ранжирование так, чтобы качество рекомендаций не пострадало. Именно эта зависимость — линейный рост стоимости ранжирования от числа кандидатов — и делает задачу настолько чувствительной для крупных сервисов: чем больше каталог и чем активнее аудитория, тем выше нагрузка на CPU и latency.
Гипотеза команды опирается на наблюдаемую стабильность интересов пользователя между соседними запросами. Человек не успевает полностью поменять предпочтения между двумя открытиями ленты, поэтому большая часть сильных кандидатов для следующего запроса уже была найдена на предыдущем. Проверка на данных показала, что внутри одного стрима система часто находит почти один и тот же набор кандидатов при последовательных запросах. Каждая точка на графиках соответствовала паре подряд идущих запросов: по оси X откладывалось время между ними в секундах, по оси Y — доля пересечения кандидатов и корреляция Спирмена между списками. На коротком интервале наборы остаются достаточно стабильными, на длинном — устаревают, поскольку появляются новые действия пользователя, свежие сигналы и обновлённые снапшоты. Важно, что графики не разрешают пользоваться одним набором кандидатов сколь угодно долго, а лишь показывают горизонт, на котором переиспользование безопасно.
Архитектурно отбор кандидатов разбит на два уровня. Верхний образуют стримы — независимые модули, каждый из которых отвечает за свой тип контента: основной персонализированный поток, свежие объекты, материалы важных авторов, промо и продуктовые гарантии. Каждый стрим сам собирает и ранжирует кандидатов, а результаты затем объединяются в единую выдачу. Нижний уровень — селекторы, которые ходят в источники данных и приносят списки айтемов. Селекторы делятся на несколько типов: item-to-item ищут похожие объекты по недавним взаимодействиям, source-to-item отбирают материалы авторов, к которым пользователь проявлял интерес, векторные работают через HNSW-индексы по эмбеддингам, неперсонализированные опираются на периодически обновляемый снапшот, а продуктовые отвечают за прогревы, промо и редакционные подборки. Отдельно стоит пояснить, что HNSW — это структура для быстрого приближённого поиска ближайших соседей в векторном пространстве: она строит многослойный граф, по которому можно добраться до похожих объектов за логарифмическое время вместо полного перебора базы. Именно тип селектора определяет стратегию кеширования. Неперсонализированные селекторы на снапшоте подходят для замены кешем лучше всего, поскольку их выдача и так меняется редко. Тяжёлые персонализированные селекторы становятся главной целью оптимизации, так как съедают основную долю вычислений. А обязательные продуктовые селекторы кешировать не стоит вовсе: риск нарушить гарантии показа выше, чем выигрыш на нескольких десятках кандидатов. Базовая схема выглядит так: после обычного запроса из каждого стрима берутся top-k кандидатов с самым высоким скором и записываются в Redis, чтобы на следующем запросе большую часть отбора можно было не повторять. Набор кандидатов собирается компактным и короткоживущим, а не полным и долговременным.
Для российского рынка рекомендательных систем такой подход важен прежде всего экономически. Крупные сервисы — видеоплатформы, маркетплейсы, музыкальные стриминги и новостные ленты — упираются в стоимость вычислений при росте аудитории и каталога. Снижение нагрузки на CPU и latency без деградации качества выдачи напрямую уменьшает затраты на инфраструктуру и позволяет масштабировать персонализацию без пропорционального роста парка серверов. Контекст усиливает актуальность: отраслевые опросы фиксируют высокий уровень доверия к ИИ-инструментам при сохранении осторожности к их результатам, а значит, инженерные оптимизации, не затрагивающие качество, воспринимаются как наиболее безопасный путь развития. В условиях, когда конкуренция за внимание пользователя идёт на уровне качества рекомендаций, возможность удержать это качество при меньших затратах становится заметным преимуществом.
По сравнению с альтернативами кеш кандидатов выглядит компромиссным решением. Можно сокращать число кандидатов на входе в ранжирование за счёт более агрессивной фильтрации, но это прямо влияет на качество. Можно наращивать железо, что увеличивает расходы. Кеширование же не меняет логику отбора, а лишь переиспользует уже найденное на коротком горизонте. Именно поэтому подход уже работает в продакшене VK Видео и VK Клипов, а не остаётся лабораторным экспериментом. Открытыми остаются вопросы настройки: как выбирать размер top-k, время жизни записи в Redis и правила инвалидации при появлении свежего контента. Ответы на них, судя по описанию, команда получает эмпирически, сопоставляя долю пересечения кандидатов с допустимым горизонтом переиспользования. Насколько универсальны эти настройки для других типов контента и сервисов, автор не уточняет — этот вопрос остаётся открытым и, вероятно, станет предметом следующих публикаций команды.