Реалізація AI-персоналізації контенту у мобільному додатку
Персоналізація контенту — це не рекомендаційна система в чистому вигляді. Це ширша задача: адаптувати порядок елементів, формат подачі, набір функцій та навіть тональність комунікації під конкретного користувача. ML тут стоїть на кількох опорах: поведінковий профіль, контекстні сигнали (час, локація, пристрій) та явні переваги.
Поведінковий профіль: що та як збирати
Профіль користувача — це вектор ознак, який оновлюється з кожною сесією. Для контентних додатків: які категорії переглядаються частіше, скільки часу витрачається, в яких годинах активний, які формати переважаються (текст / відео / короткий / довгий).
struct UserContentProfile: Codable {
var categoryWeights: [String: Double] // "tech": 0.7, "sports": 0.2
var formatPreferences: FormatPrefs
var activeHours: [Int: Double] // година -> ймовірність активності
var sessionCount: Int
var lastUpdated: Date
struct FormatPrefs: Codable {
var longReadScore: Double // 0..1
var videoScore: Double
var shortPostScore: Double
}
}
Оновлюйте профіль локально після кожної сесії — не чекайте серверної відповіді. Синхронізуйте на сервер у фоні через BGAppRefreshTask (iOS) або WorkManager (Android).
Контекстна персоналізація
Одні й ті ж користувачі поводять себе по-різному вранці та вечері, на роботі та вдома. Контекстні сигнали:
- Час доби — вранці короткі формати, вечері довгі матеріали
- День тижня — вихідні vs робочі дні
- Тип мережі — на WiFi можна завантажувати HD-превью, на LTE — ні
- Рівень батареї — при < 20% не запускати фонове завантаження
data class RequestContext(
val hourOfDay: Int,
val dayOfWeek: Int,
val networkType: NetworkType,
val batteryLevel: Float,
val location: LocationCluster? // не точна геолокація, а кластер (дім/робота)
)
class ContentRanker(private val model: TFLiteModel) {
fun rank(items: List<ContentItem>, profile: UserProfile, context: RequestContext): List<ContentItem> {
val featureMatrix = buildFeatureMatrix(items, profile, context)
val scores = model.run(featureMatrix) // Float32 array
return items.zip(scores.toList()).sortedByDescending { it.second }.map { it.first }
}
}
Персоналізація інтерфейсу
Крім контенту — сам інтерфейс. Firebase Remote Config дозволяє змінювати порядок секцій головного екрана без релізу. Growth Book або Statsig — для більш складних експериментів з UI-варіантами.
Конкретний приклад: у новинному додатку блок «Для вас» для користувачів з > 30 сесіями показується першим, для нових — після блоку «Популярне». Це просте правило помітно впливає на утримання.
Персоналізація push-сповіщень — окреме завдання. Не розсилайте одне й те ж усім. Firebase ML + Audience Builder або власна модель передбачення оптимального часу відправки для кожного користувача. Push у невідповідний час = unsubscribe.
On-Device vs Server персоналізація
| Підхід | Затримка | Приватність | Якість |
|---|---|---|---|
| Повністю серверний | 100–500 мс | Дані на сервері | Висока |
| Локальні правила | 0 мс | Дані на пристрої | Середня |
| TFLite/CoreML re-rank | < 10 мс | Дані на пристрої | Хороша |
Нормативні вимоги (GDPR, CCPA) впливають на вибір: не можна передавати поведінкові дані — on-device примусово.
Уникайте «бульбашок»
Чиста персоналізація створює filter bubble — користувач бачить тільки те, що вже цікавило. Це знижує discovery та час у додатку через кілька тижнів. Стандартне рішення: exploration coefficient — 10–15% слотів відповідає не топу за релевантністю, а випадковим висококачественим матеріалам з необроблених категорій.
Процес реалізації
Аудит поточних подій та даних. Проектування профілю користувача та схеми оновлення. Вибір архітектури персоналізації. Реалізація ранкера (on-device або server). Інтеграція контекстних сигналів. A/B-тест з контрольною групою (без персоналізації). Аналітика: retention, DAU, CTR персоналізованих блоків.
Орієнтири за часом
Rule-based персоналізація без ML — 1–2 тижні. Повна система з on-device ранкером, профілем користувача, A/B-тестуванням та аналітикою — 6–12 тижнів.







