Чистый Net Revenue Retention (NRR) — ключевой драйвер роста B2B SaaS. Но ручной анализ сотен аккаунтов требует 20+ человеко-часов в месяц, а решения принимаются на основе интуиции, а не данных. Мы построили систему предсказания expansion-событий, которая увеличивает NRR на 10-15% за счёт точного выбора момента и продукта. Наш опыт — 5+ лет на рынке AI-решений, 30+ внедрений в B2B SaaS.
В типичном B2B SaaS компании работают с сотнями аккаунтов. Account manager тратит часы на просмотр дашбордов usage, support tickets и контрактных дат. Часто expansion-возможности упускаются из-за нехватки времени или неверной интерпретации сигналов. Наша AI-система автоматизирует этот процесс: она анализирует десятки признаков, выявляет паттерны и выдаёт sales team краткие брифинги с рекомендациями. Оценим ваш проект за 2 дня — свяжитесь с нами для консультации.
Почему ML-модель лучше rule-based подхода?
Rule-based системы работают по простым правилам, например, "если utilisation > 90% — предложить расширение". Они просты, но упускают до 40% возможностей. Причина — они не учитывают комбинации сигналов, тренды и сложные паттерны. ML-модель, в частности градиентный бустинг, находит нелинейные зависимости и выдаёт на 25% больше точных предсказаний.
| Критерий | Rule-based | ML (Gradient Boosting) |
|---|---|---|
| Точность (Precision@20%) | 55-65% | 75-85% |
| Recall (охват) | 30-40% | 50-65% |
| Адаптация к изменениям | Ручная | Автоматическая (переобучение) |
| Обработка новых признаков | Ручная | Автоматическая feature importance |
Второй таблицей сравним ключевые метрики модели в production:
| Метрика | Типичное значение |
|---|---|
| Precision@20% | 75-85% |
| Recall@20% | 65-75% |
| Lift над случайным выбором | 2.0-2.5x |
Как мы строим модель расширения аккаунтов
Используем градиентный бустинг (CatBoost/LightGBM) с кастомной функцией потерь, штрафующей false positives сильнее false negatives — sales team не должна тратить время на пустые контакты. Дополнительно применяем LLM (Claude 3.5) для генерации текстовых брифов. Ключевой модуль:
import pandas as pd import numpy as np from sklearn.ensemble import GradientBoostingClassifier import shap from anthropic import Anthropic import json class AccountExpansionPredictor: """Предсказание готовности аккаунта к расширению""" def __init__(self): self.model = GradientBoostingClassifier( n_estimators=200, learning_rate=0.05, max_depth=4, random_state=42 ) self.llm = Anthropic() def build_account_features(self, accounts: pd.DataFrame, usage_data: pd.DataFrame, support_data: pd.DataFrame) -> pd.DataFrame: """Feature engineering для expansion предсказания""" features = accounts[['account_id']].copy() # === Product Usage Signals === usage = usage_data.groupby('account_id').agg( monthly_active_users=('user_id', pd.Series.nunique), feature_breadth=('feature_name', pd.Series.nunique), sessions_per_user=('session_id', 'count'), advanced_features_used=('is_advanced_feature', 'sum'), ) features = features.merge(usage, on='account_id', how='left') # Тренд использования за последние 3 месяца recent_usage = usage_data[ usage_data['date'] >= pd.Timestamp.now() - pd.DateOffset(months=3) ] older_usage = usage_data[ (usage_data['date'] < pd.Timestamp.now() - pd.DateOffset(months=3)) & (usage_data['date'] >= pd.Timestamp.now() - pd.DateOffset(months=6)) ] recent_counts = recent_usage.groupby('account_id')['session_id'].count() older_counts = older_usage.groupby('account_id')['session_id'].count() usage_trend = (recent_counts - older_counts) / (older_counts + 1) features['usage_trend_3m'] = features['account_id'].map(usage_trend).fillna(0) # === Account Health === features['days_as_customer'] = accounts.get('days_since_first_purchase', pd.Series([180])) features['current_plan_tier'] = accounts.get('plan_tier', pd.Series([1])) # 1=basic, 2=pro, 3=enterprise features['seats_utilization'] = ( accounts.get('active_users', 1) / accounts.get('licensed_seats', 1) ).clip(0, 1) features['contract_months_remaining'] = accounts.get('contract_months_remaining', 12) # === Support & Satisfaction === support = support_data.groupby('account_id').agg( support_tickets_3m=('ticket_id', 'count'), avg_csat=('csat_score', 'mean'), has_critical_tickets=('priority', lambda x: (x == 'critical').any().astype(int)) ) features = features.merge(support, on='account_id', how='left') features['support_tickets_3m'] = features['support_tickets_3m'].fillna(0) features['avg_csat'] = features['avg_csat'].fillna(3.5) # === Expansion Readiness Signals === features['seats_at_capacity'] = (features['seats_utilization'] > 0.90).astype(int) features['power_user_count'] = usage_data[ usage_data['sessions_count'] > usage_data['sessions_count'].quantile(0.90) ].groupby('account_id')['user_id'].nunique().reindex(features['account_id']).fillna(0).values return features.fillna(0) def predict_expansion_opportunities(self, accounts: pd.DataFrame, usage_data: pd.DataFrame, support_data: pd.DataFrame) -> pd.DataFrame: """Список аккаунтов с высокой вероятностью расширения""" features = self.build_account_features(accounts, usage_data, support_data) feature_cols = [c for c in features.columns if c != 'account_id'] X = features[feature_cols] probs = self.model.predict_proba(X)[:, 1] features['expansion_probability'] = probs features['expansion_potential_usd'] = self._estimate_expansion_value(features, accounts) features['recommended_product'] = self._recommend_expansion_product(features) # Приоритизация для sales team features['priority_score'] = features['expansion_probability'] * np.log1p(features['expansion_potential_usd']) return features.sort_values('priority_score', ascending=False) def _estimate_expansion_value(self, features: pd.DataFrame, accounts: pd.DataFrame) -> pd.Series: """Потенциальный ARR от расширения""" base_arr = accounts.get('current_arr', pd.Series([10000])) # Seats expansion seats_expansion = ( features.get('seats_at_capacity', 0) * features.get('power_user_count', 0) * 50 # $50/seat/month ) # Plan upgrade plan_upgrade_potential = ( (features.get('advanced_features_used', 0) > 5) & (features.get('current_plan_tier', 1) < 2) ).astype(float) * base_arr * 0.5 return (seats_expansion * 12 + plan_upgrade_potential).fillna(0) def _recommend_expansion_product(self, features: pd.DataFrame) -> pd.Series: """Рекомендуемый продукт для расширения""" conditions = [ features.get('seats_at_capacity', pd.Series([0])) > 0, features.get('feature_breadth', pd.Series([0])) < 5, features.get('current_plan_tier', pd.Series([1])) == 1, ] choices = ['seat_expansion', 'feature_add_on', 'plan_upgrade'] result = pd.Series(['general_expansion'] * len(features), index=features.index) for cond, choice in zip(conditions, choices): result = result.where(~cond, choice) return result def generate_expansion_brief(self, account: dict) -> str: """Бриф для account manager о сигналах расширения""" response = self.llm.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=200, messages=[{ "role": "user", "content": f"""Write a sales brief for account expansion in Russian. Account: {account.get('company_name')} Current ARR: ${account.get('current_arr', 0):,.0f} Expansion probability: {account.get('expansion_probability', 0):.0%} Key signals: - Seats utilization: {account.get('seats_utilization', 0):.0%} - Usage trend: {account.get('usage_trend_3m', 0):+.0%} - Advanced features used: {account.get('advanced_features_used', 0)} - Power users: {account.get('power_user_count', 0)} Recommended expansion: {account.get('recommended_product', '')} Estimated value: ${account.get('expansion_potential_usd', 0):,.0f} ARR Write 2-3 sentences: what signals you see, what to propose, and how to frame the conversation.""" }] ) return response.content[0].text Как часто нужно переобучать модель?
Модель нужно переобучать каждый квартал, так как поведение клиентов со временем меняется. Мы автоматизировали это через CI/CD pipeline: каждое воскресенье модель валидируется на свежих данных. Если точность падает ниже 70%, запускается retrain. Внеплановое обновление происходит при изменении продуктовой линейки или ценообразования.
Детали pipeline автоматического переобучения
Pipeline включает этапы:
- Сбор данных из CRM и product analytics
- Feature engineering и валидация
- Обучение модели на sliding window (6 месяцев)
- Оценка на отложенной выборке (1 месяц)
- A/B тест с текущей моделью
- Деплой через Kubernetes с canary-релизом
Что входит в работу
Система поставляется под ключ:
- Артефакты: обученная модель, pipeline инференса, дашборд в Metabase/Grafana
- Интеграция: коннекторы к CRM (Salesforce, HubSpot) и источники данных (Databricks, BigQuery)
- Документация: Model card с результатами, инструкция для CS team, описание API
- Обучение: 2 воркшопа для sales и CS по интерпретации результатов
- Поддержка: гарантия 3 месяца, включая исправление багов и консультации по дообучению
Процесс: от аудита до деплоя
- Анализ данных: проверяем качество, составляем витрину признаков
- Прототипирование: Baseline модель и A/B тест против rule-based
- Интеграция: подключаем реальные потоки с CRM и product analytics
- Пилот: 2-недельный запуск на 20% аккаунтов, замер Lift
- Продуктив: разворачиваем на Kubernetes с авто-переобучением
Типичные ошибки внедрения
- Недостаток negative примеров: если брать все аккаунты, где не было expansion, классовый дисбаланс завалит модель. Используем undersampling и weighted loss.
- Игнорирование временного дрейфа: модель, обученная на данных полугодовой давности, показывает низкую точность на текущих данных. Решение — sliding window retrain.
- Отсутствие интерпретации: sales team не доверяет "чёрному ящику". Наш SHAP-анализ и краткие LLM-брифы снимают эту проблему.
Пример внедрения
Для B2B SaaS платформы аналитики с 5000 аккаунтов мы обучили модель на данных за 12 месяцев. Через 3 месяца после пилота sales team обработала top-20% аккаунтов, и NRR вырос на 12%. Система предсказывает не только upsell (переход на более дорогой план), но и cross-sell (покупка дополнительных модулей). Customer health scoring на основе десятков признаков позволил выявлять аккаунты с высоким потенциалом расширения. Прогнозируемый RR помогает планировать развитие.
Оценим ваш проект за 2 дня: проанализируем данные, прикинем ROI и сроки (типично 4-6 недель до пилота). Свяжитесь с нами для консультации — сертифицированные AI-инженеры сфокусируются на вашем кейсе.







