Месяц назад аудит крупного e-commerce выявил классику: алгоритм упрямо советовал к флагманскому ноутбуку мышку за 300 рублей. Конверсия по блоку рекомендаций была феноменальной, а выручка с сессии стремительно падала. Система максимизировала шанс клика, подсовывая дешёвый мусор.
Если ваша рекомендательная система показывает то, что человек только что купил, или забивает драгоценный слот копеечным бестселлером — это не машинное обучение. Это генератор раздражения, который сжигает доверие быстрее, чем падает база. Нормальная рекомендательная система, которая поднимает чек, а не раздражает покупателя, строится на принципиально иной математике.
Рынок до сих пор обожает базовую коллаборативную фильтрацию (ALS, матричная факторизация). Логика проста: юзер Вася купил то же, что юзер Петя, значит, покажем Пете оставшиеся покупки Васи. Это работает, пока матрица взаимодействий не становится разреженной.
Дальше начинаются проблемы. Появляется новая куртка — у неё нет истории продаж, алгоритм её не видит. Приходит новый клиент — алгоритм слеп. Это проблема холодного старта. Но главное — коллаборативка статична. Она не понимает, что человек, который год исправно покупал кошачий корм, сегодня зашёл выбрать в подарок перфоратор.
Рекомендательная система: архитектура, которая поднимает чек
Наш подход в Morana Labs — полный отказ от плоской коллаборативки в пользу гибридной двухэтапной архитектуры с жестким реал-тайм контуром. Мы отделяем генерацию кандидатов от их финального ранжирования.
Схема индустриального рекомендательного движка выглядит так:
- Слой признаков: Redis для контекста текущей сессии (что кликал последние 5 минут) и S3/ClickHouse для исторического профиля.
- Генерация кандидатов: Векторная база (Faiss/Milvus). Контентные модели превращают картинки и тексты новых товаров в эмбеддинги. Новая куртка сразу попадает в выдачу к похожим вещам, холодного старта для товаров больше нет.
- Ранжировщик: Тяжелая модель (CatBoost или XGBoost), которая в онлайне за 50 миллисекунд перескоривает сотни отобранных кандидатов под конкретный интент юзера.
Именно на этапе ранжирования закладывается бизнес-логика. Нам нужен баланс релевантности и разнообразия. Заваливать пользователя десятью одинаковыми белыми рубашками бессмысленно. Выдавать надо сет: рубашка, контрастный галстук, запонки.
def get_mmr_recommendations(user_emb, candidates, lambda_param=0.7, price_penalty=0.15):
# lambda_param: баланс между точным попаданием в интент и разнообразием выдачи
selected = []
c_list = list(candidates.keys())
while len(selected) < 5 and c_list:
best_score = -float('inf')
best_item = None
for item in c_list:
# 1. Релевантность товара текущей сессии
rel = cosine_sim(user_emb, candidates[item]['vector'])
# 2. Штраф за похожесть на уже добавленные в карусель товары (Diversity)
div = max([cosine_sim(candidates[item]['vector'], candidates[s]['vector']) for s in selected]) if selected else 0
# 3. Буст по цене: защита среднего чека (AOV)
price_boost = math.log10(candidates[item]['price']) * price_penalty
# Итоговый скор: Релевантность - Однообразие + Финансовый вес
score = lambda_param * rel - (1 - lambda_param) * div + price_boost
if score > best_score:
best_score = score
best_item = item
selected.append(best_item)
c_list.remove(best_item)
return selectedЭто вариация алгоритма MMR (Maximal Marginal Relevance). Мы не просто ищем ближайшие вектора. Мы заставляем движок показывать товары, которые бьют в запрос, но не похожи друг на друга, и программно пушим вверх маржинальные позиции через price_boost. Мы намеренно пессимизируем дешевые расходники.
Баланс метрик и рекомендации товаров ИИ
Холодный старт нового клиента решается здесь же. Пока у нас нет его годовой истории покупок, мы строим user_emb (вектор пользователя) динамически, прямо в моменте инференса, агрегируя векторы товаров из его текущей сессии. Посмотрел три смартфона — вектор сместился в электронику. Это и есть реал-тайм персонализация.
Рынок молится на CTR (Click-Through Rate). Это ошибка выжившего. Кликнуть на мемные носки за 100 рублей легко, купить к ним классический костюм — нет.
Когда мы проектируем рекомендации товаров ИИ, мы настраиваем лосс-функции под ожидаемую маржу корзины. Если покупателю нужен ноутбук, кросс-сейл должен продавать расширенную гарантию, софт или качественный рюкзак. Пусть CTR этой карусели будет ниже на пару процентов, зато AOV (средний чек) и LTV вырастут на 15%.
Алгоритм, который гонится только за кликом, всегда скатывается на дно ценового сегмента. Настоящая инженерия в e-commerce — это умение заставить нейросеть думать в терминах юнит-экономики, а не абстрактного внимания.