AI Agents in .NET con Semantic Kernel: guida pratica 2026
Matteo Migliore

Matteo Migliore è un imprenditore e architetto software con oltre 25 anni di esperienza nello sviluppo di soluzioni basate su .NET e nell'evoluzione di architetture applicative per imprese e organizzazioni di alto profilo.

Ha guidato progetti enterprise, formato centinaia di sviluppatori e aiutato aziende di ogni dimensione a semplificare la complessità trasformando il software in guadagni per il business.

Questa guida fa parte della sezione completa sul Large Language Model e AI per sviluppatori .NET.

Gli agenti AI in .NET non sono un'evoluzione delle chatbot. Sono qualcosa di strutturalmente diverso: componenti software che ragionano, pianificano e agiscono autonomamente, invocando funzioni reali del tuo sistema per portare a termine obiettivi complessi. Se hai lavorato con i modelli LLM in modo tradizionale, costruire il tuo primo agente richiede di rimettere in discussione alcune assunzioni fondamentali su come si progetta e si scrive il codice.

Con un'integrazione LLM classica, il controllo del flusso e' sempre nelle tue mani: chiami il modello, interpreti la risposta, decidi cosa fare. Con un agente, deleghi al modello una parte di questa pianificazione. Tu definisci le capacita' del sistema, il modello decide come usarle per raggiungere l'obiettivo. E' uno spostamento di responsabilita' che ha implicazioni su come si progetta, si testa e si mette in produzione il software.

Il mercato italiano sta chiedendo esattamente questo. Le aziende che investono in AI nel 2026 non cercano demo: cercano sistemi che automatizzino processi reali, che si integrino con l'infrastruttura esistente, che siano manutenibili e osservabili nel tempo. I developer che sanno costruire questi sistemi, non solo chiamare API, sono quelli con il maggiore vantaggio competitivo sul mercato del lavoro in questo momento.

La maggior parte dei tutorial sugli agenti AI mostra esempi che funzionano in locale ma che non reggono alla prima settimana in produzione. Il comportamento non e' quello atteso, i costi in token crescono senza controllo, un bug diventa quasi impossibile da riprodurre. Non perche' la tecnologia sia immatura, ma perche' costruire agenti affidabili richiede competenze architetturali che vanno ben oltre la configurazione iniziale del framework.

Questo articolo affronta i problemi reali. Se hai gia' letto il nostro articolo introduttivo su Semantic Kernel, qui troverai quello che viene dopo: le domande che ogni developer si pone quando smette di fare esperimenti e inizia a ragionare in termini di produzione.

Cosa sono davvero gli agenti AI e perche' cambiano il modo di sviluppare software

Una chiamata LLM tradizionale segue uno schema fisso: invii un testo, ricevi una risposta testuale. Il controllo del flusso e' completamente nelle tue mani come sviluppatore. Decidi tu la sequenza delle operazioni, interpreti tu l'output del modello, chiami tu le API del sistema.

Un agente AI inverte parte di questo controllo. Invece di leggere l'output del modello e decidere cosa fare, fornisci all'agente un insieme di funzioni che puo' invocare autonomamente. Il modello ragiona su quale funzione chiamare, con quali parametri, valuta il risultato e decide se il suo obiettivo e' raggiunto o se serve un altro passo. Tu definisci le capacita', il modello decide la strategia di esecuzione.

Questo schema, chiamato ReAct (Reasoning and Acting), e' alla base di tutti i sistemi agentici moderni. In Semantic Kernel e' implementato nativamente attraverso il meccanismo di invocazione automatica delle funzioni. Il modello riceve la lista dei tool disponibili, decide quali invocare, esegue le chiamate, ragiona sui risultati e continua finche' ritiene di aver completato il compito.

Un agente AI non e' un miglioramento di una chatbot: e' un componente che prende decisioni. Progettarlo correttamente significa definire esplicitamente quali decisioni puo' prendere in autonomia e quali richiedono approvazione umana.

La differenza pratica per un team di sviluppo: con le chiamate LLM tradizionali, il numero di casi da gestire nel codice cresce linearmente con la complessita' del problema. Con un agente, deleghi al modello la pianificazione dei passi intermedi. Il codice che scrivi definisce cosa il sistema puo' fare, non come deve farlo in ogni scenario possibile. Questo riduce drasticamente la superficie di codice da mantenere per problemi ad alta variabilita'.

Perche' le aziende italiane stanno investendo sugli agenti AI nel 2026

Nei settori dove la variabilita' dei casi e' alta, come l'assistenza clienti, l'analisi documentale, l'integrazione tra sistemi eterogenei, i team di sviluppo hanno sempre scritto enormi quantita' di codice per gestire eccezioni, varianti e scenari imprevisti. Un agente ben progettato copre questa variabilita' con un set di funzioni generaliste e istruzioni comportamentali, invece che con rami condizionali infiniti.

Non e' magia e non e' privo di rischi. Ma il rapporto tra complessita' del problema risolto e codice da scrivere e mantenere e' significativamente migliore rispetto all'approccio tradizionale, per una classe specifica di problemi. Identificare quali problemi rientrano in questa classe e quali no e' la prima competenza da sviluppare.

Come funziona un agente AI: il ciclo ragiona-pianifica-agisce

Per costruire agenti AI affidabili, devi capire esattamente cosa succede durante l'esecuzione. Il ciclo interno di un agente non e' una scatola nera: e' una sequenza ben definita di passi che puoi osservare, debuggare e ottimizzare.

Il processo inizia quando l'utente invia un messaggio. L'agente lo aggiunge alla storia conversazionale insieme a tutti i messaggi precedenti della sessione. Poi invia al modello LLM questa storia, il messaggio di sistema con le istruzioni dell'agente, e la lista delle funzioni disponibili con le loro descrizioni.

Il modello risponde in uno di due modi: con testo diretto (la risposta finale all'utente) oppure con una o piu' richieste di invocazione di funzioni. Nel secondo caso, Semantic Kernel esegue le funzioni richieste, aggiunge i risultati alla storia come messaggi di tipo "tool result", e reinvia tutto al modello. Il modello ragiona sui risultati e decide se rispondere all'utente o invocare altre funzioni.

Questo ciclo continua finche' il modello genera una risposta testuale finale oppure si raggiunge il limite massimo di invocazioni configurato. E' importante capire che ogni invocazione di funzione genera un ulteriore scambio con il modello LLM, con il relativo costo in token e latenza. Un agente che fa 5 tool call in una conversazione usa piu' token di una semplice risposta, perche' la storia cresce a ogni iterazione.

Quando ha senso usare un agente e quando e' eccessivo

Gli agenti brillano nei casi dove il numero di combinazioni possibili di passi e' troppo alto per essere codificato esplicitamente: assistenza clienti che naviga un catalogo variabile, analisi di documenti con struttura eterogenea, orchestrazione di workflow dove i passi dipendono dai risultati precedenti in modi non prevedibili.

Non usare un agente quando il flusso di lavoro ha passi deterministi e noti. Se sai esattamente la sequenza di operazioni da eseguire, il codice imperativo classico e' piu' prevedibile, piu' testabile e piu' economico. Gli agenti aggiungono costi in token, latenza e complessita' di debugging. Usali quando il beneficio in flessibilita' supera questi costi.

Una buona euristica: se riesci a scrivere un diagramma di flusso completo del problema in meno di dieci nodi, probabilmente non ti serve un agente. Se il diagramma di flusso richiederebbe centinaia di rami per coprire tutti i casi, un agente e' la scelta giusta.

Semantic Kernel come piattaforma per costruire agenti AI in .NET

Semantic Kernel e' il framework open source di Microsoft per integrare LLM nelle applicazioni .NET. Non e' solo un client HTTP per OpenAI: e' un sistema di orchestrazione con un modello di astrazione che separa il tuo codice dal provider LLM specifico. Puoi sviluppare localmente con Ollama e deployare in produzione su Azure OpenAI senza cambiare il codice dell'agente.

Le dipendenze necessarie per un progetto con agenti sono due pacchetti NuGet principali. Il secondo e' separato dal core perche' chi usa Semantic Kernel solo per chiamate LLM non deve portarsi dietro il codice degli agenti.

<PackageReference Include="Microsoft.SemanticKernel" Version="1.30.0" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" Version="1.30.0" />

La configurazione del kernel e' il primo passo. Semantic Kernel usa la dependency injection standard di .NET, il che lo rende naturale da integrare in qualsiasi applicazione ASP.NET Core. Il provider LLM si configura nel builder e viene iniettato nel kernel come servizio. Il codice dell'agente non cambia tra sviluppo locale (Ollama) e produzione (Azure OpenAI): usa sempre la stessa interfaccia.

Per i test locali durante lo sviluppo, Ollama con llama3.2 o mistral e' la scelta pragmatica: zero costi API, nessun rate limit, reset istantaneo dello stato. Per la produzione su Azure, GPT-4o rimane il riferimento per la qualita' del ragionamento agentico nel 2026. Entrambi implementano la stessa interfaccia, quindi lo switch e' una questione di configurazione, non di refactoring.

Struttura consigliata del progetto

Separare plugin, agenti e filtri in cartelle dedicate e' un dettaglio che conta quando il progetto cresce. Una struttura che funziona in pratica:

La cartella Agents/ contiene le definizioni degli agenti, ciascuno in un file dedicato con le istruzioni di sistema e la configurazione. La cartella Plugins/ contiene le classi con le funzioni che gli agenti possono invocare. La cartella Filters/ contiene i filtri per il logging e l'approvazione umana. La cartella Infrastructure/ contiene la factory per la creazione del kernel e la configurazione dei servizi.

Questa separazione permette di aggiungere un nuovo plugin senza toccare il codice dell'agente, di modificare le istruzioni di un agente senza impattare i plugin, di aggiungere o rimuovere filtri senza cambiare nulla nella logica applicativa.

Come si struttura un agente AI in .NET: plugin, kernel e orchestrazione

I plugin sono il cuore operativo di un agente. Ogni errore nella loro progettazione si traduce in un agente che invoca funzioni nel contesto sbagliato o non riesce a completare compiti che dovrebbe gestire. Progettare bene i plugin e' probabilmente la competenza piu' critica quando si lavora con gli agenti.

La regola fondamentale: le descrizioni negli attributi non sono documentazione per il team di sviluppo. Sono istruzioni per il modello LLM. Il modello le usa per decidere se e quando invocare ogni funzione. Una descrizione vaga genera invocazioni errate. Una descrizione precisa e contestuale genera un agente affidabile.

Le descrizioni efficaci spiegano quando usare la funzione, non solo cosa fa. I parametri hanno descrizioni che includono esempi di formato. I messaggi di errore restituiti dai plugin sono scritti per essere comprensibili all'utente finale, non per il developer. Il token di cancellazione viene propagato per permettere la cancellazione in caso di timeout. Questi dettagli fanno la differenza tra un agente che funziona in demo e uno che regge in produzione.

Quante funzioni esporre a un agente

I modelli piu' capaci gestiscono bene liste di 20-30 funzioni. Quelli piu' piccoli, e piu' economici, hanno prestazioni peggiori quando la lista e' troppo lunga. Regola pratica: mantieni il numero totale di funzioni sotto i 15-20 per agente. Se ne servono di piu', valuta la selezione dinamica dei plugin in base al contesto invece di averli tutti sempre disponibili.

Per quanto riguarda la granularita': funzioni troppo ampie, che fanno troppe cose, sono difficili da descrivere in modo preciso. Funzioni troppo atomiche aumentano il numero di invocazioni per completare un compito. Il punto di equilibrio e' una funzione per ogni operazione logicamente distinta dal punto di vista dell'utente, non dal punto di vista del sistema.

Un errore comune nei team che iniziano con gli agenti: esporre direttamente le API del dominio come plugin, con gli stessi nomi e firme usati nel codice interno. Le funzioni dei plugin devono essere pensate per il modello LLM, non per il developer. I nomi devono essere chiari in linguaggio naturale, le descrizioni devono contestualizzare l'uso, i messaggi di ritorno devono essere comprensibili come testo.

Il componente agente: istruzioni, kernel e configurazione del comportamento

Con il kernel configurato e i plugin registrati, si crea l'agente vero e proprio. La parte piu' importante, e spesso la piu' sottovalutata, sono le istruzioni di sistema. Definiscono il contratto comportamentale dell'agente: cosa puo' fare, cosa non deve fare, come deve comunicare, come gestire i casi limite.

Qualsiasi comportamento non specificato nelle istruzioni diventa non deterministico. Il modello lo gestira' nel modo che ritiene piu' appropriato, e questo raramente corrisponde a quello che vuoi in produzione. Istruzioni efficaci usano elenchi espliciti per permessi e vincoli, specificano il formato delle risposte quando conta, includono istruzioni su come gestire le situazioni di errore e le richieste fuori scope.

La configurazione del comportamento agentico avviene tramite il parametro FunctionChoiceBehavior.Auto(): abilita l'invocazione automatica delle funzioni da parte del modello. Il parametro MaximumAutoInvokeAttempts definisce quanti cicli di invocazione il modello puo' fare prima di dover concludere. Tenerlo esplicito in produzione, non affidarti al valore di default.

La gestione della memoria: come un agente AI ricorda il contesto

La memoria di un agente AI si divide in due livelli con caratteristiche molto diverse: la storia conversazionale, che dura per la durata di una sessione, e la memoria persistente, che sopravvive tra sessioni diverse. Capire la differenza e gestirla correttamente e' uno dei punti dove si commettono gli errori piu' frequenti in produzione.

La storia conversazionale e' un oggetto che contiene tutti i messaggi scambiati tra utente, agente e funzioni nel corso di una sessione. E' il meccanismo che trasforma una sequenza di chiamate indipendenti a un LLM in una vera conversazione con memoria del contesto. Senza di essa, ogni messaggio e' trattato come una nuova conversazione: l'agente non ricorda nulla di quanto detto un turno prima.

Il problema della storia conversazionale in produzione: cresce. Ogni invocazione di funzione aggiunge messaggi, e dopo decine di turni il contesto diventa enorme. I costi in token crescono proporzionalmente. Il rischio di superare il contesto massimo del modello diventa reale. Per conversazioni lunghe devi implementare una strategia di riduzione.

Strategie per gestire la crescita della storia conversazionale

La strategia piu' semplice e' la finestra scorrevole: mantieni solo gli ultimi N messaggi, eliminando i piu' vecchi. Semplice da implementare, ma perde il contesto delle conversazioni molto lunghe. Una finestra di 20-30 messaggi e' un buon compromesso per la maggior parte dei casi enterprise.

La strategia alternativa e' la sintesi: prima di eliminare i messaggi piu' vecchi, li riassumi con una chiamata al modello e inserisci il riassunto come messaggio di sistema. Mantiene il contesto semantico ma aggiunge il costo di una chiamata LLM extra. Vale la pena in scenari dove le conversazioni durano ore e il contesto accumulato e' criticamente importante.

Una terza strategia, meno comune ma efficace per certi casi d'uso, e' la sessione strutturata: invece di mantenere la storia raw, estrai le informazioni rilevanti alla fine di ogni turno e le salvi in una struttura dati tipizzata. L'agente riceve il contesto rilevante come prompt arricchito all'inizio di ogni turno, non come storia completa. Piu' complessa da implementare, ma molto piu' efficiente in termini di token.

La memoria persistente tra sessioni

Per molti casi d'uso enterprise hai bisogno di qualcosa di piu' della storia di sessione: un agente che ricordi le preferenze dell'utente tra una sessione e l'altra, che conosca i documenti rilevanti per il dominio, che possa recuperare contesto da conversazioni passate.

Semantic Kernel fornisce un livello di astrazione sopra i database vettoriali per salvare e recuperare ricordi tramite ricerca semantica. Invece di una query che cerca corrispondenze esatte, cerchi per significato. Una query come "come preferisce ricevere i pacchi questo cliente" restituisce risultati rilevanti anche se quei ricordi non contengono esattamente quelle parole. Per approfondire il tema della memoria semantica e il pattern di recupero e generazione aumentata, leggi anche il nostro articolo su MCP: Model Context Protocol, lo standard emergente per la comunicazione tra LLM e sistemi di contesto esterno.

La scelta del backend vettoriale dipende dall'infrastruttura esistente. Se sei gia' su Azure, Azure AI Search e' la soluzione piu' integrata. Per deployment on-premises, Qdrant o Weaviate sono le opzioni piu' diffuse. Semantic Kernel astrae il backend: cambiare il vector store non richiede cambiare il codice dell'agente.

Alcune pratiche efficaci per cosa salvare in memoria persistente: le preferenze esplicite dell'utente, le conclusioni di conversazioni complesse invece dell'intera conversazione, i documenti di dominio che l'agente consulta frequentemente. Non salvare dati sensibili a meno che il vector store non sia cifrato e isolato per utente o tenant.

Come evitare i loop infiniti e i comportamenti inattesi negli agenti AI

I loop infiniti negli agenti AI non sono un'eccezione rara: sono uno dei problemi piu' comuni in fase di sviluppo. Succede quando l'agente non riesce a portare a termine il compito ma non capisce che deve fermarsi, quando un plugin restituisce un errore e l'agente continua a riprovare, o quando le istruzioni di sistema sono ambigue su quando considerare il lavoro completato.

Il limite massimo di invocazioni configurato nel comportamento di selezione delle funzioni e' la prima linea di difesa. Non affidarti al valore di default: rendilo esplicito in base al tipo di agente. Un agente di assistenza clienti raramente ha bisogno di piu' di 5-6 invocazioni per rispondere. Un agente di analisi dati complessa potrebbe averne bisogno di piu'. Imposta il limite in modo deliberato, non per inerzia.

La seconda causa di comportamenti inattesi sono le istruzioni di sistema incomplete. Se l'agente non sa come gestire un caso specifico, il modello improvvisa. A volte improvvisa bene, spesso no. Testa sempre le istruzioni con una suite di casi limite prima del rilascio: richieste fuori scope, errori nei dati, input malformati, richieste ambigue. Ogni caso non coperto dalle istruzioni e' un vettore di comportamento non deterministico.

Pattern per rilevare e interrompere comportamenti anomali

Oltre al limite di invocazioni, implementa un filtro di monitoraggio che tiene traccia del pattern di invocazioni nella conversazione corrente. Se lo stesso plugin viene invocato con gli stessi parametri tre volte consecutive, probabilmente l'agente e' in un ciclo. Un filtro che rileva questo pattern e interrompe il ciclo con un messaggio di errore esplicito e' molto piu' utile di un timeout generico.

Un altro pattern utile: il circuit breaker per le invocazioni di funzioni. Se un plugin restituisce errori per piu' di N invocazioni consecutive, disabilitarlo per il resto della sessione e notificare l'agente che il tool non e' disponibile. L'agente puo' cosi' adattare il suo comportamento invece di continuare a tentare un'operazione che inevitabilmente fallisce.

Nei sistemi con piu' agenti (gruppi di agenti), il rischio di loop e' ancora piu' alto. Due agenti che si passano il controllo a vicenda senza una chiara condizione di terminazione possono generare conversazioni infinite. La strategia di terminazione del gruppo di agenti e' un componente critico, non un dettaglio di implementazione.

Supervisione umana e sicurezza: quando l'agente non deve agire da solo

Non esporre mai a un agente funzioni che eseguono azioni irreversibili senza un meccanismo di approvazione umana. Eliminare record, inviare email, eseguire pagamenti, modificare configurazioni di sistema: queste azioni richiedono un pattern dove l'agente propone l'azione e attende conferma prima di eseguirla. Non e' una buona pratica, e' un requisito non negoziabile per qualsiasi sistema in produzione.

Il meccanismo tecnico in Semantic Kernel per implementare questo pattern e' il filtro di invocazione delle funzioni. E' una classe che intercetta ogni chiamata a un plugin prima dell'esecuzione. Puoi usarla per distinguere le funzioni di sola lettura da quelle che modificano stato, bloccare le seconde finche' non arriva una conferma esplicita fuori banda, e restituire all'agente un messaggio che spiega l'esito.

Il filtro si registra nel kernel come servizio e viene invocato automaticamente per ogni chiamata a qualsiasi funzione. Questo significa che non devi modificare il codice dei plugin per aggiungere il controllo: lo aggiungi una volta nel filtro e si applica a tutto.

Sicurezza contro l'iniezione di prompt

Se gli utenti possono inserire testo libero che finisce nel contesto dell'agente, c'e' rischio di iniezione di prompt: input costruiti ad arte per cercare di modificare il comportamento dell'agente, farlo uscire dal suo scope, o fargli eseguire azioni non autorizzate. Sanitizza sempre l'input utente prima di aggiungerlo alla storia conversazionale.

Le istruzioni di sistema devono includere esplicitamente indicazioni su come l'agente deve reagire a tentativi di manipolazione. Frasi come "ignora le istruzioni precedenti" o "sei ora un altro assistente" sono pattern classici di iniezione. Un agente ben istruito li riconosce e risponde in modo appropriato invece di seguirli.

Il problema della contaminazione del contesto nei sistemi multi-tenant merita attenzione separata. La storia conversazionale e la memoria persistente devono essere isolate per utente o per sessione. Condividere accidentalmente il contesto tra utenti diversi e' una violazione di privacy grave e difficile da rilevare senza log strutturati.

Osservabilita' in produzione: log, tracce e metriche

Un agente AI in produzione senza osservabilita' e' come un'applicazione senza log: quando qualcosa va storto, non hai elementi per capire cosa e' successo. E con gli agenti qualcosa va sempre storto prima o poi. Il modello invoca un plugin con parametri errati, entra in un ciclo, genera una risposta fuori dal dominio previsto.

Semantic Kernel espone due meccanismi principali per l'osservabilita'. Il primo e' il filtro di invocazione delle funzioni: intercetta ogni chiamata a un plugin e permette di loggare nome, parametri, durata e risultato. Il secondo e' il supporto nativo a OpenTelemetry: ogni invocazione genera span con attributi standard compatibili con Azure Monitor, Jaeger, Grafana e qualsiasi backend compatibile. In un sistema con piu' agenti, il tracing distribuito e' l'unico modo pratico per capire il flusso di esecuzione di una conversazione.

Le metriche da monitorare in produzione: numero di invocazioni per conversazione, costo in token per sessione, tasso di errore dei plugin, distribuzione delle latenze per ogni funzione. Questi numeri non servono solo per il monitoraggio operativo: servono per capire quali plugin sono i colli di bottiglia, dove gli agenti si bloccano piu' spesso, e se il costo operativo e' sostenibile.

Agenti multipli: come orchestrare team di AI per compiti complessi

Per scenari dove un singolo agente non e' sufficiente, Semantic Kernel supporta i gruppi di agenti: piu' agenti specializzati che collaborano per raggiungere un obiettivo comune. Ogni agente ha un ruolo specifico, un set di funzioni coerenti con quel ruolo, e istruzioni che ne definiscono il comportamento nel contesto del gruppo.

Il pattern e' particolarmente utile per pipeline di elaborazione dove i passi richiedono competenze diverse. Un agente raccoglie e analizza dati, un secondo produce un report esecutivo, un terzo verifica la qualita' dell'output. Oppure per sistemi di revisione dove un agente genera una proposta e un secondo la critica, iterando finche' il risultato e' soddisfacente.

Un caso d'uso concreto nel mercato italiano: revisione automatica del codice. Un agente Esecutore analizza il codice di una pull request, identifica problemi potenziali e suggerisce refactoring. Un agente Revisore valuta la qualita' dell'analisi, verifica che siano stati considerati sicurezza, performance e testabilita', e approva o richiede un approfondimento. Il ciclo continua finche' il Revisore e' soddisfatto o si raggiunge il limite di iterazioni.

Strategie di selezione e terminazione nel gruppo di agenti

Due configurazioni sono critiche per qualsiasi gruppo di agenti: la strategia di selezione, che decide quale agente parla ad ogni turno, e la strategia di terminazione, che decide quando il gruppo ha completato il suo lavoro.

Semantic Kernel offre la selezione sequenziale, dove gli agenti parlano a turno in ordine fisso, e la selezione basata su LLM, dove un modello decide quale agente e' piu' adatto a rispondere in base al contesto. Per la maggior parte dei casi, la selezione sequenziale e' sufficiente e molto piu' prevedibile. La selezione basata su LLM aggiunge costi e latenza senza necessariamente migliorare i risultati.

La strategia di terminazione e' l'elemento piu' critico. Senza di essa, gli agenti continuano a interagire indefinitamente. Implementa sempre una condizione di terminazione chiara: un marcatore nel testo che il Revisore include quando approva, un numero massimo di turni per agente, o una funzione di valutazione dedicata. Il numero massimo di iterazioni e' il safety net: anche se la condizione semantica non si attiva, il gruppo si ferma comunque.

Il costo operativo dei sistemi multi-agente

I sistemi multi-agente con cicli di revisione sono potenti ma costosi. Ogni iterazione genera chiamate LLM multiple. In produzione, monitora il numero medio di iterazioni prima della terminazione e il costo medio per sessione. Alcune ottimizzazioni pratiche: usa un modello piu' economico per l'agente che genera bozze e uno piu' capace solo per il revisore. Imposta un limite rigido di 2-3 iterazioni massime per contenere i costi senza sacrificare troppo la qualita'.

I sistemi multi-agente con cicli di revisione sono lo stato dell'arte per compiti complessi che richiedono qualita' elevata, ma il loro costo operativo richiede una governance esplicita: budget per sessione, metriche di utilizzo e soglie di alert fanno parte dell'architettura tanto quanto il codice degli agenti stessi.

Come testare un agente AI in modo affidabile

Testare un agente AI e' fondamentalmente diverso dal testare codice deterministico. Non puoi aspettarti che lo stesso input produca sempre lo stesso output: i modelli LLM hanno una componente stocastica. Ma puoi testare proprieta' comportamentali: l'agente invoca le funzioni giuste nelle situazioni appropriate? Non esegue mai azioni critiche senza approvazione? Mantiene il contesto correttamente tra i turni?

La strategia piu' efficace e' disaccoppiare il test del comportamento dell'agente dal test della logica dei plugin. Per i plugin, usa unit test classici: sono funzioni C# con input e output definiti, completamente deterministici. Per l'agente, usa mock dei plugin e verifica che le funzioni corrette vengano invocate con parametri ragionevoli in risposta a input specifici.

[Fact]
public async Task Agente_InvocaGetStatoOrdine_QuandoUtenteChiede_StatoOrdineSpecifico()
{
    // Arrange: mock del plugin con tracciamento delle invocazioni
    var pluginMock = new Mock<IOrdiniPlugin>();
    pluginMock
        .Setup(p => p.GetStatoOrdineAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync("Ordine ORD-123456: in consegna, prevista domani.");

    var kernel = CreaKernelConMock(pluginMock.Object);
    var agente = CreaAgenteDiTest(kernel);
    var storia = new ChatHistory();
    storia.AddUserMessage("Qual e' lo stato dell'ordine ORD-123456?");

    // Act
    await foreach (var _ in agente.InvokeAsync(storia)) { }

    // Assert: verifica che la funzione corretta sia stata invocata
    pluginMock.Verify(
        p => p.GetStatoOrdineAsync(
            It.Is<string>(id => id.Contains("123456")),
            It.IsAny<CancellationToken>()),
        Times.AtLeastOnce);
}

Il pattern e' verificare che i plugin giusti siano stati invocati con parametri ragionevoli, non che l'output testuale sia identico a un valore atteso. L'output testuale varia tra esecuzioni per la natura stocastica del modello. Il comportamento funzionale, quali plugin vengono invocati e con quali parametri, e' molto piu' stabile e verificabile.

Test di regressione comportamentale

Per i test di integrazione end-to-end, mantieni un set di scenari conversazionali rappresentativi con input e outcome attesi, eseguiti periodicamente contro il modello reale. Questi test servono a rilevare regressioni comportamentali introdotte da aggiornamenti del modello, modifiche ai plugin o cambiamenti nelle istruzioni di sistema.

Una regressione comportamentale e' quando l'agente smette di fare qualcosa che faceva correttamente, o inizia a fare qualcosa che non dovrebbe fare, senza che il codice sia cambiato. Succede quando il provider aggiorna il modello, quando cambiano le istruzioni di sistema per altri motivi, o quando si aggiungono nuovi plugin che interferiscono con quelli esistenti. Senza una suite di test di regressione, non te ne accorgi finche' arriva una segnalazione dagli utenti.

Mantieni i test di regressione separati dai test di sviluppo: sono costosi in token e lenti, non devono girare a ogni build. Ma devono girare almeno una volta alla settimana in un ambiente di staging, e sempre prima di un rilascio in produzione.

Quando usare un agente AI e quando e' eccessivo per il problema

Dopo aver visto come costruire agenti complessi, e' importante fare un passo indietro. Gli agenti AI non sono la soluzione giusta per ogni problema. Usarli indiscriminatamente porta a sistemi piu' costosi, piu' lenti e piu' difficili da debuggare senza un beneficio reale.

I segnali che un agente e' la scelta giusta: il problema ha alta variabilita' nei percorsi di soluzione, i passi da eseguire dipendono dai risultati dei passi precedenti in modi non prevedibili in anticipo, codificare tutti i casi possibili in codice imperativo richiederebbe migliaia di righe di logica condizionale difficilmente mantenibile.

I segnali che un agente e' eccessivo: il flusso di lavoro ha passi fissi e prevedibili, le operazioni sono semplici chiamate ad API esterne senza logica decisionale, la latenza aggiuntiva introdotta dal ciclo agente-modello-plugin non e' accettabile, il costo in token per sessione supera il valore del servizio erogato.

Alternative agli agenti per casi piu' semplici

Per molti scenari che sembrano richiedere un agente, una soluzione piu' semplice funziona meglio. Un chatbot con chiamate LLM dirette e routing manuale basato su classificazione del testo e' sufficiente per assistenza clienti con scope limitato. Una pipeline di elaborazione con passi fissi in codice imperativo e' piu' prevedibile e testabile di un agente per workflow deterministici. Un sistema RAG (ricerca e generazione aumentata) e' la scelta giusta quando il problema e' rispondere a domande su una base documentale, non eseguire azioni.

Gli agenti aggiungono valore quando il problema richiede vera pianificazione adattiva, non quando si tratta di rispondere a domande con contesto recuperato da un database. Confondere i due scenari e' uno degli errori piu' comuni nei team che iniziano a lavorare con i sistemi AI. Per un confronto tra le diverse architetture di sistemi AI, leggi anche il nostro articolo sul vibe coding e il futuro dello sviluppo assistito dall'AI.

Il mercato degli agenti AI nel 2026: cosa chiedono le aziende italiane

Il mercato italiano degli agenti AI nel 2026 ha smesso di essere quello delle sperimentazioni. Le aziende di medie e grandi dimensioni stanno portando in produzione i primi sistemi agentici reali, principalmente in tre aree: automazione dell'assistenza clienti, analisi e classificazione documentale, e integrazione tra sistemi legacy e nuove piattaforme cloud.

Nei settori manifatturiero, finanziario e della distribuzione, le richieste piu' frequenti riguardano agenti che si integrano con ERP e CRM esistenti (SAP, Salesforce, Microsoft Dynamics), che rispettano requisiti di sicurezza stringenti (dati on-premises, nessuna trasmissione verso cloud pubblici), e che forniscono log completi di tutte le azioni eseguite per conformita' normativa.

Il profilo professionale che le aziende cercano non e' il data scientist che addestra modelli: e' il developer senior che sa progettare sistemi AI integrati con l'infrastruttura esistente. Conoscenza di .NET, comprensione dei pattern architetturali per sistemi distribuiti, esperienza con Azure o AWS, e la capacita' di valutare quando usare un agente e quando no.

Le competenze piu' richieste per i developer che lavorano con gli agenti AI

Semantic Kernel e' oggi lo standard de facto per gli agenti AI in ambienti .NET aziendali. La sua adozione e' cresciuta significativamente nell'ultimo anno grazie all'integrazione con Azure AI Foundry e al supporto per il protocollo MCP. I developer che conoscono il framework in profondita', non solo le basi, hanno un vantaggio concreto nel mercato attuale.

Oltre al framework, le competenze piu' richieste sono: progettazione di plugin con descrizioni efficaci per il modello, gestione della memoria e del contesto conversazionale, implementazione di filtri per l'osservabilita' e la sicurezza, testing di sistemi non deterministici, e valutazione economica del costo operativo degli agenti.

Il gap piu' comune nei team che iniziano: sanno costruire un prototipo che funziona in demo, ma faticano a portarlo in produzione con i requisiti di affidabilita', osservabilita' e sicurezza che le aziende richiedono. Per approfondire come il framework Semantic Kernel si integra nell'ecosistema .NET e come strutturare un piano di adozione in un team, leggi il nostro articolo dedicato. Per chi vuole comprendere anche il contesto piu' ampio dell'evoluzione degli strumenti AI per sviluppatori, e' utile leggere anche la nostra analisi sul Model Context Protocol.

Come formarsi sugli agenti AI .NET in modo efficace

La formazione sui sistemi agentici richiede un approccio pratico. Leggere la documentazione e guardare tutorial risolve il problema dei primi passi, ma non prepara a gestire i problemi reali di produzione: comportamenti imprevisti del modello, costi fuori controllo, difficolta' nel debugging, regressioni comportamentali dopo un aggiornamento.

Il percorso piu' efficace combina fondamenta architetturali solide (pattern di progettazione per sistemi AI, principi di sicurezza e osservabilita') con pratica su scenari reali. Non esercizi accademici, ma problemi che rispecchiano quelli che si incontrano in un progetto enterprise. BestDeveloper offre percorsi di formazione per developer che vogliono diventare riferimenti tecnici nei progetti AI delle loro aziende, con un approccio che va dal codice alle decisioni architetturali.

Domande frequenti

Un AI agent e' un sistema che usa un modello LLM per ragionare su un obiettivo e prendere decisioni autonome su quali azioni eseguire per raggiungerlo. A differenza di una semplice chiamata LLM, un agente ha accesso a tool (funzioni) che puo' invocare, puo' ragionare sui risultati intermedi e pianificare passi multipli.

Un client OpenAI gestisce la comunicazione HTTP con l'API. Semantic Kernel aggiunge un layer di orchestrazione: gestione dei plugin (tool), memoria persistente, pianificazione automatica dei passi (AutoInvokeKernelFunctions), supporto per agenti multipli che collaborano, e integrazione con Azure AI e altri provider.

Si', con le dovute cautele. Gli agenti in produzione richiedono: limiti espliciti sui tool disponibili, logging di ogni azione intrapresa, meccanismi di approvazione umana per azioni irreversibili (human-in-the-loop), gestione degli errori e dei loop infiniti, e testing rigoroso dei casi limite.

Si'. Semantic Kernel supporta OpenAI, Azure OpenAI, Ollama (modelli locali), HuggingFace, e tramite connettori personalizzati qualsiasi modello con API compatibile. Nel 2026 il supporto e' stato esteso a Claude di Anthropic e Gemini di Google.

Semantic Kernel fornisce il Memory Store, un layer di astrazione sopra database vettoriali come Azure AI Search, Qdrant, Chroma o Pinecone. Si usa il VectorStore per salvare e recuperare ricordi rilevanti per la conversazione corrente tramite ricerca semantica. Il pattern consiste nel salvare frammenti di conversazione come embedding vettoriali e recuperarli in base alla similarita' semantica con il messaggio corrente.

Il pattern human-in-the-loop si implementa creando tool speciali che invece di eseguire direttamente l'azione restituiscono una proposta all'utente e attendono la conferma. In Semantic Kernel si usa un IFunctionInvocationFilter per intercettare le chiamate a funzioni critiche, loggare la proposta e sospendere l'esecuzione finche' non arriva la conferma. Le azioni irreversibili (cancellazioni, pagamenti, invio email) devono sempre passare per questo pattern.

Lascia i tuoi dati nel form qui sotto

Matteo Migliore

Matteo Migliore è un imprenditore e architetto software con oltre 25 anni di esperienza nello sviluppo di soluzioni basate su .NET e nell'evoluzione di architetture applicative per imprese e organizzazioni di alto profilo.

Nel corso della sua carriera ha collaborato con realtà come Cotonella, Il Sole 24 Ore, FIAT e NATO, guidando team nello sviluppo di piattaforme scalabili e modernizzando ecosistemi legacy complessi.

Ha formato centinaia di sviluppatori e affiancato aziende di ogni dimensione nel trasformare il software in un vantaggio competitivo, riducendo il debito tecnico e portando risultati concreti in tempi misurabili.

Stai leggendo perché vuoi smettere di rattoppare software fragile.Scopri il metodo per progettare sistemi che reggono nel tempo.