Разработка AI-системы персонализированных предложений для удержания

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Разработка AI-системы персонализированных предложений для удержания
Средняя
~1-2 недели
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1240
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1167
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    867
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1084
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    829

Реализация AI-системы персонализированных удержания клиентов

Персонализированные retention-предложения — ML-система, которая определяет когда и каким клиентам отправить какое предложение, чтобы предотвратить отток. Не "отправить скидку 10% всем кто не купил за 30 дней", а "дать скидку 15% тому, для кого цена — барьер, и предложить расширенный сервис тому, кто уходит из-за функциональности".

Предсказание риска оттока + причины

import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.multioutput import MultiOutputClassifier
from anthropic import Anthropic
import shap

class ChurnRiskModel:
    def __init__(self):
        self.churn_model = GradientBoostingClassifier(
            n_estimators=200, learning_rate=0.05,
            max_depth=5, random_state=42
        )
        # Многоклассовая модель причин оттока
        self.reason_model = MultiOutputClassifier(
            GradientBoostingClassifier(n_estimators=100, random_state=42)
        )
        self.llm = Anthropic()
        self.explainer = None

    def fit(self, users_df: pd.DataFrame, labels: pd.Series,
             churn_reasons: pd.DataFrame = None):
        """
        users_df: поведенческие и транзакционные признаки
        labels: 1=churned, 0=retained
        churn_reasons: multi-label для причин (price, features, competitor, quality, support)
        """
        X = users_df.fillna(0)
        self.churn_model.fit(X, labels)
        self.explainer = shap.TreeExplainer(self.churn_model)
        self.feature_names = users_df.columns.tolist()

        if churn_reasons is not None:
            self.reason_model.fit(X, churn_reasons)

    def predict_churn_risk(self, user_features: dict) -> dict:
        """Риск оттока + причины + SHAP объяснение"""
        X = pd.DataFrame([user_features])[self.feature_names].fillna(0)
        churn_prob = self.churn_model.predict_proba(X)[0][1]

        # SHAP values для объяснения
        shap_values = self.explainer.shap_values(X)
        if isinstance(shap_values, list):
            shap_vals = shap_values[1][0]
        else:
            shap_vals = shap_values[0]

        # Топ факторы риска
        top_factors = sorted(
            zip(self.feature_names, shap_vals),
            key=lambda x: abs(x[1]), reverse=True
        )[:5]

        return {
            'churn_probability': float(churn_prob),
            'risk_level': 'high' if churn_prob > 0.7 else 'medium' if churn_prob > 0.35 else 'low',
            'top_risk_factors': [
                {'feature': name, 'impact': float(impact), 'direction': 'increase' if impact > 0 else 'decrease'}
                for name, impact in top_factors
            ]
        }


class RetentionOfferEngine:
    """Выбор оптимального предложения для удержания"""

    def __init__(self, churn_model: ChurnRiskModel):
        self.churn_model = churn_model
        self.llm = Anthropic()
        self.offers = {
            'discount_10': {'type': 'discount', 'value': 10, 'cost': 0.1, 'segment': 'price_sensitive'},
            'discount_20': {'type': 'discount', 'value': 20, 'cost': 0.2, 'segment': 'high_risk'},
            'feature_unlock': {'type': 'feature', 'duration_days': 30, 'cost': 0.05, 'segment': 'power_users'},
            'personal_manager': {'type': 'service', 'cost': 0.15, 'segment': 'enterprise'},
            'loyalty_bonus': {'type': 'points', 'value': 500, 'cost': 0.03, 'segment': 'loyal'},
            'winback_survey': {'type': 'survey', 'cost': 0.01, 'segment': 'churned'},
        }

    def select_offer(self, user: dict, churn_risk: dict) -> dict:
        """Персонализированный выбор предложения"""
        risk_factors = {f['feature']: f['impact'] for f in churn_risk['top_risk_factors']}

        # Определение причины риска
        if risk_factors.get('days_since_last_purchase', 0) > 0 and \
           risk_factors.get('avg_order_value', 0) < 0:
            # Снижение среднего чека = ценовая чувствительность
            offer_key = 'discount_10' if churn_risk['churn_probability'] < 0.6 else 'discount_20'

        elif risk_factors.get('support_tickets_last_30d', 0) > 0:
            # Проблемы с сервисом
            offer_key = 'personal_manager'

        elif risk_factors.get('feature_usage_depth', 0) < 0:
            # Не использует продукт
            offer_key = 'feature_unlock'

        elif user.get('total_orders', 0) > 20:
            # Лояльный клиент
            offer_key = 'loyalty_bonus'

        else:
            offer_key = 'discount_10'

        offer = self.offers[offer_key].copy()
        offer['offer_id'] = offer_key

        # Персонализированное сообщение
        offer['message'] = self._personalize_message(user, offer, churn_risk)

        return offer

    def _personalize_message(self, user: dict, offer: dict, risk: dict) -> str:
        risk_factors_str = ", ".join([
            f['feature'] for f in risk['top_risk_factors'][:3]
        ])

        response = self.llm.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=100,
            messages=[{
                "role": "user",
                "content": f"""Write a personalized retention message (2 sentences max, warm tone).

User: {user.get('first_name', 'Customer')}, {user.get('tenure_months', 0)} months with us
Offer: {offer['type']} - {offer.get('value', '')}
Risk signals: {risk_factors_str}

Be specific, not generic. Don't mention risk/churn directly."""
            }]
        )
        return response.content[0].text

Модель, обученная на 6 месяцах истории, предсказывает отток с AUC 0.82-0.88. Precision @30% threshold (высокий риск): 65-75%. Оптимальный момент для предложения: за 7-14 дней до предполагаемого ухода, когда пользователь ещё активен. Конверсия персонализированного предложения vs массовой рассылки: 12-18% против 2-4%.