Authors: Group #6 — Lukun He, Yutao Li, Dong Zheng | ECE 285, UC San Diego
EDAgent achieves 97% end-to-end success with 0.42% average cost error vs CVXPY optimum across 30 test cases spanning IEEE 14-bus to 300-bus systems — compared to 57% success and 6.73% error for the LLM-only baseline.
Economic Dispatch (ED) is a core power systems optimization task: allocate generation output across units to meet demand at minimum cost, subject to generator capacity constraints.
The problem with LLMs alone: LLMs hallucinate numerical results, violate physical constraints (power balance, generator limits), and cannot reliably solve quadratic programs — especially for large systems with 50+ generators.
EDAgent's solution: Use the LLM as an orchestrator in a ReAct loop that calls a provably correct CVXPY solver, rather than predicting dispatch values directly.
User (natural language query)
│
▼
┌─────────────────────────────────────────────────────┐
│ ReAct Agent Loop │
│ │
│ Thought → Action → Observation → Thought → ... │
│ │
│ ┌──────────┐ ┌────────┐ ┌────────┐ ┌───────┐ │
│ │load_case │ │ cvxpy │ │ memory │ │ viz │ │
│ └──────────┘ └────────┘ └────────┘ └───────┘ │
└─────────────────────────────────────────────────────┘
│
▼
Optimal dispatch + cost (guaranteed feasible)
| Tool | Description |
|---|---|
load_case |
Loads IEEE standard bus data via pandapower |
cvxpy |
Solves quadratic ED optimization (OSQP backend) |
memory |
TF-IDF retrieval with importance weighting + time decay |
visualization |
Dispatch bar chart + load distribution pie chart |
- Working memory with priority-based retention (importance score 0–1)
- Exponential time decay for stale entries
- TF-IDF retrieval for context lookup across multi-turn queries
ED-agent/
│
├── README.md
├── .env # API key, model ID, base URL, timeout
├── start.sh # One-command startup script
│
├── ── Core Agent ──
├── app.py # FastAPI server (port 5001, OpenAI-compatible)
├── EDAgent.py # ReAct loop: Thought / Action / Observation
├── EDAgentLLM.py # LLM client wrapper (OpenAI SDK)
├── ToolExecutor.py # Tool registry and dispatcher
│
├── ── Tools ──
├── tool_cvxpy.py # CVXPY quadratic solver tool
├── load_case.py # IEEE case loader (14/30/57/118/200/300-bus)
├── memory_tool.py # Working memory: TF-IDF + time decay
├── visualize.py # Matplotlib dispatch visualization
│
├── ── Baseline (LLM-only, no tools) ──
├── BaselineAgent.py # Single-shot chain-of-thought agent
├── baseline_benchmark.py # Baseline benchmark runner
│
├── ── Evaluation ──
├── benchmark.py # EDAgent benchmark (30 test cases)
├── benchmark_reference.py # CVXPY ground-truth reference solver
├── comparison_report.py # Side-by-side comparison report generator
│
├── ── Results ──
├── benchmark_results.json # EDAgent results (30 cases)
├── baseline_benchmark_results.json # Baseline results (30 cases)
├── comparison_report_output.txt # Full generated comparison report
│
├── ── Docs ──
├── docs/
│ ├── proposal_ece285.pdf # Project proposal
│ ├── EDAgent_Final_Presentation.pptx
│ ├── EDAgent_Overview.pptx
│ └── PRESENTATION_SUMMARY.md
│
├── ── Runtime Artifacts ──
├── memory/ # Agent memory store
├── memory_storage/ # Memory index files
├── output_charts/ # Generated visualization PNGs
└── test.ipynb # Development notebook
pip install fastapi uvicorn openai python-dotenv cvxpy pandapower scikit-learn matplotlibLLM_API_KEY=your_api_key
LLM_MODEL_ID=your_model_id # e.g. gpt-4o, qwen-plus, claude-3-5-sonnet
LLM_BASE_URL=https://your_endpoint/v1
LLM_TIMEOUT=120bash start.sh
# or:
python app.py # FastAPI on port 5001The server exposes an OpenAI-compatible API at http://localhost:5001/v1/chat/completions.
Start OpenWebUI on port 3000, then add a custom model:
- API Base URL:
http://localhost:5001/v1 - Model ID:
ed-agent-react
Run Economic Dispatch for IEEE 14-bus system. Total load 259 MW.
Run Economic Dispatch for IEEE 57-bus system with Generator 1 offline.
Run Economic Dispatch for IEEE 118-bus system. Increase total load by 10%.
Run Economic Dispatch for IEEE 300-bus system. Total load 23525 MW.
| System | Buses | Generators | Load Scale |
|---|---|---|---|
| IEEE14 | 14 | 5 | ~180–260 MW |
| IEEE30 | 30 | 6 | ~90–300 MW |
| IEEE57 | 57 | 7 | ~900–1600 MW |
| IEEE118 | 118 | 54 | ~3000–4000 MW |
| IEEE200 | 200 | 29 | ~900–1200 MW |
| IEEE300 | 300 | 69 | ~20000 MW |
Test scenarios (5 per system):
baseline— standard dispatch at nominal loadunit_outage× 2 — one generator taken offlineload_lo— reduced total loadload_hi— increased total load
30 test cases (6 IEEE systems × 5 scenarios), evaluated against CVXPY ground truth.
| Metric | EDAgent (ReAct) | Baseline (LLM-only) |
|---|---|---|
| Total Test Cases | 30 | 30 |
| End-to-End Success Rate | 29/30 (97%) | 17/30 (57%) |
| Avg Cost Error vs CVXPY | 0.42% | 6.73% |
| Max Cost Error | 6.33% | 95.35% |
| Power Balance Satisfied | Guaranteed by solver | 2/30 |
| Generator Limits Respected | Guaranteed by solver | 20/30 |
| System | EDAgent Success | EDAgent Avg Err | Baseline Success | Baseline Avg Err |
|---|---|---|---|---|
| IEEE14 | 5/5 | 1.92% | 5/5 | 0.00% |
| IEEE30 | 2/5 | 0.00% | 4/5 | 0.00% |
| IEEE57 | 5/5 | 0.00% | 4/5 | 23.84% |
| IEEE118 | 4/5 | 0.00% | 2/5 | 1.40% |
| IEEE200 | 4/5 | 0.00% | 2/5 | 0.00% |
| IEEE300 | 3/5 | 0.00% | 0/5 | N/A |
IEEE 300-bus (69 generators): EDAgent completes 3/5 cases with zero cost error. The LLM-only baseline produces no valid output — demonstrating a decisive scalability advantage.
| Failure Mode | EDAgent | Baseline |
|---|---|---|
| Parse error (no cost extracted) | 6 | 8 |
| Timeout (max steps reached) | 1 | — |
-
Correctness: EDAgent delegates to CVXPY, achieving near-optimal results. The LLM baseline estimates values directly, leading to large errors (up to 95%) on larger systems.
-
Feasibility: EDAgent guarantees power balance and generator limits via the solver. The baseline violates physical constraints in 93% of cases.
-
Scalability: EDAgent works on 69-generator systems. The baseline completely fails — the number of generators exceeds LLM numerical reasoning capacity.
-
Architecture advantage: The ReAct Thought→Action→Observation loop provides structured, tool-grounded reasoning that eliminates hallucination in the critical optimization step.
-
Trade-off: The baseline is faster (single API call vs multi-step loop) but sacrifices accuracy and constraint satisfaction.
Each generator i has quadratic cost:
Cost_i(Pg_i) = a_i · Pg_i² + b_i · Pg_i + c_i
Objective: Minimize ∑ᵢ Cost_i(Pg_i)
Subject to:
- Power balance:
∑ᵢ Pg_i = P_demand - Generator limits:
Pmin_i ≤ Pg_i ≤ Pmax_ifor all active units i
# Run full EDAgent benchmark (requires server running on port 5001)
python benchmark.py
# Run LLM-only baseline benchmark
python baseline_benchmark.py
# Generate side-by-side comparison report → comparison_report_output.txt
python comparison_report.py- Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models" — ICLR 2023
- Mohammadi et al., "Large Language Models for Economic Dispatch in Smart Grids" — arXiv:2505.21931
- Wood & Wollenberg, "Power Generation, Operation, and Control" — Wiley, 2013