Как 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 недели.







