An ML-powered electricity demand forecasting platform paired with an autonomous LangGraph agent that interprets forecast results and takes operational actions — generating daily briefings, recommending demand response schedules, flagging procurement risks, and alerting on anomalies.
PJM historical demand data
↓
Feature engineering (lag features, cyclical encoding, rolling statistics)
↓
XGBoost forecasting model (0.81% MAPE on test set)
↓
48-hour demand forecast with confidence intervals
↓
LangGraph agent classifies forecast
↓
NORMAL HIGH_DEMAND LOW_CONFIDENCE ANOMALY
↓ ↓ ↓ ↓
Daily Demand response Procurement High-priority
briefing schedule risk flag alert
↓
Decision logged + dashboard updated
ML Forecasting Pipeline
- PJM hourly electricity demand data — 16 years, 145k rows
- Feature engineering: lag features (1h, 24h, 168h), cyclical encoding, rolling statistics
- Chronological train/val/test split — no data leakage
- Model comparison: Naive Baseline → Linear Regression → XGBoost
- XGBoost with early stopping — 0.81% MAPE on held-out test set
- Evaluation: MAE, RMSE, MAPE, sMAPE
Autonomous Agent
- LangGraph state machine with conditional routing
- Four classification paths: NORMAL, HIGH_DEMAND, ANOMALY, LOW_CONFIDENCE
- Deterministic classification — rule-based, no LLM for the decision logic
- LLM-generated outputs: daily briefings, demand response schedules, procurement flags, anomaly alerts
- Full decision audit log with node-level reasoning
- Runs automatically every 6 hours via APScheduler
Dashboard
- 48-hour demand forecast chart with confidence intervals
- Live system status with classification badge
- AI-generated operational briefing
- Agent decision log with full output history
- Manual agent run trigger
| Layer | Technology |
|---|---|
| Forecasting | XGBoost, scikit-learn, Prophet |
| Feature engineering | pandas, numpy |
| Agent orchestration | LangGraph |
| LLM | Groq llama-3.3-70b-versatile |
| API | FastAPI |
| Scheduling | APScheduler |
| Frontend | Jinja2 + Chart.js |
| Data | PJM Hourly Energy Consumption (Kaggle) |
| Model | MAE | RMSE | MAPE |
|---|---|---|---|
| Naive Baseline | 2,165 MW | 2,969 MW | 6.98% |
| Linear Regression | 760 MW | 976 MW | 2.45% |
| XGBoost (tuned) | 251 MW | 345 MW | 0.81% |
grid-load-forecasting-agent/
├── ml/
│ ├── features.py # Feature engineering pipeline
│ ├── split.py # Chronological train/val/test split
│ ├── evaluate.py # MAE, RMSE, MAPE, sMAPE metrics
│ ├── train.py # XGBoost training pipeline
│ └── forecast.py # 48hr forecast generation
├── agent/
│ ├── state.py # LangGraph state definition
│ ├── graph.py # Graph wiring and conditional routing
│ ├── groq_client.py # Groq API client
│ ├── runner.py # Agent entry point
│ └── nodes/
│ ├── load_forecast.py
│ ├── classify.py
│ ├── daily_briefing.py
│ ├── demand_response.py
│ ├── anomaly_alert.py
│ ├── procurement_flag.py
│ └── decision_logger.py
├── api/
│ ├── forecasts.py # Forecast endpoints
│ └── agent.py # Agent run and decision endpoints
├── ui/
│ ├── app.py # Dashboard routes
│ └── templates/ # Jinja2 templates
├── tests/
│ ├── test_features.py # Feature engineering tests
│ └── test_classify.py # Agent classification tests
├── notebooks/
│ ├── 01_eda.ipynb
│ ├── 02_feature_engineering.ipynb
│ └── 03_model_comparison.ipynb
└── main.py # FastAPI app + scheduler
- Python 3.12
- Groq API key (free tier works)
- PJM dataset from Kaggle
Download PJME_hourly.csv from PJM Hourly Energy Consumption and place it in data/.
git clone https://github.com/yourusername/grid-load-forecasting-agent.git
cd grid-load-forecasting-agent
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtGROQ_API_KEY=your_groq_api_key
DEMAND_HIGH_THRESHOLD_MW=150000
ANOMALY_SIGMA_THRESHOLD=3.0
CONFIDENCE_WIDTH_THRESHOLD=0.15
FORECAST_HORIZON_HOURS=48
APP_BASE_URL=http://localhost:8000python -m ml.trainpython main.pyDashboard available at http://localhost:8000
API docs at http://localhost:8000/docs
The agent receives a 48-hour forecast and classifies it using deterministic threshold rules — no LLM involved in the classification decision. This keeps it fast, auditable, and explainable.
Once classified, the appropriate action node runs and calls Groq to generate a structured output. Every decision is logged with the full reasoning.
| Classification | Trigger | Action |
|---|---|---|
| ANOMALY | Demand deviates >3σ from mean | High-priority alert with possible causes and recommended actions |
| HIGH_DEMAND | Peak forecast > 150,000 MW | Demand response schedule with target reduction and recommended assets |
| LOW_CONFIDENCE | Mean interval width > 15% of predicted | Procurement risk flag with recommended buffer |
| NORMAL | None of the above | Plain-English daily briefing for operations team |
pytest tests/ -v10 tests covering feature engineering and agent classification logic.
MIT