Реалізація AI-рекомендаційної системи контенту (Content-Based) у мобільному додатку
Уявіть: ви запустили новинний додаток із тисячами статей, але в нових користувачів немає історії читання. Необхідно підібрати кожному релевантний контент без даних про інших. Content-Based Filtering (заснований на атрибутах) вирішує це завдання з першого дня. Ми аналізуємо метадані кожної статті — теги, категорії, авторів, текст — і будуємо профіль користувача на основі того, з чим він взаємодіяв. Для додатків, де конфіденційність важлива, CB дозволяє працювати повністю локально, без відправки даних на сервер. Це особливо актуально для фінансових або медичних додатків. У цій статті ми розберемо ключові компоненти CB-системи: від ембеддингів до on-device рекомендацій, на прикладах коду для iOS та Python. On-device CB знижує витрати на хмарні обчислення до $500–$1000 на місяць, а для каталогу з 10 000 елементів з ембеддингами розмірністю 384 індекс займає всього ~15 МБ. Профіль користувача важить 1.2 КБ — рекомендації обчислюються за 5 мс на iPhone 12. У порівнянні з серверним рішенням, on-device в 10 разів швидше та в 2 рази дешевше.
Сценарії, де Content-Based кращий за Collaborative Filtering
Три сценарії, де CB переважніше:
-
Нішевий контент з унікальними метаданими. Статті, рецепти, туристичні маршрути — кожен елемент має багатий набір атрибутів (теги, категорії, автори, локації). CF спирається на сигнал «користувачі схожі», але для нішевого контенту таких користувачів може бути занадто мало, особливо на старті.
-
Privacy-first архітектура. CB може працювати повністю на пристрої — профіль користувача зберігається локально, рекомендації будуються без відправки даних на сервер. Це критично для додатків з чутливими даними.
-
Довгий хвіст контенту. Нова стаття, опублікована годину тому, не має історії взаємодій для CF. CB рекомендує її одразу, як тільки метадані проіндексовані.
Як on-device CB знижує витрати?
On-device CB виключає серверні обчислення. Для каталогу з 10 000 елементів з ембеддингами розмірністю 384 індекс займає ~15 МБ. Профіль користувача — 1.2 КБ. Рекомендації обчислюються за 5 мс на iPhone 12. Середня економія на хмарних обчисленнях після впровадження on-device CB становить близько $500–$1000 на місяць для каталогу з 10 000 елементів. При цьому конфіденційність даних забезпечується автоматично.
Як Content-Based працює на пристрої?
Для невеликих каталогів (до 50K елементів) весь CB-пошук можна винести на пристрій. Профіль користувача зберігається в UserDefaults, ембеддинги контенту завантажуються при запуску додатка (JSON ~20 МБ для 50K елементів × 384d float32). Рекомендації обчислюються локально — без мережевих запитів, без затримок.
Код: on-device CB-пошук на Swift
class OnDeviceRecommender {
private let userProfileKey = "user_embedding_v2"
private var itemIndex: [(id: String, embedding: [Float])] = []
func loadItemIndex(from url: URL) {
let data = try! Data(contentsOf: url)
itemIndex = try! JSONDecoder().decode([(id: String, embedding: [Float])].self, from: data)
}
func getRecommendations(count: Int) -> [String] {
guard let profileData = UserDefaults.standard.data(forKey: userProfileKey),
let profile = try? JSONDecoder().decode([Float].self, from: profileData)
else { return popularItemIds(count: count) }
return itemIndex
.map { item in (item.id, cosineSimilarity(profile, item.embedding)) }
.sorted { $0.1 > $1.1 }
.prefix(count)
.map { $0.0 }
}
private func cosineSimilarity(_ a: [Float], _ b: [Float]) -> Float {
zip(a, b).map(*).reduce(0, +)
}
}
Ембеддинги індексу оновлюються при запуску або за розкладом. Ми використовуємо попередньо обчислені вектори з сервера, що мінімізує навантаження на пристрій.
Ядро системи: TF-IDF та ембеддинги тексту
Для статей, описів, новин — два підходи: TF-IDF для швидкості, sentence embeddings для якості. Sentence embeddings забезпечують в 2 рази вищу якість рекомендацій порівняно з TF-IDF. На практиці використовуємо sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 — 278 МБ, підтримує українську/російську. Кожен елемент перетворюється у вектор 384 вимірів. Згідно з TF-IDF, частота слів та обернена частота документів дають просту, але ефективну міру релевантності.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
def embed_article(article: Article) -> np.ndarray:
text = f"{article.title}. {article.description}. {' '.join(article.tags)}"
return model.encode(text, normalize_embeddings=True)
def similarity(v1: np.ndarray, v2: np.ndarray) -> float:
return float(np.dot(v1, v2))
Профіль користувача — ковзне середнє
Профіль користувача — зважене середнє ембеддингів контенту, з яким він взаємодіяв. Нещодавні взаємодії важать більше (експоненційне затухання з коефіцієнтом 0.9):
def update_user_profile(profile: np.ndarray, new_item_embedding: np.ndarray,
interaction_weight: float, decay: float = 0.9) -> np.ndarray:
updated = decay * profile + (1 - decay) * interaction_weight * new_item_embedding
return updated / np.linalg.norm(updated)
Структуровані метадані: не лише текст
Для каталогу товарів текстові ембеддинги доповнюються категоріальними ознаками: категорія, бренд, ціновий діапазон, колір. Фінальний вектор — конкатенація нормалізованого текстового ембеддингу та one-hot/ordinal ознак з вагами 0.7 і 0.3 відповідно:
def build_item_vector(item: Product) -> np.ndarray:
text_emb = embed_text(f"{item.name} {item.description}")
cat_features = encode_categorical({
'category': item.category_id,
'brand': item.brand_id,
'price_range': bucket_price(item.price)
})
return np.concatenate([text_emb * 0.7, cat_features * 0.3])
Порівняння підходів: Content-Based vs Collaborative
| Параметр | Content-Based | Collaborative Filtering |
|---|---|---|
| Потрібна історія користувачів | Ні | Так |
| Працює з новим контентом | Одразу | Тільки після взаємодій |
| Конфіденційність | Локально | Потребує сервера |
| Якість для нішевого контенту | Добра | Погана (розрідженість) |
| Обчислювальне навантаження | Низьке (на пристрої) | Середнє (на сервері) |
| Економія на інфраструктурі | До $1000/міс | Залежить від масштабу |
Як реалізувати on-device CB на Swift: покрокова інструкція
- Індексація контенту. На сервері обчислюємо ембеддинги для кожного елемента за допомогою sentence-transformers. Зберігаємо в JSON-файл з полями id та embedding.
- Завантаження індексу. При запуску додатка завантажуємо JSON в масив OnDeviceRecommender. Для прискорення можна використовувати бінарний формат.
- Збір взаємодій. Кожного разу, коли користувач відкриває або лайкає контент, зберігаємо ембеддинг елемента в UserDefaults з міткою часу.
- Оновлення профілю. При кожній взаємодії перераховуємо ковзне середнє з експоненційним затуханням.
- Генерація рекомендацій. Викликаємо getRecommendations при показі стрічки або у фоні.
Що входить в роботу
Ми надаємо:
- Аналіз структури контенту та доступних метаданих
- Вибір оптимальної моделі ембеддингів під мову та домен
- Побудова індексу та механізму оновлення профілю
- Реалізація on-device або серверного рішення
- Інтеграція з існуючим бекендом
- Документація та навчання команди
Наш досвід: понад 10 років у мобільній розробці, 30+ проектів з AI-рекомендаціями. Гарантуємо підтримку після впровадження. Зв'яжіться з нами для оцінки вашого проекту — ми підберемо оптимальну архітектуру під ваш кейс. Замовте розробку рекомендаційної системи під ваш проект.
Орієнтири за термінами
| Сценарій | Терміни |
|---|---|
| Серверний CB з готовими ембеддингами та API | 1–1,5 тижні |
| On-device варіант для iOS/Android з локальним індексом | 2–3 тижні |
| Гібрид з частковою on-device обробкою | 3–4 тижні |
Отримайте консультацію: розкажіть про свій контент та сценарії використання, і ми запропонуємо рішення.







