Skip to main content

AI/ML System Design for CTR and Conversion Rate Prediction

Comprehensive system design for real-time click-through rate and conversion rate prediction models at scale

Modern digital platforms rely heavily on accurate click-through rate and conversion rate predictions to optimize user experience and business outcomes, requiring robust ML systems that can handle massive-scale real-time inference with low latency and high accuracy requirements.

1. Problem Statement & ML Task Definition

Clarifying questions

  1. What is the expected scale of our training data (e.g., number of samples, features) and how frequently does it update?
  2. What is the latency budget for real-time predictions (e.g., <10ms for mobile, <50ms for web)?
  3. Is this a batch or online serving system? What is the expected QPS?
  4. What's the target business metric (e.g., revenue, engagement, retention) and how do we balance accuracy vs. speed?
  5. What is the expected data freshness requirements for features and labels (e.g., real-time, hourly, daily)?
  6. What is the expected user base and item catalog size to understand scale?
  7. What is the current baseline performance (e.g., rule-based system CTR) and what improvement target do we have?

Business use case and success criteria

The system aims to predict the likelihood that a user will click on an ad or product recommendation (CTR) and subsequently convert (e.g., purchase, sign-up). This is a core component of advertising platforms, e-commerce recommendation systems, and content personalization engines.

Primary business success criteria:

  • Click-through rate (CTR): Higher CTRs lead to better ad revenue and user engagement.
  • Conversion rate (CVR): Higher CVRs translate to increased revenue or user retention.
  • User engagement: Improved click and conversion rates lead to better user experience and platform stickiness.

ML problem formulation

Task: Multi-task learning for CTR and CVR prediction, with a primary focus on CTR.

Justification:

  • CTR is the most common and immediate signal for user interest, making it a critical KPI.
  • CVR is a downstream task that can be modeled as a conditional probability given CTR, enabling multi-task learning.
  • Both tasks are classification problems with binary outcomes (clicked vs. not clicked, converted vs. not converted).
  • The system needs to support real-time scoring for user-item interactions, requiring efficient model inference.

ML evaluation metrics

Offline Evaluation Metrics:

  • AUC-ROC: For binary classification performance (CTR and CVR).
  • NDCG@K: For ranking quality if the system supports rank reordering.
  • Precision@K: For top-K recommendation accuracy.
  • BLEU Score: If generating text-based content (not primary use case but relevant for some systems).

Online Evaluation Metrics:

  • Click-Through Rate (CTR): Primary metric for ad performance.
  • Conversion Rate (CVR): Secondary metric for revenue impact.
  • Revenue per user (RPU): Business impact of improved recommendations.
  • Engagement time: Indirect measure of content relevance.

Scale and constraints

Back-of-envelope estimates:

  • Training data size: 100M user-item interactions (e.g., 10M users × 10K items)
  • Number of features: ~50K (user, item, context, and interaction features)
  • Embedding matrix memory footprint:
    • 50K features × 128 dimensions × 4 bytes = ~256 MB per embedding matrix
  • Serving QPS math:
    • Target: 10,000 QPS
    • Latency budget: 50ms (p99)
    • Model size: ~1GB (compressed)
    • Estimated inference time per request: <5ms (assuming efficient serving stack)

Non-ML baseline strategy

  • Rule-based fallback: Use simple heuristics like "most popular items" or "user's last clicked item" for cold start.
  • Cold start handling: For new users or items, use content-based filtering or popularity-based ranking.
  • Static feature-based models: Use simple logistic regression or gradient boosting models trained on historical data as a fallback.
# Baseline rule for cold start handling (example)
def cold_start_recommendation(user_id, item_pool):
    if user_id not in user_history:
        return top_popular_items(item_pool)  # Fallback to popular items
    else:
        return user_history[user_id][-1]  # Last clicked item

2. Data Strategy

Training Data Sources

  • Explicit feedback: User clicks, purchases, and other direct engagement signals (e.g., "Add to Cart", "Save for Later")
  • Implicit signals: Time spent on page, scroll depth, view-through rates, session duration, and user navigation patterns
  • Third-party data: Demographic information from partner APIs, contextual signals from web pages (e.g., category tags), and historical behavioral data from similar platforms
  • Synthetic data: Generated for edge cases or rare events to improve model robustness

Labeling Pipeline Design

  • Human annotation: For high-value, rare events like conversions (e.g., purchase confirmation) where precision is critical. Labeling done via internal annotation platform with quality control (inter-annotator agreement > 90%).
  • Weak supervision: Using heuristics and rules to generate labels for large-scale training (e.g., "User clicked on item X within 30 seconds of viewing it" → CTR=1).
  • Programmatic labeling: For implicit feedback, such as treating time spent > 5 seconds on an item as a positive signal for interest.

Class Imbalance Handling Strategy

  • Target rate: ~1% click-through rate and ~0.5% conversion rate, indicating severe class imbalance
  • Strategy: Oversampling minority classes (clicks/conversions) using SMOTE or synthetic generation, and undersampling majority classes (non-clicks/non-conversions) to balance the dataset
  • Justification: Conversion events are rare but highly valuable, so we must ensure the model learns to distinguish between high-value and low-value signals without being biased toward majority class

Negative Sampling Approach

  • Strategy: Stratified random sampling with a 1:5 ratio of negative to positive samples (clicks/conversions)
  • Method: For each positive sample, randomly select 5 negative samples from the same user session or time window to maintain temporal consistency
  • Justification: Ensures model learns meaningful patterns from both positive and negative examples while preserving session-level coherence

Data Freshness and Update Frequency Requirements

  • Training data: Daily batch updates with 24-hour lag to ensure freshness and reduce drift
  • Real-time features: Updated every 5 minutes for user behavior and item popularity signals
  • Label freshness: Real-time for clicks, 1-hour lag for conversions (to allow for confirmation processing)
  • Back-of-envelope estimate:
    • Training data size: ~50M samples/day (clicks + conversions)
    • Feature dimensions: ~10K features (user, item, context)
    • Memory footprint for embedding matrix: ~10GB (assuming 512-dim embeddings per user/item)
    • Serving QPS: ~50,000 (with 99th percentile latency < 100ms)

Privacy Compliance

  • GDPR/CCPA compliance: All personal data is anonymized using hashing techniques (e.g., SHA-256) and stored in encrypted format
  • Data retention policy: User data retained for 24 months, after which it is deleted or permanently hashed
  • Consent management: Explicit opt-in for behavioral tracking and personalization features
  • Data minimization: Only collect necessary features (e.g., session ID, item category, timestamp) to reduce risk exposure

Data Quality Validation and Monitoring

  • Validation checks:
    • Timestamps must be in valid range (within last 30 days)
    • User IDs and item IDs must exist in the system
    • Feature values must be within expected bounds (e.g., session duration < 1 hour)
  • Monitoring:
    • Daily data quality reports (missing values, outliers, drift in distribution)
    • Alert thresholds: >5% missing features or >10% drift in key metrics (e.g., CTR, conversion rate)
    • Automated retraining triggers when data quality drops below threshold

3. Feature Engineering

Feature Taxonomy

Features are categorized into four main types:

  1. User Features: Demographics, behavior history, engagement patterns
  2. Item Features: Content attributes, popularity metrics, category information
  3. Context Features: Time, device, location, session characteristics
  4. Interaction Features: User-item interaction history, temporal signals

Embedding Design

Entity Embeddings (User ID, Item ID, Category):

  • Dimensionality: 128 for user/item, 64 for categorical features
  • Training: Pre-trained with collaborative filtering, fine-tuned during model training

Text Embeddings (Item title, description):

  • Dimensionality: 256
  • Training: BERT-based model fine-tuned on item content, pre-trained with sentence-transformers

Graph Embeddings (User-item interaction graph):

  • Dimensionality: 128
  • Training: Node2Vec or GraphSAGE on user-item interaction graphs

Real-time vs Batch Feature Computation

Feature TypeComputation ModeReason
User behavior historyReal-timeLow latency requirements, frequent updates
Item popularity metricsBatchStable over time, computed hourly
Context featuresReal-timeTime-sensitive, requires current session data
User embeddingsBatchComputed once per user, updated daily

Feature Store Design

Online Store:

  • Low-latency key-value store (e.g., Redis or DynamoDB)
  • Optimized for sub-millisecond lookups
  • TTL of 1 hour for user features, 24 hours for item features

Offline Store:

  • Data warehouse (e.g., Snowflake or BigQuery)
  • For training data generation and batch feature computation
  • Partitioned by date for efficient querying

Feature Freshness and TTL

FeatureSourceUpdate FrequencyStore Type
User IDUser profileReal-timeOnline
Item categoryItem catalogDailyOffline
User session countSession logsReal-timeOnline
Item popularityHistorical clicksHourlyOffline
Time of daySystem clockReal-timeOnline

Cross Features and Feature Interactions

Cross features are generated using:

  1. Product combinations: User-category, Item-category interactions
  2. Temporal cross features: User-item temporal patterns (e.g., last interaction time)
  3. Aggregated features: User average engagement per item category

Feature Importance and Selection

  • Methodology: SHAP values, permutation importance from trained models
  • Selection criteria:
    • Top 200 features by SHAP importance for training
    • Dynamic feature selection based on A/B test performance
  • Redundancy handling: Correlation matrix filtering to remove highly correlated features
import numpy as np
from sklearn.feature_selection import SelectKBest, f_classif

class FeatureSelector:
    def __init__(self, k=200):
        self.k = k
        self.selector = SelectKBest(score_func=f_classif, k=k)
    
    def fit_transform(self, X, y):
        return self.selector.fit_transform(X, y)
    
    def get_support_mask(self):
        return self.selector.get_support()
    
    def get_feature_importance_scores(self):
        # Assuming f_classif scores are available
        return self.selector.scores_

# Example usage for feature selection in CTR model
def select_important_features(X_train, y_train, X_val, y_val):
    selector = FeatureSelector(k=200)
    
    # Fit selector on training data
    X_train_selected = selector.fit_transform(X_train, y_train)
    
    # Apply same transformation to validation data
    X_val_selected = selector.transform(X_val)
    
    return X_train_selected, X_val_selected, selector

# Feature importance visualization (mock example)
def visualize_feature_importance(selector, feature_names):
    scores = selector.get_feature_importance_scores()
    top_features_idx = np.argsort(scores)[-20:][::-1]
    
    print("Top 20 Important Features:")
    for i, idx in enumerate(top_features_idx):
        print(f"{i+1}. {feature_names[idx]} (score: {scores[idx]:.4f})")

4. Model Architecture

Model Selection with Justification

For a CTR/Conversion rate prediction system, I recommend a two-tower DNN architecture with multi-task learning capabilities:

  • Why not Logistic Regression or GBM? While linear models are interpretable and fast, they struggle with complex user-item interactions and feature combinations that are crucial for CTR prediction. GBMs can capture non-linearities but lack the scalability and real-time serving capabilities needed for high QPS systems.

  • Why DNN? Deep neural networks excel at learning complex feature interactions and can scale to large embedding spaces. The two-tower design enables efficient user-item representation learning.

  • Why Multi-task? We can jointly optimize for both CTR and Conversion Rate, leveraging shared representations while maintaining task-specific heads. This improves generalization and provides better signal for both objectives.

Architecture Diagram

graph TD
    A[User Features] --> B[User Tower]
    C[Item Features] --> D[Item Tower]
    B --> E[Merged Embeddings]
    D --> E
    E --> F[MLP Layers]
    F --> G[CTR Head]
    F --> H[Conversion Head]
    G --> I[Final Output]
    H --> I

Two-Tower / Multi-Task Design

The model uses a two-tower architecture:

  • User Tower: Processes user features (demographics, behavior history, etc.)
  • Item Tower: Processes item features (product attributes, category, etc.)
  • Shared MLP: Merges representations and learns cross-interactions
  • Task Heads: Separate branches for CTR and Conversion Rate prediction

Pre-trained Model Selection and Fine-tuning Strategy

For foundational capabilities, we can leverage:

  • Pre-trained text embeddings (e.g., BERT for product descriptions)
  • Image encoders (e.g., ResNet for product images)
  • Cross-modal embeddings for multi-modality features

Fine-tuning follows a freeze-pretrain-then-finetune approach:

  1. Pre-trained embeddings are frozen initially
  2. After initial training, gradually unfreeze layers for fine-tuning
  3. Use learning rate warmup and gradient clipping for stable training

Model Complexity vs Latency Trade-off Analysis

ModelParametersInference Latency (ms)Memory Usage (GB)
Logistic Regression10K0.50.01
GBM (XGBoost)1M2.00.1
Two-Tower DNN (Small)5M5.00.5
Two-Tower DNN (Medium)20M15.02.0
Two-Tower DNN (Large)100M50.08.0

Offline Evaluation Baseline Framing

Baseline model: Logistic Regression with engineered features Expected baseline performance:

  • CTR AUC: ~0.65
  • Conversion AUC: ~0.60

Proposed model (Two-Tower DNN):

  • CTR AUC: ~0.75 (improvement of 15%)
  • Conversion AUC: ~0.68 (improvement of 13%)

Core Model Code Snippet

import torch
import torch.nn as nn
import torch.nn.functional as F

class TwoTowerCTRModel(nn.Module):
    def __init__(self, user_feature_dim, item_feature_dim, 
                 embedding_dim=128, hidden_dims=[256, 128, 64]):
        super(TwoTowerCTRModel, self).__init__()
        
        # User tower
        self.user_embedding = nn.Embedding(user_feature_dim, embedding_dim)
        self.user_mlp = nn.Sequential(
            nn.Linear(embedding_dim, hidden_dims[0]),
            nn.ReLU(),
            nn.Linear(hidden_dims[0], hidden_dims[1]),
            nn.ReLU()
        )
        
        # Item tower
        self.item_embedding = nn.Embedding(item_feature_dim, embedding_dim)
        self.item_mlp = nn.Sequential(
            nn.Linear(embedding_dim, hidden_dims[0]),
            nn.ReLU(),
            nn.Linear(hidden_dims[0], hidden_dims[1]),
            nn.ReLU()
        )
        
        # Shared layers
        self.shared_mlp = nn.Sequential(
            nn.Linear(hidden_dims[1] * 2, hidden_dims[2]),
            nn.ReLU(),
            nn.Linear(hidden_dims[2], hidden_dims[2] // 2),
            nn.ReLU()
        )
        
        # Task heads
        self.ctr_head = nn.Linear(hidden_dims[2] // 2, 1)
        self.conv_head = nn.Linear(hidden_dims[2] // 2, 1)
        
    def forward(self, user_ids, item_ids):
        # User tower
        user_emb = self.user_embedding(user_ids).mean(dim=1)  # Average if multiple embeddings
        user_repr = self.user_mlp(user_emb)
        
        # Item tower
        item_emb = self.item_embedding(item_ids).mean(dim=1)
        item_repr = self.item_mlp(item_emb)
        
        # Merge representations
        merged = torch.cat([user_repr, item_repr], dim=1)
        
        # Shared representation
        shared = self.shared_mlp(merged)
        
        # Task-specific predictions
        ctr_logit = self.ctr_head(shared)
        conv_logit = self.conv_head(shared)
        
        return {
            'ctr': torch.sigmoid(ctr_logit),
            'conversion': torch.sigmoid(conv_logit)
        }
    
    def compute_loss(self, predictions, targets):
        ctr_loss = F.binary_cross_entropy(predictions['ctr'], targets['ctr'])
        conv_loss = F.binary_cross_entropy(predictions['conversion'], targets['conversion'])
        
        # Multi-task loss with weighted sum
        total_loss = 0.7 * ctr_loss + 0.3 * conv_loss
        return total_loss

# Example usage:
model = TwoTowerCTRModel(user_feature_dim=10000, item_feature_dim=50000)
user_ids = torch.randint(0, 10000, (32,))
item_ids = torch.randint(0, 50000, (32,))
predictions = model(user_ids, item_ids)
print(f"CTR prediction: {predictions['ctr'].shape}")
print(f"Conversion prediction: {predictions['conversion'].shape}")

This implementation provides:

  • Modular architecture for easy extension
  • Multi-task learning capability
  • Efficient forward pass with proper embedding handling
  • Clear loss computation for joint training
  • Ready-to-use PyTorch model that can be deployed in production

5. Serving & Inference Architecture

System Diagram

graph TD
    A[User Request] --> B[Load Balancer]
    B --> C[API Gateway]
    C --> D{Online/Offline}
    D -->|Online| E[Ranking Service]
    D -->|Offline| F[Batch Processing]
    E --> G[Feature Store]
    G --> H[Embedding Cache]
    H --> I[Model Server]
    I --> J[Scoring Engine]
    J --> K[Response Formatter]
    K --> L[Return Result]
    
    subgraph "Real-time Serving"
        E
        G
        H
        I
        J
        K
    end
    
    subgraph "Batch Processing"
        F
    end

Online vs Batch Serving Decision

For CTR and conversion rate prediction, we require real-time online serving because:

  • User interactions must be scored within 100ms for web/mobile experiences
  • Conversion prediction requires immediate feedback loop to optimize user journey
  • Online serving enables personalization at scale with low latency requirements

Two-Stage Pipeline Design

Stage 1: Candidate Retrieval (p50: 20ms, p99: 50ms)
- Retrieve top-K candidates from embedding index
- Use approximate nearest neighbor search (FAISS/Annoy)
- Filter by user context and item category

Stage 2: Scoring & Re-ranking (p50: 30ms, p99: 80ms)
- Compute per-item CTR probability using trained model
- Apply business rules and constraints (e.g., campaign limits)
- Re-rank items based on predicted conversion value

Serving Infrastructure

We use TorchServe for model serving with the following configuration:

  • Model format: ONNX or TorchScript for optimal inference performance
  • GPU acceleration (NVIDIA A10 GPUs) with 2 models per GPU for batching efficiency
  • Model versioning and rollback capability through model registry
  • Auto-scaling based on QPS with 3x redundancy for fault tolerance

Latency Budget Breakdown

Stagep50 Latencyp99 LatencyBudget
Request Parsing2ms5ms5ms
Feature Retrieval10ms20ms20ms
Model Inference15ms35ms35ms
Response Formatting2ms5ms5ms
Total30ms65ms65ms

Model Compression Strategy

We implement a multi-layer compression approach:

  1. Quantization: INT8 quantization reduces model size by 4x with <2% accuracy loss
  2. Pruning: Remove 30% of weights with minimal impact on performance
  3. Distillation: Student model trained to mimic teacher model behavior

Caching Strategy

Cache TypePurposeTTLSize
Prediction CacheStore recent top-K predictions5min1GB
Embedding CacheHot embeddings for frequent users/items30min2GB
KV CacheFor LLM-based content understanding (if applicable)1hr500MB

Auto-scaling and Capacity Planning

  • Target QPS: 10,000 requests/sec with 95th percentile < 65ms
  • Auto-scaling: Horizontal scaling of model servers based on QPS and latency metrics
  • Capacity planning: 1000 concurrent requests per model server with 2x buffer for peak traffic
  • Health checks: Liveness probe every 30s, readiness probe every 5s

Model Serving Pipeline Flow

class CTRModelServing:
    def __init__(self, model_path, feature_store):
        self.model = torch.jit.load(model_path)
        self.feature_store = feature_store
        self.embedding_cache = {}
        
    def predict(self, user_id, item_id, context_features):
        # 1. Feature retrieval from store
        features = self.feature_store.get_features(user_id, item_id, context_features)
        
        # 2. Cache lookup for embeddings
        if (user_id, item_id) in self.embedding_cache:
            user_emb, item_emb = self.embedding_cache[(user_id, item_id)]
        else:
            user_emb = self.feature_store.get_user_embedding(user_id)
            item_emb = self.feature_store.get_item_embedding(item_id)
            self.embedding_cache[(user_id, item_id)] = (user_emb, item_emb)
        
        # 3. Model inference
        input_tensor = self._prepare_input(features, user_emb, item_emb)
        ctr_score = self.model(input_tensor).sigmoid().item()
        
        # 4. Apply business constraints
        conversion_score = self._apply_conversion_logic(ctr_score, features)
        
        return {
            "ctr_probability": ctr_score,
            "conversion_probability": conversion_score,
            "timestamp": time.time()
        }
    
    def _prepare_input(self, features, user_emb, item_emb):
        # Combine all features into tensor for model input
        return torch.cat([
            torch.tensor(features['user_features']),
            user_emb,
            item_emb,
            torch.tensor(features['context_features'])
        ])

This architecture supports both high-throughput real-time serving and efficient batch processing while maintaining low latency requirements for user-facing applications.

6. Evaluation Framework

Offline Evaluation Methodology

For offline evaluation, we use temporal cross-validation to ensure our model generalizes to future data. We split the dataset chronologically into 6-month windows, with the most recent window used for testing and previous windows for training. This approach addresses data drift and temporal skew while maintaining realistic performance estimates. For model comparison, we use holdout validation with 20% of the most recent data as a test set.

Slice-Based Evaluation

We evaluate model performance across critical user segments:

  • User demographics: Age groups (18-25, 26-35, 36+), gender
  • Device types: Mobile vs desktop vs tablet
  • Geographic regions: US, EU, APAC, LATAM
  • Engagement levels: New users vs returning users vs high-engagement users

Key slices include:

  • Mobile users (high CTR potential but different behavior)
  • New user cohort (cold start challenge)
  • High-value customers (conversion impact)

A/B Test Design

Randomization Unit: User ID with session-level randomization to prevent leakage

Sample Size Calculation:

  • Power: 80%
  • Significance level: 5%
  • Minimum detectable effect (MDE): 2% for CTR, 1% for conversion rate
  • Baseline rates: 2.5% CTR, 0.8% conversion rate
  • Estimated sample size: ~2.5M users per variant

Test Duration: 4 weeks (allowing for seasonal variation and user behavior patterns)

Primary Metrics:

  • CTR: p-value < 0.05, effect size > 2%
  • Conversion rate: p-value < 0.05, effect size > 1%
  • Revenue per user (RPU): p-value < 0.05, effect size > 1%

Guardrail Metrics and Blocking Conditions

Guardrail thresholds:

  • CTR drop below baseline by 5% (blocking condition)
  • Conversion rate drop below baseline by 3% (blocking condition)
  • Revenue per user drop below baseline by 2% (blocking condition)

Blocking conditions:

  • If any guardrail metric exceeds thresholds, A/B test is stopped and model reverted to baseline
  • If confidence intervals overlap 95% of the time, test is extended by 2 weeks

Shadow Mode Rollout Plan

Before full A/B testing, we implement shadow mode for 2 weeks:

  • All traffic is routed to both baseline and new model in parallel
  • Shadow logs capture predictions, features, and user behavior
  • Offline evaluation using shadow logs to validate model performance
  • Shadow mode allows for early detection of performance degradation or unexpected behavior

Long-Term Metric Measurement

Delayed Conversion Tracking:

  • 7-day, 30-day, and 90-day conversion rates to capture long-term user value
  • Revenue attribution across multiple touchpoints

Engagement Decay Monitoring:

  • Weekly engagement rate decline to detect model drift in user retention
  • Session frequency and duration tracking for behavioral changes

User Lifetime Value (LTV) Analysis:

  • 3-month and 6-month LTV tracking to ensure model impact extends beyond immediate CTR/conversion gains
# Example A/B test evaluation logic in Python
import numpy as np
from scipy import stats

class ABTestEvaluator:
    def __init__(self, baseline_ctr=0.025, baseline_conv_rate=0.008):
        self.baseline_ctr = baseline_ctr
        self.baseline_conv_rate = baseline_conv_rate
        
    def evaluate_ctr(self, variant_ctr, baseline_ctr, sample_size):
        """Evaluate CTR A/B test results"""
        # Two-sample proportion z-test
        pooled_p = (variant_ctr * sample_size + baseline_ctr * sample_size) / (2 * sample_size)
        pooled_se = np.sqrt(pooled_p * (1 - pooled_p) / sample_size)
        
        z_score = (variant_ctr - baseline_ctr) / pooled_se
        p_value = 2 * (1 - stats.norm.cdf(abs(z_score)))
        
        return {
            'p_value': p_value,
            'z_score': z_score,
            'statistically_significant': p_value < 0.05,
            'effect_size': (variant_ctr - baseline_ctr) / baseline_ctr * 100
        }
    
    def evaluate_conversion_rate(self, variant_conv, baseline_conv, sample_size):
        """Evaluate conversion rate A/B test results"""
        # Two-sample proportion z-test for conversion rates
        pooled_p = (variant_conv * sample_size + baseline_conv * sample_size) / (2 * sample_size)
        pooled_se = np.sqrt(pooled_p * (1 - pooled_p) / sample_size)
        
        z_score = (variant_conv - baseline_conv) / pooled_se
        p_value = 2 * (1 - stats.norm.cdf(abs(z_score)))
        
        return {
            'p_value': p_value,
            'z_score': z_score,
            'statistically_significant': p_value < 0.05,
            'effect_size': (variant_conv - baseline_conv) / baseline_conv * 100
        }

# Example usage:
evaluator = ABTestEvaluator()
ctr_results = evaluator.evaluate_ctr(
    variant_ctr=0.026, 
    baseline_ctr=0.025, 
    sample_size=2500000
)
print(f"CTR A/B test results: {ctr_results}")

7. Training Pipeline

Training Data Pipeline

The training pipeline begins with data ingestion from multiple sources including user interaction logs, item metadata, and contextual signals. Data is first preprocessed through a series of ETL steps:

  1. Data Cleaning: Remove invalid records, handle missing values, and apply data quality filters
  2. Feature Engineering: Extract temporal features, user/item embeddings, and interaction signals
  3. Sampling: Apply stratified sampling to handle class imbalance between clicks and non-clicks
  4. Shuffling: Implement shuffling at multiple levels (per-day, per-user) to ensure training stability
  5. Batching: Process data in batches of 10,000 samples for efficient training
import torch
from torch.utils.data import Dataset, DataLoader
import pandas as pd

class CTRDataset(Dataset):
    def __init__(self, data_path, feature_columns, target_column):
        self.data = pd.read_parquet(data_path)
        self.features = self.data[feature_columns].values
        self.targets = self.data[target_column].values.astype(float)
        
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, idx):
        return {
            'features': torch.FloatTensor(self.features[idx]),
            'target': torch.FloatTensor([self.targets[idx]])
        }

# Data loading with shuffling and batching
def create_training_dataloader(data_path, feature_columns, batch_size=10000):
    dataset = CTRDataset(data_path, feature_columns, 'click')
    return DataLoader(
        dataset,
        batch_size=batch_size,
        shuffle=True,
        num_workers=4,
        pin_memory=True
    )

Distributed Training Strategy

For large-scale training, we implement data parallelism across multiple GPUs with model parallelism for the embedding layers:

  • Data Parallelism: Split training data across multiple GPUs (e.g., 8 GPUs with 1250 samples per GPU)
  • Model Parallelism: Partition embedding layers across GPUs to handle large vocabulary sizes
  • Pipeline Parallelism: For very deep models, pipeline stages can be distributed across GPUs

Training cluster configuration:

  • 8x NVIDIA A100 GPUs (40GB VRAM each)
  • 256GB total memory capacity
  • Estimated training time: 4 hours for 10M samples

Training Infrastructure

The training infrastructure is designed to handle both batch and real-time training requirements:

  • GPU Cluster: 8x A100 GPUs with 256GB total memory
  • Storage: SSD-backed storage for fast data access (100GB/s read bandwidth)
  • Framework: PyTorch with distributed training capabilities
  • Job Scheduling: Kubernetes-based job orchestration with GPU resource allocation

Hyperparameter Tuning Approach

We use Bayesian optimization for hyperparameter tuning with the following key parameters:

  • Learning Rate: [0.001, 0.01] (log scale)
  • Batch Size: [256, 4096] (log scale)
  • Embedding Dimension: [32, 256] (log scale)
  • Number of Layers: [2, 6]
  • Dropout Rate: [0.1, 0.5]
from skopt import gp_minimize
from skopt.space import Real, Integer

def objective(hyperparams):
    lr, batch_size, embedding_dim, layers, dropout = hyperparams
    
    # Initialize model with given hyperparameters
    model = CTRModel(
        embedding_dim=embedding_dim,
        num_layers=layers,
        dropout=dropout
    )
    
    # Train model and return validation AUC-ROC
    train_loss = train_model(model, lr, batch_size)
    val_auc = evaluate_model(model, validation_data)
    
    # Return negative AUC (since we minimize)
    return -val_auc

# Bayesian optimization search space
search_space = [
    Real(1e-4, 1e-2, prior='log-uniform', name='learning_rate'),
    Integer(64, 8192, prior='log-uniform', name='batch_size'),
    Integer(32, 512, prior='log-uniform', name='embedding_dim'),
    Integer(2, 8, name='num_layers'),
    Real(0.05, 0.5, name='dropout_rate')
]

# Run optimization
best_params = gp_minimize(objective, search_space, n_calls=50, random_state=42)

Experiment Tracking and Reproducibility

We implement comprehensive experiment tracking using MLflow:

  • Experiment Registry: Store model versions, hyperparameters, and metrics
  • Parameter Logging: Track all training configurations and runtime parameters
  • Artifact Management: Store model checkpoints, training logs, and evaluation results
  • Reproducibility: Use fixed random seeds (42) and deterministic training modes

Model Versioning and Registry Strategy

Model versioning follows semantic versioning with strict registry policies:

  • Versioning: Major.Minor.Patch (e.g., 1.2.3)
  • Registry: Centralized model registry with version control
  • Validation: Pre-launch validation including A/B test readiness
  • Rollback Capability: Support for quick model rollback with version tags

Continual / Online Learning Design

For real-time adaptation to changing user behavior:

  • Online Learning Window: 30-day sliding window for model updates
  • Incremental Updates: Use Adam optimizer with small learning rates (1e-5)
  • Drift Detection: Monitor feature and label drift for model retraining triggers
  • Ensemble Strategy: Maintain 3 most recent model versions for adaptive serving

The training pipeline is designed to support both batch training for model development and online learning for model adaptation, with robust monitoring and version control to ensure model quality and reliability.

8. Monitoring & Observability

Data Drift Detection

Data drift monitoring is critical for maintaining model performance in production. We implement drift detection using:

  • Population Stability Index (PSI) for categorical features and numerical distributions
  • KL Divergence for continuous feature distributions
  • Chi-square tests for categorical feature shifts
import numpy as np
from scipy import stats
import pandas as pd

def calculate_psi(expected, actual, bins=10):
    """Calculate PSI for distribution shift detection"""
    # Ensure both distributions have same bins
    _, bin_edges = np.histogram(expected, bins=bins)
    
    # Count occurrences in each bin
    expected_counts, _ = np.histogram(expected, bins=bin_edges)
    actual_counts, _ = np.histogram(actual, bins=bin_edges)
    
    # Avoid zero division
    expected_counts = np.where(expected_counts == 0, 1e-6, expected_counts)
    actual_counts = np.where(actual_counts == 0, 1e-6, actual_counts)
    
    psi = np.sum((actual_counts - expected_counts) * 
                 np.log(actual_counts / expected_counts))
    return psi

def detect_drift_features(expected_df, actual_df, features):
    """Detect drift across feature set"""
    drift_results = {}
    for feature in features:
        if feature in actual_df.columns:
            psi_value = calculate_psi(expected_df[feature], actual_df[feature])
            drift_results[feature] = psi_value
    return drift_results

Prediction Drift and Label Drift Monitoring

We monitor both prediction drift (model outputs changing over time) and label drift (true labels shifting):

  • Prediction drift: Track distribution shifts in model confidence scores
  • Label drift: Monitor change in conversion rates over time windows

Model Performance Degradation Alerting

We set up comprehensive alerting for model performance degradation:

  • AUC-ROC drop > 5% over 7-day window → high severity alert
  • NDCG@10 drop > 3% over 7-day window → medium severity alert
  • CTR drift > 10% over 3-day window → high severity alert

Retraining Trigger Strategy

We implement a multi-trigger retraining strategy:

  • Scheduled retraining: Every 2 weeks for model updates
  • Drift-triggered: PSI > 0.2 for any feature or prediction drift > 5%
  • Performance-triggered: AUC drops below threshold (0.75) for 3 consecutive days

Logging Design

Comprehensive logging pipeline:

  • Prediction logs: User ID, item ID, timestamp, model score, features, actual label
  • Feature logs: Real-time feature values for each prediction request
  • Label collection pipeline: Conversion tracking with proper timestamp alignment

Feedback Loop for Continuous Improvement

We implement a feedback collection system:

class FeedbackCollector:
    def __init__(self, logging_client):
        self.client = logging_client
    
    def collect_feedback(self, user_id, item_id, action_type, timestamp):
        """Collect feedback for model improvement"""
        feedback_data = {
            "user_id": user_id,
            "item_id": item_id,
            "action_type": action_type,  # click, conversion, view
            "timestamp": timestamp,
            "source": "production"
        }
        
        # Log to monitoring system for drift analysis
        self.client.log_event("feedback", feedback_data)
        
        # Optionally queue for retraining data
        if action_type == "conversion":
            self.client.queue_for_retraining(feedback_data)

Key Metrics for Production Monitoring

MetricAlert ThresholdMonitoring FrequencyPurpose
AUC-ROCDrop > 5% over 7 daysHourlyOverall model quality
NDCG@10Drop > 3% over 7 daysHourlyRanking quality
CTRDrop > 10% over 3 daysDailyBusiness impact
Model ConfidenceDistribution shift > 0.1 PSIHourlyPrediction reliability

Drift Detection Dashboard

We build a real-time dashboard with:

  • Feature drift heatmaps (PSI values)
  • Model performance over time (AUC, NDCG)
  • Conversion rate trends
  • Prediction distribution shifts

Anomaly Detection for Model Outputs

We implement anomaly detection on model outputs:

from sklearn.ensemble import IsolationForest

class PredictionAnomalyDetector:
    def __init__(self):
        self.anomaly_detector = IsolationForest(contamination=0.1)
        
    def detect_anomalies(self, model_scores):
        """Detect anomalous prediction patterns"""
        # Normalize scores for anomaly detection
        normalized_scores = (model_scores - np.mean(model_scores)) / np.std(model_scores)
        
        # Fit and predict anomalies
        anomaly_labels = self.anomaly_detector.fit_predict(normalized_scores.reshape(-1, 1))
        
        return anomaly_labels

Incident Response Plan

When drift or performance issues are detected:

  1. Immediate: Route traffic to fallback model or rule-based system
  2. Investigation: Analyze drift root causes and data quality issues
  3. Remediation: Retrain model with updated data or adjust thresholds
  4. Recovery: Gradually ramp back to new model after validation

Data Quality Monitoring

We monitor:

  • Missing feature rates: >5% missing → alert
  • Feature value ranges: Out-of-bounds values → logging
  • Label consistency: Inconsistent conversion tracking → investigation

Cross-System Integration

We integrate with:

  • ML Platform: Model version tracking and deployment status
  • Feature Store: Feature freshness and availability monitoring
  • Data Pipeline: ETL job success rates and data freshness
  • Business Intelligence: Conversion rate and revenue tracking

This comprehensive monitoring system ensures model robustness, enables rapid response to performance degradation, and supports continuous improvement through feedback loops. The system is designed to be proactive rather than reactive, with early warning systems that prevent business impact while maintaining high availability.

9. Responsible AI & Safety

Bias Analysis

  • Training data audit: Conduct comprehensive audits to identify demographic imbalances in user and item representations, particularly examining underrepresented groups (e.g., age, gender, geography) in both training and serving data.
  • Slice-based fairness evaluation: Evaluate model performance across user segments (age groups, regions, device types) to detect potential bias in CTR predictions. Use demographic parity and equalized odds as fairness metrics.
  • Impact: Bias in CTR prediction can lead to unfair exposure of content or products, potentially causing user dissatisfaction and regulatory scrutiny.

Fairness Metrics and Constraints

  • Demographic parity: Ensure that the model's prediction probability is independent of sensitive attributes (e.g., gender, region).
  • Equalized odds: Ensure that the true positive and false positive rates are equal across different user segments.
  • Decision: Prioritize demographic parity for user exposure fairness, with additional equalized odds checks to prevent systematic misclassification of specific groups.
  • Justification: Ensures equitable content distribution and prevents algorithmic discrimination in ad placement or content recommendations.

Explainability Requirements

  • SHAP values: Implement SHAP-based explainability for high-stakes predictions to understand feature contributions to CTR and conversion probability.
  • Attention visualization: For transformer-based models, visualize attention weights to understand which user or item features influenced the model's decision.
  • Stakeholder requirements: Business users need to understand why certain content is prioritized, while compliance teams require auditability of model decisions.
  • Implementation: Integrate SHAP explainer in the serving pipeline with a 10% sample of predictions logged for explainability review.

For LLM Systems (if applicable)

  • Content filtering: Implement content safety filters to prevent harmful, misleading, or inappropriate content from being recommended.
  • Output validation: Validate model outputs for factual accuracy and alignment with brand guidelines before serving to users.
  • Rate limiting: Apply rate limits to prevent abuse or overuse of recommendation systems by malicious actors.
  • Red teaming: Conduct adversarial testing to identify edge cases and potential safety issues in model behavior.
  • Guardrail thresholds: Set thresholds for toxicity, misinformation, and inappropriate content scores to block or flag problematic recommendations.

Model Card Documentation Plan

  • Content: Document model architecture, training data sources, performance metrics, fairness analysis, and known limitations.
  • Distribution: Make model cards available in internal documentation systems (e.g., Confluence, GitHub) and accessible to ML engineers, product managers, and compliance teams.
  • Updates: Version model cards with each model release to reflect changes in training data, performance, or bias mitigation strategies.

Incident Response Plan for Model Failures

  • Failure detection: Alert on sudden drops in model performance (e.g., CTR drop >5%) or prediction drift (PSI > 0.1 for key features).
  • Fallback logic: Implement rule-based fallback for critical user segments when model confidence drops below threshold (e.g., <0.7).
  • Escalation: Define escalation paths for model failures (e.g., ML team → engineering → compliance) with SLA of 2 hours for root cause analysis.
  • Recovery: Automate retraining and rollback to last stable model version if drift exceeds thresholds.
  • Post-mortem: Conduct post-mortem analysis for any significant model failure, documenting root cause and mitigation steps.
# Example: SHAP-based explainability integration in serving pipeline
import shap
import numpy as np

class CTRModelExplainability:
    def __init__(self, model, explainer):
        self.model = model
        self.explainer = explainer  # e.g., shap.Explainer(model)
    
    def explain_prediction(self, user_features, item_features):
        # Combine features into a single input
        input_vector = np.hstack([user_features, item_features])
        
        # Get SHAP values for the prediction
        shap_values = self.explainer.shap_values(input_vector)
        
        # Return feature importance scores
        return {
            "feature_importance": shap_values,
            "prediction_score": self.model.predict_proba(input_vector)[1]
        }

# Example usage in serving pipeline
def serve_with_explanation(user_features, item_features):
    model = load_trained_model()
    explainer = shap.Explainer(model)
    
    explainability_engine = CTRModelExplainability(model, explainer)
    
    explanation = explainability_engine.explain_prediction(user_features, item_features)
    
    return {
        "ctr_score": explanation["prediction_score"],
        "feature_importance": explanation["feature_importance"]
    }

10. Scalability & Reliability

Bottleneck Analysis per Pipeline Stage

StageComponentEstimated BottleneckBack-of-Envelope Calculation
Data IngestionFeature extractionCPU-bound processing10M users × 100 features = 1B features/sec at peak
TrainingModel trainingGPU memory50M samples × 100 features × 4 bytes = ~20GB model
ServingReal-time scoringLatency100ms p99 target → 20ms for 5 stages
Feature StoreOnline lookupNetwork latency100ms p99 → 50ms for 200 features
Model ServingBatch inferenceMemory bandwidth1M QPS × 100ms = 100M requests/sec

Scale-up Strategy

Horizontal Scaling of Serving:

  • Use Kubernetes-based model serving with auto-scaling
  • Implement multi-tenant model versioning to support A/B testing
  • Distribute model shards across multiple nodes for parallel inference

Distributed Feature Computation:

  • Implement feature caching with Redis/Memcached
  • Use distributed feature stores (e.g., Feast) for real-time feature retrieval
  • Partition feature computation by user segments to reduce hotspots

Fault Tolerance

Model Serving Fallbacks:

class FallbackModelServing:
    def __init__(self, primary_model, fallback_model):
        self.primary = primary_model
        self.fallback = fallback_model
    
    def predict(self, features):
        try:
            return self.primary.predict(features)
        except Exception as e:
            logger.error(f"Primary model failed: {e}")
            return self.fallback.predict(features)

Stale Model Serving on Failure:

  • Implement model version rollback with circuit breaker pattern
  • Maintain last known good model version for graceful degradation
  • Use cache warming to pre-load fallback models

Cold Start Handling Strategy

New User Handling:

class ColdStartHandler:
    def __init__(self, popularity_baseline, user_segmentation):
        self.popularity_baseline = popularity_baseline
        self.user_segmentation = user_segmentation
    
    def predict_for_new_user(self, user_features):
        # Fallback to popularity-based predictions
        if not user_features.get('user_id'):
            return self.popularity_baseline.predict()
        
        # Segment-based fallback
        segment = self.user_segmentation.get_segment(user_features)
        return self.popularity_baseline.predict(segment=segment)

New Item Handling:

  • Use content-based embeddings for new items
  • Implement candidate sampling from popular items until sufficient signal is gathered
  • Use item popularity as proxy for new item CTR

Multi-region Serving Strategy

Architecture:

graph TD
    A[User Request] --> B[Edge Proxy]
    B --> C{Region Lookup}
    C -->|US East| D[US-East Serving Cluster]
    C -->|EU West| E[EU-West Serving Cluster]
    C -->|Asia Pacific| F[APAC Serving Cluster]
    
    D --> G[Model Server]
    E --> G
    F --> G
    
    G --> H[Feature Store]
    G --> I[Embedding Cache]

Implementation Considerations:

  • Use consistent hashing for user routing
  • Implement cross-region model synchronization with eventual consistency
  • Maintain region-specific feature stores to reduce latency
  • Use CDN for static model artifacts and embeddings

Traffic Distribution:

  • 60% US East, 25% EU West, 15% Asia Pacific
  • Implement A/B testing across regions for model performance comparison
  • Use region-specific feature engineering (timezone, language, currency)

11. Open Questions, Risks & Trade-offs

Decisions requiring product / engineering / policy alignment

  • Cross-functional alignment on success metrics: Should we optimize for CTR or conversion rate, or both? How do we balance user experience vs. business revenue?
  • Model retraining frequency: Should we retrain daily, weekly, or based on drift detection? This impacts infrastructure cost and model freshness.
  • User privacy vs. personalization: How much user behavioral data can we collect and use for training without violating privacy regulations or causing user backlash?
  • A/B testing scope: Should we run large-scale experiments across all users or segment by user type (e.g., new vs. returning users)?
  • Cold start handling strategy: Should we use content-based filtering or fallback to popular items for new users/items?

Key ML risks

RiskImpactLikelihoodMitigation
Data drift in user behaviorHighMediumImplement real-time drift detection, set up automatic retraining triggers
Label shift (conversion rate changes)HighMediumMonitor conversion rate trends, use drift-aware training
Cold start for new users/itemsMediumHighImplement hybrid models with content-based fallbacks
Model overfitting to training dataMediumHighUse cross-validation, early stopping, regularization
Negative sampling biasMediumMediumValidate with holdout sets, use stratified sampling
Feature unavailability in servingHighLowImplement graceful degradation and fallback logic

Trade-offs made with justification

Trade-offJustification
Accuracy vs. latencyPrioritize sub-100ms serving latency over marginal accuracy gains, especially for real-time personalization
Freshness vs. costAccept slightly delayed feature updates to reduce infrastructure costs and complexity
Model size vs. qualityUse model compression (quantization, pruning) to ensure low latency while maintaining >95% of model quality
Online vs. batch trainingUse online learning for real-time feedback, but maintain batch training for model stability
Rule-based fallback vs. ML modelImplement rule-based fallback to handle edge cases and ensure system reliability

Alternatives considered and rejected

  • Rule-based systems: Rejected due to lack of personalization and inability to adapt to changing user behavior
  • Simple logistic regression: Rejected for limited expressiveness in capturing complex user-item interactions
  • Real-time feature engineering: Rejected due to high latency cost and complexity in maintaining consistency across training and serving
  • Single model for both CTR and conversion: Rejected due to different optimization objectives and user behavior patterns

Technical debt acknowledged

  • Feature store inconsistency: Current implementation may have eventual consistency issues between online and offline stores, requiring careful synchronization
  • Model versioning gaps: No formal model versioning strategy in place, which could lead to serving stale models in production
  • Limited explainability: Current model architecture (DNN) provides limited insight into feature importance, making it harder to debug or optimize
  • No shadow testing: Production traffic is not being logged for model validation, increasing risk of deploying underperforming models
  • Manual A/B test setup: Current process requires manual configuration, increasing chance of human error in experiment design and execution

12. Phased Implementation Roadmap

Phase 1: MVP (Weeks 1-8)

Objective: Establish baseline system with rule-based fallback and simple ML model

Deliverables:

  • Rule-based CTR prediction engine with business logic fallback
  • Simple logistic regression model trained on historical data (1M+ samples)
  • Basic feature store with 50 core features
  • Online serving endpoint with 100 QPS capacity
  • A/B testing infrastructure with 5% randomization

Dependencies:

  • Data pipeline ready (1M+ samples)
  • Feature store infrastructure provisioned
  • ML platform access (MLflow/W&B)

Critical Path:

  1. Rule-based baseline implementation (Week 1-2)
  2. Data pipeline validation and feature extraction (Week 2-3)
  3. Simple model training and validation (Week 3-4)
  4. Online serving setup with basic caching (Week 4-5)
  5. A/B test infrastructure integration (Week 5-6)
  6. Performance monitoring setup (Week 6-7)
  7. Production deployment (Week 7-8)

Phase 2: Scale (Weeks 9-16)

Objective: Expand to real-time features, distributed training, and full A/B testing

Deliverables:

  • Real-time feature computation pipeline (user/item context)
  • Distributed training infrastructure (multi-GPU cluster)
  • Advanced model architectures (DNN with attention)
  • Feature store with 500+ features and real-time updates
  • Full A/B testing with statistical significance (95% confidence)
  • Multi-region serving capability

Dependencies:

  • Distributed training infrastructure provisioned
  • Feature store with real-time capabilities
  • Multi-region cloud infrastructure (AWS/GCP)
  • Data pipeline with 10M+ samples

Critical Path:

  1. Real-time feature pipeline (Week 9-10)
  2. Distributed training setup (Week 10-11)
  3. Advanced model implementation (Week 11-12)
  4. Multi-region serving setup (Week 12-13)
  5. A/B test statistical validation (Week 13-14)
  6. Performance optimization (Week 14-15)
  7. Production rollout (Week 15-16)

Phase 3: Excellence (Weeks 17-24)

Objective: Advanced models, continuous learning, and production optimization

Deliverables:

  • Multi-task learning model (CTR + conversion rate)
  • Online learning capability with drift detection
  • Production-grade monitoring and alerting (99.9% uptime)
  • Model compression for latency optimization
  • Continuous improvement feedback loops
  • Advanced explainability and fairness monitoring

Dependencies:

  • Online learning infrastructure (streaming data)
  • Model compression tools (quantization/distillation)
  • Advanced monitoring platform (Prometheus/Grafana)
  • Fairness and explainability tools (SHAP/LIME)

Critical Path:

  1. Multi-task model development (Week 17-18)
  2. Online learning implementation (Week 18-19)
  3. Model compression and optimization (Week 19-20)
  4. Production monitoring enhancement (Week 20-21)
  5. Fairness and explainability integration (Week 21-22)
  6. Continuous improvement pipeline (Week 22-23)
  7. Final optimization and deployment (Week 23-24)

Risk Mitigation Strategy:

  • Data quality risks: Implement data validation at each phase
  • Latency issues: Monitor QPS and latency throughout all phases
  • Model drift: Establish drift detection triggers in Phase 2
  • A/B test validity: Ensure proper randomization and statistical power

Success Metrics:

  • QPS capacity: 1000+ (Phase 1) → 5000+ (Phase 3)
  • Model accuracy: 2% improvement over baseline (Phase 1) → 15% (Phase 3)
  • Latency: <200ms (Phase 1) → <50ms (Phase 3)
  • Uptime: 99.9%+ (all phases)

Resource Allocation:

  • Phase 1: 2 engineers, 1 ML engineer
  • Phase 2: 3 engineers, 2 ML engineers, 1 DevOps
  • Phase 3: 4 engineers, 3 ML engineers, 2 DevOps, 1 SRE

Was this article helpful?

Topics in this article

More from AI/ML System Design

  • AI/ML System Design

    CTR Prediction Model System Design

    Comprehensive architecture for real-time click-through rate prediction system with scalable ML pipelines and low-latency serving

  • AI/ML System Design

    Gradient Boosting Machine Design and Implementation

    Comprehensive system design document for gradient boosting frameworks including XGBoost and LightGBM architectures, trade-offs, and production implementation strategies.

  • AI/ML System Design

    Feature Backfill Strategy for ML Systems

    Comprehensive guide to designing robust feature backfill strategies for machine learning pipelines, covering incremental updates, data consistency, and system reliability patterns.

  • AI/ML System Design

    Real-time Feature Computation at Serving Time

    Comprehensive system design for real-time feature computation in machine learning serving systems with low latency and high throughput requirements.

Stay in the Loop

Get curated DSA patterns, coding problems, frontend and backend LLD/HLD, and AI/ML System Design insights delivered straight to your inbox. No spam, just focused interview and engineering content.