We are developing LLM for ANDES for transient stability modeling and simulation; LLM for AMS for scheduling modeling and simulation.
Conversational LangGraph agent that drives CURENT LTB AMS β DCOPF, RTED, ED, UC, ACOPF β through natural-language commands.
Built as a sibling to pv-curve-llm; same multi-agent architecture, swapped domain engine (AMS / cvxpy / ANDES instead of pandapower).
- Overview
- Phase 1 Routes (1-6)
- Architecture
- Installation
- Quick Start
- Usage Examples
- LangGraph Workflow
- Configuration
- Project Structure
- Roadmap (Phase 2 & 3)
- License
LLM-AMS lets you ask things like
"Load case ieee14_uced, trip generator PV_1, then solve with SCS"
β¦and have the agent translate that into the exact AMS API calls you'd otherwise write by hand from examples/ex2.ipynb:
sp = ams.load(ams.get_case('ieee14/ieee14_uced.xlsx'), setup=True, no_output=True)
sp.StaticGen.set(src='u', idx='PV_1', attr='v', value=0)
sp.RTED.update()
sp.RTED.run(solver='SCS')The agent uses a LangGraph state machine with a classifier β router β six route-specific nodes (Q&A, Discovery, Case I/O, Configure, Modify, Solve), plus a planner for compound queries like "change load PQ_1 to 3.2 then solve".
Technology stack
- Agent framework: LangGraph + LangChain
- LLMs: Ollama (default, local) or OpenAI
- Power simulator: LTB AMS (
ltbams) + ANDES + cvxpy - Solvers: open-source CLARABEL, OSQP, SCS, HiGHS, SCIP, SCIPY (commercial GUROBI / MOSEK / CPLEX / COPT auto-detected if installed)
| Route | Node | Maps to AMS API | ex2 cell |
|---|---|---|---|
| 1 β Q&A | question_general |
concept Q&A: routines, constraints, cvxpy DCP | (educational) |
| 2 β Discovery | question_parameter |
cvxpy.installed_solvers(), all_routines, list loads / gens / lines, constraint ON/OFF |
cell 64 |
| 3 β Case I/O | case_io |
ams.load(ams.get_case(...)), case info |
cells 6, 50, 59 |
| 4 β Configure | configure |
active routine, solver, routine.config.update(t=...), routine.disable([...]), routine.enable([...]) |
cells 69, 76, 81, 92 |
| 5 β Modify | modify |
PQ.alter('p0', ...), StaticGen.set('u', ...), Line.alter('u', ...), Line.set('rate_a', ...) |
cells 19, 41, 52, 61 |
| 6 β Solve | solve |
routine.run(solver=...) β pg, plf, pd, obj + bar-chart plots |
cells 13, 23, 34, 45, 54, 66, 72, 78, 89, 96, 103 |
Routes 7-11 (multi-period temporal, ANDES co-sim, custom cvxpy formulations, exporting) are Phase 2 / 3.
βββββββββββ
β START β
ββββββ¬βββββ
β
βΌ
ββββββββββββββ
β CLASSIFIER β β one of six message_type labels
ββββββ¬ββββββββ
β
βΌ
ββββββββββββββ
β ROUTER β β simple single-route OR planner for compound
ββββββ¬ββββββββ
β
ββββΊ QUESTION_GENERAL βββββΊ END | ADVANCE_STEP
ββββΊ QUESTION_PARAMETER βββΊ END | ADVANCE_STEP
ββββΊ CASE_IO ββββββββββββββΊ END | ADVANCE_STEP | ERROR_HANDLER
ββββΊ CONFIGURE ββββββββββββΊ END | ADVANCE_STEP | ERROR_HANDLER
ββββΊ MODIFY βββββββββββββββΊ END | ADVANCE_STEP | ERROR_HANDLER
ββββΊ SOLVE ββββββββββββββββΊ END | ADVANCE_STEP | ERROR_HANDLER
ββββΊ PLANNER ββββββββββββββΊ STEP_CONTROLLER βββΊ (any of the 6) βββΊ ADVANCE_STEP βββΊ SUMMARY βββΊ END
ββββββββββββββββββ
β ERROR_HANDLER β ββββββΊ ADVANCE_STEP | END
ββββββββββββββββββ
- State (
agent/state/app_state.py): TypedDict LangGraph state holding messages, currentInputs, lastresults, plan / step counter, error info. - Inputs (
agent/schemas/inputs.py): pydantic model βcase_path,routine,solver,config_t,disabled_constraints,load_overrides,gen_off,line_off,line_rate_overrides. - AMSContext (
agent/ams_engine/engine.py): thin object that owns oneams.Systemand exposes idempotent methods matching ex2's API (load_case,alter_load_p0,set_gen_status,set_line_status,set_config_t,disable_constraints,solve, β¦). Held by the SessionManager; bound into node closures (same pattern asretrieverin pv-curve-llm). - Workflow (
agent/workflows/workflow.py): compiled LangGraph StateGraph wiring all 13 nodes. - Plotting (
agent/ams_engine/plotting.py): bar charts forpg,plf,pdsaved undergenerated/.
- Python β₯ 3.11 (tested on 3.12)
- conda or any venv tool
- Ollama for local LLM (optional if you use OpenAI)
conda create -n llm-ams python=3.12 -y
conda activate llm-ams
pip install -r requirements.txtrequirements.txt pulls in ltbams (which brings ANDES + cvxpy + kvxopt), LangChain stack, plus open-source solvers highspy + pyscipopt. cvxpy's bundled CLARABEL, OSQP, SCS, SCIPY are always available.
ollama pull llama3.1:8bAdd a .env file (copy .env.example) if you want OpenAI:
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-minipython -c "import ams, cvxpy; print(ams.__version__, cvxpy.installed_solvers())"
# 1.3.0 ['CLARABEL', 'SCS', 'SCIP', 'SCIPY', 'HIGHS', 'OSQP']conda activate llm-ams
cd LLM_AMS
python main.pyYou will be asked three things in order (each has a default β just hit Enter):
- Provider:
openaiorollama(default ollama) - Routine: any AMS class name (
RTED,DCOPF,ED,UC, β¦) (default RTED) - Solver: shown filtered by your routine's compatibility (default first in list)
The agent then loads the ex2 default case 5bus/pjm5bus_demo.xlsx and you're at the prompt.
Message: Change load PQ_1 to 3.2 and PQ_2 to 3.2
β modify: load PQ_1 p0 β 3.2 pu, load PQ_2 p0 β 3.2 pu
Message: Solve
β solve: RTED with CLARABEL, obj = 0.846329
pg = [0.20, 1.64, 0.60, 5.96, 2.00] β exact match with ex2
Message: Trip generator PV_1 then solve
β planner: 2 steps
β modify: tripped generator PV_1
β solve: pg = [-0.00, 0.50, 0.60, 2.97, 0.33] β matches ex2 cell 47
Message: Disable plflb and plfub
β configure: disabled plflb, disabled plfub
Message: Solve
β solve: line-flow limits ignored; plf swings to ex2 cell 74 values
Message: Switch routine to DCOPF
Message: Use solver SCS
Message: Load case ieee14_uced
Message: Solve
β DCOPF on IEEE-14 with SCS, plots saved under generated/
Message: What routines are available?
β list of 33 routines grouped by family
Message: Which solvers can I use for UC?
β ['SCIP', 'SCIPY'] β only MIP-capable installed solvers
Message: What is RTED and how is it different from DCOPF?
β educational answer from the AMS concepts reference
Type quit (or q) to exit.
13 nodes wired in agent/workflows/workflow.py:
| Category | Nodes |
|---|---|
| Routing | classifier, router |
| Planning | planner, step_controller, advance_step, summary |
| Actions (Routes 1-6) | question_general, question_parameter, case_io, configure, modify, solve |
| Recovery | error_handler |
Simple-query path: START β classifier β router β <one route> β END.
Multi-step path (planner-triggered by "then", "and then", "compare", or change-then-solve patterns):
START β classifier β router β planner β
step_controller β <route node> β advance_step β
... loop ...
β summary β END
Recovery: any route node may attach error_info; the conditional edge routes to error_handler, which uses the LLM to explain the failure and resets retry state.
# Default β local Ollama
OLLAMA_MODEL=llama3.1:8b
OLLAMA_BASE_URL=http://localhost:11434
# Optional β OpenAI
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini
# Where to drop generated plots
AMS_OUTPUT_DIR=generated# GUROBI (license required)
pip install gurobipy
# MOSEK (license required)
pip install mosekBoth are auto-detected via cvxpy.installed_solvers() and will appear in the solver-selection prompt for compatible routines (UC, ACOPF, large-scale DCOPF).
Drop any AMS-readable file (.xlsx, .json, .raw, MATPOWER .m) into AMS's cases/ folder, or pass an absolute path:
Message: Load case /Users/me/my_grid.xlsx
The startup banner is an ASCII-art string in
agent/utils/display.py (constant _BANNER_LINES,
ANSI-Shadow font). Edit those lines to change the wordmark.
LLM_AMS/
βββ main.py # entry point
βββ cli.py # terminal interface (provider β routine β solver prompts)
βββ requirements.txt
βββ .env.example
β
βββ agent/
β βββ core.py # LLM + AMSContext + graph factory
β βββ session.py # SessionManager (bootstraps default case, streams turns)
β βββ prompts.py # all system / user prompts
β β
β βββ workflows/
β β βββ workflow.py # compiled LangGraph
β β
β βββ nodes/ # 13 nodes
β β βββ classify.py
β β βββ route.py
β β βββ planner.py
β β βββ step_controller.py
β β βββ advance_step.py
β β βββ summary.py
β β βββ error_handler.py
β β βββ question_general.py # Route 1
β β βββ question_parameter.py # Route 2
β β βββ case_io.py # Route 3
β β βββ configure.py # Route 4
β β βββ modify.py # Route 5
β β βββ solve.py # Route 6
β β
β βββ state/
β β βββ app_state.py # TypedDict
β β
β βββ schemas/ # pydantic structured-output schemas
β β βββ inputs.py
β β βββ classifier.py
β β βββ parameter.py
β β βββ planner.py
β β βββ response.py
β β
β βββ ams_engine/ # the AMS-side "engine" (mirrors pv_curve/)
β β βββ engine.py # AMSContext: live ams.System wrapper
β β βββ routines.py # routine β solver compatibility
β β βββ plotting.py # pg / plf / pd bar charts
β β
β βββ utils/
β βββ common_utils.py
β βββ context.py
β βββ display.py # rich banner / parameter table / streaming
β
βββ generated/ # output plots (gitignored)
Phase 1 ships Routes 1-6 (single-period DCOPF / RTED workflows from ex1-ex4). The following routes from the design table are deferred:
| Phase | Route | Function |
|---|---|---|
| 2 | 7 β Temporal | multi-period ED / UC schedule, time-series plots |
| 2 | 8 β Scenario | snapshot + compare two solve results (matches pv-curve Route 8) |
| 3 | 9 β ANDES | ss.to_andes(...) co-simulation (AMS's unique feature) |
| 3 | 10 β Custom Formulation | runtime cvxpy extension (ex8) |
| 3 | 11 β Export | dump case to xlsx / JSON / MATPOWER |
This project follows the licenses of its dependencies:
- LangChain / LangGraph: MIT
- LTB AMS: GPL-3.0
- cvxpy: Apache-2.0
- ANDES: GPL-3.0
- CURENT LTB β the testbed AMS is part of
- pv-curve-llm β the architecture this project mirrors
- LTB AMS β the scheduling simulator being driven
- LangChain / LangGraph β agent framework
- Ollama β local LLM runtime