Разработка AI-системы оптимизации размещения товаров на складе
Где именно хранится каждый SKU — прямо влияет на скорость сборки. Правильное слотирование сокращает пробег сборщика на 20–35% без изменения технологии или оборудования.
Задача слотирования
Цели размещения:
- Минимизировать суммарный пробег при сборке заказов
- Сократить время комплектации срочных заказов
- Обеспечить эргономику: тяжёлые/крупные в нижних ячейках
- Разделить несовместимые категории (алкоголь, химия, пища)
Принцип ABC-XYZ:
| Класс | Оборот | Вариация | Размещение |
|---|---|---|---|
| AX | Высокий | Стабильный | «Золотая зона» — ближайшая к зоне упаковки |
| AY | Высокий | Нестабильный | Близко к зоне сборки |
| AZ | Высокий | Непредсказуемый | Средняя зона, резервный запас |
| BX/BY | Средний | Любая | Средняя зона |
| CX/CY/CZ | Низкий | Любая | Дальняя зона, высокие стеллажи |
ML-прогнозирование «горячести» SKU
Классический ABC строится на исторических данных. ML улучшает точность прогноза будущей активности:
import lightgbm as lgb
import pandas as pd
from datetime import datetime, timedelta
def predict_sku_activity(order_history, sku_features, forecast_horizon_days=30):
"""
Прогноз количества отборок по SKU на следующие N дней.
Используется для пересчёта слотирования.
"""
# Признаки временного ряда
df = order_history.groupby(['sku', 'date'])['qty_picked'].sum().reset_index()
df = df.sort_values(['sku', 'date'])
features = []
for sku in df['sku'].unique():
sku_df = df[df['sku'] == sku].set_index('date')['qty_picked']
# Лаговые признаки
feat = {
'sku': sku,
'avg_picks_7d': sku_df.tail(7).mean(),
'avg_picks_30d': sku_df.tail(30).mean(),
'avg_picks_90d': sku_df.tail(90).mean(),
'trend': sku_df.tail(14).mean() - sku_df.tail(28).head(14).mean(),
'cv': sku_df.tail(30).std() / (sku_df.tail(30).mean() + 0.001),
**sku_features.get(sku, {}) # категория, вес, габариты
}
features.append(feat)
X = pd.DataFrame(features).drop('sku', axis=1).fillna(0)
# LightGBM для прогноза среднедневной активности
model = lgb.LGBMRegressor(n_estimators=200, learning_rate=0.05)
# (предобученная модель)
predicted_daily_picks = model.predict(X)
return dict(zip([f['sku'] for f in features], predicted_daily_picks))
Задача переслотирования (Re-slotting)
Перемещать ВСЕ SKU дорого (трудозатраты). Оптимальный re-slotting:
- Ранжировать SKU по выгоде от перемещения (delta_travel_time * picks_per_week)
- Ограничение: перемещение ≤ 200 SKU/неделю (пропускная способность команды)
- Выбрать топ-200 с максимальным суммарным эффектом
Integer Programming для выбора перемещений:
import pulp
def select_moves(sku_benefits, sku_current_slots, slot_candidates, max_moves=200):
"""
sku_benefits: {sku: expected_travel_savings_hours_per_week}
Выбрать max_moves перемещений с максимальной суммарной экономией
"""
prob = pulp.LpProblem("slotting_optimization", pulp.LpMaximize)
move_vars = {sku: pulp.LpVariable(f"move_{sku}", cat='Binary')
for sku in sku_benefits}
# Объектив: максимальная экономия
prob += pulp.lpSum(sku_benefits[sku] * move_vars[sku]
for sku in sku_benefits)
# Ограничение: не более max_moves перемещений
prob += pulp.lpSum(move_vars.values()) <= max_moves
prob.solve(pulp.PULP_CBC_CMD(msg=0))
return [sku for sku, var in move_vars.items() if var.value() > 0.5]
Совместное хранение (Affinity Analysis)
Товары, часто заказываемые вместе → хранить рядом. Affinity matrix из истории заказов:
- Market Basket Analysis (Apriori / FP-Growth) на заказах
- Lift > 2.0 и поддержка > 5% → кандидаты на совместное размещение
- Ограничение: совместимость (химия и пища — запрещено)
Результат: 15–20 «кластеров аффинности» на складе, каждый группирует часто-совместные SKU.
Поддержка решений
Визуализация:
- 2D план склада с тепловой картой: текущие «горячие» ячейки
- Предлагаемые перемещения: откуда / куда / ожидаемая экономия
- ROI расчёт: экономия трудочасов × ставка сборщика
Срок разработки: 2–3 месяца для системы с ABC-XYZ, ML-прогнозированием активности и оптимизатором re-slotting с интеграцией в WMS.







