Реалізація AI-персоналізації рекомендацій в email-кампаніях
Середній Open Rate масових розсилок — 15-20%, CTR — 1-2%. Клієнти ігнорують нерелевантні пропозиції, відписуються, а LTV падає. Ручне сегментування за віком, статтю чи містом дає виграш у 5-10% до Open Rate, але цього недостатньо. Ми вирішуємо проблему за допомогою ML-персоналізації email-розсилок: кожен отримувач бачить лише ті товари, час і тему, які відповідають його поведінці. Це піднімає Open Rate до 35%, CTR до 8%, а Revenue per Email — у 4-5 разів. В одному проєкті для інтернет-магазину одягу ми підняли CTR з 1.2% до 7.8% за місяць — це в 6 разів. Колаборативна фільтрація — основа рекомендацій, а LLM генерує персоналізовані тексти.
Які проблеми вирішуємо?
- Generic-теми на кшталт «Новинки місяця» не чіпляють. AI генерує індивідуальні заголовки, згадуючи ім'я клієнта або його останню покупку. Наприклад, «Олексію, ці кросівки Nike створені для тебе». Це підвищує Open Rate на 30-50%.
- Якщо розсилати всім однакові товари, 60% отримувачів вважатимуть їх спамом. Персоналізовані рекомендації знижують відписки на 30-50% і збільшують CTR у 2-3 рази.
- Відкриваність варіюється залежно від часового поясу та звичок. ML визначає оптимальну годину для кожного користувача, збільшуючи шанс прочитання до 40%. У результаті конверсія з листа зростає.
Як влаштована система?
В основі — гібридний підхід: колаборативна фільтрація для рекомендацій товарів + LLM (Claude 3.5 Sonnet) для генерації контенту. Стек: Python, Pandas, NumPy, Anthropic SDK. Ось як виглядає ядро:
import pandas as pd
import numpy as np
from anthropic import Anthropic
import json
class EmailPersonalizationEngine:
def __init__(self, recommender, user_database):
self.recommender = recommender # Рекомендаційна система
self.user_db = user_database
self.llm = Anthropic()
def generate_personalized_email(self, user_id: str,
campaign_type: str,
product_pool: list[dict]) -> dict:
"""Повністю персоналізований лист"""
user = self.user_db.get_user(user_id)
if not user:
return self._generate_fallback_email(campaign_type, product_pool)
# Персоналізовані товари
user_recs = self.recommender.recommend(user_id, n=6)
rec_ids = {r[0] for r in user_recs}
# З пулу кампанії обираємо ті, що релевантні користувачеві
personalized_products = [
p for p in product_pool if p['id'] in rec_ids
][:3]
# Якщо мало персоналізованих — додаємо популярні
if len(personalized_products) < 3:
popular = sorted(product_pool, key=lambda x: x.get('popularity', 0), reverse=True)
personalized_products += [p for p in popular
if p not in personalized_products][:3 - len(personalized_products)]
# Персоналізована тема листа
subject = self._generate_subject(user, personalized_products, campaign_type)
# Персоналізований текст
body_intro = self._generate_intro(user, personalized_products, campaign_type)
# Оптимальний час відправлення
send_time = self._optimal_send_time(user)
return {
'user_id': user_id,
'subject': subject,
'body_intro': body_intro,
'products': personalized_products,
'cta_text': self._get_cta_text(campaign_type, user),
'send_at': send_time
}
def _generate_subject(self, user: dict, products: list,
campaign_type: str) -> str:
"""AI генерує персоналізовану тему"""
product_names = [p.get('name', '') for p in products[:2]]
top_category = products[0].get('category', '') if products else ''
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=80,
messages=[{
"role": "user",
"content": f"""Write an email subject line (max 50 chars).
Customer: {user.get('first_name', 'Customer')}
Campaign: {campaign_type}
Featured: {', '.join(product_names)}
Top interest: {top_category}
Rules: personalize with name or interest, create curiosity, no spam words (FREE, !!!).
Return only the subject line."""
}]
)
return response.content[0].text.strip()
def _generate_intro(self, user: dict, products: list,
campaign_type: str) -> str:
"""Персоналізований вступний абзац"""
user_context = f"""
First name: {user.get('first_name', 'Customer')}
Last purchase: {user.get('last_purchase_category', 'N/A')}
Member since: {user.get('member_months', 0)} months
Preferred brand: {user.get('top_brand', 'N/A')}
"""
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=100,
messages=[{
"role": "user",
"content": f"""Write a 2-sentence personalized email intro.
User: {user_context}
Campaign: {campaign_type}
Products to highlight: {[p.get('name') for p in products[:2]]}
Be warm and personal. Reference past purchase or interest if relevant."""
}]
)
return response.content[0].text
def _optimal_send_time(self, user: dict) -> str:
"""Оптимальний час відправлення за патернами користувача"""
# Історичні дані про час відкриттів
open_hours = user.get('email_open_hours', [])
if open_hours:
# Знаходимо годину з максимальною кількістю відкриттів
hour_counts = np.bincount(open_hours, minlength=24)
best_hour = int(np.argmax(hour_counts))
else:
# Default: 10:00 ранку як найкращий час для більшості
best_hour = 10
# День тижня (якщо дані є)
open_days = user.get('email_open_days', [])
best_day = int(np.bincount(open_days, minlength=7).argmax()) if open_days else 2 # Tuesday default
from datetime import datetime, timedelta
today = datetime.now()
days_until = (best_day - today.weekday()) % 7
send_date = today + timedelta(days=days_until)
return send_date.strftime(f"%Y-%m-%d {best_hour:02d}:00:00")
def _get_cta_text(self, campaign_type: str, user: dict) -> str:
cta_map = {
'new_arrivals': 'Shop New Arrivals',
'sale': f"Get Your {user.get('loyalty_tier', '').title()} Discount",
'abandoned_cart': 'Complete Your Purchase',
'reactivation': 'Discover What\'s New',
'birthday': 'Claim Your Birthday Gift'
}
return cta_map.get(campaign_type, 'Shop Now')
def _generate_fallback_email(self, campaign_type: str,
product_pool: list[dict]) -> dict:
"""Не-персоналізований лист як fallback"""
top_products = sorted(
product_pool, key=lambda x: x.get('popularity', 0), reverse=True
)[:3]
return {
'subject': 'Special picks just for you',
'products': top_products,
'cta_text': 'Shop Now'
}
Batch-генерація для розсилки
def generate_campaign_batch(self, user_ids: list,
campaign_type: str,
product_pool: list[dict]) -> pd.DataFrame:
"""Генерація листів для всієї бази"""
results = []
for user_id in user_ids:
try:
email = self.generate_personalized_email(
user_id, campaign_type, product_pool
)
results.append({'user_id': user_id, 'status': 'generated', **email})
except Exception as e:
results.append({'user_id': user_id, 'status': 'failed', 'error': str(e)})
return pd.DataFrame(results)
Чому AI-персоналізація ефективніша за ручні сегменти?
Ручне сегментування (за віком, статтю, містом) дає виграш у 5-10% до Open Rate. AI-персоналізація враховує сотні факторів: історію покупок, час кліків, покинуті кошики, перегляди категорій. Наприклад, користувач, який переглядав кросівки Nike, отримає лист саме з ними, а не із загальним каталогом. В одному з проєктів для інтернет-магазину одягу ми підняли CTR з 1.2% до 7.8% за місяць — зростання в 6 разів. Згідно з документацією Anthropic, моделі сімейства Claude оптимізовані для генерації коротких продаючих текстів, що підвищує релевантність розсилки.
Порівняння: AI-персоналізація vs Generic-розсилки
| Метрика | Generic | AI-персоналізація | Покращення |
|---|---|---|---|
| Open Rate | 15-20% | 22-35% | +50-100% |
| CTR | 1-2% | 3-8% | +150-300% |
| Revenue per Email | базовий | зростання в 4-5 разів | +300-500% |
| Відписки | 0.5-1% | 0.2-0.4% | -50% |
Важливі технічні обмеження: LLM-генерація 10K суб'єктів займає 15-30 хвилин, тому для великих баз потрібно попередньо генерувати шаблони. Ми використовуємо пайплайни з чергами для batch-обробки.
Етапи впровадження
| Етап | Тривалість | Результат |
|---|---|---|
| Аналітика | 1-2 тижні | Збір та очистка даних, побудова профілів користувачів |
| Проєктування | 1 тиждень | Вибір метрик, стеку (PyTorch, Hugging Face, Anthropic) |
| Розробка | 2-4 тижні | Код рекомендаційної системи та інтеграція з ESP |
| Тестування | 1-2 тижні | A/B-тест на 10% бази, вимірювання Open Rate та CTR |
| Деплой | 1 тиждень | Впровадження на повний обсяг, моніторинг |
Типові помилки при впровадженні
- Недостатність даних для холодного старту. Якщо у нових користувачів немає історії, рекомендації будуть неточними. Рішення — використовувати популярні товари як fallback і поступово збирати дані через A/B-тести.
- Ігнорування часу відправлення. Навіть ідеальний лист не відкриють, якщо він прийшов о 3 годині ночі. ML-модель повинна враховувати часові зони та звички кожного клієнта.
- Переоптимізація під CTR. Гонитва за кліками може призвести до агресивних CTA, які дратують користувачів. Важливо балансувати між залученням та довгостроковим LTV.
Що входить в роботу?
- Аудит поточної email-стратегії — аналіз відкриваності, сегментів, контенту.
- Розробка ML-моделі — підбір алгоритму рекомендацій та LLM для генерації контенту.
- Інтеграція з CRM/ESP — API-з'єднання з вашою платформою розсилок (Mailchimp, SendPulse, власна).
- A/B-тестування — порівняння персоналізованих листів з контрольною групою.
- Документація та навчання — передача коду, інструкції для маркетологів, навчання команди.
- Підтримка 3 місяці — моніторинг метрик, доналаштування моделей.
Ми займаємося AI-персоналізацією понад 5 років і реалізували 50+ проєктів для e-commerce, fintech та edtech. Гарантуємо підвищення Open Rate щонайменше на 20% – при невиконанні доналаштовуємо безкоштовно. Оцінимо ваш проєкт за 1-2 дні, отримайте консультацію та зв'яжіться з нами, щоб обговорити деталі.







