Разработка алгоритмической ленты рекомендаций в мобильном приложении
Мы разрабатываем алгоритмические ленты рекомендаций для мобильных приложений, которые в реальном времени ранжируют контент под каждого пользователя. В отличие от хронологической ленты, наша система использует 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). Контекст устройства (время суток, тип сети, заряд батареи) также улучшает ранжирование.
| Тип сигнала | Примеры | Вес в ранжировании |
|---|---|---|
| Явные | 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 месяца)
Ориентиры по срокам
| Этап | Сроки |
|---|---|
| Аудит и проектирование | 1–2 недели |
| Разработка клиента | 2–3 недели |
| Серверный ранкер (опционально) | 4–6 недель |
| A/B тестирование | 2–3 недели |
Стоимость рассчитывается индивидуально, в зависимости от объёма контента, требуемой латентности и наличия готовой аналитической инфраструктуры.
Почему стоит выбрать нас
Мы имеем 5+ лет опыта в разработке рекомендательных систем и реализовали более 30 проектов в этой области. Наши инженеры владеют полным стеком: Swift, Kotlin, Flutter, Python, ML. Гарантируем стабильную работу ленты под высокой нагрузкой и прозрачную отчётность на каждом этапе.
Свяжитесь с нами, чтобы обсудить вашу задачу и получить предварительную оценку бюджета.







