Проблема: почему косметика подходит не всем
Клиент покупает дорогой крем с ретинолом, а через неделю получает раздражение. Или наносит 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). Стоимость рассчитывается индивидуально — зависит от объёма данных и сложности логики. Оценим ваш проект за один день после заполнения брифа.
Получите консультацию — свяжитесь с нами, чтобы обсудить пилот на ваших данных. Гарантируем прозрачный расчёт и фиксированные сроки. Закажите внедрение — первые результаты через месяц.







