The "hello-world" forecasting example — the smallest end-to-end use of
the evaluation framework, and a good first stop if the Predictor /
backtest / evaluate loop is new to you.
The task deliberately keeps the framework surface minimal - a single
series, a single 1-month horizon, one BacktestSpec, the backtest()
and evaluate() entry points - so the evaluation loop itself is clear
before you meet the richer patterns in
implementations/food_price_forecasting/ (multi-target,
multi-horizon trajectories, avg/avg YoY, cached artefacts).
Forecast Canada CPI Gasoline (index, 2002=100) exactly 1 month ahead. Evaluated at every monthly origin from 2000 to 2025, with a held-out eval set covering Jan 2025 – Mar 2026.
Why gasoline? Because it breaks our models, visibly. The backtest window covers four textbook regime shifts — the 2008 crude-oil collapse, the 2014–16 OPEC-led decline, the 2020 COVID demand shock, and the 2021–22 Russia/Ukraine surge. Even at h=1 the series makes large enough month-over-month jumps during these events that last-value and ARIMA both struggle. The CRPS spikes are exactly the motivation for the richer techniques the other implementations explore: exogenous covariates, LLM context, and agents that can retrieve that context.
Why 1-month ahead? StatCan publishes CPI ~3 weeks after the reference month, so a forecast made today resolves at the next print. This is short enough to run genuine live / prospective tests: make a prediction now, validate it next month.
Headline cpi_all_items_canada was the original target here and is a
fine series - just too smooth to teach anything interesting.
Score: Continuous Ranked Probability Score or CRPS for short (lower is better). CRPS rewards both calibration (is the probability band the right width?) and sharpness (is it as narrow as it can be?).
New to the project? Start here. This self-guided preflight notebook checks
every major capability you'll need — LLM inference through the Vector proxy,
Langfuse tracing, E2B code execution, StatCan and (optional) FRED data access,
and a full end-to-end mini backtest — one cell at a time. Run it top to bottom
(Run All is safe); each check reports ✅ / .env, so it's the fastest way to confirm your setup is complete
before opening the notebooks below.
The FRED check is optional for getting_started itself, but required by the
S&P 500 reference implementation and useful for the BoC rate decisions one. FRED
API keys are free but must be requested individually — we cannot provide one
for you. Request yours early at https://fred.stlouisfed.org/docs/api/api_key.html
(approval is usually quick but can take some time). A description like "Requesting
an API key to explore the effectiveness of various forecasting techniques on
economic data." works well. Once approved, add FRED_API_KEY=your_key to your
.env.
Populate the local data cache (the stats-can download is gitignored):
uv run python scripts/fetch_cpi.pyThis registers all 47 Canada-wide CPI series from StatCan table
18-10-0004-11 into data/statcan/. Re-running is idempotent.
Registers three focus series (all-items, gasoline,
shelter), shows the cutoff-enforcement pattern, plots levels and
year-over-year change, and constructs a ForecastingTask by hand so
you can see what the YAML spec turns into.
Walks through the full cycle:
- Load
specs/cpi_gasoline_1m.yamlinto aBacktestSpec. - Construct a
LastValuePredictor(the floor) and aDartsAutoARIMAPredictor(a real baseline). - Run
backtest()for both, print a CRPS comparison table. - Plot observed gasoline vs. AutoARIMA forecasts with shaded 80% CI.
- Inspect the worst-performing origins and match them to real-world events.
- Show how
evaluate()+EvalTrackerwould spend a run from the held-out 2025 eval window. - Re-run the same predictors against shelter for a side-by-side regime-contrast.
- Serialise the
BacktestResultto YAML.
Read aieng-forecasting/aieng/forecasting/methods/baselines/naive.py for a
step-by-step annotated reference. Subclass Predictor:
from aieng.forecasting.evaluation import Predictor
class MyPredictor(Predictor):
@property
def predictor_id(self) -> str:
return "my_predictor"
def predict(self, task, context):
series = context.get_series(task.target_series_id)
...Then point backtest(predictor=MyPredictor(), spec=spec, data_service=svc)
at cpi_gasoline_1m.yaml and see whether you beat AutoARIMA.
Re-run backtest() with two or more predictors against the same spec;
the BacktestResult.mean_score values are directly comparable.
(For continuous tasks like this one the metric is CRPS; binary event
tasks — see the BoC rate-decision reference — use the Brier score.)
Once you have a predictor you're confident about, run evaluate()
against cpi_gasoline_eval_2025.yaml
— monthly origins from Jan 2025 through Mar 2026, all currently resolved.
max_runs: 5 — spend deliberately.
Questions about how the repository works? Open
99_repo_concierge.ipynb — a lite-model repo
concierge that answers onboarding questions, points you to the right notebooks
and modules, and can quote snippets from the committed public-main catalog.
-
Notebook cells are gated by
RUN_AGENT(safeRun All). -
For longer conversations, run the ADK CLI from the repository root:
uv run adk run implementations/getting_started/concierge_agent
(
uv run adk web implementations/getting_started/concierge_agentopens the same agent in a browser.)From
implementations/getting_started/, the shorteruv run adk run concierge_agentworks too.
This is different from each domain's 99_starter_agent.ipynb — those are
hackable forecasting agents; the concierge only explains the repo.
Maintainers regenerate the catalog with
uv run python scripts/build_concierge_context.py when library code,
implementations, or notebooks change.
This implementation is the minimal subset of the evaluation framework. The other reference implementations are independent — pick whichever problem fits what you're building:
food_price_forecasting/— the same evaluation story scaled up: nine correlated CPI sub-indices, a 12-step trajectory per origin,MultiTargetBacktestSpec,cached_multi_backtest(), helper modules (data.py,analysis.py,plots.py), and the avg/avg YoY metric that Canada's Food Price Report actually publishes.boc_rate_decisions/— the same harness applied to a discrete cut/hold/hike event instead of a continuous series (Brier / RPS).energy_oil_forecasting/— daily prices, news-grounded and code-executing agents, and an agent that learns a strategy from data.
getting_started/ # this directory
├── README.md
├── specs/ # backtest and eval YAML
├── concierge_agent/ # repo concierge ADK agent + catalog + artifacts
├── 00_environment_check.ipynb # self-guided setup preflight — run this first
├── 01_cpi_data_exploration.ipynb
├── 02_cpi_backtest_demo.ipynb
└── 99_repo_concierge.ipynb # ask questions about the repo (onboarding helper)
Reference predictors live in the aieng-forecasting package under
aieng/forecasting/methods/:
baselines/for floor baselines such asLastValuePredictornumerical/for Darts-based numerical predictors
Reference specs (co-located with this use case):
getting_started/specs/
├── cpi_gasoline_1m.yaml # backtest spec (2000–2025) - use freely
└── cpi_gasoline_eval_2025.yaml # eval spec (Jan 2025–Mar 2026) - 5 runs max
from aieng.forecasting.evaluation import (
Predictor, # ABC - implement this
backtest, # run a backtest, returns BacktestResult
evaluate, # run against the held-out eval window
BacktestSpec, # loaded from specs/ YAML
EvalSpec, # loaded from specs/ YAML
EvalTracker, # file-backed run counter
ContinuousForecast, # forecast payload (point + quantiles)
Prediction, # full prediction record (payload + metadata)
STANDARD_QUANTILES, # [0.05, 0.10, ..., 0.90, 0.95]
)
from aieng.forecasting.data import DataService # register series, create contexts