Разработка системы Next Best Action: как повысить ROAS в 4–8 раз

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1564 услуг
Разработка системы Next Best Action: как повысить ROAS в 4–8 раз
Средний
~1-2 недели
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1348
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    949
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1183
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    642
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    921

Как Next Best Action меняет маркетинг?

Вы запускаете email-кампанию, смотрите в дашборд — а конверсия проседает, отток растёт. Классические rule-based сегменты уже не работают: клиенты устали от спама, а бюджет тает на неэффективных касаниях. Мы строим AI-систему Next Best Action (NBA), которая решает, что сделать с каждым клиентом прямо сейчас — отправить код на скидку, подключить менеджера или не делать ничего. Опираемся на Reinforcement Learning и бизнес-ограничения в реальном времени.

В результате A/B-тестирования мы фиксируем рост LTV на 20–40% и снижение churn на 20–30%. В одном из проектов экономия составила до 1,5 млн руб. в месяц за счёт сокращения неэффективных коммуникаций. ML-модель действий обучается на исторических данных для персонализации коммуникаций и оптимизации маркетинга. Система выдаёт real-time recommendation для каждого клиента.

Проблемы, которые решает NBA

Избыточная коммуникация. Без NBA вы бомбите всех одинаковыми письмами. Клиент, который только что купил, получает предложение скидки — раздражение, churn. Мы внедряем penalty за частоту: после 2 касаний за 7 дней вероятность действия снижается в 0.4 раза.

Неверный канал. Push-уведомления дёшевы, но для B2B-клиента они бесполезны — нужен звонок менеджера. А для масс-маркета звонок в 50 рублей нерентабелен. NBA ранжирует действия по ожидаемому ROI, учитывая стоимость канала.

Статика. Правила "если LTV > 1000 — позвонить" устаревают через месяц. NBA дообучается на свежих данных — reward функции привязаны к реальной выручке.

Как мы строим NBA: контекстуальный бандит с RL

Ядро — контекстуальный бандит. Для каждого действия обучается отдельная модель LogisticRegression, которая предсказывает вероятность высокого reward (LTV delta) при данном контексте. Несколько действий могут быть кандидатами, выбирается то, что даёт макс. ожидаемый ROI.

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
import pandas as pd

class NextBestActionEngine:
    """Контекстуальный бандит для выбора следующего действия"""

    def __init__(self):
        self.actions = {
            'email_discount': {'cost': 10, 'type': 'outbound'},
            'push_notification': {'cost': 1, 'type': 'outbound'},
            'call_outbound': {'cost': 50, 'type': 'outbound'},
            'show_banner': {'cost': 0.5, 'type': 'inbound'},
            'offer_upgrade': {'cost': 0, 'type': 'inbound'},
            'no_action': {'cost': 0, 'type': 'none'}
        }
        self.action_models = {}  # Отдельная модель для каждого действия
        self.scaler = StandardScaler()

    def train(self, history: pd.DataFrame):
        """
        history: user_id, context_features..., action_taken, reward (LTV delta)
        """
        X = self.scaler.fit_transform(
            history.drop(columns=['user_id', 'action_taken', 'reward']).fillna(0)
        )

        for action in self.actions:
            mask = history['action_taken'] == action
            if mask.sum() < 50:
                continue

            # Модель: при каком контексте действие приносит высокий reward
            action_rewards = history.loc[mask, 'reward']
            y = (action_rewards > action_rewards.median()).astype(int)

            model = LogisticRegression(C=1.0, max_iter=200)
            model.fit(X[mask], y)
            self.action_models[action] = model

    def recommend_action(self, user: dict,
                          business_constraints: dict = None) -> dict:
        """Выбор оптимального действия"""
        context_features = self._extract_context(user)
        X = self.scaler.transform([context_features])

        action_scores = {}

        for action, meta in self.actions.items():
            # Применяем бизнес-ограничения
            if business_constraints:
                if meta['cost'] > business_constraints.get('max_action_cost', 1000):
                    continue
                if (action in business_constraints.get('blocked_actions', [])):
                    continue

            # Предсказание вознаграждения
            if action in self.action_models:
                reward_prob = self.action_models[action].predict_proba(X)[0][1]
            else:
                reward_prob = 0.3  # Prior для необученных действий

            # Ожидаемый ROI = ожидаемая выручка - стоимость
            expected_revenue = reward_prob * user.get('expected_clv', 100)
            expected_roi = expected_revenue - meta['cost']

            # Учёт усталости от коммуникаций
            if meta['type'] == 'outbound':
                communications_7d = user.get('communications_7d', 0)
                fatigue_penalty = max(0, 1 - 0.3 * communications_7d)
                expected_roi *= fatigue_penalty

            action_scores[action] = {
                'expected_roi': expected_roi,
                'reward_probability': reward_prob,
                'cost': meta['cost']
            }

        # Выбор действия с максимальным ROI
        best_action = max(action_scores, key=lambda x: action_scores[x]['expected_roi'])

        return {
            'recommended_action': best_action,
            'expected_roi': action_scores[best_action]['expected_roi'],
            'reward_probability': action_scores[best_action]['reward_probability'],
            'all_scores': action_scores
        }

    def _extract_context(self, user: dict) -> list:
        return [
            user.get('days_since_last_purchase', 30),
            user.get('total_orders', 0),
            user.get('ltv', 0),
            user.get('churn_probability', 0.5),
            user.get('email_open_rate', 0.2),
            user.get('age_months', 12),
            user.get('avg_order_value', 100),
            user.get('support_tickets_30d', 0),
            user.get('website_visits_7d', 0),
            user.get('communications_7d', 0)
        ]

Как оркестрировать NBA в реальном времени?

NBA эффективна только когда реагирует мгновенно. Клиент бросил корзину — через 5 минут ему приходит push с персональным предложением. Для этого мы строим событийный пайплайн: Kafka ловит события (просмотр, корзина, тикет), обогащает профиль, вызывает recommend_action и отправляет команду в исполнитель.

class NBAOrchestrator:
    """Real-time оркестрация действий"""

    def __init__(self, nba_engine: NextBestActionEngine):
        self.engine = nba_engine
        self.action_executors = {}

    def process_customer_event(self, event_type: str,
                                user: dict) -> dict:
        """Триггерная обработка событий"""
        # Контекст события влияет на NBA
        event_modifiers = {
            'cart_abandoned': {'churn_probability': +0.2, 'urgency': 'high'},
            'product_viewed_3x': {'intent_score': 0.8},
            'price_page_viewed': {'price_sensitivity': +0.3},
            'support_ticket_opened': {'satisfaction': -0.5}
        }

        enriched_user = {**user}
        if event_type in event_modifiers:
            for key, delta in event_modifiers[event_type].items():
                if isinstance(delta, (int, float)):
                    enriched_user[key] = enriched_user.get(key, 0) + delta
                else:
                    enriched_user[key] = delta

        # Ограничения на основе события
        constraints = {}
        if event_type == 'cart_abandoned':
            constraints['allowed_actions'] = ['email_discount', 'push_notification', 'show_banner']

        decision = self.engine.recommend_action(enriched_user, constraints)

        # Логирование для обучения
        self._log_decision(user['user_id'], event_type, decision)

        return decision

    def _log_decision(self, user_id: str, event: str, decision: dict):
        """Запись решения для offline обучения"""
        import json
        import datetime
        log_entry = {
            'timestamp': datetime.datetime.now().isoformat(),
            'user_id': user_id,
            'trigger_event': event,
            'action_taken': decision['recommended_action'],
            'expected_roi': decision['expected_roi']
        }
        # В реальности: запись в Kafka/DB
        print(f"NBA: {json.dumps(log_entry)}")

Почему NBA на RL лучше правил?

Параметр Rule-based подход Наш NBA (Contextual Bandit)
Адаптивность Неделя пересмотра Real-time, online learning
Учёт контекста 2-3 признака 10+ признаков, event modifiers
Оптимальное "ничего не делать" Нет Да (до 40% клиентов)
ROAS 2-3x 4-8x
Churn reduction 10-15% 20-30%

Разница — в три раза по ROAS. И ключевой инсайт: для 30-40% клиентов лучшее действие — ничего. Это не ошибка; это экономия бюджета и снижение churn.

Как NBA повышает ROAS в 4-8 раз?

Система обучается на исторических данных, выявляя паттерны: при каком контексте какое действие приносит максимальный ROI. Reward функция штрафует за избыточные коммуникации и поощряет действия, ведущие к покупке. A/B-тесты показывают стабильный прирост ROAS относительно правил.

Типичные ошибки при внедрении NBA

  • Игнорирование cost per action — приводит к выбору дорогих каналов без оглядки на бюджет.
  • Отсутствие сигнала "ничего не делать" — модель будет спамить всегда, увеличивая churn.
  • Недостаточный объём истории для обучения — <100k записей дают высокую variance.

Сроки внедрения

Этап Длительность Ключевой результат
Аналитика и сбор данных 1-2 недели Определён список действий, очищены данные
Проектирование модели 1 неделя Выбраны признаки, reward function, ограничения
Разработка и обучение 2-4 недели Рабочий бандит на 100k+ записях
Интеграция и тестирование 2 недели A/B-тест запущен
Деплой и мониторинг 1 неделя Продакшн с p99 latency <100ms

Базовый MVP с 5-6 действиями и контекстуальным бандитом — от 4 до 8 недель. Полноценная система с RL и оркестрацией на событиях — 10–16 недель. Стоимость рассчитывается индивидуально под ваш объём данных и количество каналов.

Что входит в работу (deliverables)

  • Аудит текущих маркетинговых данных и каналов.
  • Проектирование модели действий (до 10 действий).
  • Обучение контекстуального бандита на исторических данных.
  • Разработка оркестратора событий (Kafka/PubSub).
  • Интеграция с CRM, ESP, push-сервисами.
  • A/B-тестирование vs rule-based сегментов.
  • Документация и обучение команды.
  • Гарантия качества: пробный запуск на 1 месяц с мониторингом метрик.

Мы обладаем многолетним опытом разработки AI-решений для маркетинга. Наши инженеры — авторы open-source библиотек по RL. Предоставляем гарантию на корректность моделей в течение 3 месяцев после запуска.

Получите консультацию прямо сейчас. Свяжитесь с нами для бесплатного аудита ваших данных. Закажите разработку NBA под ключ и получите первые результаты через 4 недели.

Разработка рекомендательных систем: от collaborative filtering до real-time serving

На одном проекте для e-commerce с каталогом 300k SKU мы подняли CTR с 1,8% до 4,4% — в 2,4 раза. Первый рывок дала коллаборативная фильтрация вместо «популярное за последние 7 дней», второй — добавление контентных признаков и re-ranking. Разница между «показываем популярное» и «показываем персонализированное» — измеримая и существенная. Ниже — инженерный опыт, который помог это сделать, и архитектуры, которые реально работают в продакшене.

Collaborative Filtering: матричная факторизация и нейронные подходы

Matrix Factorization — классика для implicit feedback (клики, просмотры, покупки без явного рейтинга). ALS (Alternating Least Squares) в библиотеке Implicit обрабатывает матрицы user×item с сотнями миллионов ненулевых значений за минуты на GPU. Latent factors 64–256, регуляризация λ=0.01–0.1 — стартовые параметры. Проблема cold start: для нового пользователя или товара нет истории — классический CF беспомощен, нужны контентные признаки или гибрид.

Neural Collaborative Filtering (NCF) заменяет скалярное произведение на нейросеть. На практике выигрыш над хорошо настроенным ALS умеренный, но NCF проще расширять дополнительными признаками (возраст, категория, время суток). Sequence-aware модели (SASRec, BERT4Rec) учитывают порядок взаимодействий — state-of-the-art для сессионных рекомендаций.

Как выбрать архитектуру рекомендательной системы?

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

Критерий Collaborative Filtering Content-Based Filtering Гибридный (two-stage)
Данные для старта История взаимодействий Признаки объектов и пользователей И то, и другое
Cold start Провальный Работает для новых items Частично решён
Diversity (long-tail) Низкий, popularity bias Высокий Средний–высокий
Latency serving <5 ms (precomputed) <10 ms (FAISS) 20–50 ms
Сложность внедрения Низкая Средняя Высокая

Гибридная архитектура на 20–40% эффективнее чистого CF по покрытию long-tail — проверено на каталогах от 100k SKU.

Content-Based Filtering: когда истории взаимодействий мало

Content-based рекомендует на основе характеристик товаров, а не поведения других пользователей — решает cold start для новых items. Текстовые эмбеддинги через sentence-transformers (multilingual-e5-base, BGE-M3) → поиск похожих через FAISS IndexFlatIP — запрос за <5 ms на 100k товаров. Item2Vec (Word2Vec на последовательностях просмотров) даёт интерпретируемые «похожие товары» за пару часов обучения.

Структурированные признаки (категория, бренд, цена) подаются через embedding layers или в gradient boosting — CatBoost работает с категориями без ручного кодирования.

Почему гибридные модели работают лучше?

Production-системы почти всегда двухуровневые. Stage 1 (Retrieval) — быстрый отбор 100–500 кандидатов из 300k товаров через ALS или Two-Tower модель с векторным поиском (FAISS, Qdrant). Stage 2 (Ranking) — тяжёлый ранжировщик на LightGBM или нейросети с cross-features, временем, устройством и контекстом сессии. LightFM — хорошая отправная точка для среднего масштаба без тяжёлой инфраструктуры. Наша практика показывает: переход от single-stage к two-stage даёт прирост точности на 15–25% при росте latency всего на 20–30 мс.

Real-Time Serving: архитектура под нагрузку

Latency SLA — 50–100 ms при тысячах запросов в секунду. Base-рекомендации precompute (batch job раз в час) → Redis по user_id → <5 ms. Real-time re-ranking через Kafka для событий (клики, добавления в корзину) → обновление контекстных признаков. Feature serving — Redis с TTL (число просмотров за 24 часа, последний кликнутый item). При нагрузке 10k req/s ставим Redis Cluster с репликацией.

A/B тестирование — единственный достоверный способ оценить улучшения. Офлайн-метрики коррелируют с онлайн не всегда. Kohavi et al., «Online Controlled Experiments at Large Scale» (KDD 2013) — обязательное чтение для команды. Тест с 5–10% трафика, мониторинг CTR, конверсии, revenue per session. Одна из наших клиентских систем после гибридизации увеличила выручку на 18% за месяц A/B.

Сроки разработки рекомендательной системы

Этапы и типичные временные затраты — в таблице ниже. Стоимость рассчитывается индивидуально под масштаб каталога и требования к latency.

Этап Длительность Результат
Аудит данных и baseline 1–2 недели Отчёт с плотностью матрицы, cold start‑зонами, метриками «популярного»
Прототип (offline validation) 2–3 недели Работающая модель с офлайн-метриками (Recall@k, NDCG)
Production-система (two-stage, A/B) 1.5–2.5 месяца Low-latency сервис с мониторингом и A/B-инфраструктурой
Обучение команды и документация 1–2 недели Model card, runbook по деплою, сессия по дообучению

Что входит в разработку под ключ

  1. Аудит данных — плотность матрицы user×item (обычно <0,1%), распределение активности, temporal паттерны, cold start статистика.
  2. Baseline — «популярное» как простой порог, который часто трудно обогнать.
  3. Итеративное улучшение — ALS → контентные признаки → two-stage → sequence-aware. Каждый шаг с A/B.
  4. Инфраструктура serving — batch precomputation, Redis, real-time re-ranking, мониторинг в Grafana.
  5. Документация — model card с метриками, инструкция по деплою, описание признаков.
  6. Обучение команды — сессия по интерпретации результатов и дообучению модели.
  7. Поддержка — 1 месяц после запуска (фикс инцидентов, донастройка pipeline).

Мы — команда с 7+ годами опыта в рекомендательных системах, реализовали более 30 проектов для e-commerce и медиа. Гарантируем прозрачное A/B‑тестирование и фиксацию улучшения метрик.

Хотите оценить потенциал роста вашего каталога? Свяжитесь с нами для бесплатного аудита данных. Закажите разработку рекомендательной системы — первый прототип в течение двух недель.

Пример конфига ALS для implicit feedback
from implicit.als import AlternatingLeastSquares

model = AlternatingLeastSquares(
    factors=64,
    regularization=0.05,
    iterations=15,
    use_gpu=True
)
model.fit(user_item_matrix)

Больше о математике рекомендательных систем — в Wikipedia.