Quando l'intelligenza pianifica, ma non controlla l'esecuzione
Per molto tempo abbiamo progettato gli agenti AI secondo un modello relativamente semplice: un Large Language Model interpreta una richiesta, seleziona uno strumento, ne osserva il risultato e decide cosa fare successivamente.
Il modello funziona bene per task brevi. Diventa però progressivamente meno efficiente quando deve coordinare decine di strumenti, elaborare grandi volumi di dati, gestire retry, attendere eventi esterni e garantire che operazioni già completate non vengano ripetute accidentalmente.
Con Dynamic Workflows for Azure Functions Hosted Skills, annunciato da Microsoft l'8 ottobre 2026, emerge un'architettura differente: l'LLM genera un piano strutturato, mentre un runtime durevole e deterministico si occupa della sua esecuzione.
La distinzione è fondamentale. Il modello non diventa improvvisamente affidabile perché produce JSON anziché testo. È il sistema che interpreta quel JSON a dover imporre vincoli, autorizzazioni, dipendenze e garanzie operative.
Principio architetturale: un LLM può proporre una sequenza di azioni, ma non dovrebbe essere l'autorità finale che decide se quelle azioni sono consentite, sicure o già state eseguite.
1. Il problema del reasoning loop tradizionale
Consideriamo un agente che deve analizzare un evento meteorologico, interrogare servizi GIS, produrre una mappa di rischio e inviare una notifica.
User / Event
|
v
LLM
|
+-- Tool: read rainfall
| |
| v
| LLM
|
+-- Tool: read terrain
| |
| v
| LLM
|
+-- Tool: run spatial analysis
| |
| v
| LLM
|
+-- Tool: generate map
| |
| v
| LLM
|
+-- Tool: publish result
|
v
LLM
Ogni operazione comporta un nuovo passaggio attraverso il modello. Se gli strumenti restituiscono dati voluminosi, il contesto si riempie di risultati intermedi che il modello potrebbe non aver bisogno di interpretare direttamente.
Il problema non è soltanto economico. È anche architetturale:
- Latenza: le chiamate al modello possono serializzare operazioni indipendenti.
- Context pollution: risultati intermedi e log possono occupare una parte significativa della context window.
- Recovery: un crash durante un'operazione lunga richiede meccanismi di ripresa espliciti.
- Retry: ripetere un tool può duplicare effetti esterni.
- Audit: ricostruire perché un'azione sia stata eseguita può diventare difficile.
- Security: il contenuto restituito da un tool può influenzare impropriamente le decisioni successive dell'agente.
Un reasoning loop è appropriato quando ogni risultato richiede una nuova decisione semantica. Non è necessariamente la scelta migliore quando le operazioni sono note, verificabili e largamente indipendenti.
2. L'architettura emergente: Plan, Validate, Execute, Verify
La nuova separazione delle responsabilità può essere rappresentata così:
USER / EVENT
|
v
+---------------+
| LLM PLANNER |
+---------------+
|
Proposed DAG
|
v
+---------------+
| DAG VALIDATOR |
| Policy Engine |
+---------------+
|
Approved Plan
|
v
+---------------+
| DURABLE ENGINE|
+---------------+
/ | \
v v v
Tool A Tool B Tool C
\ | /
\ | /
v v v
AGGREGATION
|
v
VERIFICATION
|
v
FINAL RESULT
Il passaggio più importante è quello fra planner e runtime.
Il piano generato dal modello deve essere considerato un input non attendibile, anche quando il modello appartiene a un provider affidabile. La validazione non può essere una semplice verifica della sintassi JSON: deve includere controlli strutturali, semantici, autorizzativi e di consumo delle risorse.
Microsoft applica questo paradigma nella preview Dynamic Workflows di Azure Functions Hosted Skills. Il runtime utilizza Durable Functions per eseguire il piano senza riportare continuamente i risultati intermedi nel reasoning loop dell'LLM.
È importante distinguere la funzionalità specifica Microsoft, attualmente in preview e basata su tool Python, da un'implementazione equivalente realizzata autonomamente in C# e .NET con Durable Functions.
3. Il DAG come contratto eseguibile
Un Directed Acyclic Graph è un grafo diretto senza cicli. Ogni nodo rappresenta un'operazione; ogni arco rappresenta una dipendenza.
Consideriamo un piano per valutare il rischio associato a precipitazioni intense:
ReadRainfall
|
+----------------+
| |
v v
LoadTerrain LoadAssets
| |
v |
ComputeRunoff |
| |
+--------+-------+
|
v
IntersectRisk
|
v
GenerateMap
|
v
PublishResult
Il DAG esplicita immediatamente il parallelismo possibile: LoadTerrain e LoadAssets possono partire quando ReadRainfall è completato, se le rispettive operazioni non dipendono l'una dall'altra.
In un sistema reale conviene spingersi oltre, rendendo indipendenti tutte le acquisizioni che non richiedono il risultato delle precipitazioni.
Un contratto JSON minimale
{
"schemaVersion": "1.0",
"workflowId": "rainfall-risk-20261009",
"nodes": [
{
"id": "rainfall",
"tool": "gis.readRainfall",
"dependsOn": []
},
{
"id": "terrain",
"tool": "gis.loadTerrain",
"dependsOn": []
},
{
"id": "assets",
"tool": "gis.loadAssets",
"dependsOn": []
},
{
"id": "risk",
"tool": "gis.computeRisk",
"dependsOn": [
"rainfall",
"terrain",
"assets"
]
},
{
"id": "map",
"tool": "gis.generateMap",
"dependsOn": ["risk"]
}
]
}
Questo JSON è una rappresentazione concettuale del nostro contratto applicativo, non lo schema ufficiale della preview Microsoft.
Un contratto production-grade dovrebbe inoltre includere versione del piano, input tipizzati, riferimenti agli output, classificazione dei tool, limiti di esecuzione e policy di autorizzazione. Gli argomenti non devono poter contenere endpoint arbitrari o istruzioni eseguibili non previste.
4. DAG validation: il vero confine di sicurezza
La validazione di un piano prodotto da un LLM deve essere eseguita prima che il workflow venga avviato.
I controlli minimi comprendono:
- Identificatori univoci dei nodi.
- Assenza di dipendenze inesistenti.
- Assenza di cicli.
- Limiti su numero di nodi, profondità e fan-out.
- Tool presenti in una allowlist server-side.
- Compatibilità tra input e output dei tool.
- Autorizzazioni coerenti con utente, tenant e risorsa.
- Limiti su costo, durata e concorrenza.
- Approvazioni esplicite per operazioni con effetti esterni sensibili.
Validazione strutturale in C#
public sealed record WorkflowNode(
string Id,
string Tool,
string[] DependsOn);
public sealed record WorkflowPlan(
string SchemaVersion,
WorkflowNode[] Nodes);
public static class DagValidator
{
private static readonly HashSet<string> AllowedTools =
new(StringComparer.Ordinal)
{
"gis.readRainfall",
"gis.loadTerrain",
"gis.loadAssets",
"gis.computeRisk",
"gis.generateMap"
};
public static void Validate(WorkflowPlan plan)
{
ArgumentNullException.ThrowIfNull(plan);
if (plan.SchemaVersion != "1.0")
throw new InvalidOperationException(
"Unsupported schema version.");
if (plan.Nodes is null ||
plan.Nodes.Length is < 1 or > 50)
throw new InvalidOperationException(
"Invalid workflow size.");
var nodes = new Dictionary<string, WorkflowNode>(
StringComparer.Ordinal);
foreach (var node in plan.Nodes)
{
if (string.IsNullOrWhiteSpace(node.Id) ||
!nodes.TryAdd(node.Id, node))
throw new InvalidOperationException(
"Invalid or duplicate node ID.");
if (!AllowedTools.Contains(node.Tool))
throw new InvalidOperationException(
$"Tool not allowed: {node.Tool}");
}
var indegree = nodes.Keys.ToDictionary(
id => id,
_ => 0,
StringComparer.Ordinal);
var children = nodes.Keys.ToDictionary(
id => id,
_ => new List<string>(),
StringComparer.Ordinal);
foreach (var node in nodes.Values)
{
var dependencies = node.DependsOn ??
throw new InvalidOperationException(
"Dependencies cannot be null.");
foreach (var dependency in dependencies.Distinct())
{
if (!nodes.ContainsKey(dependency))
throw new InvalidOperationException(
$"Unknown dependency: {dependency}");
indegree[node.Id]++;
children[dependency].Add(node.Id);
}
}
var ready = new Queue<string>(
indegree
.Where(x => x.Value == 0)
.Select(x => x.Key));
var visited = 0;
while (ready.Count > 0)
{
var id = ready.Dequeue();
visited++;
foreach (var child in children[id])
{
if (--indegree[child] == 0)
ready.Enqueue(child);
}
}
if (visited != nodes.Count)
throw new InvalidOperationException(
"Workflow contains a cycle.");
}
}
L'algoritmo utilizza una variante del topological sorting di Kahn. La complessità è O(V + E), dove V rappresenta i nodi ed E le dipendenze.
Questo codice valida soltanto la struttura e una allowlist di base. Non rappresenta un security validator completo. In produzione servono anche controllo degli argomenti, autorizzazione contestuale, compatibilità dei tipi, quote e validazione della provenienza del piano.
Un ulteriore accorgimento consiste nel calcolare un hash canonico del piano validato, registrando insieme ad esso identità del richiedente, versione delle policy e identificativo dell'esecuzione. Il runtime dovrebbe eseguire esattamente quel piano immutabile, evitando modifiche successive alla validazione.
5. Durable Functions: perché l'orchestrazione deve essere deterministica
Azure Durable Functions utilizza una forma di event sourcing per ricostruire lo stato delle orchestrazioni.
Quando un'orchestrazione riprende dopo un evento, il runtime può rieseguire il codice dell'orchestratore dall'inizio, recuperando dalla history i risultati delle attività già completate.
Questo meccanismo prende il nome di replay.
Execution history
|
+-- ActivityScheduled(A)
+-- ActivityCompleted(A)
+-- ActivityScheduled(B)
+-- ActivityCompleted(B)
|
v
Orchestrator Replay
|
+-- A: result from history
+-- B: result from history
+-- C: schedule new activity
Il codice dell'orchestratore deve quindi essere deterministico. Non dovrebbe effettuare direttamente chiamate HTTP, interrogazioni SQL, operazioni GIS o letture dell'orologio di sistema.
Le operazioni con effetti esterni appartengono alle Activity Functions.
Esempio di orchestrazione C# con .NET isolated worker
using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
public static class GeoWorkflow
{
[Function(nameof(RunGeoWorkflow))]
public static async Task<string> RunGeoWorkflow(
[OrchestrationTrigger]
TaskOrchestrationContext context)
{
var rainfallTask =
context.CallActivityAsync<string>(
"ReadRainfall");
var terrainTask =
context.CallActivityAsync<string>(
"LoadTerrain");
var assetsTask =
context.CallActivityAsync<string>(
"LoadAssets");
await Task.WhenAll(
rainfallTask,
terrainTask,
assetsTask);
var input = new RiskInput(
rainfallTask.Result,
terrainTask.Result,
assetsTask.Result);
var risk =
await context.CallActivityAsync<string>(
"ComputeRisk",
input);
return await context.CallActivityAsync<string>(
"GenerateMap",
risk);
}
}
public sealed record RiskInput(
string RainfallUri,
string TerrainUri,
string AssetsUri);
Questo è un esempio di orchestrazione statica. Non è ancora un interprete dinamico di DAG: serve a mostrare il modello Durable Functions e il parallelismo fan-out/fan-in.
Le tre Activity iniziali restituiscono riferimenti a dati persistenti, non interi raster o dataset serializzati nella history dell'orchestrazione.
Per interpretare DAG generati dinamicamente è preferibile utilizzare un executor generico che riceva un piano validato, identifichi i nodi pronti e li programmi attraverso un catalogo di Activity consentite.
6. Un DAG executor dinamico: la differenza fra scheduling e reasoning
Il runtime non deve chiedere all'LLM quale nodo eseguire dopo ogni completamento. Deve applicare una regola deterministica:
Ready(node) =
AllDependenciesCompleted(node)
AND PolicyAllows(node)
AND ResourcesAvailable(node)
Un possibile algoritmo è:
completed = {}
pending = allNodes
while pending is not empty:
ready = nodes where:
every dependency is completed
if ready is empty:
fail invalid workflow
execute ready nodes concurrently
await completion
persist outputs
mark nodes completed
remove nodes from pending
Questo pseudocodice illustra l'idea, ma in produzione richiede alcuni raffinamenti importanti.
Prima di tutto, i nodi devono essere ordinati stabilmente per evitare divergenze durante il replay. Inoltre la concorrenza deve essere limitata, gli errori devono essere gestiti per nodo e il risultato di ogni Activity deve essere registrato con un identificatore stabile.
Un semplice Task.WhenAll() su tutti i nodi pronti può produrre fan-out eccessivo. In un workflow geografico, cinquanta richieste simultanee a un servizio ArcGIS possono saturare il servizio, esaurire risorse o produrre throttling.
È quindi utile distinguere tre livelli di concorrenza:
- Workflow concurrency: quante orchestrazioni possono essere attive.
- Node concurrency: quanti nodi dello stesso DAG possono essere eseguiti contemporaneamente.
- Resource concurrency: quante operazioni possono utilizzare uno specifico servizio, database o pool di worker.
Il terzo livello è particolarmente importante: limitare il fan-out di una singola orchestrazione non impedisce a cento orchestrazioni concorrenti di sovraccaricare lo stesso servizio.
7. Idempotenza: at-least-once non significa exactly-once
Uno dei problemi più pericolosi dei workflow distribuiti è la ripetizione delle operazioni.
Durable Functions può rieseguire un'Activity quando si verifica un errore o quando il completamento dell'attività non è stato registrato correttamente.
Supponiamo che un'Activity esegua:
POST /arcgis/rest/services/Analysis/GPServer/SubmitJob
Il servizio remoto riceve la richiesta e avvia il job. Subito dopo, il worker Azure Functions si interrompe prima di registrare il risultato.
Al riavvio, il runtime può ripetere l'Activity.
Il risultato potrebbe essere:
First attempt --> ArcGIS Job 1001
Worker crash
Second attempt --> ArcGIS Job 1002
Il sistema ha prodotto due elaborazioni per una sola richiesta logica.
Il retry è quindi corretto dal punto di vista dell'infrastruttura, ma non necessariamente dal punto di vista del business.
La soluzione: Operation Ledger e Idempotency Key
Ogni operazione con effetti esterni dovrebbe avere una chiave stabile:
IdempotencyKey =
WorkflowId + ":" + NodeId
Una tabella SQL può mantenere lo stato dell'operazione:
CREATE TABLE WorkflowOperations
(
OperationKey NVARCHAR(200) NOT NULL
PRIMARY KEY,
State NVARCHAR(30) NOT NULL,
ExternalJobId NVARCHAR(200) NULL,
ResultUri NVARCHAR(2000) NULL,
UpdatedAt DATETIMEOFFSET NOT NULL
);
Il pattern operativo diventa:
1. Reserve OperationKey atomically
2. Check previous execution state
3. Submit or reconcile external job
4. Persist ExternalJobId
5. Poll external job
6. Persist ResultUri
7. Mark operation Completed
È fondamentale riconoscere che il ledger, da solo, non garantisce exactly-once.
Esiste infatti una finestra critica fra l'invio della richiesta al sistema esterno e il salvataggio dell'ExternalJobId. Se il processo si interrompe in quel punto, il database locale non sa se l'operazione remota sia stata accettata.
Per eliminare questa ambiguità serve un meccanismo di riconciliazione: una chiave di idempotenza supportata dal servizio remoto, un identificatore applicativo ricercabile oppure un adapter che possa individuare un job già creato.
Se l'API esterna non supporta alcuna forma di deduplicazione o riconciliazione, la garanzia di exactly-once non può essere ottenuta semplicemente aggiungendo retry e una tabella SQL.
8. Retry, timeout, circuit breaker e compensazione
Un workflow distribuito affidabile deve distinguere gli errori transitori da quelli permanenti.
Un HTTP 429 o 503 può giustificare un retry con backoff. Un errore di autorizzazione, un input GIS non valido o un piano che viola una policy non dovrebbe invece essere ripetuto automaticamente.
Per gli errori transitori è possibile utilizzare le retry policy delle Activity Durable Functions.
Per operazioni che modificano sistemi esterni è inoltre utile introdurre una logica di compensazione.
Consideriamo:
CreateAnalysisJob
|
v
PublishFeatureLayer
|
v
UpdateWebMap
|
v
NotifyUsers
Se UpdateWebMap fallisce dopo la pubblicazione del layer, il sistema potrebbe dover eliminare il layer temporaneo o ripristinare la configurazione precedente.
Questo modello è vicino al pattern Saga: ogni azione può avere un'azione compensativa, ma la compensazione non equivale necessariamente a un rollback transazionale perfetto.
Per un workflow geografico occorre inoltre distinguere:
- Risultati temporanei, eliminabili automaticamente.
- Risultati pubblicati, che richiedono autorizzazioni specifiche per la rimozione.
- Modifiche a dati autorevoli, che possono richiedere approvazione umana.
- Notifiche già inviate, che non possono essere semplicemente annullate.
La progettazione delle compensazioni deve essere parte del catalogo dei tool, non una decisione improvvisata dall'LLM dopo un errore.
9. Isolamento dei sub-agent: un agente specializzato non è un processo fidato
Un workflow può delegare attività a sub-agent specializzati.
Per esempio:
GeoCoordinator
|
+-- RainfallAgent
|
+-- TerrainAgent
|
+-- InfrastructureAgent
|
+-- RiskVerificationAgent
Il vantaggio è la specializzazione. Il rischio è l'ampliamento della superficie di attacco.
Un sub-agent non dovrebbe ereditare automaticamente l'intera cronologia del coordinatore, tutte le sue credenziali o la capacità di invocare qualsiasi tool.
Nella preview Microsoft Dynamic Workflows, le invocazioni dei sub-agent utilizzano sessioni isolate e stateless, con istruzioni, modelli, strumenti e timeout propri. Non ricevono automaticamente la conversation history o la sandbox del coordinatore.
Questo è un buon punto di partenza, ma non sostituisce l'isolamento infrastrutturale.
Capability-based execution
Ogni sub-agent dovrebbe ricevere soltanto le capability necessarie.
RainfallAgent
READ rainfall observations
READ station metadata
NO write access
NO publishing permissions
TerrainAgent
READ elevation datasets
EXECUTE terrain analysis
NO access to notifications
PublisherAgent
READ approved outputs
PUBLISH to approved folders
NO arbitrary service access
Il controllo deve essere imposto dal gateway dei tool e dalle identità utilizzate verso i servizi, non soltanto da istruzioni testuali come "non pubblicare dati".
In Azure, Managed Identity, Azure RBAC, Key Vault e isolamento di rete possono contribuire a questo modello, purché le identità siano effettivamente separate secondo i confini di autorizzazione richiesti.
10. Context engineering: la memoria dell'agente non è lo stato del workflow
Un altro errore frequente consiste nell'utilizzare la conversation history come archivio dello stato operativo.
La memoria del modello è utile per mantenere obiettivi, vincoli e informazioni semantiche. Non dovrebbe essere la fonte autorevole per determinare se un job è completato, quale output è stato pubblicato o quali autorizzazioni sono state concesse.
Propongo di separare quattro livelli:
+----------------------------------+
| Semantic Context |
| Goal, assumptions, constraints |
+----------------------------------+
| Execution State |
| Node status, retries, timestamps |
+----------------------------------+
| Artifact Store |
| Raster, JSON, logs, results |
+----------------------------------+
| Audit & Authorization |
| Identity, approvals, provenance |
+----------------------------------+
Il modello dovrebbe ricevere soltanto il contesto necessario per decidere il piano e, alla fine, interpretare i risultati.
Gli output voluminosi dovrebbero essere conservati in storage e rappresentati attraverso riferimenti immutabili o versionati, accompagnati da metadata come checksum, schema, sistema di riferimento e provenienza.
Questo evita che raster, grandi FeatureSet, log o migliaia di record GIS vengano inseriti nella context window senza alcun beneficio.
11. GeoAgent: un laboratorio architetturale con ArcGIS e Azure
Immaginiamo di voler realizzare un agente che risponda alla richiesta:
Analizza le precipitazioni delle ultime 24 ore, individua le aree potenzialmente critiche e produci una mappa delle infrastrutture esposte.
Il modello non dovrebbe generare direttamente una mappa di rischio basandosi soltanto sul testo. Deve selezionare strumenti GIS deterministici, ciascuno con input, output e limiti ben definiti.
Pipeline proposta
Weather / Rainfall API
|
v
Observation Validation
|
v
Spatial Interpolation
IDW / Spline
|
v
Rainfall Raster
|
+------------------+
| |
v v
Terrain Data Asset Inventory
| |
+---------+--------+
|
v
Spatial Analysis
|
v
Exposure Overlay
|
v
Result Validation
|
v
ArcGIS Publishing
|
v
WebMap / App
Una possibile implementazione utilizza:
- C#/.NET: API di ingresso, validazione, orchestrazione e integrazione enterprise.
- Azure Durable Functions: scheduling durevole, retry e recovery.
- Azure SQL: operation ledger, metadata, policy e audit applicativo.
- Azure Blob Storage: artifact store per input e output voluminosi.
- ArcGIS Enterprise: geoprocessing, analisi raster, feature service e pubblicazione.
- LLM: interpretazione della richiesta, costruzione del piano e sintesi finale.
È importante non confondere l'interpolazione delle precipitazioni con una simulazione idrologica o idraulica completa.
IDW e Spline producono superfici interpolate a partire dalle osservazioni. Per modellare runoff, propagazione delle piene o dinamiche fisiche occorrono modelli e dati aggiuntivi, opportunamente calibrati e validati.
Inoltre l'eventuale esecuzione di Spatial Analyst richiede di verificare disponibilità delle capability e licenze nella versione e nell'ambiente ArcGIS effettivamente distribuiti.
12. Un adapter ArcGIS robusto deve conoscere il ciclo di vita dei job
Un adapter per un servizio ArcGIS Geoprocessing asincrono non dovrebbe limitarsi a invocare SubmitJob e attendere indefinitamente.
Deve modellare esplicitamente gli stati del job remoto:
NotSubmitted
|
v
Submitted
|
v
Executing
|
+----> Succeeded
|
+----> Failed
|
+----> Cancelled
|
+----> TimedOut
La gestione deve distinguere lo stato del job ArcGIS dallo stato dell'Activity Azure Functions.
Un job ArcGIS può continuare a essere eseguito anche quando il worker che lo ha avviato non è più disponibile. Per questo è preferibile salvare l'identificatore del job e utilizzare un meccanismo di polling o riconciliazione durevole.
Per processi molto lunghi, il pattern può diventare:
Submit GP Job
|
v
Persist Job ID
|
v
Durable Timer
|
v
Check GP Status
|
+-- Running --> Durable Timer
|
+-- Success --> Fetch Results
|
+-- Failure --> Error Policy
Il polling non dovrebbe occupare un thread o una Function instance per tutta la durata del job.
Per i servizi GIS occorre inoltre definire timeout, frequenza di polling, politiche di cancellazione e comportamento in caso di perdita temporanea della connettività.
13. Observability: misurare il workflow, non soltanto i token
Un sistema agentico enterprise dovrebbe essere osservabile su più livelli.
Il livello LLM deve registrare modello, versione, token, latenza, versione del prompt e identificativo del piano generato.
Il livello workflow deve registrare durata dei nodi, retry, timeout, dipendenze, errori e stato complessivo.
Il livello GIS deve registrare servizio utilizzato, identificativo del job, tempi di elaborazione, parametri analitici, dataset e riferimenti agli output.
Una struttura di correlazione può essere:
TraceId
|
+-- PlanningSpan
|
+-- ValidationSpan
|
+-- WorkflowInstanceId
|
+-- Node: rainfall
+-- Node: terrain
+-- Node: risk
+-- Node: publishing
|
+-- ArcGIS JobId
OpenTelemetry e Application Insights possono contribuire a questa osservabilità, ma occorre propagare esplicitamente gli identificatori di correlazione fra sistemi.
Il replay delle orchestrazioni richiede inoltre attenzione: log prodotti ingenuamente durante il replay possono essere duplicati. Dove disponibile, conviene utilizzare il replay-safe logger fornito dal runtime Durable Functions.
Metriche che misurerei
- Planning latency e planning token cost.
- Percentuale di piani rifiutati dal validator.
- Numero di nodi e profondità media del DAG.
- Parallelismo effettivo rispetto a quello teorico.
- Retry per tool e per servizio esterno.
- Numero di job remoti riconciliati dopo failure.
- Workflow completion rate.
- Tempo medio e percentile P95/P99 per nodo.
- Costo per workflow completato.
- Accuratezza e validità dei risultati GIS.
Una riduzione dei token non rappresenta automaticamente un miglioramento del sistema se aumentano i workflow falliti o diminuisce la qualità del risultato.
14. Sicurezza: il piano generato dall'LLM è una superficie di attacco
Un piano apparentemente valido può essere pericoloso anche senza contenere codice eseguibile.
Consideriamo alcuni scenari:
- Tool escalation: il modello seleziona un tool di pubblicazione quando l'utente ha richiesto soltanto un'analisi.
- Data exfiltration: un parametro contiene un endpoint esterno non autorizzato.
- Resource exhaustion: il piano richiede centinaia di analisi raster molto costose.
- Cross-tenant access: un nodo tenta di utilizzare dati appartenenti a un altro tenant.
- Prompt injection: un dataset o documento esterno influenza il planner inducendolo a inserire operazioni non richieste.
- Approval spoofing: un output intermedio dichiara falsamente che l'utente ha autorizzato un'azione.
Le contromisure devono essere applicate fuori dal modello:
Untrusted User / Tool Data
|
v
LLM Planner
|
v
Schema Validator
|
v
Policy Decision
|
v
Approval Gateway
|
v
Tool Dispatcher
|
v
Authorized Execution
Un'approvazione dovrebbe essere un evento autenticato e correlato a una specifica operazione, non una proprietà booleana modificabile dal modello.
Il tool dispatcher dovrebbe risolvere le credenziali dal contesto server-side, evitando che il piano possa scegliere liberamente identità, segreti o endpoint.
15. Benchmark Microsoft: cosa dimostrano realmente i numeri
Nel proprio annuncio, Microsoft ha confrontato un normale reasoning loop con Dynamic Workflows su un benchmark sintetico di analisi di dieci servizi.
I risultati riportati sono:
| Metrica | Reasoning loop | Dynamic Workflow |
|---|---|---|
| Token utilizzati | 99.097 | 6.781 |
| Latenza | 247,1 s | 12,7 s |
| Riduzione token | — | 93,1% |
| Riduzione latenza | — | 95,1% |
I numeri sono notevoli, ma vanno interpretati correttamente. Il benchmark riguarda un task specifico, strutturato e adatto alla parallelizzazione. Non significa che qualsiasi workflow agentico possa ottenere automaticamente riduzioni equivalenti.
Il vantaggio dipende soprattutto da tre fattori:
- Le attività indipendenti possono essere eseguite in parallelo.
- Gli output intermedi non devono attraversare continuamente il modello.
- Il numero di round-trip LLM viene drasticamente ridotto.
Un workflow che richiede decisioni semantiche dopo ogni passaggio potrebbe invece beneficiare meno di questo modello.
16. Il trade-off: meno autonomia durante l'esecuzione, più affidabilità
Separare pianificazione ed esecuzione introduce anche un limite.
Un DAG statico non può adattarsi arbitrariamente a qualsiasi informazione inattesa. Se un risultato intermedio richiede una nuova strategia, il workflow deve prevedere una decisione condizionale oppure una fase esplicita di replanning.
Per questo considero particolarmente interessante un modello ibrido:
LLM Planning
|
v
Validated DAG
|
v
Deterministic Execution
|
+-- Expected Result
| |
| v
| Continue DAG
|
+-- Unexpected Result
|
v
Controlled Replan
|
v
New Validation
|
v
Resume Execution
Il replanning deve essere limitato e tracciato. Ogni nuovo piano deve essere nuovamente validato, e il sistema deve conoscere quali operazioni precedenti siano già state completate.
Non dovrebbe essere possibile aggirare un rifiuto del validator semplicemente generando ripetutamente nuovi piani.
17. Verso una nuova architettura: il GeoAgent come compilatore di workflow geografici
La prospettiva più interessante è considerare l'LLM non come il motore di esecuzione, ma come un compilatore semantico.
L'utente esprime un obiettivo in linguaggio naturale. Il modello lo traduce in una rappresentazione intermedia tipizzata. Il sistema valida questa rappresentazione, la ottimizza e la esegue utilizzando strumenti GIS affidabili.
Natural Language Goal
|
v
LLM Planner
|
v
GeoWorkflow IR
|
v
Semantic Validation
|
v
Optimization Passes
|
v
Execution Plan
|
v
Durable GIS Runtime
|
v
Verified GeoArtifacts
Questa analogia con un compilatore è particolarmente potente.
La rappresentazione intermedia potrebbe contenere informazioni tipizzate come:
- Sistema di riferimento spaziale.
- Tipo geometrico.
- Risoluzione raster.
- Unità di misura.
- Estensione geografica.
- Dipendenze tra dataset.
- Requisiti di licenza e capability GIS.
- Classificazione dei dati.
- Stima del costo computazionale.
Il validator potrebbe rifiutare un'operazione che combina raster con sistemi di riferimento incompatibili, utilizza unità di misura non coerenti oppure richiede capability non disponibili.
Un optimizer potrebbe invece individuare acquisizioni parallelizzabili, eliminare elaborazioni duplicate, riutilizzare risultati già presenti nello storage o selezionare differenti backend di elaborazione.
È importante distinguere ciò che è già disponibile da ciò che rappresenta una possibile evoluzione progettuale: questa GeoWorkflow IR è una proposta architetturale, non un prodotto Esri o Microsoft attualmente disponibile con tale nome.
18. Oltre il DAG: workflow gerarchici, feedback loop e sistemi autonomi
Il DAG è ideale per rappresentare dipendenze acicliche. Non descrive però naturalmente sistemi che devono reagire indefinitamente a nuovi eventi.
Un sistema di monitoraggio territoriale continuo può richiedere cicli di osservazione, analisi, verifica e aggiornamento.
La soluzione non è introdurre cicli arbitrari dentro un DAG non controllato, ma comporre workflow durevoli di durata limitata attraverso eventi, sub-orchestrazioni e nuove istanze.
Observation Event
|
v
Analysis Workflow
|
v
Verification
|
+-- No Change --> Archive
|
+-- Relevant Change
|
v
New Event
|
v
Follow-up Workflow
In questo modo ogni esecuzione rimane identificabile, verificabile e soggetta a quote, mentre il sistema complessivo può funzionare continuamente.
È una distinzione importante per il futuro degli agenti persistenti: persistenza della responsabilità non significa esecuzione illimitata di un singolo processo o di una singola conversazione LLM.
19. Checklist di produzione
Prima di portare in produzione un'architettura agentic workflow, verificherei almeno questi aspetti:
- Il piano viene validato prima dell'esecuzione.
- Ogni tool è registrato in un catalogo server-side.
- Gli input sono tipizzati e soggetti a limiti.
- Le autorizzazioni vengono verificate sul backend.
- Le operazioni con effetti esterni hanno idempotency key e riconciliazione.
- Gli orchestratori rispettano i vincoli di determinismo del replay.
- I job remoti possono essere recuperati dopo un crash.
- Gli output voluminosi sono esternalizzati dalla history.
- I sub-agent hanno capability limitate.
- Le approvazioni sono eventi autenticati.
- Il parallelismo è limitato anche a livello di risorsa condivisa.
- Le modifiche ai workflow già attivi sono gestite con versioning.
- Gli audit log sono protetti da modifiche non autorizzate.
- Le metriche misurano correttezza, costo e affidabilità, non soltanto latenza.
- Esistono test di fault injection per crash, timeout, duplicazioni e retry.
20. Conclusione: l'LLM non deve diventare il transaction manager
Dynamic Workflows rappresenta un passaggio significativo nell'evoluzione delle architetture agentiche.
Non perché renda i modelli più intelligenti, ma perché riconosce esplicitamente che intelligenza, autorizzazione ed esecuzione affidabile sono problemi differenti.
Il modello interpreta obiettivi ambigui e propone piani. Il validator controlla che quei piani siano ammissibili. Il workflow engine esegue le attività rispettando dipendenze, retry e checkpoint. I tool applicano le operazioni reali attraverso API e identità autorizzate.
Nel mondo GIS questa separazione è ancora più importante: un LLM può scegliere quali analisi geospaziali effettuare, ma la correttezza geometrica, statistica e fisica deve rimanere responsabilità di algoritmi, dati e procedure verificabili.
La prossima generazione di GeoAgent potrebbe quindi non essere un chatbot con accesso a qualche geoprocessing tool, ma un vero sistema capace di compilare richieste territoriali in workflow geografici tipizzati, verificabili, riproducibili e osservabili.
La direzione è chiara: l'LLM definisce l'intenzione, il piano diventa un contratto e il runtime garantisce l'esecuzione. L'autonomia utile nasce quando il ragionamento probabilistico incontra un'infrastruttura deterministica.
Riferimenti tecnici
- Microsoft — Dynamic Workflows in Azure Functions Hosted Skills
- Microsoft Learn — Dynamic Workflows Overview
- Microsoft Learn — Create and Run Dynamic Workflows
- Microsoft Learn — Durable Functions .NET Isolated Worker
- Microsoft Learn — Durable Orchestrations and Replay
- Microsoft Learn — Orchestrators, Activities and Entities