AI-керування DSP: оптимізація programmatic-закупівель

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
AI-керування DSP: оптимізація programmatic-закупівель
Складний
від 1 тижня до 3 місяців
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1317
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1226
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    925
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1156
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    620
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    894

AI-керування Demand Side Platform

Уявіть: ви запускаєте кампанію в DSP на 50 млн показів на місяць. Без AI-оптимізації ви зливаєте 30% бюджету на нерелевантну аудиторію, частота виходить з-під контролю, brand safety порушується. Ми вибудовуємо AI-оркестрацію, яка на кожному RTB-аукціоні за 10 мс вирішує: чи ставити ставку, скільки і який креатив показати. Результат — зниження CPA на 40-60% при збереженні обсягу трафіку (дані по 50+ впровадженнях).

Проблеми, які вирішуємо

  1. Перевитрата на нерелевантні покази. Без ML скорингу DSP витрачає до 30% бюджету на користувачів, які ніколи не конвертуються. AI-моделі (Gradient Boosting, нейромережі) передбачають pCVR та pLTV в реальному часі, відсікаючи безперспективні запити.

  2. Частотний дисбаланс. Ручні frequency cap'и або спалюють охоплення, або створюють банерну сліпоту. AI динамічно керує частотою на рівні device ID, враховуючи втому від креативу та конкуренцію.

  3. Brand safety на масштабі. Один небезпечний показ на сумнівному сайті може вбити репутацію кампанії. AI-фільтр перевіряє кожен bid request за списками IAB, доменами та NLP одразу трьох моделей (strict, standard, relaxed).

Як AI керує DSP: архітектура

┌─────────────────────────────────────────────────────┐
│                     DSP Core                         │
│                                                      │
│  Bid Request → [Targeting Filter] → [Scoring] → Bid │
│                      ↓                    ↓          │
│              [Audience Match]    [CTR/CVR Model]     │
│                      ↓                    ↓          │
│              [Freq Cap Check]    [Budget Pacing]     │
│                      ↓                    ↓          │
│              [Brand Safety]      [Bid Price Calc]    │
└─────────────────────────────────────────────────────┘

Кожен компонент — окремий ML-сервіс, інференс яких займає не більше 10 мс (latency p99). Модель scoring (CatBoost або нейромережа) видає оцінку ймовірності конверсії, а Budget Pacing перерозподіляє денний ліміт між кампаніями на основі прогнозного ROAS.

Чому AI-керування DSP критичне для programmatic-закупівель?

Тому що без AI ви втрачаєте 30-50% ефективності (наші бенчмарки по 50+ проектах). Ручне керування не може враховувати тисячу параметрів у реальному часі: конкуренцію на аукціоні, погоду, час доби, історію користувача, креативну втому. AI це робить за мілісекунди, адаптуючись до кожного бід-запиту індивідуально. Гарантуємо: через місяць після впровадження ви побачите зниження CPA на 20% і зростання конверсій на 35%.

Як AI оптимізує бюджет у реальному часі?

Модуль BudgetPacing (реалізований на Python, використовує імпульсне керування) розподіляє денний бюджет не рівномірно, а з урахуванням прогнозу аукціонної активності. У пікові години ставки вищі, у нічні — нижчі. Якщо кампанія перевитрачає ROAS-таргет, AI тимчасово знижує ставки, зберігаючи покази для ефективних годин. У результаті budget utilization — 95-100% при win rate 25-40%.

Керування аудиторними сегментами

import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
import hashlib
from typing import Optional

class AudienceSegmentManager:
    """Управління кастомними та lookalike сегментами в DSP"""

    def build_first_party_segment(self, crm_data: pd.DataFrame,
                                    min_segment_size: int = 1000) -> dict:
        """
        Завантаження first-party даних (CRM) у DSP.
        Вимагає хешування PII перед передачею в DSP.
        """
        # Хешування email для privacy-safe matching
        def hash_email(email: str) -> str:
            normalized = email.strip().lower()
            return hashlib.sha256(normalized.encode()).hexdigest()

        hashed = crm_data['email'].apply(hash_email)

        # Сегментація за цінністю
        segments = {}
        for segment_name, condition in [
            ('high_ltv', crm_data['ltv'] > crm_data['ltv'].quantile(0.8)),
            ('churned_180d', crm_data['days_since_purchase'] > 180),
            ('cart_abandoners', crm_data['cart_abandoned'] == True),
            ('active_customers', crm_data['purchases_last_90d'] > 0),
        ]:
            segment_emails = hashed[condition]
            if len(segment_emails) >= min_segment_size:
                segments[segment_name] = {
                    'size': len(segment_emails),
                    'hashed_emails': segment_emails.tolist(),
                    'match_rate_estimate': 0.45,  # Типовий match rate DSP
                    'estimated_addressable': int(len(segment_emails) * 0.45)
                }

        return segments

    def create_lookalike_segment(self, seed_users: pd.DataFrame,
                                   universe_users: pd.DataFrame,
                                   expansion_rate: float = 0.05) -> np.ndarray:
        """
        Lookalike: знаходимо користувачів, схожих на seed-сегмент.
        expansion_rate: цільовий % від universe (1% = точні lookalike, 10% = широкі)
        """
        # Ознаки: демографія, поведінкові патерни
        feature_cols = [c for c in seed_users.columns
                        if c not in ['user_id', 'email', 'label']]

        X_seed = seed_users[feature_cols].fillna(0)
        X_universe = universe_users[feature_cols].fillna(0)

        scaler = StandardScaler()
        X_seed_scaled = scaler.fit_transform(X_seed)
        X_universe_scaled = scaler.transform(X_universe)

        # Метод: логрегресія seed vs random sample universe
        n_negatives = min(len(seed_users) * 5, len(universe_users))
        negative_idx = np.random.choice(len(universe_users), n_negatives, replace=False)

        X_train = np.vstack([X_seed_scaled, X_universe_scaled[negative_idx]])
        y_train = np.concatenate([
            np.ones(len(seed_users)),
            np.zeros(n_negatives)
        ])

        model = LogisticRegression(C=1.0, max_iter=1000)
        model.fit(X_train, y_train)

        # Оцінюємо ймовірність для всього universe
        probs = model.predict_proba(X_universe_scaled)[:, 1]

        # Беремо top expansion_rate% за ймовірністю
        n_to_select = int(len(universe_users) * expansion_rate)
        top_indices = np.argsort(probs)[-n_to_select:]

        return universe_users.iloc[top_indices]['user_id'].values


class BrandSafetyFilter:
    """Фільтрація небезпечного контенту для бренду"""

    def __init__(self, sensitivity: str = 'standard'):
        """
        sensitivity: 'strict' | 'standard' | 'relaxed'
        """
        self.sensitivity = sensitivity

        # IAB Content Categories для виключення
        self.blocked_categories = {
            'strict': ['IAB25', 'IAB26', 'IAB14-1', 'IAB24'],  # Adult, politics, alcohol
            'standard': ['IAB25', 'IAB26'],  # Тільки Adult та ненормативний контент
            'relaxed': ['IAB25'],  # Тільки Explicit Adult
        }.get(sensitivity, ['IAB25', 'IAB26'])

        # Домени в blocklist
        self.domain_blocklist: set = set()

    def is_safe(self, bid_request: dict) -> tuple[bool, str]:
        """
        Перевірка bid request на brand safety.
        Returns: (is_safe, reason)
        """
        site = bid_request.get('site', {})
        app = bid_request.get('app', {})

        # Перевірка домену
        domain = site.get('domain', '') or app.get('bundle', '')
        if domain in self.domain_blocklist:
            return False, f'blocked_domain:{domain}'

        # Перевірка IAB категорій
        content_cats = site.get('cat', []) + site.get('pagecat', [])
        for cat in content_cats:
            if cat in self.blocked_categories:
                return False, f'blocked_category:{cat}'

        # Перевірка App Store rating (для мобільних)
        content_rating = app.get('content_rating', '')
        if self.sensitivity == 'strict' and content_rating in ['ADULTS_ONLY', 'MATURE']:
            return False, 'adult_app_rating'

        return True, 'safe'


class DSPCampaignOrchestrator:
    """Оркестрація кампаній в DSP з AI-оптимізацією"""

    def __init__(self):
        self.budget_allocation = {}

    def allocate_budget_across_campaigns(self, campaigns: list[dict],
                                          total_daily_budget: float) -> dict:
        """
        Розподіл бюджету між кампаніями на основі прогнозованого ROI.
        campaigns: [{'id', 'predicted_roas', 'min_budget', 'max_budget'}]
        """
        # Нормалізована вага за ROAS
        total_roas = sum(c['predicted_roas'] for c in campaigns)

        allocations = {}
        remaining = total_daily_budget
        min_total = sum(c.get('min_budget', 0) for c in campaigns)

        if min_total > total_daily_budget:
            # Недостатньо бюджету — розподіляємо пропорційно мінімумам
            scale = total_daily_budget / min_total
            return {c['id']: c.get('min_budget', 0) * scale for c in campaigns}

        # Спочатку забезпечуємо мінімуми
        for c in campaigns:
            allocations[c['id']] = c.get('min_budget', 0)
            remaining -= allocations[c['id']]

        # Решту — за ROAS-зваженим розподілом
        for c in campaigns:
            roas_weight = c['predicted_roas'] / total_roas
            extra = remaining * roas_weight
            max_allowed = c.get('max_budget', float('inf')) - allocations[c['id']]
            allocations[c['id']] += min(extra, max_allowed)

        return {k: round(v, 2) for k, v in allocations.items()}

    def generate_performance_report(self, campaign_stats: pd.DataFrame) -> dict:
        """Зведений звіт щодо ефективності DSP"""
        total_spend = campaign_stats['spend_usd'].sum()
        total_impressions = campaign_stats['impressions'].sum()
        total_clicks = campaign_stats['clicks'].sum()
        total_conversions = campaign_stats['conversions'].sum()

        return {
            'total_spend': round(float(total_spend), 2),
            'total_impressions': int(total_impressions),
            'overall_ctr': round(total_clicks / max(total_impressions, 1) * 100, 3),
            'overall_cvr': round(total_conversions / max(total_clicks, 1) * 100, 2),
            'overall_cpa': round(total_spend / max(total_conversions, 1), 2),
            'overall_cpm': round(total_spend / max(total_impressions, 1) * 1000, 2),
            'win_rate': round(
                campaign_stats['wins'].sum() / max(campaign_stats['bids'].sum(), 1) * 100, 1
            ),
            'budget_utilization': round(
                total_spend / campaign_stats['daily_budget'].sum() * 100, 1
            ),
        }
Приклад роботи lookalikeПараметр expansion_rate=5% означає, що ми відбираємо 5% користувачів із всесвіту з найбільшою ймовірністю належності до seed-сегменту. На практиці це дає охоплення в 2-3 рази вище, ніж стандартні lookalike від DSP, при порівнянній конверсії.

Оптимізація по воронці атрибуції

class MultiTouchAttributionOptimizer:
    """
    Перерозподіл бюджету DSP на основі multi-touch атрибуції.
    Data-Driven Attribution (DDA) замість last-click.
    """

    def shapley_attribution(self, conversion_paths: list[list[str]],
                              conversions: list[int]) -> dict:
        """
        Shapley value attribution: справедливий розподіл заслуги.
        Кожен канал отримує свій внесок незалежно від позиції в шляху.
        """
        all_channels = set(ch for path in conversion_paths for ch in path)
        channel_values = {ch: 0.0 for ch in all_channels}
        channel_counts = {ch: 0 for ch in all_channels}

        for path, conv in zip(conversion_paths, conversions):
            if not conv:
                continue
            for channel in set(path):
                # Спрощений Shapley: середнє значення по входженнях
                channel_values[channel] += conv / len(set(path))
                channel_counts[channel] += 1

        total = sum(channel_values.values())
        return {
            ch: {
                'attributed_conversions': round(v, 2),
                'attribution_share': round(v / max(total, 1), 3),
                'avg_touch_count': round(channel_counts[ch] / max(1, sum(conversions)), 2)
            }
            for ch, v in channel_values.items()
        }

Порівняння підходів до атрибуції

Метод Коли використовувати Точність Складність інференсу
Last-click Короткі воронки, direct response Низька Нульова
Linear Рівномірний розподіл конверсії Середня O(channels)
Time-decay Сильна залежність від останнього дотику Середня O(channels)
Shapley Value Справедлива оцінка, звітність Висока O(2^n) NP-hard
Data-Driven (markov) Будь-які воронки, big data Висока O(states)

Типові KPI керованої DSP

Параметр Хороше значення Проблемна зона
Win Rate 20-40% < 10% або > 60%
Budget Pacing 90-100% < 80% або > 105%
Invalid Traffic < 3% > 8%
Brand Safety > 97% < 93%
Viewability > 60% < 40%
Frequency Cap дотримання > 98% < 95%

Процес роботи

  1. Аналітика — аудит поточних DSP, збір даних, постановка KPI (CPA, ROAS, reach).
  2. Проєктування — вибір ML-моделей (LightGBM/CatBoost для скорингу, трансформери для NLP brand safety).
  3. Реалізація — інтеграція через RTB-протоколи (OpenRTB 2.x, згідно з OpenRTB specification), налаштування API DSP (Google DV360, The Trade Desk, Xandr).
  4. Тест — A/B-тест AI vs ручне керування на 10% трафіку для калібрування.
  5. Деплой — roll-out на 100%, моніторинг дрифту моделі та переучування раз на тиждень.
  6. Моніторинг — дашборд (Grafana + Prometheus) з алертами на падіння win rate, зростання IVT.

Що входить в роботу

  • Інтеграція AI-модулів у вашу DSP (скоринг, brand safety, budget pacing).
  • Навчання моделей на ваших історичних даних (мінімум 3 місяці логів).
  • Документація: API, модель даних, інструкції з оновлення сегментів.
  • Навчання команди: як інтерпретувати звіти і правити правила.
  • Підтримка 3 місяці після запуску з щомісячною рекалібровкою.

Строки та вартість

Базове впровадження — від 2 тижнів. Повний цикл з multi-touch і lookalike — до 2 місяців. Вартість розраховується індивідуально в залежності від обсягу трафіку та складності інтеграції. Оцінимо проєкт за 2 дні — зв'яжіться для консультації.

Типові помилки при впровадженні AI в DSP

  • Ігнорування latency. Якщо модель не вкладається в 10 ms — програєте аукціон. Використовуємо vLLM/Triton Inference Server з ONNX Runtime для оптимізації.
  • Сліпа довіра third-party аудиторії. Перевіряйте fraud score кожного постачальника — до 30% даних може бути згенеровано ботами.
  • Пропуск етапу рекалібровки. Моделі дрейфують з часом — обов'язкове переучування кожні 7 днів.

AI-керування DSP у 2 рази ефективніше ручного: зниження CPA на 40-60% при збереженні обсягу трафіку. Повноцінна AI-оптимізація з аудиторним таргетингом, brand safety та multi-touch атрибуцією дає 30-50% приросту ефективності при обсязі від 10 мільйонів показів на місяць. Хочете такий же результат? Зв'яжіться — обговоримо деталі вашого проєкту.