Розробка алгоритмічної стрічки рекомендацій у мобільному додатку
Ми розробляємо алгоритмічні стрічки рекомендацій для мобільних додатків, які в реальному часі ранжують контент під кожного користувача. Джерело: Wikipedia На відміну від хронологічної стрічки, наша система використовує predicted engagement score та збирає сигнали прямо з додатка: від video_completion_rate до швидкості свайпу. Це дозволяє підвищити залученість на 20–40% (за досвідом наших проектів). За 5+ років роботи ми реалізували такі фіди для новинних, відео та E-commerce додатків — і накопичили інженерні практики, якими ділимося нижче. Гарантуємо стабільну роботу навіть при пікових навантаженнях.
Як влаштована архітектура стрічки рекомендацій?
Алгоритмічна стрічка працює в два етапи, і мобільний додаток критично залежить від обох.
Candidate generation — з мільйонів одиниць контенту відбираємо кілька сотень кандидатів для конкретного користувача. Зазвичай це полегшена модель (Approximate Nearest Neighbor по user embedding) або набір правил: followed users, trending in geo, topic affinity. Цей етап має вкладатися в 50–100ms.
Ranking — кандидати ранжуються важкою моделлю, яка передбачає ймовірність взаємодії (like, share, comment, completion rate). Gradient boosted trees (XGBoost, LightGBM), two-tower neural networks або DLRM. Результат — упорядкований список з scores.
Serving — мобільний додаток запитує N наступних елементів стрічки, отримує їх з попередньо розрахованим порядком. Prefetch наступної сторінки до того, як користувач дійде до кінця поточної.
Чому якість сигналів вирішує все?
Якість алгоритму визначається якістю сигналів. Мобільний додаток — головне джерело. Збираємо явні (like, share, comment) та неявні сигнали (completion rate, dwell time, swipe away velocity). Контекст пристрою (час доби, тип мережі, заряд батареї) також покращує ранжування. Машинне навчання дає приріст залученості на 20–40% порівняно з хронологічною стрічкою.
| Тип сигналу | Приклади | Вага в ранжуванні |
|---|---|---|
| Явні | like, share, comment | Високий |
| Неявні | completion rate, dwell time | Середній |
| Контекстні | час доби, тип мережі | Низький (але покращує) |
| Негативні | skip < 0.5s, report | Дуже високий |
Трекінг video completion на iOS:
Приклад реалізації на iOS
class VideoProgressTracker {
private var timeObserver: Any?
private let player: AVPlayer
private let itemId: String
private var maxProgress: Float = 0
init(player: AVPlayer, itemId: String) {
self.player = player
self.itemId = itemId
setupObserver()
}
private func setupObserver() {
let interval = CMTime(seconds: 0.5, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
guard let self,
let duration = self.player.currentItem?.duration.seconds,
duration > 0 else { return }
let progress = Float(time.seconds / duration)
if progress > self.maxProgress {
self.maxProgress = progress
}
}
}
func reportCompletion() {
Analytics.track(.videoProgress(itemId: itemId,
completionRate: maxProgress,
source: .algorithmicFeed))
}
}
На Android — ExoPlayer c AnalyticsListener.onPlaybackStateChanged() і Player.Listener.onPositionDiscontinuity().
Як реалізувати нескінченний скрол без втрати UX?
Користувач не має бачити лоадер при скролі. Стандартний підхід: підвантажуємо наступну сторінку, коли користувач дійшов до передостаннього елемента поточної. Prefetch з порогом 7–10 елементів для відео-стрічки скорочує час завантаження в 2–3 рази порівняно з відсутністю prefetch.
// Android, RecyclerView + ViewModel
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val lastVisible = layoutManager.findLastVisibleItemPosition()
val total = layoutManager.itemCount
if (total - lastVisible <= PREFETCH_THRESHOLD) {
viewModel.loadNextPage()
}
}
})
PREFETCH_THRESHOLD — зазвичай 3–5 елементів. Для відео-стрічки збільшуємо до 7–10, тому що завантаження відео довше. Дедуплікація: сервер може повернути один і той же item у двох пагінованих відповідях. Клієнт зберігає Set<String> показаних ID і фільтрує дублі перед додаванням у список.
Як ми тестуємо та запускаємо?
Нову версію ранжуючої моделі не викочують одразу на всіх. Типова схема: 5% трафіку → 20% → 50% → 100%, з моніторингом метрик сесії (retention D1/D7, середній час у додатку, engagement rate) на кожному кроці. Feature flags керуються через Firebase Remote Config або власну систему. Клієнт передає experiment_variant у кожному запиті до feed API — це дозволяє серверу вибрати потрібний ранкер.
Що входить у роботу
- Аудит поточного трекінгу та аналітики
- Проектування event schema та архітектури стрічки
- Розробка клієнтської частини (iOS/Android) з prefetch, дедуплікацією, трекінгом
- Інтеграція з feed API (REST/GraphQL)
- Реалізація пояснювальних міток (explanation labels) та UI контролю
- Налаштування A/B тестування та моніторингу
- Документація та код-рев'ю
- Підтримка після запуску (2 місяці)
Пропонуємо впровадження під ключ за 2-3 місяці.
Орієнтири за термінами
| Етап | Терміни |
|---|---|
| Аудит і проектування | 1–2 тижні |
| Розробка клієнта | 2–3 тижні |
| Серверний ранкер (опціонально) | 4–6 тижнів |
| A/B тестування | 2–3 тижні |
Вартість базової інтеграції від $5000.
Чому варто обрати нас
Ми маємо 5+ років досвіду в розробці рекомендаційних систем і реалізували понад 30 проектів у цій галузі. Наші інженери володіють повним стеком: Swift, Kotlin, Flutter, Python, ML. Гарантуємо стабільну роботу стрічки під високим навантаженням і прозору звітність на кожному етапі.
Зв'яжіться з нами, щоб обговорити ваше завдання та отримати попередню оцінку бюджету.







