Розробка AI-рекомендаційної системи
Рекомендаційна система — це ML-модель, яка передбачає, що користувач захоче подивитися, купити або прочитати далі. Різниця між хорошою та поганою реалізацією: 15–20% виручки в першому випадку проти 2–3% lift у другому. Архітектурних підходів кілька — вибір залежить від обсягу даних, холодного старту та бізнес-контексту.
Вибір архітектури за обсягом даних
| Обсяг трансакцій | Рекомендований підхід | Recall@10 | Latency |
|---|---|---|---|
| < 10K | Content-based + правила | 15–25% | < 5ms |
| 10K – 500K | Matrix Factorization (ALS) | 25–40% | < 20ms |
| 500K – 5M | Two-tower neural + MF ensemble | 35–50% | < 50ms |
| > 5M | Two-tower + GNN + re-ranking | 45–65% | < 100ms |
Two-Tower нейронна архітектура
import torch
import torch.nn as nn
import numpy as np
from torch.utils.data import DataLoader, Dataset
class UserTower(nn.Module):
"""Енкодер користувача"""
def __init__(self, n_users: int, n_categories: int,
embedding_dim: int = 64, hidden_dim: int = 128):
super().__init__()
self.user_emb = nn.Embedding(n_users + 1, embedding_dim, padding_idx=0)
self.category_emb = nn.Embedding(n_categories + 1, 16, padding_idx=0)
self.mlp = nn.Sequential(
nn.Linear(embedding_dim + 16 * 5 + 10, hidden_dim),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(hidden_dim, 64),
nn.LayerNorm(64)
)
def forward(self, user_id, top_categories, behavior_features):
user_vec = self.user_emb(user_id)
cat_vecs = self.category_emb(top_categories).view(top_categories.shape[0], -1)
combined = torch.cat([user_vec, cat_vecs, behavior_features], dim=1)
return self.mlp(combined)
class ItemTower(nn.Module):
"""Енкодер товару/контенту"""
def __init__(self, n_items: int, n_categories: int,
embedding_dim: int = 64, text_dim: int = 128):
super().__init__()
self.item_emb = nn.Embedding(n_items + 1, embedding_dim, padding_idx=0)
self.category_emb = nn.Embedding(n_categories + 1, 16, padding_idx=0)
self.mlp = nn.Sequential(
nn.Linear(embedding_dim + 16 + text_dim + 5, 128),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(128, 64),
nn.LayerNorm(64)
)
def forward(self, item_id, category_id, text_features, item_features):
item_vec = self.item_emb(item_id)
cat_vec = self.category_emb(category_id)
combined = torch.cat([item_vec, cat_vec, text_features, item_features], dim=1)
return self.mlp(combined)
class TwoTowerModel(nn.Module):
def __init__(self, n_users, n_items, n_categories, text_dim=128):
super().__init__()
self.user_tower = UserTower(n_users, n_categories)
self.item_tower = ItemTower(n_items, n_categories, text_dim=text_dim)
self.temperature = nn.Parameter(torch.ones(1) * 0.05)
def forward(self, user_inputs, item_inputs):
user_emb = self.user_tower(**user_inputs)
item_emb = self.item_tower(**item_inputs)
# Cosine similarity
user_norm = nn.functional.normalize(user_emb, dim=1)
item_norm = nn.functional.normalize(item_emb, dim=1)
scores = torch.sum(user_norm * item_norm, dim=1) / self.temperature
return scores
def get_user_embedding(self, user_inputs) -> torch.Tensor:
with torch.no_grad():
return nn.functional.normalize(self.user_tower(**user_inputs), dim=1)
def get_item_embedding(self, item_inputs) -> torch.Tensor:
with torch.no_grad():
return nn.functional.normalize(self.item_tower(**item_inputs), dim=1)
In-Batch Negative Sampling навчання
Мета навчання: максимізувати подібність між користувачем та товаром з contrastive loss (InfoNCE). Типові метрики: Recall@10, NDCG@5, Hit Rate. Two-tower архітектура дозволяє real-time serving через ANN індекси (Milvus, Pinecone) без переобучення вкладень щодня.
Інтеграція через REST API: FastAPI endpoint отримує контекст користувача, повертає top-K кандидатів за < 50ms. Шар персоналізації додає бізнес-правила: немає повторних товарів, дотримуйся фільтрів користувача, різноманітність бренду.
Строки: базова two-tower рекомендаційна система — 3–4 тижні. Production-ready з A/B тестуванням, feature store та real-time оновленнями — 8–12 тижнів.







