Questo repository contiene un sistema di monitoraggio urbano basato su un Multi‑Agent System (MAS), con integrazione di sensori simulati via MQTT, un backend web per la persistenza e la visualizzazione dei dati, e un LLM Gateway che incapsula un modello linguistico per supportare le decisioni di escalation e il coordinamento tra quartieri.
Il documento è focalizzato sugli aspetti di build & deploy, ma fornisce anche una breve panoramica dell’architettura e della struttura della repository per facilitare l’onboarding e l’utilizzo del progetto.
L’architettura è composta dai seguenti servizi, orchestrati tramite Docker Compose:
-
mqtt-broker Broker MQTT basato su Eclipse Mosquitto, responsabile della ricezione dei messaggi pubblicati dai simulatori di sensori e della loro consegna al MAS.
-
sim-sensors Servizio Python che simula sensori distribuiti su più quartieri. Pubblica periodicamente misure (ad esempio traffico e inquinamento) su topic MQTT del tipo
city/<district>/<sensor_type>. -
mas-core Core del sistema multi‑agente.
-
Ascolta i topic MQTT e converte i messaggi in eventi strutturati.
-
Instrada gli eventi ai DistrictMonitoringAgent responsabili dei singoli quartieri.
-
Gestisce un CityCoordinatorAgent per le decisioni globali e il coordinamento multi‑quartiere.
-
Interagisce con:
- il backend web per la persistenza di eventi e azioni;
- il LLM Gateway per il supporto decisionale.
-
-
web-backend Backend web basato su FastAPI, con:
- persistenza su SQLite (
data/urban_monitoring.db); - API per la registrazione e consultazione di Event e Action;
- dashboard HTML/Jinja2 per la visualizzazione interattiva dello stato urbano e delle azioni intraprese.
- persistenza su SQLite (
-
llm-gateway Micro‑servizio FastAPI che incapsula l’accesso a un LLM Engine esterno (ad es. Ollama), fornendo:
- un endpoint per la decisione di escalation a livello di quartiere (
/llm/decide_escalation); - un endpoint per la pianificazione del coordinamento multi‑quartiere (
/llm/plan_coordination); - validazione e normalizzazione delle risposte del modello in formato JSON strutturato.
- un endpoint per la decisione di escalation a livello di quartiere (
Il LLM Engine vero e proprio non è incluso nei container del progetto: viene raggiunto tramite HTTP all’URL configurato (default: http://host.docker.internal:11434).
Struttura logica della directory principale:
.
├── docker-compose.yml # Orchestrazione di tutti i servizi
├── README.md # Questo documento
├── docs/
│ ├── written_report.pdf # Relazione tecnica
│ └── diagram_screenshots/ # Screenshot dei diagrammi (architettura, sequenza, ed ER)
├── data/
│ └── urban_monitoring.db # Database SQLite (montato nel container web-backend)
├── mosquitto/
│ └── mosquitto.conf # Configurazione del broker MQTT
├── sims/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app/
│ ├── main.py # Simulatore di sensori MQTT
│ └── __init__.py
├── mas/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app/
│ ├── main.py # Avvio del MAS e dei thread degli agenti
│ ├── agent.py # DistrictMonitoringAgent, CityCoordinatorAgent, Message, SensorEvent
│ ├── mqtt_bridge.py # Listener MQTT e adattatore verso il router interno
│ ├── router.py # Router eventi/controllo verso gli agenti di quartiere
│ ├── persistence.py # Client HTTP verso il backend per Event/Action
│ ├── llm_client.py # Client HTTP verso il LLM Gateway
│ ├── config.py # Parametri di configurazione (MQTT, backend, LLM)
│ └── __init__.py
├── web/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app/
│ ├── main.py # Applicazione FastAPI + dashboard HTML
│ ├── database.py # Configurazione SQLAlchemy (SQLite)
│ ├── models.py # Modelli ORM (Event, Action)
│ ├── schemas.py # Schemi Pydantic per API REST
│ ├── static/ # File statici (CSS, JS)
│ └── templates/ # Template Jinja2 (dashboard e viste dati)
└── llm_gateway/
├── Dockerfile
├── requirements.txt
└── app/
├── main.py # API FastAPI per decide_escalation e plan_coordination
├── config.py # Caricamento e validazione delle impostazioni LLM
├── llm_client.py # Client verso il motore LLM esterno
├── schemas.py # Schemi Pydantic per richieste e risposte LLM
└── __init__.py
Per eseguire l’intero stack tramite Docker Compose sono richiesti:
- Git (per clonare il repository);
- Docker (versione recente, ad es. ≥ 20.x);
- Docker Compose (plugin integrato in Docker Desktop oppure
docker composeCLI).
Per l’esecuzione del modello LLM esterno, nella configurazione di default si assume:
-
Ollama (o servizio equivalente) in ascolto su
http://localhost:11434, con il modello:qwen2.5:0.5b
In caso non si utilizzi Ollama, è sufficiente predisporre un endpoint HTTP compatibile e aggiornare le variabili d’ambiente del LLM Gateway (vedi sezione 4.2).
Per l’esecuzione diretta dei servizi su host, senza Docker, sono richiesti:
-
Git per clonare il repository;
-
Python 3.10+ con
pipattivo; -
Mosquitto installato su host;
-
un LLM Engine accessibile via HTTP. In configurazione di riferimento si assume:
- Ollama in ascolto su
http://localhost:11434; - modello
qwen2.5:0.5b.
- Ollama in ascolto su
Le stesse indicazioni sul motore LLM valgono sia per l’esecuzione con Docker sia per l’esecuzione diretta.
Il carico computazionale del sistema è contenuto; tuttavia, per un utilizzo fluido, si consiglia:
- almeno 4 GB di RAM disponibili per i container Docker o per i processi Python;
- spazio su disco sufficiente per il database SQLite e per eventuali modelli LLM locali (nel caso di Ollama, alcuni GB a seconda del modello scelto).
Le variabili chiave sono impostate in docker-compose.yml per l’esecuzione containerizzata e possono essere ridefinite tramite un file .env o variabili d’ambiente esterne. Le stesse variabili sono richieste anche in esecuzione senza Docker e vanno impostate a livello di shell.
Servizi MAS e simulatori
-
MQTT_BROKER_HOST
Host del broker MQTT.
Default (Docker):mqtt-broker.
Default (senza Docker):localhost. -
MQTT_BROKER_PORT
Porta TCP del broker MQTT. Default:1883. -
PUBLISH_INTERVAL_SECONDS(solosim-sensors)
Intervallo in secondi tra due pubblicazioni consecutive dei sensori. Default:5. -
WEB_BACKEND_URL(solomas-core)
URL del backend web.
Default (Docker):http://web-backend:8000.
Default (senza Docker):http://localhost:8000. -
LLM_GATEWAY_URL(solomas-core)
URL del LLM Gateway.
Default (Docker):http://llm-gateway:8000.
Default (senza Docker):http://localhost:8001(o porta configurata).
Servizio LLM Gateway
-
LLM_API_BASE
Base URL del motore LLM esterno.
Default (Docker):http://host.docker.internal:11434.
Default (senza Docker):http://localhost:11434. -
LLM_MODEL_NAME
Nome del modello LLM da utilizzare. Default:qwen2.5:0.5b. -
LLM_TIMEOUT_SECONDS
Timeout in secondi per le chiamate al LLM Engine. Default:60.
Con la configurazione di default il LLM Gateway si aspetta:
- un servizio LLM raggiungibile da host su
http://localhost:11434; - lo stesso servizio raggiungibile dai container su
http://host.docker.internal:11434.
Esempio con Ollama:
-
Installare Ollama sulla macchina host.
-
Scaricare il modello di riferimento:
ollama pull qwen2.5:0.5b
-
Avviare il server Ollama (se non già in esecuzione):
ollama serve
-
Verificare che la chiamata HTTP da host:
curl http://localhost:11434/api/tags
restituisca l’elenco dei modelli disponibili.
Se si desidera utilizzare un endpoint diverso (ad esempio un LLM remoto), è necessario aggiornare le variabili d’ambiente del LLM Gateway.
Esempio in Docker (docker-compose.yml):
environment:
- LLM_API_BASE=http://<nuovo-endpoint>
- LLM_MODEL_NAME=<nome-modello>
- LLM_TIMEOUT_SECONDS=60Esempio in esecuzione senza Docker (Linux/macOS, Bash):
export LLM_API_BASE=http://<nuovo-endpoint>
export LLM_MODEL_NAME=<nome-modello>
export LLM_TIMEOUT_SECONDS=60Esempio in esecuzione senza Docker (Windows, PowerShell):
$env:LLM_API_BASE="http://<nuovo-endpoint>"
$env:LLM_MODEL_NAME="<nome-modello>"
$env:LLM_TIMEOUT_SECONDS="60"Il backend web utilizza un database SQLite collocato in:
./data/urban_monitoring.db
Nel container web-backend il database è montato come volume in /app/data, con URL:
SQLALCHEMY_DATABASE_URL = "sqlite:///./data/urban_monitoring.db"Il file urban_monitoring.db viene creato e popolato automaticamente alla prima esecuzione del backend. È possibile:
- effettuare un backup del database copiando il file nella directory
data/; - eliminare il file per ripartire da uno stato "pulito" (si perderanno però tutti gli eventi e le azioni registrate).
Il servizio mqtt-broker utilizza l’immagine ufficiale eclipse-mosquitto:2 e carica la configurazione da:
./mosquitto/mosquitto.conf
Nel file di configurazione è possibile regolare, ad esempio:
- politiche di autenticazione e ACL;
- livelli di log;
- impostazioni di persistenza del broker.
Nell’esecuzione con Docker, le directory di dati e log sono montate su volumi Docker (mosquitto_data, mosquitto_log) per preservare lo stato tra esecuzioni successive. Nell’esecuzione senza Docker, è possibile riutilizzare lo stesso file di configurazione avviando Mosquitto direttamente su host.
git clone <URL_REPOSITORY> urban-mas-iot-llm
cd urban-mas-iot-llmAssicurarsi che nella root sia presente il file docker-compose.yml.
Con il motore LLM già in esecuzione sull’host (vedi sezione 4.2), è possibile avviare l’intero sistema con:
docker compose up --buildL’opzione --build forza la ricostruzione delle immagini Docker per sim-sensors, mas-core, web-backend e llm-gateway sulla base dei rispettivi Dockerfile e requirements.txt.
Il comando avvia i seguenti container:
mqtt-brokerweb-backend(porta host:8000)mas-coresim-sensorsllm-gateway(porta host:8100)
Una volta che i container sono in esecuzione:
-
Aprire il browser su:
http://localhost:8000 -
La dashboard del backend web dovrebbe mostrare:
- gli eventi generati dai simulatori;
- eventuali azioni di escalation e coordinamento;
- indicatori sintetici dello stato urbano.
Per verificare lo stato dei container:
docker compose psPer ispezionare i log del MAS:
docker compose logs mas-corePer verificare che il LLM Gateway sia raggiungibile:
curl http://localhost:8100/docsDovrebbe essere visualizzata la documentazione interattiva OpenAPI esposta da FastAPI.
Per arrestare tutti i container mantenendo i volumi (incluso il database):
docker compose downPer arrestare i container e rimuovere anche i volumi (inclusi database e dati Mosquitto):
docker compose down -vAttenzione: l’opzione -v elimina definitivamente i dati persistenti.
L’esecuzione senza Docker è pensata per scenari di sviluppo o debug. In questo caso tutti i servizi vengono eseguiti come processi Python (più Mosquitto su host).
Anche per l’esecuzione senza Docker il primo passo consiste nel clonare il repository:
git clone <URL_REPOSITORY> urban-mas-iot-llm
cd urban-mas-iot-llmpython -m venv .venv
source .venv/bin/activate # su Windows (PowerShell): .venv\\Scripts\\Activate.ps1Installare i requisiti dei singoli servizi:
pip install -r sims/requirements.txt
pip install -r mas/requirements.txt
pip install -r web/requirements.txt
pip install -r llm_gateway/requirements.txtInstallare Mosquitto su host e avviarlo con la configurazione fornita:
mosquitto -c mosquitto/mosquitto.confVerificare che sia in ascolto sulla porta 1883 su localhost.
Prima di avviare i servizi Python è necessario impostare tutte le variabili d’ambiente utilizzate dal sistema, descritte in sezione 4.1.
Esempio (Linux/macOS, Bash):
export MQTT_BROKER_HOST=localhost
export MQTT_BROKER_PORT=1883
export PUBLISH_INTERVAL_SECONDS=5
export WEB_BACKEND_URL=http://localhost:8000
export LLM_GATEWAY_URL=http://localhost:8001
export LLM_API_BASE=http://localhost:11434
export LLM_MODEL_NAME=qwen2.5:0.5b
export LLM_TIMEOUT_SECONDS=60Esempio (Windows, PowerShell):
$env:MQTT_BROKER_HOST="localhost"
$env:MQTT_BROKER_PORT="1883"
$env:PUBLISH_INTERVAL_SECONDS="5"
$env:WEB_BACKEND_URL="http://localhost:8000"
$env:LLM_GATEWAY_URL="http://localhost:8001"
$env:LLM_API_BASE="http://localhost:11434"
$env:LLM_MODEL_NAME="qwen2.5:0.5b"
$env:LLM_TIMEOUT_SECONDS="60"Le variabili devono essere impostate nei terminali dai quali verranno avviati web-backend, llm-gateway, mas-core e sim-sensors.
In quattro terminali separati, dopo aver attivato l’ambiente virtuale e impostato le variabili d’ambiente:
-
Backend web
cd web uvicorn app.main:app --host 0.0.0.0 --port 8000 -
LLM Gateway
cd llm_gateway uvicorn app.main:app --host 0.0.0.0 --port 8001 -
MAS core
cd mas python -m app.main -
Simulatori di sensori
cd sims python -m app.main
La dashboard sarà accessibile da browser all’indirizzo:
http://localhost:8000
Per testare il comportamento del sistema è possibile osservare gli scenari chiave direttamente dalla dashboard e dai log, sia in esecuzione con Docker sia in esecuzione diretta su host.
-
Scenario non critico
- I valori simulati restano sotto le soglie; il MAS registra gli eventi ma non genera escalation né azioni di coordinamento.
- La dashboard mostra un flusso di eventi regolare, con severità bassa o moderata.
-
Scenario critico con LLM attivo
- Valori oltre soglia producono eventi critici.
- I DistrictMonitoringAgent possono interrogare il LLM tramite il LLM Gateway per affinare la severità e decidere l’escalation.
- Il CityCoordinatorAgent può richiedere un piano di coordinamento multi‑quartiere a
/llm/plan_coordination, generando una o più azioni registrate inactions.
-
Scenario di fallimento LLM con fallback
-
Arrestando il motore LLM o alterando
LLM_API_BASE, le chiamate al LLM falliscono. -
Il MAS attiva le politiche di fallback:
- decisioni basate su soglie e regole deterministiche;
- motivazioni esplicite nel campo
reasondelle azioni, che evidenziano l’uso di fallback.
-
Questa sezione riporta alcuni comandi ricorrenti esclusivamente per la gestione dello stack tramite Docker Compose.
# Ricostruire e avviare tutti i servizi
docker compose up --build
# Vedere i log in tempo reale del MAS
docker compose logs -f mas-core
# Vedere i log del LLM Gateway
docker compose logs -f llm-gateway
# Controllare lo stato dei container
docker compose ps
# Arrestare lo stack mantenendo i dati
docker compose down
# Arrestare lo stack eliminando volumi e dati
docker compose down -vQuesto README fornisce le informazioni essenziali per il build & deploy del sistema, sia in modalità containerizzata sia in esecuzione diretta su host, insieme alle indicazioni operative per la verifica del corretto funzionamento dei servizi e degli scenari principali.