-----------------------------------

Acquista i software ArcGIS tramite Studio A&T srl, rivenditore autorizzato dei prodotti Esri.

I migliori software GIS, il miglior supporto tecnico!

I migliori software GIS, il miglior supporto tecnico!
Azienda operante nel settore GIS dal 2001, specializzata nell’utilizzo della tecnologia ArcGIS e aderente ai programmi Esri Italia Business Network ed Esri Partner Network

-----------------------------------



mercoledì 30 settembre 2026

DiskANN in Azure SQL: Vector Search, RAG e GeoAI direttamente nel database relazionale

La ricerca vettoriale sta progressivamente entrando nel cuore dei database relazionali. Non si tratta semplicemente di aggiungere una nuova funzione SQL: significa poter interrogare gli stessi dati contemporaneamente nello spazio relazionale, nello spazio geografico e nello spazio semantico degli embedding.

Con DiskANN, Azure SQL può memorizzare embedding e utilizzare un indice Approximate Nearest Neighbor direttamente accanto a tabelle, chiavi, transazioni, metadati, filtri di sicurezza e, potenzialmente, dati spaziali.

Per un architect questo apre una domanda interessante: abbiamo davvero bisogno di introdurre un vector database separato per ogni applicazione RAG?

In molti scenari la risposta potrebbe essere no.

Cos'è DiskANN

DiskANN significa Disk-based Approximate Nearest Neighbor. È una famiglia di tecniche sviluppate per eseguire rapidamente ricerche di similarità su collezioni vettoriali di grandi dimensioni.

Non genera embedding, non interpreta documenti e non è un Large Language Model. DiskANN interviene dopo che i dati sono già stati trasformati in vettori.

Document
    ↓
Text extraction
    ↓
Chunking
    ↓
Embedding model
    ↓
Vector
    ↓
Azure SQL
    ↓
DiskANN
    ↓
Nearest neighbors

Il problema che risolve è apparentemente semplice: dato un vettore q, trovare i vettori del database che gli sono più vicini.

Dallo spazio semantico allo spazio vettoriale

Un embedding model trasforma un oggetto, ad esempio una frase:

ArcGIS Enterprise supports federated GIS servers.

in una sequenza numerica:

[0.0182, -0.0317, 0.0041, ..., 0.0227]

Formalmente possiamo pensare all'embedding come a una funzione:

f : X → ℝᵈ

dove X è lo spazio degli oggetti originali e d è la dimensionalità del vettore.

La singola coordinata non ha generalmente un significato interpretabile isolatamente. È la posizione complessiva del vettore nello spazio multidimensionale a rappresentare le caratteristiche apprese dal modello.

Se due contenuti hanno significato simile, il modello tende a collocarli in regioni vicine dello spazio vettoriale.

Exact Nearest Neighbor: perché non basta

Il modo più semplice di trovare i vettori più vicini consiste nel confrontare la query con ogni vettore presente nella tabella.

query
  │
  ├── distance(vector 1)
  ├── distance(vector 2)
  ├── distance(vector 3)
  ├── ...
  └── distance(vector N)

Con N vettori e dimensionalità D, il lavoro cresce approssimativamente come:

O(N × D)

Con poche migliaia di record può essere perfettamente accettabile.

Con:

10.000.000 vectors
×
1.536 dimensions

la scansione esaustiva diventa invece molto più costosa.

È qui che entra in gioco l'Approximate Nearest Neighbor Search.

ANN: sacrificare un po' di perfezione per molta velocità

Un algoritmo ANN non garantisce necessariamente di restituire sempre gli stessi vicini che otterremmo esaminando esaustivamente l'intero dataset.

Accetta un compromesso:

Exactness
    ↓ leggermente

Search space
    ↓ drasticamente

Latency
    ↓ drasticamente

Supponiamo che i veri dieci nearest neighbors siano:

A B C D E F G H I J

e che ANN restituisca:

A B C D E F G H I K

Il recall@10 sarebbe:

9 / 10 = 0.90

Per molte pipeline RAG questo trade-off è estremamente conveniente: non abbiamo bisogno di dimostrare matematicamente quale chunk sia il più vicino, ma di recuperare molto rapidamente un insieme di candidati altamente rilevanti.

DiskANN e grafi di prossimità

DiskANN utilizza un approccio graph-based. Possiamo immaginare ogni embedding come un nodo collegato ad altri nodi utili per navigare nello spazio vettoriale.

              ●──────●
             /        \
        ●───●          ●
        │    \        /
        ●─────●──────●
               \
                ●────●

La ricerca non deve quindi fare:

query → confronta tutti i vettori

ma può procedere concettualmente attraverso il grafo:

query
  ↓
entry point
  ↓
candidate neighbors
  ↓
better neighbors
  ↓
better neighbors
  ↓
Top-K

Il grafo consente di raggiungere rapidamente regioni promettenti dello spazio senza valutare ogni riga.

Perché si chiama DiskANN

Uno degli elementi caratteristici del progetto DiskANN è l'attenzione alla possibilità di lavorare con collezioni vettoriali molto grandi senza dipendere esclusivamente dalla RAM.

              RAM
       ┌────────────────┐
       │ search state   │
       │ cache          │
       │ graph metadata │
       └───────┬────────┘
               │
               │ selective access
               ▼
       ┌────────────────┐
       │ SSD / storage  │
       │ vector data    │
       └────────────────┘

Naturalmente, quando utilizziamo DiskANN tramite Azure SQL non dobbiamo confondere il principio algoritmico con l'implementazione interna del servizio managed: cache, storage engine, I/O scheduling, quantizzazione e query optimization sono responsabilità del database engine.

DiskANN è ora production-ready su Azure SQL

Il 29 settembre 2026 Microsoft ha annunciato la General Availability di DiskANN Vector Index & Search su Azure SQL Database, su Azure SQL Managed Instance configurato con la policy di aggiornamento always-up-to-date e su SQL database in Microsoft Fabric.

La versione GA include elementi particolarmente importanti per workload reali:

  • Approximate Nearest Neighbor Search basata su DiskANN;
  • supporto a INSERT, UPDATE e DELETE;
  • manutenzione asincrona dell'indice vettoriale;
  • iterative filtering;
  • integrazione con il query optimizer;
  • possibilità di combinare vector search e predicati relazionali.

Il tipo VECTOR di SQL

Il database può memorizzare direttamente un embedding in una colonna vettoriale.

Un modello dati orientato a RAG potrebbe essere:

CREATE TABLE dbo.Documents
(
    Id          BIGINT IDENTITY PRIMARY KEY,
    TenantId    INT NOT NULL,
    FileName    NVARCHAR(500) NOT NULL,
    Title       NVARCHAR(500) NULL,
    MimeType    NVARCHAR(100) NULL,
    CreatedAt   DATETIME2 NOT NULL
        DEFAULT SYSUTCDATETIME()
);

I chunk possono invece essere mantenuti separatamente:

CREATE TABLE dbo.DocumentChunks
(
    Id               BIGINT IDENTITY PRIMARY KEY,
    DocumentId       BIGINT NOT NULL,
    TenantId         INT NOT NULL,

    PageNumber       INT NULL,
    ChunkNumber      INT NOT NULL,

    Content          NVARCHAR(MAX) NOT NULL,

    EmbeddingModel   NVARCHAR(100) NOT NULL,
    ChunkingVersion  INT NOT NULL,

    Embedding        VECTOR(1536) NOT NULL,

    CONSTRAINT FK_DocumentChunks_Documents
        FOREIGN KEY (DocumentId)
        REFERENCES dbo.Documents(Id)
);

1536 è solamente un esempio. La dimensionalità deve essere coerente con il modello che genera gli embedding.

Versionare embedding e pipeline

Un embedding dovrebbe essere trattato come dato derivato, non come sorgente primaria.

Conviene quindi conservare almeno:

Original document
Extracted content
Chunk
ChunkingVersion
Embedding
EmbeddingModel
EmbeddingVersion
CreatedAt

Questa informazione diventa fondamentale quando cambiamo modello.

Due modelli differenti possono produrre spazi vettoriali differenti: non possiamo semplicemente mischiare embedding generati da modelli diversi e aspettarci che le distanze rimangano semanticamente confrontabili.

Creazione dell'indice DiskANN

Sulla colonna vettoriale possiamo creare un indice:

CREATE VECTOR INDEX IX_DocumentChunks_Embedding
ON dbo.DocumentChunks(Embedding)
WITH
(
    METRIC = 'cosine',
    TYPE = 'diskann'
);

Le metriche supportate dalla vector search SQL comprendono:

  • cosine;
  • dot;
  • euclidean.

La metrica non va scelta arbitrariamente: deve essere coerente con il modello di embedding e con il modo in cui è stato addestrato.

Exact search con VECTOR_DISTANCE

Possiamo eseguire una ricerca esatta calcolando la distanza:

DECLARE @query VECTOR(1536) = @QueryEmbedding;

SELECT TOP (10)
    Id,
    DocumentId,
    Content,
    VECTOR_DISTANCE(
        'cosine',
        @query,
        Embedding
    ) AS Distance
FROM dbo.DocumentChunks
ORDER BY Distance;

Questa strategia è utile anche come baseline per misurare la qualità dell'indice ANN.

Possiamo infatti confrontare:

Exact Top-K
     vs
DiskANN Top-K

e misurare il recall effettivo sul nostro dataset.

Approximate search con VECTOR_SEARCH

Con gli indici vettoriali di nuova generazione la sintassi corrente utilizza VECTOR_SEARCH insieme a:

TOP (N) WITH APPROXIMATE

Ad esempio:

DECLARE @query VECTOR(1536) = @QueryEmbedding;

SELECT TOP (10) WITH APPROXIMATE
    c.Id,
    c.DocumentId,
    c.Content,
    r.distance
FROM VECTOR_SEARCH(
    TABLE = dbo.DocumentChunks AS c,
    COLUMN = Embedding,
    SIMILAR_TO = @query,
    METRIC = 'cosine'
) AS r
ORDER BY r.distance;

La precedente forma basata sul parametro:

TOP_N = 10

appartiene alla generazione precedente dell'indice ed è deprecata per i nuovi indici.

WITH APPROXIMATE non è solo sintassi

Con:

SELECT TOP (10) WITH APPROXIMATE

stiamo dicendo esplicitamente al motore che accettiamo risultati ANN.

Senza WITH APPROXIMATE, VECTOR_SEARCH può eseguire una ricerca kNN esatta.

VECTOR_SEARCH
      │
      ├── exact kNN
      │
      └── approximate ANN / DiskANN

La distinzione è molto importante quando facciamo benchmarking.

Il query optimizer entra nella vector search

Uno degli aspetti architetturalmente più interessanti è che la ricerca vettoriale non viene trattata come una scatola completamente separata dal motore SQL.

Azure SQL può valutare se utilizzare la strategia ANN oppure altre strategie in funzione della query e della selettività.

Supponiamo di avere:

100.000.000 chunks

ma di applicare:

WHERE TenantId = 42

e che il tenant 42 contenga soltanto 5.000 chunk. In determinate condizioni un piano differente potrebbe risultare più conveniente rispetto all'attraversamento del grafo ANN globale.

FORCE_ANN_ONLY

Quando vogliamo imporre l'utilizzo dell'indice Approximate Nearest Neighbor, Azure SQL mette a disposizione anche l'hint:

FORCE_ANN_ONLY

Concettualmente:

SELECT TOP (10) WITH APPROXIMATE
    ...
FROM VECTOR_SEARCH(
    TABLE = dbo.DocumentChunks AS c,
    COLUMN = Embedding,
    SIMILAR_TO = @query,
    METRIC = 'cosine'
) AS r WITH (FORCE_ANN_ONLY)
ORDER BY r.distance;

È utile soprattutto per test, benchmark o casi in cui sappiamo esattamente quale strategia vogliamo utilizzare.

Come ogni hint SQL, non dovrebbe diventare automaticamente la scelta predefinita.

Iterative filtering: fondamentale per sistemi reali

Immaginiamo una piattaforma SaaS multi-tenant.

Il retrieval deve rispettare:

TenantId = 42

Una implementazione ANN ingenua potrebbe fare:

DiskANN
   ↓
10 nearest vectors
   ↓
WHERE TenantId = 42
   ↓
2 risultati validi

Gli altri otto vettori potrebbero appartenere ad altri tenant.

Con l'iterative filtering la ricerca può continuare nel grafo finché non vengono trovati abbastanza risultati che soddisfano il predicato:

DiskANN
   ↓
candidate set
   ↓
relational filter
   ↓
enough results?
   │
   ├── yes → return Top-K
   │
   └── no
        ↓
   continue graph traversal
        ↓
   more candidates
        ↓
   relational filter

Questa caratteristica è importantissima per:

  • multi-tenancy;
  • ACL;
  • categorie;
  • stati applicativi;
  • vincoli temporali;
  • filtri geografici o amministrativi;
  • security policies.

Vector search e security boundary

In un'applicazione RAG enterprise la sicurezza non deve essere applicata dopo il retrieval.

Il flusso corretto deve essere progettato come:

User
 ↓
Identity
 ↓
Tenant / ACL / Security Policy
 ↓
Vector retrieval
 ↓
Permitted chunks
 ↓
LLM

In altre parole: il retrieval fa parte del security boundary dell'applicazione.

Il vero RAG inizia prima di DiskANN

Una delle semplificazioni più pericolose è pensare che una pipeline RAG sia:

PDF → embedding → vector database

Una pipeline seria assomiglia molto di più a:

                   PDF
                    │
          ┌─────────┴──────────┐
          │                    │
     Native text          Scanned PDF
          │                    │
   Text extraction            OCR
          │                    │
          └─────────┬──────────┘
                    ↓
             normalization
                    ↓
          structure analysis
                    ↓
               chunking
                    ↓
               embedding
                    ↓
               Azure SQL
                    ↓
                DiskANN

PDF nativi e PDF scansionati

Un PDF può contenere un vero text layer. In questo caso è possibile estrarre direttamente:

Page
 ├── Heading
 ├── Paragraph
 ├── Paragraph
 └── Table

Un PDF scansionato può invece contenere essenzialmente immagini:

PDF
 ├── page-001 image
 ├── page-002 image
 └── page-003 image

In questo caso serve OCR.

In ambiente Azure una pipeline possibile è:

Azure Blob Storage
        ↓
Document ingestion service
        ↓
Azure AI Document Intelligence
        ↓
OCR + Layout + Tables + Structure
        ↓
Semantic chunking
        ↓
Embedding model
        ↓
Azure SQL
        ↓
DiskANN

Il punto importante è che non basta recuperare caratteri: serve preservare il più possibile la struttura semantica del documento.

Chunking: spesso più importante del vector database

Consideriamo un manuale tecnico di 500 pagine.

Creare:

manual.pdf → one embedding

è generalmente poco utile.

È molto più efficace ottenere:

manual.pdf
   │
   ├── chunk 001 → embedding
   ├── chunk 002 → embedding
   ├── chunk 003 → embedding
   ├── ...
   └── chunk 850 → embedding

Fixed-size chunking

L'approccio più semplice consiste nel suddividere il testo per numero di token:

chunk 1 → tokens   0 - 499
chunk 2 → tokens 450 - 949
chunk 3 → tokens 900 - 1399

L'overlap aiuta a evitare che un concetto venga spezzato esattamente sul confine tra due chunk.

Semantic chunking

Per documentazione tecnica possiamo però fare di meglio.

Section
 ├── paragraph
 ├── paragraph
 ├── code sample
 ├── table
 └── note

L'obiettivo è costruire unità informative semanticamente coerenti, non semplicemente blocchi di lunghezza costante.

Hierarchical chunking

Possiamo mantenere una gerarchia:

Document
   ↓
Chapter
   ↓
Section
   ↓
Chunk

Se DiskANN recupera il chunk 37 possiamo, ad esempio, recuperare anche:

chunk 36
chunk 37
chunk 38

oppure la sezione padre.

Per questo conviene conservare:

DocumentId
SectionId
ParentChunkId
PageNumber
ChunkNumber

Embedding generation lato applicazione

Una pipeline .NET può essere concettualmente molto semplice:

var chunks = chunker.Split(document);

foreach (var chunk in chunks)
{
    var embedding =
        await embeddingService.GenerateAsync(chunk.Text);

    db.DocumentChunks.Add(
        new DocumentChunk
        {
            DocumentId = documentId,
            TenantId = tenantId,
            PageNumber = chunk.Page,
            ChunkNumber = chunk.Index,
            Content = chunk.Text,
            EmbeddingModel = embedding.Model,
            ChunkingVersion = 1,
            Embedding = embedding.Vector
        });
}

await db.SaveChangesAsync();

Dal punto di vista architetturale terrei ben separati:

Extraction
Chunking
Embedding
Persistence
Indexing
Retrieval
Generation

Questo rende la pipeline versionabile, osservabile e riprocessabile.

Azure SQL può generare embedding direttamente

Lo stack SQL moderno consente anche di registrare modelli esterni e invocarli dal database.

Un external model può essere definito concettualmente così:

CREATE EXTERNAL MODEL MyEmbeddingModel
WITH
(
    LOCATION = '...',
    API_FORMAT = 'Azure OpenAI',
    MODEL_TYPE = EMBEDDINGS,
    MODEL = '...',
    CREDENTIAL = ...
);

e successivamente:

AI_GENERATE_EMBEDDINGS(
    N'ArcGIS Server federation'
    USE MODEL MyEmbeddingModel
)

Microsoft supporta inoltre scenari in cui AI_GENERATE_CHUNKS e AI_GENERATE_EMBEDDINGS vengono combinati direttamente da T-SQL.

Questo rende possibile una pipeline:

SQL row
   ↓
AI_GENERATE_CHUNKS
   ↓
AI_GENERATE_EMBEDDINGS
   ↓
VECTOR
   ↓
DiskANN

Embedding nel database o nell'applicazione?

Il fatto che qualcosa sia possibile in SQL non significa che debba necessariamente essere eseguito lì.

Generare embedding nell'application layer offre generalmente maggiore controllo su:

  • retry;
  • rate limiting;
  • batching;
  • fallback;
  • observability;
  • model routing;
  • versioning della pipeline.

Generarli direttamente nel database può invece semplificare alcune pipeline data-centric.

È quindi una decisione architetturale, non semplicemente sintattica.

RAG: Retrieve Wide, Rank Narrow

DiskANN non deve necessariamente restituire direttamente i chunk che finiranno nel prompt.

Una pipeline più sofisticata può essere:

10.000.000 chunks
       │
       │ DiskANN
       ↓
      50
       │
       │ reranker
       ↓
       8
       │
       │ context builder
       ↓
      LLM

Questo pattern viene spesso sintetizzato come:

Retrieve wide
     ↓
Rank narrow

Reranking

La prima fase privilegia throughput e recall.

Una seconda fase può utilizzare un modello più costoso per stimare meglio la rilevanza rispetto alla domanda originale:

Question
   +
50 candidate chunks
        ↓
     Reranker
        ↓
   Best 5 - 10

DiskANN e reranker risolvono quindi problemi differenti:

DiskANN:
find plausible candidates quickly

Reranker:
order those candidates accurately

Hybrid Search

Gli embedding non sostituiscono necessariamente la ricerca lessicale.

Una query come:

KB5034123 ArcGIS Server TLS

contiene token precisi, codici e identificativi che possono essere estremamente significativi.

Una strategia moderna può combinare:

Vector similarity
       +
Keyword search
       +
Relational filters
       +
Reranking

La vector search è quindi un ulteriore retrieval signal, non necessariamente l'unico.

.NET ed Entity Framework Core

Per chi sviluppa applicazioni .NET è importante distinguere le versioni.

In EF Core 10 Microsoft ha introdotto il supporto alla traduzione di VectorDistance(), quindi alla distanza vettoriale esatta.

In EF Core 11 Microsoft documenta inoltre le API dedicate a vector index e VECTOR_SEARCH.

Ad esempio:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<DocumentChunk>()
        .HasVectorIndex(
            x => x.Embedding,
            "cosine");
}

La ricerca ANN può essere espressa concettualmente come:

var results = await db.DocumentChunks
    .VectorSearch(
        x => x.Embedding,
        queryEmbedding,
        "cosine")
    .OrderBy(x => x.Distance)
    .Take(10)
    .WithApproximate()
    .ToListAsync();

WithApproximate() corrisponde semanticamente alla richiesta:

TOP (...) WITH APPROXIMATE

È però importante notare che Microsoft documenta attualmente queste API di EF Core 11 come funzionalità ancora soggette a evoluzione.

Per chi oggi usa .NET 10

In un'applicazione .NET 10 / EF Core 10 possiamo comunque utilizzare pienamente Azure SQL Vector Search attraverso T-SQL, stored procedure, raw SQL o VectorDistance() dove appropriato.

Non è quindi necessario aspettare EF Core 11 per costruire una soluzione DiskANN.

.NET 10
   ↓
EF Core / ADO.NET
   ↓
VECTOR_SEARCH T-SQL
   ↓
Azure SQL
   ↓
DiskANN

Architettura RAG completa su Azure

                 ┌────────────────────┐
                 │ Azure Blob Storage │
                 └─────────┬──────────┘
                           │
                           ▼
                 ┌────────────────────┐
                 │ .NET Ingestion     │
                 │ Worker / Service   │
                 └─────────┬──────────┘
                           │
            ┌──────────────┴──────────────┐
            │                             │
            ▼                             ▼
     Text extraction          Document Intelligence
                                     OCR/Layout
            │                             │
            └──────────────┬──────────────┘
                           ▼
                    Semantic Chunking
                           │
                           ▼
                     Embedding Model
                           │
                           ▼
                   ┌────────────────┐
                   │   Azure SQL    │
                   │                │
                   │ relational     │
                   │ metadata       │
                   │ security       │
                   │ chunks         │
                   │ vectors        │
                   │ DiskANN        │
                   └───────┬────────┘
                           │
                           ▼
                       Retrieval
                           │
                           ▼
                        Reranker
                           │
                           ▼
                    Context Builder
                           │
                           ▼
                          LLM
                           │
                           ▼
                       Response

Vector database dedicato o Azure SQL?

Non esiste una risposta universale.

Un vector database specializzato può essere preferibile quando:

  • la vector search domina completamente il workload;
  • la scala è estremamente elevata;
  • servono feature vector-native molto specializzate;
  • l'architettura richiede distribuzione specificamente progettata per ANN.

Azure SQL è invece particolarmente interessante quando:

  • i dati applicativi sono già relazionali;
  • servono transazioni;
  • la sicurezza dipende dal modello relazionale;
  • i filtri sui metadati sono importanti;
  • vogliamo evitare sincronizzazione tra database;
  • vector search integra, ma non sostituisce, il workload applicativo.

La domanda corretta diventa quindi:

Which vector database should I add?

oppure:

Do I actually need another database?

Sono due domande architetturalmente molto diverse.

DiskANN + Spatial SQL: il collegamento con il GIS

Per chi lavora con GIS la parte più interessante inizia probabilmente qui.

Una feature geografica potrebbe avere contemporaneamente:

Feature
 ├── Id
 ├── Geometry
 ├── Attributes
 ├── Description
 ├── Category
 ├── Temporal information
 └── Embedding

La stessa entità appartiene quindi a tre spazi differenti.

Relational space
Geographic space
Semantic vector space

Tre tipi diversi di distanza

Consideriamo due aree territoriali.

La distanza geografica può essere:

180 km

ma la loro distanza nello spazio degli embedding può indicare una fortissima similarità:

Semantic similarity = very high

Due territori possono essere lontani fisicamente ma molto simili rispetto a:

  • demografia;
  • uso del suolo;
  • mobilità;
  • densità commerciale;
  • accessibilità;
  • servizi;
  • indicatori economici;
  • caratteristiche ambientali.

GeoAI: da distanza geometrica a similarità funzionale

Una possibile query concettuale potrebbe essere:

Find areas

within 50 km

AND

land_use = 'industrial'

AND

area > 50000 m²

AND

semantically similar to:

"areas suitable for logistics,
close to major transport infrastructure,
with low residential pressure"

Qui stiamo combinando:

Spatial predicate
       +
Relational predicate
       +
Vector similarity

Spatial Index e Vector Index sono concetti differenti

Uno spatial index indicizza oggetti come:

POINT
LINESTRING
POLYGON

Un vector index indicizza invece:

[0.018, -0.032, 0.004, ..., 0.071]

Il fatto che entrambi utilizzino la parola "vector" in alcuni contesti non deve creare confusione.

Sono strutture pensate per risolvere problemi completamente differenti.

Ma possono lavorare insieme.

Un possibile modello GeoAI

CREATE TABLE GeoAssets
(
    Id           BIGINT PRIMARY KEY,
    TenantId     INT NOT NULL,

    Name         NVARCHAR(250),
    Category     NVARCHAR(100),

    Geometry     GEOGRAPHY,

    Description  NVARCHAR(MAX),

    Embedding    VECTOR(1536)
);

Concettualmente potremmo eseguire:

Relational filtering
        ↓
Spatial filtering
        ↓
Vector retrieval
        ↓
Reranking
        ↓
GeoAI result

Embedding territoriali

Possiamo andare ancora oltre e generare un embedding non da un semplice testo, ma da una rappresentazione complessa del territorio.

Territory
   │
   ├── Population
   ├── Income
   ├── Land use
   ├── Mobility
   ├── POIs
   ├── Accessibility
   ├── Satellite features
   └── Demographics
             │
             ▼
          Encoder
             │
             ▼
       Territory embedding

A quel punto possiamo chiedere:

Find areas similar to this area

senza limitarci a una distanza euclidea o geografica.

Passiamo dalla prossimità geometrica alla similarità funzionale appresa.

Osservabilità

Una pipeline RAG production-grade va misurata end-to-end.

Almeno:

Document extraction latency
OCR latency
Chunking throughput
Embedding latency
Embedding failures
Indexing throughput
ANN latency
Exact KNN latency
Recall@K
Reranking latency
Context size
LLM latency
Token usage
End-to-end latency

Possiamo modellare la latenza totale come:

Ttotal =
    Textract
  + Tembed
  + Tretrieve
  + Trerank
  + Tcontext
  + Tllm

Ottimizzare DiskANN di 10 ms ha poco senso se la generazione dell'LLM richiede diversi secondi.

Valutare scientificamente il retrieval

Un buon sistema RAG non dovrebbe essere valutato soltanto chiedendo:

La risposta sembra buona?

Dobbiamo costruire un dataset di valutazione:

Question
Expected relevant chunks
Expected source documents

e misurare:

  • Recall@K;
  • Precision@K;
  • MRR;
  • NDCG;
  • latency;
  • cost per query.

Possiamo così confrontare in modo ripetibile:

Embedding Model A vs B

Chunk size 300 vs 800

Overlap 50 vs 150

Exact KNN vs DiskANN

Top-10 vs Top-50

With reranker vs without reranker

Vector-only vs Hybrid Search

DiskANN non sostituisce il database design

La presenza di embedding non rende improvvisamente irrilevanti:

  • primary key;
  • foreign key;
  • indici B-tree;
  • statistics;
  • query plans;
  • partitioning;
  • security;
  • transactions;
  • data lifecycle;
  • backup e disaster recovery.

La vector search è un'altra modalità di accesso al dato, non un sostituto del modello relazionale.

La vera convergenza

L'aspetto più interessante di Azure SQL + DiskANN non è poter eseguire una query con cosine distance.

È poter mantenere nello stesso dominio dati:

Transactions
Business entities
Users
Security
Documents
Metadata
Spatial objects
Embeddings

e interrogarli utilizzando:

Relational Search
Full-Text Search
Spatial Search
Vector Search

L'AI non deve necessariamente possedere una copia parallela del database aziendale.

Può diventare un'altra modalità con cui l'applicazione interroga gli stessi dati operativi.

Conclusione

DiskANN è interessante dal punto di vista algoritmico perché rende possibile una Approximate Nearest Neighbor Search efficiente su collezioni vettoriali di grandi dimensioni.

Ma il cambiamento più importante è probabilmente architetturale.

Azure SQL
   │
   ├── Relational data
   ├── Transactions
   ├── Security
   ├── Documents
   ├── Spatial data
   ├── Vectors
   └── DiskANN

In una moderna applicazione AI questo può ridurre la necessità di introdurre un'infrastruttura dati parallela esclusivamente per il retrieval vettoriale.

E nel GIS il concetto diventa ancora più interessante.

Relational space
      +
Geographic space
      +
Semantic vector space
      ↓
     GeoAI

La domanda GIS tradizionale:

What is near this location?

può evolvere verso:

What is geographically, semantically and functionally similar to this location?

È qui che DiskANN smette di essere semplicemente una tecnologia per "fare RAG sui PDF" e diventa qualcosa di più generale: un nuovo strumento per interrogare dati, conoscenza e territorio.

Riferimenti tecnici

martedì 29 settembre 2026

Embedding nel GIS: quando una posizione geografica diventa un vettore

Negli ultimi anni il concetto di embedding è diventato centrale nel mondo dell'intelligenza artificiale. Nei Large Language Model una frase, un documento o un concetto vengono trasformati in un vettore numerico che ne rappresenta, in modo distribuito, il significato.

Lo stesso paradigma sta entrando nel GIS.

Una posizione geografica, un quartiere, una cella territoriale, un'immagine satellitare o una feature GIS possono essere rappresentati non soltanto attraverso coordinate, geometrie e attributi, ma attraverso un vettore ad alta dimensionalità appreso da un modello.

Il risultato è un cambiamento concettuale importante:

da "dove si trova questa feature?" e "quali attributi possiede?" a "che tipo di luogo rappresenta e quali altri luoghi le assomigliano?"

ArcGIS sta integrando questo paradigma direttamente nei propri workflow GeoAI. Gli USA Geodemographic Embeddings 2026 ne sono un esempio particolarmente interessante: migliaia di variabili demografiche, socioeconomiche, abitative e ambientali vengono trasformate in un vettore compatto di 256 dimensioni per ogni area geografica.

Ma il concetto va molto oltre quel dataset specifico. Gli embedding possono diventare una nuova primitiva dell'informazione geografica, insieme a geometria, attributi, topologia e coordinate.

1. Un embedding è prima di tutto algebra lineare

Formalmente possiamo descrivere un encoder come una funzione:

f : X → R^d

dove X rappresenta lo spazio originale dei dati e R^d uno spazio vettoriale di dimensione d.

Un oggetto complesso:

x ∈ X

viene trasformato in:

e = f(x)

e = [e₀, e₁, e₂, ..., e₍d-1₎]

Il vettore e viene chiamato embedding.

Nel caso di un modello linguistico:

"spatial database for urban analysis"
                │
                ▼
             Encoder
                │
                ▼
[0.18, -0.42, 0.71, ..., -0.09]

Nel caso GIS potremmo invece avere:

Location / Area / Raster / Feature
                │
                ▼
       Geospatial Encoder
                │
                ▼
[0.31, 0.08, -0.67, ..., 0.22]

La caratteristica fondamentale è che le singole componenti del vettore normalmente non hanno un significato interpretabile isolatamente.

Non possiamo quindi dire:

embedding[17] = reddito
embedding[42] = densità
embedding[103] = urbanizzazione

Il significato è distribuito nell'intero spazio latente.

È il pattern complessivo delle componenti a rappresentare il fenomeno.

2. Coordinate ed embedding non sono la stessa cosa

Nel GIS siamo già abituati a rappresentare un punto attraverso numeri:

P = (x, y)

oppure:

P = (longitude, latitude)

Ma queste coordinate descrivono esclusivamente la posizione geometrica.

Un location embedding risponde a una domanda differente.

Coordinate:
45.46, 9.19

Embedding:
[0.31, -0.12, 0.77, ..., -0.22]

Le coordinate dicono:

Dove si trova questo luogo?

L'embedding cerca invece di codificare:

Che tipo di luogo è?

A seconda del modello utilizzato, il vettore può rappresentare informazioni relative a:

  • urbanizzazione;
  • demografia;
  • uso del suolo;
  • morfologia urbana;
  • vegetazione;
  • infrastrutture;
  • caratteristiche ambientali;
  • immagini satellitari;
  • POI;
  • mobilità;
  • testi associati alla feature;
  • relazioni spaziali con altre entità.

Quindi:

geometry ≠ embedding

Sono due rappresentazioni complementari dello stesso oggetto geografico.

3. Due spazi differenti: geographic space ed embedding space

Questa distinzione porta a uno dei concetti più interessanti del GeoAI.

Nel normale spazio geografico possiamo avere:

A ●--------------------------------● B
              500 km

La distanza viene calcolata utilizzando coordinate, sistemi di riferimento e metriche spaziali.

Nello spazio degli embedding, gli stessi oggetti potrebbero invece essere:

A ●----● B

perché, nonostante siano geograficamente lontani, presentano caratteristiche estremamente simili.

Oppure due aree fisicamente vicine:

Geographic space

A ●---● B

Embedding space

A ●-------------------------------● B

potrebbero risultare molto differenti dal punto di vista socioeconomico, urbanistico o ambientale.

Possiamo quindi distinguere due funzioni:

SpatialDistance(A, B)

e:

EmbeddingDistance(E(A), E(B))

La prima misura una relazione nello spazio geografico. La seconda misura una relazione nello spazio latente appreso dal modello.

4. La cosine similarity

Uno dei modi più comuni per confrontare embedding è la cosine similarity.

Dati due vettori A e B:

               A · B
cos(A,B) = -----------------
             ||A|| ||B||

Il prodotto scalare è:

A · B = Σ AᵢBᵢ

mentre la norma euclidea è:

||A|| = √Σ Aᵢ²

La cosine similarity misura essenzialmente l'angolo fra due vettori.

Se i vettori normalizzati puntano nella stessa direzione:

similarity → 1

sono molto simili secondo lo spazio semantico costruito dal modello.

Attenzione però a un errore interpretativo frequente:

una cosine similarity di 0.90 non significa che due luoghi siano "uguali al 90%".

È una misura geometrica nello spazio degli embedding, il cui significato dipende dal modello, dal training e dalla distribuzione dei dati.

5. Calcolare la similarity con NumPy

Il calcolo è estremamente semplice.

import numpy as np

a = np.array([0.21, 0.74, -0.32, 0.61], dtype=np.float32)
b = np.array([0.19, 0.70, -0.29, 0.58], dtype=np.float32)

similarity = np.dot(a, b) / (
    np.linalg.norm(a) *
    np.linalg.norm(b)
)

print(similarity)

Dietro una parte importante della cosiddetta "semantic search" c'è quindi algebra lineare relativamente semplice.

La parte complessa non è il confronto fra i vettori.

La vera complessità consiste nel costruire uno spazio vettoriale nel quale la distanza abbia un significato utile per il dominio applicativo.

6. Che cosa possiamo trasformare in embedding nel GIS?

Praticamente qualsiasi sorgente informativa associata allo spazio.

                         GIS Feature
                              │
          ┌───────────────────┼───────────────────┐
          │                   │                   │
          ▼                   ▼                   ▼
       Geometry             Imagery           Attributes
          │                   │                   │
          ▼                   ▼                   ▼
    Geo Encoder          Vision Encoder      Tabular/Text
          │                   │                   │
          └───────────────────┼───────────────────┘
                              │
                              ▼
                         Embedding
                     [e₀ ... eₙ]

Location embeddings

Rappresentano il contesto associato a una posizione geografica.

Image embeddings

Un modello visuale o geospatial foundation model trasforma chip di immagini satellitari o aeree in vettori.

Text embeddings

Descrizioni, metadata, documenti, toponimi e altri campi testuali collegati a feature GIS possono essere trasformati in vettori semantici.

Geodemographic embeddings

Comprimono centinaia o migliaia di indicatori territoriali in una rappresentazione numerica compatta.

Multimodal embeddings

È probabilmente la direzione più interessante:

Satellite imagery ──► Vision encoder ──────┐
                                           │
Demography ─────────► Tabular encoder ─────┤
                                           │
POI ─────────────────► POI encoder ────────┼──► PLACE EMBEDDING
                                           │
Text ────────────────► Text encoder ───────┤
                                           │
Road network ────────► Graph encoder ──────┘

Il risultato sarebbe una sorta di fingerprint digitale del luogo.

7. Gli USA Geodemographic Embeddings di Esri

Un'implementazione concreta di questo paradigma è rappresentata dagli USA Geodemographic Embeddings 2026 disponibili nell'ecosistema ArcGIS.

Gli embedding vengono costruiti attraverso il Geodemographic Foundation Model (GDFM) di Esri.

Il modello utilizza quattro grandi viste informative.

Dataset Informazione Variabili
Age & Race Census Struttura demografica e variazioni nel tempo 2.049
American Community Survey Istruzione, lavoro, reddito, commuting, household 1.617
Housing & Household Housing units, occupancy, tenure, composizione familiare 1.521
Environment Temperatura, precipitazioni, land cover e indicatori fisici 113

Parliamo quindi di oltre 5.000 variabili originarie.

Dopo preprocessing, pulizia, imputazione e scaling, queste informazioni vengono elaborate da un'architettura multiview autoencoder.

8. Multiview autoencoder: come nasce il vettore

Un autoencoder classico contiene due parti:

Input
  │
  ▼
Encoder
  │
  ▼
Latent representation
  │
  ▼
Decoder
  │
  ▼
Reconstructed input

L'obiettivo del training è ricostruire il più fedelmente possibile l'input dopo averlo compresso attraverso uno spazio latente più piccolo.

Nel modello geodemografico Esri il concetto viene esteso utilizzando viste informative differenti:

Census ─────────► Encoder 1 ──┐
                              │
ACS ────────────► Encoder 2 ──┤
                              │
Housing ────────► Encoder 3 ──┼──► Latent vector
                              │      256 dimensions
Environment ────► Encoder 4 ──┘
                                      │
                    ┌─────────────────┼─────────────────┐
                    ▼                 ▼                 ▼
                 Decoder          Decoder           Decoder
                    │                 │                 │
                    ▼                 ▼                 ▼
              reconstruct         reconstruct       reconstruct

Il modello viene addestrato minimizzando l'errore di ricostruzione delle differenti viste.

Il vettore latente finale ha:

D = 256

dimensioni.

Un intero territorio viene quindi trasformato da migliaia di variabili esplicite a:

E(location) ∈ R²⁵⁶

senza che ciascuna dimensione debba corrispondere direttamente a una singola variabile originale.

9. H3 come unità spaziale

Gli USA Geodemographic Embeddings vengono distribuiti utilizzando celle Uber H3 resolution 7.

Concettualmente:

territory
    │
    ▼
H3 tessellation
    │
    ├── hex 1 ──► embedding[256]
    ├── hex 2 ──► embedding[256]
    ├── hex 3 ──► embedding[256]
    │
    └── ...

Questa scelta è importante perché l'embedding diventa associato a un'unità spaziale uniforme e interrogabile come una normale feature GIS.

10. ArcGIS Pro: gli embedding diventano un tipo di informazione GIS

ArcGIS Pro dispone oggi di un toolset dedicato alla Embeddings Based Analysis.

Tra gli strumenti principali troviamo:

  • Generate Embeddings Using AI Models;
  • Find Similar Features Using Embeddings;
  • Merge Embeddings;
  • Extract Embeddings To Fields.

Questo è rilevante architetturalmente.

L'embedding non viene più considerato soltanto un artefatto interno a una pipeline di machine learning, ma diventa un elemento persistente del dataset GIS.

11. Come ArcGIS memorizza realmente un embedding

ArcGIS Pro persiste gli embedding in un campo geodatabase di tipo BLOB chiamato normalmente Embedding.

La rappresentazione è particolarmente interessante per uno sviluppatore.

Ogni componente viene serializzata come:

IEEE-754 32-bit floating point
little-endian

Il payload è costituito semplicemente dalla sequenza dei valori:

[e₀][e₁][e₂]...[e₍D-1₎]

senza header, delimitatori o metadata aggiuntivi.

Ogni componente occupa:

4 bytes

perciò:

payload_size = D × 4

Per un embedding da 256 dimensioni:

256 × 4 = 1024 bytes

ovvero circa 1 KB per feature, senza considerare l'overhead del database.

12. Leggere direttamente il BLOB con Python

import arcpy
import numpy as np

feature_class = r"C:\GIS\Data.gdb\Embeddings"
dimension = 256

with arcpy.da.SearchCursor(
    feature_class,
    ["OBJECTID", "Embedding"]
) as cursor:

    for object_id, blob in cursor:

        if blob is None:
            continue

        expected_size = dimension * 4

        if len(blob) != expected_size:
            raise ValueError(
                f"Embedding non valido per OID {object_id}: "
                f"{len(blob)} bytes invece di {expected_size}"
            )

        vector = np.frombuffer(
            blob,
            dtype="<f4"
        )

        print(object_id, vector.shape)

Il dtype:

<f4

significa:

  • < = little-endian;
  • f = floating point;
  • 4 = quattro byte.

13. Scrivere un embedding in una Feature Class

È possibile effettuare anche l'operazione opposta.

import arcpy
import numpy as np

embedding = np.array(
    [0.12, -0.98, 1.42, 0.33],
    dtype="<f4"
)

embedding_bytes = np.asarray(
    embedding,
    dtype="<f4",
    order="C"
).tobytes()

with arcpy.da.InsertCursor(
    feature_class_path,
    ["SHAPE@", "Name", "Embedding"]
) as cursor:

    cursor.insertRow([
        geometry,
        "Sample Feature",
        embedding_bytes
    ])

Questo apre una possibilità interessante: gli embedding non devono necessariamente essere generati da ArcGIS.

Possiamo produrli attraverso un modello esterno, serializzarli nel formato previsto e inserirli in una feature class per utilizzarli nei workflow GIS.

14. Base64 e Feature Service

Quando il BLOB deve transitare attraverso un canale testuale, ad esempio JSON o REST, il payload binario viene normalmente rappresentato attraverso Base64.

Float32[]
   │
   ▼
binary payload
   │
   ▼
Base64
   │
   ▼
JSON / REST

La rappresentazione logica del vettore non cambia.

15. Similarity Search in ArcGIS Pro

Supponiamo di voler trovare negli Stati Uniti aree con caratteristiche analoghe a una determinata zona universitaria.

Il workflow concettuale è:

Query polygon
      │
      ▼
intersect embedding cells
      │
      ▼
E₁, E₂, ..., Eₙ
      │
      ▼
mean embedding
      │
      ▼
       Q
      │
      ▼
cosine similarity
      │
      ▼
all embeddings
      │
      ▼
SIMILARITY ≥ threshold
      │
      ▼
output Feature Class

Se la query interessa più feature, ArcGIS costruisce un unico query embedding attraverso la media:

        1
Q = -------- Σ Eᵢ
        n

Il vettore risultante viene quindi confrontato con gli embedding dello spazio di ricerca utilizzando la cosine similarity.

16. ArcPy: Find Similar Features Using Embeddings

L'operazione può essere automatizzata direttamente in Python:

import arcpy

embedding_features = (
    r"C:\GIS\GeoAI.gdb\LocationEmbeddings"
)

query_features = (
    r"C:\GIS\GeoAI.gdb\QueryArea"
)

output_features = (
    r"C:\GIS\GeoAI.gdb\SimilarAreas"
)

threshold = 0.85

arcpy.geoai.FindSimilarFeaturesUsingEmbeddings(
    embedding_features,
    query_features,
    output_features,
    threshold
)

Il risultato è una nuova feature class contenente le feature che superano la soglia di similarità.

Questa query:

Find areas similar to this area

è profondamente diversa da:

Find areas within 50 km

oppure:

population > 100000
AND income BETWEEN ...
AND age BETWEEN ...
AND ...

Nel primo caso non stiamo definendo manualmente le caratteristiche che rendono due aree simili.

Utilizziamo invece la struttura dello spazio latente appresa dal modello.

17. Implementare la stessa ricerca senza il tool ArcGIS

Possiamo riprodurre il concetto direttamente con NumPy.

import numpy as np

# N feature × D dimensioni
embeddings = np.asarray(embeddings, dtype=np.float32)

# D dimensioni
query = np.asarray(query, dtype=np.float32)

# normalizzazione
embeddings_norm = embeddings / np.linalg.norm(
    embeddings,
    axis=1,
    keepdims=True
)

query_norm = query / np.linalg.norm(query)

# similarity di tutte le feature in una singola operazione matriciale
scores = embeddings_norm @ query_norm

threshold = 0.85

matching_indices = np.where(
    scores >= threshold
)[0]

for index in matching_indices:
    print(index, scores[index])

Questa riga:

scores = embeddings_norm @ query_norm

è particolarmente significativa.

Con una singola moltiplicazione matrice-vettore otteniamo la similarità fra la query e tutte le feature.

18. Il problema della scala: brute force e ANN

Su qualche migliaio di feature un confronto esaustivo è perfettamente gestibile.

Se però abbiamo:

10 milioni di feature
×
768 dimensioni

la ricerca lineare diventa più costosa.

È qui che entrano in gioco gli algoritmi di Approximate Nearest Neighbor, o ANN.

Tra le strutture più utilizzate troviamo:

  • HNSW;
  • IVF;
  • IVF-PQ;
  • product quantization;
  • graph-based vector indexes.

Il concetto è analogo a ciò che da decenni facciamo nei database spaziali.

GIS

Geometry
   │
   ▼
Spatial Index
R-tree / grid / other
   │
   ▼
candidate pruning
   │
   ▼
exact geometry operation

nel mondo vettoriale:

Embedding
   │
   ▼
Vector Index
HNSW / IVF / ...
   │
   ▼
candidate pruning
   │
   ▼
vector similarity

19. Spatial Index + Vector Index

La combinazione delle due tecnologie è probabilmente una delle architetture GIS più interessanti dei prossimi anni.

Feature
   │
   ├── Geometry
   │      │
   │      └── Spatial Index
   │
   ├── Attributes
   │      │
   │      └── B-tree / column index
   │
   └── Embedding
          │
          └── Vector Index

La stessa entità può essere interrogata secondo tre dimensioni differenti:

  • dove si trova;
  • quali proprietà possiede;
  • a cosa assomiglia.

20. La query GIS del futuro

Una query concettuale potrebbe diventare:

SELECT *
FROM Places
WHERE ST_Distance(
        Geometry,
        @SearchPoint
      ) < 50000
ORDER BY VectorDistance(
        Embedding,
        @QueryEmbedding
      )
LIMIT 20;

Prima applichiamo un vincolo geografico:

entro 50 km

e successivamente ordiniamo i candidati in base alla similarità semantica:

più simili al luogo di riferimento

Spatial query e vector search non sono quindi tecnologie concorrenti.

Risolvono dimensioni differenti dello stesso problema.

21. Aggregare gli embedding nello spazio

Un problema molto GIS riguarda il cambio di scala.

Supponiamo di avere embedding a livello H3 ma di voler effettuare un'analisi a livello di contea:

H3 embeddings
     │
     ▼
spatial overlay
     │
     ▼
County
     │
     ▼
aggregated embedding

ArcGIS Pro mette a disposizione Merge Embeddings.

Quando le sorgenti sono poligonali, l'aggregazione considera l'area di sovrapposizione con il poligono target.

In termini concettuali:

                 Σ wᵢ Eᵢ
E_target = -----------------------
                    Σ wᵢ

dove il peso può dipendere dall'area di overlap.

Questo introduce un problema affascinante:

che cosa significa aggregare semanticamente lo spazio?

Nella statistica tradizionale sappiamo aggregare popolazione, reddito, superficie o densità.

Con gli embedding stiamo aggregando invece rappresentazioni latenti apprese.

22. Merge Embeddings con ArcPy

import arcpy

target_features = r"C:\GIS\Data.gdb\Counties"

embedding_features = (
    r"C:\GIS\Data.gdb\H3_Embeddings"
)

output = (
    r"C:\GIS\Data.gdb\CountyEmbeddings"
)

arcpy.geoai.MergeEmbeddings(
    target_features,
    embedding_features,
    output
)

23. Da BLOB a variabili esplicative

Molti algoritmi tradizionali di machine learning si aspettano una matrice tabulare:

X =
[
  [x₁₁, x₁₂, ..., x₁d],
  [x₂₁, x₂₂, ..., x₂d],
  ...
]

Per questo ArcGIS permette di estrarre le componenti dell'embedding dal BLOB creando campi come:

emb_0
emb_1
emb_2
...
emb_255

Il dataset diventa quindi:

OBJECTID
SHAPE
Population
Income
...
emb_0
emb_1
...
emb_255

e può essere utilizzato come input di modelli di regressione, classificazione, clustering o AutoML.

24. Embedding come feature engineering automatizzato

Tradizionalmente un data scientist GIS potrebbe costruire manualmente decine o centinaia di variabili:

population_density
median_income
road_density
distance_to_station
green_area_percentage
building_density
average_age
employment_rate
...

Questa attività viene chiamata feature engineering.

Un embedding può essere visto, con le dovute cautele, come una forma di:

learned feature engineering.

Il modello apprende automaticamente una rappresentazione compatta delle relazioni presenti nei dati.

Questo non significa che gli attributi originali diventino inutili.

Al contrario, una delle strategie più potenti consiste nel combinare:

domain variables
      +
spatial variables
      +
embedding dimensions
      │
      ▼
ML model

25. Un embedding non è una spiegazione

Questa distinzione è fondamentale.

Se un modello utilizza:

median_income = 42,000

la variabile è interpretabile.

Se utilizza:

emb_147 = -0.2738

quel numero, da solo, normalmente non ha alcun significato leggibile.

Gli embedding introducono quindi un trade-off:

feature engineering manuale
        │
        ├── maggiore interpretabilità
        └── maggiore lavoro

embedding
        │
        ├── rappresentazione ricca
        ├── maggiore riusabilità
        └── minore interpretabilità diretta

26. Image embeddings e Earth Observation

Il concetto diventa ancora più potente nel remote sensing.

Invece di classificare immediatamente un'immagine:

Satellite image
      │
      ▼
Classifier
      │
      ▼
urban / forest / water / ...

possiamo produrre prima una rappresentazione generale:

Satellite image
      │
      ▼
Foundation model
      │
      ▼
Embedding
      │
      ├── similarity search
      ├── clustering
      ├── anomaly detection
      ├── classification
      ├── segmentation
      └── downstream fine tuning

Questo è uno dei motivi per cui i geospatial foundation model sono così interessanti.

La rappresentazione può essere riutilizzata in task differenti senza ricominciare ogni volta dal dato grezzo.

27. Location embeddings con ArcGIS API for Python

L'ArcGIS API for Python espone anche una classe Embeddings nel modulo arcgis.learn.

Fra i tipi supportati troviamo:

image
text
location

Concettualmente:

from arcgis.learn import Embeddings

model = Embeddings(
    dataset_type="location"
)

result = model.get(
    input_path,
    return_embeddings=True
)

Per i location embedding la documentazione ArcGIS API for Python indica come backbone predefinito una variante di SatCLIP addestrata su Sentinel-2.

Qui il concetto è differente dal geodemographic embedding.

Non stiamo comprimendo migliaia di variabili Census, ma stiamo costruendo una rappresentazione geografica utilizzando un modello addestrato a catturare struttura e contesto spaziale.

28. "Embedding GIS" non identifica quindi una sola tecnologia

È importante evitare di utilizzare il termine embedding come se identificasse un'unica rappresentazione universale.

Possiamo avere:

Text embedding
Image embedding
Location embedding
Geodemographic embedding
POI embedding
Network embedding
Trajectory embedding
Graph embedding
Multimodal embedding

Due vettori della stessa dimensione prodotti da modelli differenti non appartengono necessariamente allo stesso spazio semantico e non sono automaticamente confrontabili.

Se:

E₁(x) ∈ R²⁵⁶
E₂(x) ∈ R²⁵⁶

non significa:

cos(E₁(x), E₂(y))

abbia un significato valido.

La compatibilità dipende dallo spazio latente costruito durante il training.

29. Model versioning diventa data governance

Da sviluppatore questo porta immediatamente a un problema architetturale.

Se memorizziamo embedding persistentemente, dobbiamo sapere quale modello li ha generati.

Un dataset production-ready dovrebbe quindi conservare informazioni come:

Embedding
EmbeddingModel
EmbeddingModelVersion
EmbeddingDimension
EmbeddingGeneratedAt
EmbeddingSourceVersion

Perché:

model v1 embedding
        ≠
model v2 embedding

anche quando la dimensione è identica.

Aggiornare un modello può richiedere il ricalcolo dell'intero indice vettoriale.

30. Un esempio C#

La cosine similarity non richiede necessariamente Python.

Una semplice implementazione C# potrebbe essere:

static float CosineSimilarity(
    ReadOnlySpan<float> a,
    ReadOnlySpan<float> b)
{
    if (a.Length != b.Length)
        throw new ArgumentException(
            "Vectors must have the same dimension.");

    double dot = 0;
    double normA = 0;
    double normB = 0;

    for (int i = 0; i < a.Length; i++)
    {
        dot += a[i] * b[i];
        normA += a[i] * a[i];
        normB += b[i] * b[i];
    }

    if (normA == 0 || normB == 0)
        return 0;

    return (float)(
        dot /
        (Math.Sqrt(normA) * Math.Sqrt(normB))
    );
}

Un'applicazione .NET potrebbe quindi leggere gli embedding provenienti da ArcGIS, da un database vettoriale o da un modello AI ed effettuare direttamente ranking e filtering.

31. Decodificare il formato Float32 ArcGIS in C#

Dal momento che il BLOB ArcGIS contiene float32 little-endian contigui, il concetto lato .NET è:

static float[] DecodeEmbedding(
    byte[] bytes,
    int expectedDimension)
{
    if (bytes.Length != expectedDimension * sizeof(float))
        throw new InvalidOperationException(
            "Unexpected embedding payload size.");

    var result = new float[expectedDimension];

    for (int i = 0; i < expectedDimension; i++)
    {
        result[i] = BitConverter.ToSingle(
            bytes,
            i * sizeof(float)
        );
    }

    return result;
}

Su una piattaforma little-endian come l'architettura Windows/x64 normalmente utilizzata da ArcGIS Pro, il mapping è diretto; in codice interoperabile è comunque opportuno trattare esplicitamente l'endianness prevista dal formato.

32. Vector database e GIS

Un database vettoriale memorizza oggetti del tipo:

ID
metadata
embedding

Un database GIS tradizionale memorizza:

ID
geometry
attributes

L'evoluzione naturale è:

ID
geometry
attributes
embedding

con:

spatial index
+
attribute indexes
+
vector index

Questo modello rende possibili query ibride estremamente potenti.

33. Hybrid Spatial-Vector Search

Consideriamo una richiesta:

Trova entro 30 km da questa posizione aree che assomigliano a questo distretto commerciale.

La pipeline potrebbe essere:

                         Query
                           │
             ┌─────────────┴─────────────┐
             │                           │
             ▼                           ▼
       Geographic filter           Query embedding
             │                           │
             ▼                           ▼
       Spatial Index               Vector Index
             │                           │
             └─────────────┬─────────────┘
                           ▼
                    Candidate set
                           │
                           ▼
                    similarity rank
                           │
                           ▼
                        Results

Questo tipo di ricerca combina contemporaneamente:

  • geografia;
  • semantica;
  • attributi;
  • AI.

34. GeoRAG: Retrieval Augmented Generation geografico

Il passaggio successivo è collegare questo sistema a un LLM.

In un normale RAG:

User question
     │
     ▼
Text embedding
     │
     ▼
Vector search
     │
     ▼
Documents
     │
     ▼
LLM

In un possibile GeoRAG:

User
 │
 │ "Trova aree industriali simili a questa
 │  entro 50 km e spiegami le differenze"
 │
 ▼
LLM / Agent
 │
 ├────────► intent extraction
 │
 ├────────► spatial query
 │
 ├────────► vector similarity
 │
 ├────────► feature attributes
 │
 ├────────► imagery embeddings
 │
 └────────► external/context data
                │
                ▼
          ArcGIS / Spatial DB
                │
                ▼
           Feature collection
                │
                ▼
               LLM
                │
                ▼
      explanation + map results

L'LLM non deve inventare il risultato geografico.

Il GIS rimane il motore deterministico per geometria, coordinate, overlay, network analysis e spatial constraints.

Il motore vettoriale aggiunge invece il retrieval semantico.

L'LLM orchestra e interpreta i risultati.

35. Geometry, semantics e language reasoning

Possiamo vedere l'architettura come tre livelli.

┌────────────────────────────────────┐
│        LANGUAGE / REASONING        │
│              LLM                   │
├────────────────────────────────────┤
│        SEMANTIC RETRIEVAL          │
│ Embeddings / Vector Search / ANN   │
├────────────────────────────────────┤
│         SPATIAL COMPUTATION        │
│ Geometry / Topology / CRS / GIS    │
└────────────────────────────────────┘

Ognuno risolve un problema differente.

Il GIS calcola.

Gli embedding rappresentano e recuperano similarità.

L'LLM ragiona sull'intento e costruisce una risposta comprensibile.

36. Embedding e Tobler's First Law

Nel GIS è quasi inevitabile collegare questo argomento alla nota prima legge della geografia di Waldo Tobler:

Things that are near tend to be more related than things that are far apart.

Gli embedding introducono però una nuova dimensione.

Due fenomeni possono essere:

far in geographic space
but
near in embedding space

La prossimità geografica rimane fondamentale, ma non è più l'unico concetto di vicinanza disponibile.

Possiamo parlare di:

  • prossimità geografica;
  • prossimità topologica;
  • prossimità temporale;
  • prossimità semantica.

37. Attenzione alla spatial autocorrelation

Gli embedding geografici introducono anche problemi statistici specifici.

Se il training set viene suddiviso casualmente:

80% train
20% test

feature geograficamente vicine possono finire nei due insiemi.

A causa della spatial autocorrelation, questo può produrre valutazioni eccessivamente ottimistiche.

In molti problemi GeoAI è preferibile valutare anche strategie come:

  • spatial block cross-validation;
  • geographic holdout;
  • leave-one-region-out;
  • temporal-spatial split.

Un embedding sofisticato non elimina le regole fondamentali della statistica spaziale.

38. Similarità non significa causalità

Un altro punto essenziale:

embedding similarity
        ≠
causal relationship

Due territori possono avere embedding simili perché condividono numerosi pattern statistici senza che esista alcuna relazione causale diretta.

Gli embedding sono eccellenti strumenti per:

  • retrieval;
  • clustering;
  • feature enrichment;
  • anomaly detection;
  • candidate generation;
  • prediction.

Non costituiscono automaticamente una spiegazione causale.

39. Distribution shift

Un modello di embedding apprende dalla distribuzione osservata durante il training.

Se viene applicato a:

  • un'altra nazione;
  • un altro periodo storico;
  • sensori differenti;
  • urbanizzazioni radicalmente differenti;
  • dati con diversa qualità;

potrebbe verificarsi distribution shift.

Questo è particolarmente importante in ambito geospaziale, dove le distribuzioni cambiano nello spazio e nel tempo.

40. Un embedding USA non è automaticamente un embedding europeo

Gli USA Geodemographic Embeddings sono stati progettati utilizzando dataset e geografie statunitensi.

Il principio è generale, ma il modello non deve essere interpretato come rappresentazione universale di qualsiasi territorio.

Per costruire un equivalente europeo o italiano sarebbe necessario definire un insieme coerente di sorgenti, ad esempio:

ISTAT
Copernicus
Sentinel
OpenStreetMap
land cover
meteorological data
mobility
POI
cadastral/urban information
socioeconomic indicators
...

e addestrare una rappresentazione coerente con il dominio geografico di interesse.

41. Un possibile "Italian Place Embedding"

Immaginiamo, puramente a livello architetturale:

ISTAT ──────────────────────┐
                            │
Sentinel / Copernicus ──────┤
                            │
OpenStreetMap ───────────────┤
                            ├──► Multi-view encoder
POI ────────────────────────┤
                            │
Mobility ───────────────────┤
                            │
Climate / Environment ──────┘
                                   │
                                   ▼
                             PLACE VECTOR
                                 R^d

Ogni cella territoriale italiana avrebbe una rappresentazione numerica general-purpose.

A quel punto potremmo eseguire query come:

Quali aree italiane presentano un profilo urbano, infrastrutturale e socioeconomico simile a questo quartiere?

senza costruire manualmente decine di filtri.

42. Verso il "place foundation model"

Il passo successivo rispetto al semplice embedding è un modello capace di comprendere in maniera multimodale il concetto di luogo.

                 PLACE FOUNDATION MODEL

       ┌──────────────┬──────────────┬──────────────┐
       │              │              │              │
       ▼              ▼              ▼              ▼
    Imagery        Geometry       Network         Text
       │              │              │              │
       └──────────────┼──────────────┼──────────────┘
                      │
                      ▼
              Shared latent space
                      │
       ┌──────────────┼──────────────┐
       ▼              ▼              ▼
   Retrieval      Prediction      Reasoning

In prospettiva potremmo non avere soltanto:

text → vector

ma:

place → vector

e magari:

text ↔ place ↔ image

all'interno di uno spazio multimodale condiviso.

43. Dal GIS basato sugli attributi al GIS basato sulle rappresentazioni

Per decenni una feature GIS è stata concettualmente:

Feature =
Geometry
+
Attributes

Con il GeoAI possiamo iniziare a pensare:

Feature =
Geometry
+
Attributes
+
Learned Representation

Il cambiamento può sembrare piccolo, ma è architetturalmente profondo.

La geometria rappresenta dove.

Gli attributi rappresentano ciò che sappiamo esplicitamente.

L'embedding rappresenta una sintesi latente di ciò che il modello ha appreso.

44. Gli embedding non sostituiranno il GIS classico

Gli embedding non eliminano:

  • buffer;
  • overlay;
  • spatial join;
  • network analysis;
  • coordinate systems;
  • geocoding;
  • topologia;
  • spatial statistics.

Se devo sapere se due poligoni si intersecano:

ST_Intersects(A, B)

rimane la soluzione corretta.

Non avrebbe senso chiedere a un embedding di approssimare un predicato geometrico deterministico.

Ma se la domanda è:

quali territori presentano un contesto simile a questo?

allora entriamo esattamente nel dominio degli embedding.

45. La vera evoluzione è l'integrazione

Il GIS futuro probabilmente non sarà:

GIS
oppure
AI

ma:

             GIS PLATFORM

Geometry ─────── Spatial Engine
                     │
Attributes ───── Data Engine
                     │
Embeddings ───── Vector Engine
                     │
Models ───────── GeoAI Engine
                     │
LLM ──────────── Agent / Reasoning
                     │
                     ▼
              Geographic Intelligence

Ed è probabilmente qui che il concetto di GeoAI diventa realmente interessante per chi sviluppa sistemi GIS.

Conclusioni

Gli embedding stanno introducendo nel GIS un nuovo modo di rappresentare l'informazione geografica.

Non descrivono semplicemente dove si trova un oggetto e non sostituiscono gli attributi tradizionali.

Costruiscono invece uno spazio latente nel quale luoghi, immagini e feature possono essere confrontati in funzione delle caratteristiche apprese da un modello.

La distinzione fondamentale è:

Geographic distance
        ≠
Semantic distance

e le due possono essere utilizzate contemporaneamente.

Spatial Index
     +
Vector Index
     +
GIS Attributes
     +
Foundation Models
     +
LLM / Agents

aprono la strada a sistemi capaci non soltanto di rispondere:

Dove si trova?

ma anche:

A quali luoghi assomiglia?

e, in prospettiva:

Quali caratteristiche rendono questo luogo simile ad altri, quali differenze sono geograficamente rilevanti e come posso utilizzarle per prendere una decisione?

Per chi lavora nel GIS questo è probabilmente uno dei passaggi più interessanti dell'attuale evoluzione GeoAI: la feature geografica non è più soltanto una geometria con attributi. Può diventare una rappresentazione appresa.


Riferimenti tecnici

  • Esri — Concepts of USA Geodemographic Embeddings
  • Esri — Use the USA Geodemographic Embeddings
  • ArcGIS Pro — Embeddings Based Analysis toolset
  • ArcGIS Pro — Find Similar Features Using Embeddings
  • ArcGIS Pro — How Find Similar Features Using Embeddings works
  • ArcGIS Pro — Merge Embeddings
  • ArcGIS Pro — Embeddings in BLOB fields
  • ArcGIS API for Python — arcgis.learn.Embeddings

Nota: gli USA Geodemographic Embeddings 2026 citati nell'articolo sono un modello/dataset specifico dell'ecosistema ArcGIS e, al momento della stesura, Esri li indica come Beta. Gli esempi architetturali relativi a place embeddings, GeoRAG e sistemi multimodali descrivono invece pattern generali e possibili evoluzioni tecnologiche, non uno specifico prodotto ArcGIS.

Blazor diventa agentic: costruire applicazioni AI-native con .NET

Per molto tempo integrare l'intelligenza artificiale in un'applicazione ha significato soprattutto una cosa: aggiungere una chat.

Una finestra laterale, un prompt, una risposta generata da un LLM.

Con i nuovi componenti sperimentali Microsoft.AspNetCore.Components.AI, Microsoft sta però esplorando un modello molto più interessante: portare gli agenti direttamente dentro l'architettura e lo stato delle applicazioni Blazor.

Non più soltanto:

Utente → Prompt → LLM → Testo

ma qualcosa di molto più vicino a:

Utente → UI → Agent → Tools → Application State → UI

Microsoft definisce questo modello Agentic UI.

Microsoft.AspNetCore.Components.AI

Il nuovo package sperimentale introduce componenti e astrazioni pensati per integrare interazioni agentiche direttamente nelle applicazioni Blazor.

Al momento il package richiede il .NET 11 RC1 SDK e può essere installato come prerelease:

dotnet add package Microsoft.AspNetCore.Components.AI --prerelease

Uno degli elementi centrali è UIAgent.

Partendo dall'astrazione IChatClient di Microsoft.Extensions.AI possiamo creare un agente utilizzabile direttamente dalla UI:

IChatClient chatClient = GetChatClient();

var agent = new UIAgent(chatClient);

Per ottenere rapidamente una classica interfaccia conversazionale possiamo utilizzare ChatPage:

<ChatPage Agent="_agent"
          Placeholder="Ask me anything…" />

ChatPage gestisce già diversi aspetti dell'interazione, tra cui lista dei messaggi, input, streaming e retry.

Ma la parte più interessante non è la chat.

UIAgent trasforma infatti l'output progressivo dell'agente in ContentBlock osservabili che i componenti Blazor possono renderizzare e aggiornare mentre l'interazione procede.

Dal testo alla UI strutturata

In una normale applicazione AI il risultato di un tool finirebbe spesso all'interno della risposta testuale del modello.

Immaginiamo per esempio un agente che invochi:

get_weather("Milano")

Potremmo semplicemente visualizzare:

Milano: 18°C

Con Agentic UI possiamo invece associare quella chiamata a un blocco fortemente tipizzato:

[ToolBlock("get_weather")]
public partial class WeatherToolBlock
    : FunctionInvocationContentBlock
{
    [ToolParameter(Name = "location")]
    public string? Location { get; set; }

    [ToolResult]
    public WeatherInfo? Weather { get; set; }
}

Blazor può quindi decidere come rappresentare quel risultato:

<BlockRenderer TBlock="WeatherToolBlock">

    <div class="weather-card">
        <strong>@context.Location</strong>
        <div>@context.Weather?.Temperature °C</div>
    </div>

</BlockRenderer>

Il punto architetturalmente interessante è questo:

l'agente decide cosa fare, mentre l'applicazione mantiene il controllo su come rappresentarlo.

L'LLM non deve quindi generare HTML arbitrario. Può produrre tool call e dati strutturati, mentre Blazor continua a gestire componenti, dependency injection, CSS, localizzazione e logica applicativa.

Backend Tools e Frontend Tools

Agentic UI distingue anche tra operazioni eseguite sul backend e operazioni che appartengono direttamente alla UI.

Un backend tool potrebbe interrogare:

  • database;
  • API REST;
  • servizi aziendali;
  • motori di ricerca;
  • sistemi GIS;
  • servizi cloud.

L'architettura potrebbe essere:

Agent
   ↓
Backend Tool
   ↓
ASP.NET Core
   ↓
Database / API / Service

Ma possiamo anche definire frontend tools, cioè funzioni eseguite direttamente dall'applicazione Blazor.

L'esempio Microsoft modifica il colore dell'interfaccia:

var setAccentColor =
    AIFunctionFactory.Create(
        async (string color) =>
        {
            await InvokeAsync(() => _accent = color);

            return $"Accent color set to {color}.";
        },
        name: "set_accent_color",
        description: "Set the accent color of the page.");

Questo concetto può essere applicato a operazioni molto più interessanti:

set_status_filter("Unavailable")

select_service("GIS03")

open_details_panel("GIS03")

Un utente potrebbe quindi scrivere:

Mostrami solamente i servizi ArcGIS che hanno problemi.

L'agente potrebbe interpretare l'intenzione e modificare direttamente lo stato dell'interfaccia.

Non stiamo più semplicemente generando una risposta.

L'agente sta interagendo con l'applicazione.

Human in the Loop

Quando gli agenti iniziano a utilizzare strumenti capaci di modificare sistemi reali, il controllo dell'utente diventa fondamentale.

I nuovi componenti supportano esplicitamente il pattern Human in the Loop.

Un'operazione sensibile può quindi richiedere un'approvazione:

<BlockRenderer TBlock="FunctionApprovalBlock"
               Context="block">

    @if (block.Status == ApprovalStatus.Pending)
    {
        <button @onclick="block.Approve">
            Approve
        </button>

        <button @onclick="() => block.Reject()">
            Reject
        </button>
    }

</BlockRenderer>

Immaginiamo un sistema di monitoraggio GIS.

L'utente chiede:

Riavvia tutti i servizi che risultano Unavailable.

L'agente individua tre servizi, ma invece di eseguire immediatamente l'operazione visualizza:

The agent wants to restart:

MapService01
FeatureService07
ImageService02

[ Approve ]   [ Reject ]

Solo dopo l'approvazione dell'utente il backend esegue realmente l'operazione.

È un pattern fondamentale per qualsiasi applicazione enterprise che esponga agli agenti strumenti con effetti reali.

UIAgent<TState>: agente e applicazione condividono lo stato

Probabilmente una delle funzionalità più interessanti è UIAgent<TState>.

Possiamo definire uno stato applicativo fortemente tipizzato:

public class MonitorState
{
    public List<ServiceStatus> Services { get; set; } = [];

    public string? SelectedServer { get; set; }

    public string? Filter { get; set; }
}

e utilizzarlo attraverso:

UIAgent<MonitorState>

A questo punto l'interfaccia e l'agente possono collaborare sullo stesso stato.

Blazor Components
        ↘
     Shared State
        ↗
       Agent

Una Grid può visualizzare Services.

L'utente può cambiare manualmente Filter.

L'agente può impostare SelectedServer.

Una modifica dello stato provoca automaticamente l'aggiornamento dei componenti interessati.

È un modello molto più potente rispetto alla continua trasformazione dello stato dell'applicazione in testo da inserire nei prompt.

Predictive State: l'AI propone, l'utente decide

Un'altra idea particolarmente interessante è quella del Predictive State.

L'agente può proporre una modifica dello stato senza applicarla immediatamente.

Current State
     ↓
AI Proposal
     ↓
Diff
     ↓
Accept / Reject

Possiamo quindi mostrare all'utente la differenza tra lo stato corrente e quello suggerito dall'AI prima di modificare realmente l'applicazione.

Il modello diventa:

AI proposes → Human reviews → Application applies

Per applicazioni gestionali, DevOps, GIS, configuratori o strumenti amministrativi è un pattern estremamente interessante.

AG-UI: collegare l'interfaccia agli agenti remoti

I componenti Blazor possono funzionare con qualsiasi IChatClient, ma Microsoft mostra anche l'integrazione con AG-UI.

AG-UI è un protocollo open ed event-based progettato per standardizzare la comunicazione tra agenti e applicazioni rivolte agli utenti.

Non definisce come deve essere costruita la UI: definisce gli eventi scambiati tra agente e applicazione.

Un'architettura completa può diventare:

Blazor
   │
   │ AG-UI
   │ HTTP + Server-Sent Events
   ▼
ASP.NET Core
   │
   ▼
Microsoft Agent Framework
   │
   ▼
Microsoft Foundry
   │
   ▼
LLM

Lato Blazor, AGUIChatClient implementa ancora IChatClient.

Questo permette di mantenere una separazione interessante tra interfaccia e implementazione dell'agente.

Dal punto di vista di Blazor l'agente potrebbe essere:

  • in-process;
  • remoto;
  • basato su Microsoft Agent Framework;
  • collegato a Microsoft Foundry;
  • implementato attraverso altri provider compatibili con IChatClient.

Microsoft Agent Framework e Aspire

Nel sample completo Microsoft combina diversi elementi dell'ecosistema .NET:

Blazor
   ↓
Microsoft.AspNetCore.Components.AI
   ↓
UIAgent
   ↓
IChatClient
   ↓
AG-UI
   ↓
ASP.NET Core
   ↓
Microsoft Agent Framework
   ↓
Microsoft Foundry
   ↓
LLM

Aspire viene utilizzato per orchestrare i diversi progetti, fornire configurazione e service discovery e centralizzare log e tracing.

Inizia quindi a emergere uno stack Microsoft abbastanza completo per lo sviluppo di applicazioni agentiche.

Generative UI senza lasciare il controllo all'LLM

Quando si parla di Generative UI si potrebbe immaginare un LLM che genera direttamente HTML e interfacce arbitrarie.

L'approccio mostrato da Microsoft è più controllato.

L'agente può produrre o aggiornare uno stato strutturato:

{
  "steps": [
    {
      "name": "Connect to Portal",
      "status": "completed"
    },
    {
      "name": "Analyze services",
      "status": "running"
    },
    {
      "name": "Generate report",
      "status": "pending"
    }
  ]
}

Blazor può trasformarlo in un'interfaccia:

✓ Connect to Portal
◉ Analyze services
○ Generate report

e aggiornarla progressivamente durante l'esecuzione dell'agente.

La distinzione è importante:

l'agente genera e modifica dati e stato; Blazor mantiene il controllo del rendering.

Questo permette di conservare tipizzazione, sicurezza, componentizzazione e prevedibilità dell'interfaccia.

Un esempio concreto: un GeoService Monitor agentico

Immaginiamo una dashboard dedicata al monitoraggio di servizi ArcGIS.

La soluzione più semplice sarebbe aggiungere una classica finestra:

Ask AI...

Ma con un'architettura agentica potremmo andare molto oltre.

L'utente potrebbe chiedere:

Analizza GIS03 e cerca di capire perché il servizio non risponde.

L'agente potrebbe automaticamente:

  1. interrogare ArcGIS REST;
  2. verificare la raggiungibilità HTTPS;
  3. controllare il certificato TLS;
  4. analizzare lo storico del monitoraggio;
  5. recuperare gli ultimi errori;
  6. confrontare il comportamento con altri servizi.

La UI potrebbe aggiornarsi progressivamente:

GIS03 Analysis

✓ HTTPS reachable
✓ Certificate valid
✓ ArcGIS Server reachable
✗ Service initialization failed

Possible cause:
Data source unavailable

L'agente potrebbe quindi proporre:

Restart GIS03?

[ Approve ]   [ Reject ]

Dopo l'approvazione, il backend esegue l'operazione e lo stato della dashboard viene aggiornato.

Questa non sarebbe più semplicemente una dashboard con una chat AI.

Sarebbe una vera applicazione agentica.

Dalla AI feature all'AI-native application

Negli ultimi anni abbiamo spesso aggiunto l'intelligenza artificiale alle applicazioni secondo questo modello:

Application
     +
AI Chat

Agentic UI suggerisce invece qualcosa di diverso:

              ┌── UI
              │
User ──→ Agent ──→ State
              │
              ├── Tools
              │
              └── Backend

L'agente diventa un partecipante dell'architettura applicativa.

Può utilizzare strumenti, osservare e modificare stato, proporre operazioni e coordinare workflow complessi, mentre l'applicazione continua a mantenere il controllo su autorizzazioni, rendering e operazioni sensibili.

È probabilmente questo il cambiamento più interessante.

Non si tratta semplicemente di costruire chatbot migliori.

Si tratta di progettare applicazioni nelle quali utente, UI, stato, agenti e tool collaborano all'interno dello stesso workflow.

Lo stack .NET da tenere d'occhio

Lo stack che sta emergendo nell'ecosistema Microsoft è particolarmente interessante:

.NET 11
Blazor
Microsoft.AspNetCore.Components.AI
Microsoft.Extensions.AI
Microsoft Agent Framework
AG-UI
ASP.NET Core
Microsoft Foundry
Aspire

Microsoft.AspNetCore.Components.AI è ancora un package sperimentale, quindi oggi eviterei di trasformarlo in una dipendenza critica di un'applicazione production senza un opportuno livello di astrazione.

Ma il modello architetturale che propone merita attenzione già adesso.

Per chi sviluppa applicazioni enterprise .NET, la domanda nei prossimi anni potrebbe quindi non essere più:

Come aggiungo una chat AI alla mia applicazione?

ma:

Quali parti della mia applicazione possono diventare agentiche?

Fonte e approfondimenti

Microsoft .NET Blog — Build Agentic UI with the new Blazor AI components
devblogs.microsoft.com/dotnet/build-agentic-ui-blazor/

lunedì 28 settembre 2026

NicoGIS Tech Weekly — 28 settembre 2026 - #3

Quando un agente diventa un sistema distribuito

La settimana appena conclusa ha prodotto poche novità davvero interessanti, ma alcune sono abbastanza sostanziali da meritare un'analisi architetturale. Il tema dominante è il passaggio dall'AI “a richiesta e risposta” verso sistemi agentici persistenti, osservabili, recuperabili dopo un fault e collegati a UI e tool reali.

In parallelo, Esri ha pubblicato indicazioni concrete per ArcGIS Pro su Azure e, soprattutto, un nuovo security bulletin per Portal for ArcGIS. Sul fronte LLM, GPT-6 Sol e Luna spostano ancora di più la discussione dalla pura qualità del modello al costo per task riuscito, al caching e al routing.

Questa settimana quindi niente riempitivi: Microsoft Agent Framework e AG-UI, GPT-6 e AI FinOps, ArcGIS Pro su Azure, ArcGIS Security Watch, .NET production diagnostics e un nuovo From the Lab dedicato a NeuralPad.


Microsoft Agent Framework: non è più una chat, è un runtime applicativo

Il 24 settembre Microsoft ha pubblicato un aggiornamento importante di Microsoft Agent Framework che mette insieme quattro capacità che, prese singolarmente, sembrano feature; viste insieme, invece, descrivono una direzione architetturale precisa: AG-UI, memory, CodeAct e resilient execution.

Il cambio di prospettiva è questo:

LLM call
   ↓
Agent loop
   ↓
Tools
   ↓
Memory
   ↓
Checkpoint / recovery
   ↓
User-facing event stream

Un agente che esegue lavoro reale non può essere trattato come una singola chiamata HTTP lunga. Deve possedere stato, un modello di recovery, isolamento, autorizzazione, telemetria e semantica dei side effect.

AG-UI: un protocollo tra agent backend e applicazione

Il giorno successivo, il team .NET ha annunciato un SDK .NET first-class per AG-UI. Il protocollo standardizza gli eventi che un agent backend invia al client: inizio/fine run, streaming del testo, reasoning, tool invocation, state delta, interrupt e altri eventi tipizzati.

L'elemento interessante è che AG-UI non richiede Microsoft Agent Framework. Il server può essere costruito direttamente attorno a IChatClient di Microsoft.Extensions.AI, mentre Agent Framework usa ora lo stesso SDK AG-UI come base della propria integrazione ASP.NET Core.

Web / Mobile / Terminal / Teams
             │
             │ AG-UI events
             ▼
       ASP.NET Core
             │
             ▼
         IChatClient
             │
      ┌──────┼─────────┐
      │      │         │
    Model   Tools     State

Il trasporto predefinito è Server-Sent Events; esiste anche un codec Protobuf opzionale che copre un sottoinsieme degli eventi. Il client .NET espone a sua volta l'agente remoto come IChatClient, quindi un backend scritto in Python o TypeScript può essere consumato da codice .NET senza cambiare il contratto applicativo.

Analisi. Questa separazione è più importante dell'ennesimo componente UI per una chat. Significa che il confine tra agent runtime e presentation layer inizia ad assomigliare al confine che abbiamo già imparato a gestire fra backend e frontend nelle applicazioni distribuite. L'UI non deve conoscere il framework agentico, ma soltanto un protocollo di eventi.

Conversation state, memory e sandbox sono tre cose diverse

Un secondo punto molto importante è la separazione fra conversazione, memoria e sessione hosted. Microsoft specifica esplicitamente che una Foundry hosted session non è una conversazione: la conversazione contiene messaggi e tool call, mentre la hosted session rappresenta un sandbox VM-isolated con filesystem e stato di lavoro persistente.

User identity
     │
     ├── Conversation history
     │
     ├── Long-term memory
     │
     └── Hosted sandbox session
              │
              ├── files
              ├── code
              └── working state

Inoltre, user isolation e session isolation sono controlli indipendenti. L'identità può derivare direttamente dal token Microsoft Entra oppure essere delegata da un middle tier fidato; la sessione del sandbox può invece essere creata dal servizio o gestita esplicitamente dall'applicazione.

Questo evita un errore concettuale frequente nei progetti agentici: usare un thread ID o un conversation ID come se fosse una boundary di sicurezza. Microsoft lo dice chiaramente anche per AG-UI: un thread identifica una conversazione, ma non dimostra chi sia autorizzato a leggerla.

Memory: non è “salvare tutta la chat”

Il nuovo FoundryMemoryProvider recupera memorie rilevanti prima del run e invia informazioni della conversazione al memory store per l'estrazione asincrona dopo il run. Il punto chiave è che la long-term memory può essere usata senza ricaricare ogni volta l'intera transcript.

Valutazione. Il modello corretto per un sistema enterprise dovrebbe essere:

short-term transcript
        │
        ├── current reasoning context
        │
long-term memory
        │
        ├── selected / retrieved facts
        │
application database
        │
        └── authoritative state

Queste tre sorgenti non dovrebbero essere confuse. La memoria di un agente non sostituisce il database applicativo e non dovrebbe diventare una fonte autorevole per dati transazionali.

Resilient execution: retry non significa exactly-once

La parte più interessante, da architetto, è probabilmente la resilient execution. Agent Framework può collegare checkpoint di workflow e sessioni hosted alle background responses persistenti. Un processo può essere interrotto, riavviato e riconnettersi al lavoro salvato.

Ma Microsoft evidenzia un punto fondamentale: il recovery non garantisce exactly-once execution degli effetti esterni. Uno step interrotto può essere rieseguito.

Agent step
   │
   ├── write DB
   ├── send email
   └── call external API
          │
       process crash
          │
       checkpoint restore
          │
       step may run again

Quindi ogni tool con side effect dovrebbe essere progettato con idempotency key, deduplica o compensating action.

È lo stesso problema che conosciamo da workflow engine, code di messaggi e sistemi distribuiti: l'LLM cambia la logica decisionale, non le leggi della distributed systems engineering.

CodeAct e il confine di sicurezza

CodeAct consente al modello di esprimere una sequenza di operazioni come programma e di ottenere un risultato consolidato, riducendo il ping-pong model → tool → model → tool per task adatti a questo pattern.

Ma Microsoft fa una distinzione fondamentale: Hyperlight isola il codice generato dal modello; i tool registrati vengono invece eseguiti nel runtime dell'applicazione e mantengono i propri privilegi.

Analisi. La sandbox protegge dal codice generato, ma non trasforma automaticamente in sicuro un tool pericoloso. Un tool DeleteDatabase() rimane pericoloso anche se il programma che lo invoca gira in una sandbox. L'autorizzazione deve stare sul confine del tool.

Fonti primarie: Microsoft Agent Framework — Interactive experiences, memory and resilient execution; .NET Blog — AG-UI Protocol now has a first-class .NET SDK; Microsoft Agent Framework — Foundry hosted agent isolation.


GPT-6 Sol e Luna: il modello migliore non è necessariamente il modello corretto

OpenAI ha rilasciato il 22 settembre GPT-6 Sol e GPT-6 Luna nell'API, in Codex e in ChatGPT Work. Per l'API, il prezzo standard dichiarato per prompt fino a 272K token è:

ModelloInput / 1MCached input / 1MOutput / 1M
GPT-6 Sol$2.00$0.20$10.00
GPT-6 Luna$0.10$0.01$0.50

Il dato interessante non è solo il prezzo. OpenAI ha modificato anche il prompt caching per GPT-6: i cached input-token reads ricevono uno sconto del 90%, e reasoning effort e disponibilità dei tool possono essere modificati senza invalidare automaticamente il prefisso già riutilizzabile.

Questo porta direttamente a un problema di AI FinOps.

Task
 │
 ├── cheap model
 │      ├── success → done
 │      └── fail → retry/escalation
 │
 └── expensive model
        └── success → done

Con rapporti di prezzo molto diversi, la metrica corretta non è semplicemente $/1M tokens.

Effective cost =
  total inference cost
  + retry cost
  + tool cost
  + latency cost
  + escalation cost

Cost-per-successful-task =
  Effective cost / successful tasks

Analisi. Un modello che costa un decimo può risultare più caro se aumenta significativamente retry, tool call, correzioni o escalation. Il routing va quindi valutato su workload reali con metriche di successo applicative, non solo sui benchmark del vendor.

Session affinity: un dettaglio apparentemente piccolo che tocca caching e continuità

Microsoft Foundry Model Router ha introdotto a settembre una session affinity in preview per Chat Completions. L'applicazione può inviare un session ID opaco e chiedere al router di tentare lo stesso modello eleggibile nei turni successivi.

L'affinità è best-effort: policy, safety, capability, quota, availability e fallback hanno precedenza. L'associazione scade dopo 30 minuti senza una richiesta riuscita e non garantisce un cache hit.

Conversation turn N
        │
        ▼
      Router
        │
        ├── same model → behavioral continuity
        │                 + better cache opportunity
        │
        └── fallback → availability/capability wins

Nota importante. La documentazione attuale del Model Router elenca ancora la famiglia GPT-5.6 nel pool documentato; non va quindi interpretata questa sezione come una dichiarazione che GPT-6 Sol/Luna siano già instradati dal Model Router.

Operational note: rerun delle evaluation multimodali

Il 25 settembre OpenAI ha corretto un bug nell'image encoding che degradava la comprensione delle immagini per GPT-6 Sol e Luna nell'API e in Codex. Per workload con input visuali OpenAI raccomanda di rieseguire le evaluation e riprovare i workflow eventualmente interessati.

Questo è un buon promemoria operativo: quando un modello cambia anche senza cambiare model ID, una regression suite applicativa è più importante del semplice controllo della versione.

Fonti primarie: OpenAI — Introducing GPT-6 Sol and Luna; OpenAI API Changelog; Microsoft Foundry — What's new in Model Router e How to use Model Router.


ArcGIS Pro su Azure: la GPU è solo una parte del problema

Il 21 settembre Esri ha pubblicato una nuova guida specifica per il deployment e il dimensionamento di ArcGIS Pro su Microsoft Azure.

La raccomandazione corrente di Esri è significativa: per la maggior parte dei deployment ArcGIS Pro, NVadsA10_v5 è la famiglia GPU preferita; NCasT4_v3 rimane una buona alternativa quando è già in uso o quando disponibilità regionale e altri vincoli Azure la rendono più pratica.

Single-session: partire dal workload, non dalla SKU

ProfiloNVadsA10_v5NCasT4_v3
Light — 2D / viewingNV6ads_A10_v5NC4as_T4_v3
Medium — editing / 2D-3DNV12ads_A10_v5NC8as_T4_v3
Heavy — 3D / analysisNV18ads_A10_v5NC16as_T4_v3

Esri specifica esplicitamente che questi valori sono punti di partenza e devono essere verificati con workload reali.

A10 vs T4: non è soltanto una questione di VRAM

La serie NVadsA10_v5 usa GPU NVIDIA A10 e CPU AMD EPYC 74F3v. Azure consente configurazioni frazionarie della GPU A10 a partire da 1/6 della GPU con 4 GiB di frame buffer, fino alla GPU completa da 24 GiB. Le VM della serie includono una licenza NVIDIA GRID.

NCasT4_v3 usa invece NVIDIA T4 da 16 GB e AMD EPYC 7V12. Azure documenta questa famiglia sia per real-time AI inference sia per grafica e visualizzazione interattiva; per i workload grafici è necessario installare il driver GRID supportato.

ArcGIS Pro workload
       │
       ├── 2D / editing
       │      └── CPU + latency + storage
       │
       ├── 3D / scene
       │      └── GPU + VRAM + remote display
       │
       ├── raster / imagery
       │      └── CPU/GPU + storage throughput
       │
       └── deep learning
              └── CUDA capability + VRAM + compute

Analisi. La VM “più potente” non è automaticamente quella più corretta. Un flusso 2D che legge feature o file geodatabase attraverso una rete lenta può essere limitato da data locality e round trip molto prima di saturare la GPU. Una scena 3D sposta invece il collo di bottiglia verso rendering e VRAM; un task GeoAI può dipendere più da CUDA compute e memoria GPU che dal desktop remoto.

AVD: la user density è una metrica, non un numero fisso

Esri indica come starting point per ambienti multi-session:

ProfiloSKU di riferimentoDensità indicativa
LightNV18ads_A10_v5 / NC16as_T4_v3fino a 6 utenti
MediumNV18ads_A10_v5 / NC16as_T4_v3fino a 4 utenti
HeavyNV36ads_A10_v5 / NC64as_T4_v3fino a 3 utenti

La densità dipende da CPU, RAM, VRAM, storage, data performance e concorrenza. In altre parole: la user density deve essere misurata con progetti reali, non estrapolata da un foglio Excel.

Data locality: spesso il vero collo di bottiglia

Esri raccomanda di tenere compute e dati nella stessa regione Azure e, per shared file-based GIS data ad alte prestazioni, indica Azure NetApp Files. Per il dimensionamento vanno considerate contemporaneamente latenza, throughput, IOPS, concurrency e caratteristiche dei dataset.

Questo è particolarmente importante nel GIS: un'applicazione desktop GPU-accelerated che apre dataset remoti non è un benchmark della GPU, ma dell'intera catena:

ArcGIS Pro
   ↓
GPU / CPU
   ↓
virtual desktop protocol
   ↓
network
   ↓
file service / geodatabase / feature service
   ↓
storage

Per creare baseline ripetibili Esri continua a raccomandare ArcGIS Pro Performance Assessment Tool, che misura startup, caricamento mappe/bookmark e rendering dei layer e permette anche script personalizzati.

Fonti primarie: Esri — ArcGIS Pro on Microsoft Azure: Deployment and Performance Guidance; Microsoft Learn — NVadsA10_v5 e NC family; Esri — ArcGIS Pro Performance Assessment Tool.


ArcGIS Security Watch: Portal for ArcGIS 2026 Security Update 4

Questa settimana la parte security non è un box secondario. Il 24 settembre Esri ha pubblicato Portal for ArcGIS 2026 Security Update 4 e raccomanda ai clienti ArcGIS Enterprise di applicarlo il prima possibile.

Il patch è cumulativo e non richiede l'installazione preventiva dei precedenti Portal security patch.

CVECWECVSS base pubblicatoVersioni coinvolte
CVE-2026-69227CWE-306 — Missing Authentication for Critical Function9.8 — CriticalPortal 12.1 e precedenti
CVE-2026-69226CWE-863 — Incorrect Authorization6.5 — MediumPortal 12.1 e precedenti
CVE-2026-10759CWE-90 — LDAP Injection5.5 — MediumPortal 12.1 e precedenti

C'è una particolarità che vale la pena segnalare: il testo introduttivo del bulletin Esri parla di “one medium and two critical severity vulnerabilities”, mentre la tabella dettagliata dello stesso bulletin riporta un CVSS critical e due medium. Fino a eventuale correzione del testo, la cosa corretta è riportare i valori individuali pubblicati per ogni CVE e non dedurre una classificazione diversa.

Dal punto di vista operativo, questa incongruenza non cambia la priorità: un CVSS 9.8 su una funzione critica di autenticazione è già sufficiente per trattare l'aggiornamento come urgente.

Mitigation non significa remediation

Esri indica alcune mitigazioni: un WAF può contribuire a bloccare pattern malevoli e il profilo base dell'ArcGIS Hardening Guide riduce l'esposizione. Per CVE-2026-69227, Esri indica inoltre che rimuovere un eventuale default role mitiga il bypass delle restrizioni di creazione account.

Ma la mitigazione non sostituisce il patch.

Advisory
   ↓
Exposure analysis
   ↓
Temporary mitigation
   ↓
Patch in staging
   ↓
Regression test
   ↓
Production rollout
   ↓
Post-patch validation

Analisi. In un'architettura ArcGIS Enterprise sarebbe utile trattare Portal come un componente identitario, non solo come un frontend GIS. Patch che toccano autenticazione, autorizzazione o directory integration hanno una priorità diversa da una normale correzione funzionale.

Fonte primaria: Esri — September 2026 ArcGIS Security Bulletin.


.NET Production Watch: dump di memoria e supply-chain trust

Creare un memory dump direttamente da C#

Il 22 settembre il .NET Blog ha pubblicato un esempio per generare programmaticamente un memory dump da C# quando viene rilevata una possibile saturazione del ThreadPool.

L'esempio usa un watcher thread che periodicamente invia un lavoro al ThreadPool e misura quanto impiega a partire. Se il ritardo supera una soglia, il processo genera un dump.

Su Windows l'esempio usa MiniDumpWriteDump da dbghelp.dll; su Linux usa l'utility createdump distribuita con il runtime .NET.

La parte più importante è però la nota di sicurezza: un full dump può contenere credenziali, token, connection string e altri dati sensibili.

dump trigger
   ↓
rate limit / cooldown
   ↓
restricted storage
   ↓
retention policy
   ↓
secure transfer
   ↓
analysis
   ↓
deletion

Analisi. In produzione un dump non è semplicemente “un file di diagnostica”: è potenzialmente una fotografia di segreti in memoria. Va gestito come materiale sensibile.

NuGet: rotazione del certificato Microsoft di author signing

Dal 23 settembre Microsoft ha iniziato a usare un nuovo certificato X.509 per firmare i nuovi package NuGet Microsoft.

Il cambiamento impatta soprattutto chi usa signatureValidationMode=require, trustedSigners in nuget.config oppure verifica esplicitamente fingerprint con dotnet nuget verify.

Il nuovo fingerprint SHA-256 pubblicato da Microsoft è:

9A1B131BEE0605433056A4EA3815478A8E177961A968C6C0027C1093D1FEB630

Per aggiungerlo alla policy:

dotnet nuget trust author Microsoft \
9A1B131BEE0605433056A4EA3815478A8E177961A968C6C0027C1093D1FEB630 \
--algorithm SHA256

I vecchi certificati vanno mantenuti nella allow list per continuare a validare i package già firmati in passato. Se una pipeline applica una trusted signer policy ma non conosce il nuovo certificato, il restore può fallire con NU3034.

Analisi. È un esempio perfetto di supply-chain control che funziona: il blocco della pipeline non è un bug della pipeline, ma l'effetto previsto di una policy che non riconosce più il signer. Il problema operativo è assicurarsi che la rotazione dei trust anchor faccia parte della manutenzione della CI/CD.

Fonti primarie: .NET Blog — Creating a memory dump in C#; .NET Blog — Microsoft author-signing certificate update.


From the Lab — NeuralPad: rendere osservabile una rete neurale

Questa settimana inauguro anche una piccola sezione dedicata ai progetti che sto costruendo o sperimentando direttamente.

NeuralPad è un visual neural network debugger sperimentale per .NET, pensato con una filosofia volutamente simile a LINQPad: invece di nascondere la rete dietro poche API di training, prova a rendere direttamente osservabili matematica e stato runtime.

C#
 ↓
network definition
 ↓
forward pass
 ↓
weighted contributions
 ↓
activations
 ↓
loss
 ↓
backpropagation
 ↓
gradients
 ↓
optimizer step
 ↓
updated parameters

Il progetto è attualmente basato su .NET 10, WPF e DevExpress WPF. La soluzione separa il motore di calcolo dalla UI:

  • NeuralPad.Core: motore deterministico senza dipendenza WPF;
  • NeuralPad.App: debugger visuale, scripting, training UI e visualizzazione.

La caratteristica progettuale a cui tengo di più è che uno step del debugger corrisponde a una vera operazione matematica, non a un'animazione costruita sopra un training già avvenuto.

Tra le funzionalità già presenti ci sono forward e backward incrementali, ReLU/Sigmoid/Tanh/Linear, Binary Cross Entropy, reti dense configurabili, watch su attivazioni, bias e pesi, training breakpoint, snapshot/compare dei parametri, separazione fra Forward/Backward/Optimizer, grafico visuale della rete e C# scripting tramite Roslyn con editor AvalonEdit e primi servizi di IntelliSense/diagnostica.

Analisi. L'interesse del progetto non è competere con PyTorch o ML.NET come framework di training. È il contrario: rimuovere deliberatamente parte dell'astrazione per poter osservare cosa significa realmente:

gradient computed
      ≠
parameter updated

Backpropagation calcola i gradienti; l'optimizer step modifica i parametri. Separare visualmente questi momenti aiuta a capire molte cose che nei framework moderni vengono compresse in pochissime righe.

Repository pubblico: nicogis/NeuralPad.


Technical Takeaways

  • Gli agent stanno diventando runtime applicativi. Memory, session isolation, checkpointing, protocollo UI e recovery sono problemi di software architecture, non funzionalità decorative intorno all'LLM.
  • Exactly-once non compare magicamente perché esiste un checkpoint. I tool con side effect devono essere idempotenti o compensabili.
  • Protocollo e framework sono concetti separati. AG-UI permette di disaccoppiare backend agentico e client; IChatClient rende questa separazione particolarmente naturale in .NET.
  • L'AI FinOps va misurata a livello di task. Il costo per token è solo una componente di retry, escalation, cache reuse, tool call e latenza.
  • Nel GIS cloud la GPU non è il sistema. CPU, VRAM, protocollo di remote display, rete, data locality e storage possono diventare il collo di bottiglia prima della GPU.
  • Portal for ArcGIS va trattato come componente security-sensitive. Il nuovo security update include almeno una vulnerabilità CVSS 9.8 e deve entrare rapidamente nel normale ciclo staging → regression → production.
  • La supply chain ha stato. Una trusted signer policy richiede manutenzione dei certificati esattamente come qualsiasi altra root of trust.

Lab della settimana

Lab 1 — Esporre un agente .NET via AG-UI

Creare un ASP.NET Core minimal endpoint con AGUI.Server, usare un IChatClient locale o remoto e osservare gli eventi SSE generati durante streaming e tool call.

Obiettivo: verificare in pratica la separazione fra agent implementation e presentation protocol.

Lab 2 — Benchmark ArcGIS Pro A10 vs T4

Usare lo stesso progetto ArcGIS Pro e gli stessi dati su una VM NVadsA10_v5 e una NCasT4_v3 comparabile. Eseguire ArcGIS Pro Performance Assessment Tool e raccogliere startup time, map loading, layer rendering e utilizzo GPU.

Aggiungere una seconda prova spostando i dati lontano dal compute: è un modo semplice per dimostrare quanto la data locality possa falsare un confronto puramente GPU.

Lab 3 — Cost-per-successful-task: Sol vs Luna

Creare un piccolo set di 30-50 task reali — coding, estrazione strutturata, tool calling — ed eseguirli su GPT-6 Luna e GPT-6 Sol registrando:

input tokens
cached input tokens
output tokens
latency
tool calls
retries
task success
estimated cost

La metrica finale non deve essere il costo medio della chiamata, ma il costo medio del task completato correttamente.