back to work
Personal Project · In Development
In Progress

Demand-Forecasting Agent

Agentic ML pipeline for retail demand forecasting

View on GitHub

A demand-forecasting system for retail sales data in the M5 canonical format — a sales table (series × time), a calendar, and weekly sell prices. The ML core is built and validated as plain, defensible code first; an agent layer (planner → executor → critic → report) wraps it last. Format-general and threshold-adaptive by design: it ingests any M5-format retail dataset and calibrates its decision thresholds to that dataset's own distribution.

STATUSPhase 2 of 5 complete
TESTS96 passing
SERIES30,490 store-item
01 / Roadmap

Roadmap

Five phases — each gated by review before proceeding.

EDA & Dataset Selection
Complete

Three branch signals over M5; four sub-datasets selected at pattern extremes; calibrated thresholds.

L2 Baseline
Complete

Plain L2 (Ridge regression) baseline per dataset — the number every later model must beat. WMAPE on a rolling-origin holdout, frozen feature set, sparse-series mean fallback.

3
LightGBM Bake-off

Per dataset: L2 vs Tweedie vs Poisson on WMAPE, proper time-series holdout, with an explicit leakage check. Quantile models added per B4.

4
Agent Wrapper (Agno)

Wrap the working core: planner → executor → critic → report. The critic must actually gate acceptance.

5
Final Test

Run the finished agent end-to-end on the held-out sub-dataset D.

02 / Agent architecture

Agent architecture

The agent (Phase 4) orchestrates a core that already stands on its own.

01
ValidatorM5-schema strict

Confirms M5 schema: required columns present, dates continuous, no missing crucial fields. Flags problems, does not repair.

02
PlannerEDA + Signals

Runs EDA, interprets the three branch signals (intermittency, spikes, day-of-week η²), and does preprocessing.

03
ExecutorFits per branch

Applies deterministic, documented branch rules — selects which branch applies, does not invent modeling decisions.

04
CriticGates acceptance

WMAPE vs threshold + sanity checks (non-negative forecasts, plausible magnitudes). A model that fails is flagged, not accepted.

05
ReportStructured summary

Short, structured summary to the user with per-dataset results and branch coverage.

03 / Branch logic

Branch logic

Deterministic, documented rules the executor applies — the agent selects which branch, it does not invent decisions.

B1 — Tweedie
IF High intermittency — modelable and zero-share genuinely high
LightGBM Tweedie

Zero-inflated demand; Tweedie's compound Poisson-Gamma form fits, unlike squared error.

Standard
IF Modelable but below the B1 cut
LightGBM L2 / Poisson (per bake-off)

Lower-intermittency series don't need Tweedie. Explicit complement of B1.

B2 — Sparse Fallback
IF Too sparse (ADI in the upper tail)
Simple baseline (MA / Croston)

Not enough signal for a heavy model; knowing when not to use it is deliberate.

B4 — Quantile
IF Use case needs inventory intervals
LightGBM quantiles (0.1 / 0.5 / 0.9)

Requirement-driven — a range answers a different question than a point.

04 / Selected sub-datasets

Selected sub-datasets

Each pick sits at a pattern extreme and stresses one branch. D is held out, frozen until Phase 5.

Pick
Cell
Zero %
Stresses
A — dense / fast
CA_3 × FOODS_3
0.35
Standard objective + baseline
B — intermittent
CA_2 × HOUSEHOLD_2
0.72
B1 (Tweedie)
C — slow / sparse
CA_4 × HOBBIES_2
0.93
B2 (baseline fallback)
D — held-out (mixed)
TX_1 × FOODS_2
0.64
Phase 5 general test
05 / Phase 2 baseline results

Phase 2 baseline results

5-fold rolling-origin CV. The bar for Phase 3 is min(baseline, 1.0) — a zero forecast scores exactly 1.0 under WMAPE.

A — dense
CA_3 × FOODS_3
WMAPE
0.621
Phase 3 bar
0.621

Ridge α=1e4, raw — the fitted floor is a real bar

B — intermittent
CA_2 × HOUSEHOLD_2
WMAPE
1.106
Phase 3 bar
1.000

Ridge α=0.01, log1p — baseline lost to a zero forecast

C — slow / sparse
CA_4 × HOBBIES_2
WMAPE
1.631
Phase 3 bar
1.000

Ridge α=10, log1p — baseline lost to a zero forecast (n=149, full cell)

06 / Design decisions

Design decisions

Each is documented in the plans and enforced by a test.

Core First, Agent Last

The ML core is built and validated as plain, defensible code. The agent wrapper (Phase 4) orchestrates what already works — it is not load-bearing.

Data-Relative Thresholds

Branch cuts are percentiles of each dataset's own distribution, so they adapt to new data. Literature constants (Syntetos–Boylan) stay absolute and cited.

WMAPE, Not WRMSSE

WMAPE is volume-weighted and robust on zero-heavy series. WRMSSE re-imports the squared-error sensitivity that Tweedie avoids — rejected by design.

Held-Out Integrity

Dataset D informs no distribution and no threshold. The four sub-datasets are disjoint by construction with symmetric cell exclusions.

Seasonality Is Not a Branch

Day-of-week explains only ~1% of median item variance (η² ≈ 0.012). The per-series gate was dropped; every series gets calendar features instead.

Flag, Don't Fake

Validation and the critic flag problems rather than guessing or silently patching. A model that fails the critic is flagged, not accepted.

07 / Tech stack

Tech stack

ML Core
PythonLightGBMscikit-learnSciPy
Data
PandasParquetM5 (Kaggle)
Signals
Intermittency (ADI, CV², SB-class)η²MAD spikes
Metric
WMAPE (sum-then-divide, volume-weighted)
Validation
Rolling-origin CVExpanding windowLeakage checks
Agent
Agno (Phase 4 — planned)
Testing
pytest (96 tests)

Thanks for reading. Want to see the rest?

Back to all work