Nello scorso script abbiamo iniziato ad occuparci dei Large Language Model, e in particolare di come integrare la nostra applicazione con essi tramite Semantic Kernel.
L'esempio che abbiamo realizzato sfrutta il cosiddetto endpoint sincrono: è di semplice utilizzo, ma ha il difetto di restituire la risposta solo dopo che questa sia stata interamente elaborata del modello AI. Ciò si traduce in tempi di attesa per l'utente, durante i quali effettivamente non accade nulla.
Un'alternativa - che richiede alcune minime modifiche al codice - è quella di utilizzare lo streaming endpoint, che invece ritorna uno stream di parole che, dal nostro controller, possiamo direttamente girare al client.
Riprendiamo l'esempio che abbiamo visto in precedenza, e modifichiamo la action in questo modo:
[HttpPost] public async IAsyncEnumerable<string> PostMessage([FromBody] string message) { ChatHistory.AddUserMessage(message); var result = _chatCompletionService.GetStreamingChatMessageContentsAsync(ChatHistory); string responseMessage = string.Empty; await foreach (var messageContent in result) { responseMessage += messageContent.Content; yield return messageContent.Content; } ChatHistory.AddAssistantMessage(responseMessage); }
Come possiamo notare, innanzi tutto il tipo restituito dal codice in alto è ora un IAsyncEnumerable, ossia un array di string che viene ritornato al client sotto forma di stream. Ci siamo occupati di questa funzionalità di ASP.NET Core in un precedente script (https://www.aspitalia.com/script/1458/Effettuare-Stream-Risposta-ASP.NET-Core-Tramite-IAsyncEnumerable.aspx).
Inoltre, questa volta abbiamo invocato il metodo GetStreamingChatMessageContentsAsync, che invece dell'intera risposta, ritorna a sua volta un oggetto IAsyncEnumerable, che possiamo iterare tramite un costrutto aync foreach.
Ognuno degli elementi della risposta, che altro non sono i vari token generati dal modello, può essere poi restituito al client tramite yield return. Come possiamo notare, però, è anche importante accumulare tutti gli elementi all'interno di una variable responseMessage, così che una volta che la risposta sia terminata, possiamo aggiungerla interamente alla history in modo da mantenerne traccia nella successive interazioni.
Se ora proviamo a eseguire questo codice, vedremo semplicemente che il risultato ottenuto è questa volta un array di elementi string. Ma se proviamo a invocarlo da un client che supporti lo streaming, come per esempio il codice di questo script (https://www.aspitalia.com/script/1459/Sfruttare-Streaming-Chiamata-Http-Blazor.aspx) noteremo come effettivamente la risposta di ChatGPT si componga gradualmente, man mano che viene generata dal modello in Azure.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Generare la software bill of material (SBOM) in GitHub
Utilizzare la funzione EF.Parameter per forzare la parametrizzazione di una costante con Entity Framework
Managed deployment strategy in Azure DevOps
Eseguire una ricerca avanzata per recuperare le issue di GitHub
Utilizzare DeepSeek R1 con Azure AI
Potenziare la ricerca su Cosmos DB con Full Text Search
Triggerare una pipeline su un altro repository di Azure DevOps
Popolare una classe a partire dal testo, con Semantic Kernel e ASP.NET Core Web API
Ordinare randomicamente una lista in C#
Recuperare App Service cancellati su Azure
Documentare i servizi REST con Swagger e OpenAPI con .NET 9
Utilizzare gRPC su App Service di Azure