Проблема: чому косметика підходить не всім
Клієнт купує дорогий крем з ретинолом, а через тиждень отримує подразнення. Або наносить vitamin C вранці разом з AHA — і отримує пілінг. Звичайні рекомендаційні системи (collaborative filtering) спираються на поведінку натовпу, ігноруючи біохімію шкіри. Результат — повернення 15–25% у категорії догляду.
Наша AI-система підбору косметики враховує тип шкіри, клімат, вік, поточний догляд і сумісність інгредієнтів. Повернення падають на 30%, конверсія зростає на 18–30%. Більше 10 років досвіду в ML для beauty e-commerce, 12+ впроваджень з каталогами від 500 до 50 000 SKU. Середня економія магазину на поверненнях — до кількох сотень тисяч гривень на місяць.
Які складнощі вирішуємо
- Несумісність інгредієнтів: retinol + vitamin C, AHA + retinol, benzoyl peroxide + retinol. Ці пари викликають подразнення або нейтралізують один одного. Двигун аналізує комбінації та пропонує розділення на AM/PM або заміну.
- Ігнорування типу шкіри: жирній потрібні саліцилова кислота та ніацинамід, сухій — кераміди та гіалуронка. Стандартні рекомендації не розрізняють.
- Сезонність і клімат: взимку потрібні щільні текстури, влітку — легкі. Система адаптується під регіон.
- Перевантаження користувача: видавати 50 продуктів марно. Віддаємо топ-5 з поясненням, чому саме вони.
Як AI-система враховує сумісність компонентів?
В основі — content-based filtering з ручними правилами несумісності. Кожен продукт представлений вектором ознак: інгредієнти, тип шкіри, рейтинг. Для користувача будується профіль (анкета або історія). Потім рахуємо косинусну близькість, попередньо відфільтрувавши несумісні пари. Це дозволяє давати персоналізовані рекомендації догляду.
Типовий кейс: клієнт хоче anti-age сироватку з ретинолом і зволожувальний крем з vitamin C. Двигун виявляє конфлікт і пропонує: «Ретинол — на ніч, vitamin C — вранці, використовуйте SPF вдень». Або замінює vitamin C на пептиди. Реалізовано на Python + pandas + sklearn:
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class SkincareRecommender:
def build_skin_profile(self, user_data: dict) -> dict:
return {
'skin_type': user_data.get('skin_type', 'normal'),
'concerns': user_data.get('concerns', []),
'sensitivities': user_data.get('sensitivities', []),
'current_routine': user_data.get('current_products', []),
'climate': user_data.get('climate', 'temperate'),
'age_group': user_data.get('age_group', '25-34'),
}
def check_ingredient_compatibility(self, product_a: dict,
product_b: dict) -> dict:
incompatible_pairs = [
({'retinol', 'retinoids'}, {'vitamin_c', 'ascorbic_acid'}),
({'aha', 'glycolic_acid', 'lactic_acid'}, {'retinol', 'retinoids'}),
({'benzoyl_peroxide'}, {'retinol', 'vitamin_c'}),
({'niacinamide'}, {'vitamin_c'}),
]
ingredients_a = set(product_a.get('key_ingredients', []))
ingredients_b = set(product_b.get('key_ingredients', []))
conflicts = []
for group_a, group_b in incompatible_pairs:
if ingredients_a & group_a and ingredients_b & group_b:
conflicts.append({
'ingredient_a': list(ingredients_a & group_a)[0],
'ingredient_b': list(ingredients_b & group_b)[0],
'recommendation': 'Use at different times of day (AM/PM)'
})
elif ingredients_b & group_a and ingredients_a & group_b:
conflicts.append({
'ingredient_a': list(ingredients_b & group_a)[0],
'ingredient_b': list(ingredients_a & group_b)[0],
'recommendation': 'Use at different times of day'
})
return {
'compatible': len(conflicts) == 0,
'conflicts': conflicts
}
def recommend_for_concern(self, concern: str,
products_catalog: pd.DataFrame,
skin_type: str,
top_k: int = 5) -> list[dict]:
suitable = products_catalog[
products_catalog['suitable_skin_types'].apply(
lambda types: skin_type in types or 'all' in types
)
].copy()
concern_ingredients = {
'acne': ['salicylic_acid', 'benzoyl_peroxide', 'niacinamide', 'zinc'],
'aging': ['retinol', 'peptides', 'hyaluronic_acid', 'vitamin_c'],
'hyperpigmentation': ['vitamin_c', 'niacinamide', 'kojic_acid', 'alpha_arbutin'],
'dryness': ['hyaluronic_acid', 'ceramides', 'glycerin', 'squalane'],
'sensitivity': ['centella_asiatica', 'aloe_vera', 'panthenol', 'allantoin'],
}.get(concern, [])
def concern_score(product_ingredients):
if not isinstance(product_ingredients, list):
return 0
matches = sum(1 for ing in concern_ingredients if ing in product_ingredients)
return matches / max(len(concern_ingredients), 1)
suitable['concern_relevance'] = suitable['key_ingredients'].apply(concern_score)
suitable['final_score'] = (
suitable['concern_relevance'] * 0.6 +
suitable['avg_rating'].fillna(3.5) / 5.0 * 0.3 +
suitable['review_count'].fillna(0).clip(0, 500) / 500 * 0.1
)
top = suitable.nlargest(top_k, 'final_score')
return [
{
'product_id': row['product_id'],
'name': row['name'],
'concern_relevance': round(row['concern_relevance'], 2),
'rating': row.get('avg_rating', 0),
'key_actives': row.get('key_ingredients', [])[:3],
}
for _, row in top.iterrows()
]
Чому саме content-based, а не колаборативна фільтрація?
Косметика — не фільми. Якщо людина купила крем з ретинолом, не потрібно рекомендувати ще три таких самих: шкіра не витримає. Collaborative filtering бачить лише кореляцію покупок, але не знає, що два засоби разом викликають подразнення. У результаті клієнт повертає обидва, магазин втрачає гроші та лояльність. Ми використовуємо гібридні рекомендації для косметики: content-based як ядро + правила несумісності + легкий collaborative для cross-sell (наприклад, «з цим тональним часто беруть консилер»). Це забезпечує і точність, і персоналізацію.Порівняння підходів: content-based vs collaborative filtering
| Характеристика | Content-based (наш) | Collaborative filtering |
|---|---|---|
| Врахування інгредієнтів | Так, повністю | Ні |
| Врахування типу шкіри | Так | Побічно |
| Холодний старт (новий товар) | Працює одразу | Вимагає покупок |
| Точність для нішевих продуктів | Висока | Низька |
| Зниження повернень | 25–35% | 5–10% |
Content-based рекомендації знижують повернення в 3 рази ефективніше порівняно з collaborative filtering — це підтверджено на наших впровадженнях.
Метрики до та після впровадження (приклад)
| Метрика | До | Після |
|---|---|---|
| Return rate | 22% | 8% |
| Conversion rate (категорія догляду) | 3.5% | 5.2% |
| Середній чек (AOV) | 2800 грн | 3200 грн |
| Час підбору (на клієнта) | 15 хв | 2 сек |
Що ви отримаєте в результаті впровадження?
- Розгорнута документація API та моделі даних.
- Вихідний код рекомендаційного двигуна на Python.
- Інтеграція з вітриною (REST/gRPC).
- Навчання команди (2 вебінари + чат підтримки).
- Гарантія на алгоритм (виправлення багів 6 місяців).
- Пост-запуск: щомісячні звіти за метриками.
- Персоналізація догляду за шкірою на основі даних.
Процес впровадження
- Аналітика: аудит каталогу, збір інгредієнтів і типів шкіри, створення матриці конфліктів.
- Проектування: архітектура двигуна, вибір метрик (precision@k, return rate, CR).
- Реалізація: інтеграція з вашим API, сервіс на Python + FastAPI, контейнеризація.
- Тест: A/B-тест на 10% трафіку — порівняння конверсії та повернень.
- Деплой: повний rollout, моніторинг latency (p99 <200 мс), логування рекомендацій.
Терміни та вартість
Терміни: від 4 тижнів (до 1000 SKU) до 12 тижнів (50 000+ SKU з інтеграцією в ERP). Вартість розраховується індивідуально — залежить від обсягу даних і складності логіки. Оцінимо ваш проект за один день після заповнення брифу.
Отримайте консультацію — зв'яжіться з нами, щоб обговорити пілот на ваших даних. Гарантуємо прозорий розрахунок і фіксовані терміни. Замовте впровадження — перші результати через місяць.







