Реализация AI-системы рекомендаций Upsell для продаж
AI-upsell рекомендует покупателю более дорогую или расширенную версию того, что он уже смотрит. Отличие от cross-sell: предлагаем тот же товар класса выше, а не дополнение. ML-модель определяет момент предложения, персонализирует аргументацию и выбирает правильный ценовой шаг.
Upsell-модель с контекстуальным бандитом
import numpy as np
import pandas as pd
from anthropic import Anthropic
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.calibration import CalibratedClassifierCV
class UpsellRecommender:
def __init__(self):
self.llm = Anthropic()
self.model = None
self.product_catalog = {}
def train(self, sessions_df: pd.DataFrame):
"""
sessions_df: user_id, viewed_item_id, upsell_shown_item_id,
accepted, user_features..., item_features...
"""
features = self._extract_features(sessions_df)
X = features.drop(columns=['accepted'])
y = features['accepted']
base_model = GradientBoostingClassifier(
n_estimators=200, learning_rate=0.05,
max_depth=5, random_state=42
)
# Калибруем вероятности для правильного порога
self.model = CalibratedClassifierCV(base_model, cv=3, method='isotonic')
self.model.fit(X, y)
def _extract_features(self, df: pd.DataFrame) -> pd.DataFrame:
"""Feature engineering для upsell модели"""
features = pd.DataFrame()
# Ценовой разрыв между текущим и upsell товаром
features['price_delta'] = df['upsell_price'] - df['current_price']
features['price_ratio'] = df['upsell_price'] / df['current_price'].clip(0.01)
# Пользовательские признаки
features['user_avg_order'] = df['user_avg_order_value']
features['user_premium_ratio'] = df['user_premium_purchases'] / df['user_total_purchases'].clip(1)
features['session_depth'] = df['pages_viewed']
features['cart_value'] = df['current_cart_value']
# Товарные признаки
features['upsell_rating_delta'] = df['upsell_rating'] - df['current_rating']
features['current_category_encoded'] = df['category'].astype('category').cat.codes
features['accepted'] = df['accepted']
return features
def recommend_upsell(self, user: dict, current_item: str) -> dict:
"""Рекомендация upsell с пояснением"""
candidates = self._get_upsell_candidates(current_item)
if not candidates:
return None
# Скоринг кандидатов
best_candidate = None
best_prob = 0
for candidate in candidates:
features = self._build_prediction_features(user, current_item, candidate)
if self.model:
prob = self.model.predict_proba([features])[0][1]
else:
prob = 0.3 if candidate['price'] < user.get('avg_order', 0) * 1.5 else 0.15
if prob > best_prob and prob > 0.2: # Показываем только с достаточной вероятностью
best_prob = prob
best_candidate = (candidate, prob)
if not best_candidate:
return None
candidate, prob = best_candidate
# AI генерирует персонализированное предложение
pitch = self._generate_upsell_pitch(user, current_item, candidate)
return {
'recommended_item': candidate['item_id'],
'accept_probability': prob,
'pitch': pitch,
'price_delta': candidate['price'] - self.product_catalog.get(current_item, {}).get('price', 0)
}
def _get_upsell_candidates(self, item_id: str) -> list[dict]:
"""Товары той же категории но более дорогие"""
current = self.product_catalog.get(item_id, {})
current_price = current.get('price', 0)
current_category = current.get('category', '')
return [
item for item in self.product_catalog.values()
if item.get('category') == current_category
and current_price * 1.1 <= item.get('price', 0) <= current_price * 2.5
and item.get('rating', 0) >= current.get('rating', 0) - 0.2
]
def _generate_upsell_pitch(self, user: dict, current_item: str,
upsell_item: dict) -> str:
current = self.product_catalog.get(current_item, {})
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=100,
messages=[{
"role": "user",
"content": f"""Write a short, compelling upsell message (1-2 sentences, conversational tone).
Customer is viewing: {current.get('name', current_item)} (${current.get('price', 0)})
Upsell option: {upsell_item.get('name', '')} (${upsell_item.get('price', 0)})
Key difference: {upsell_item.get('upgrade_feature', 'better quality')}
Customer history: avg order ${user.get('avg_order', 0):.0f}
Be direct, mention the specific benefit, not generic praise."""
}]
)
return response.content[0].text
Типичный upsell acceptance rate при правильно настроенной модели: 8-15% (без ML: 3-5%). Ключевой инсайт: оптимальный ценовой шаг для upsell — 20-40% выше текущей цены. Выше 50% — конверсия падает вдвое.







