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
Utilizzare l'espressione if inline in una pipeline di Azure DevOps
Utilizzare il metodo ExceptBy per eseguire operazione di sottrazione tra liste
Loggare le query più lente con Entity Framework
Utilizzare l nesting nativo dei CSS
Gestire la cancellazione di una richiesta in streaming da Blazor
Ordine e importanza per @layer in CSS
Usare i servizi di Azure OpenAI e ChatGPT in ASP.NET Core con Semantic Kernel
Usare il colore CSS per migliorare lo stile della pagina
Generare un hash con SHA-3 in .NET
Aggiornare a .NET 9 su Azure App Service
Rendere i propri workflow e le GitHub Action utilizzate più sicure
Gestire eccezioni nei plugin di Semantic Kernel in ASP.NET Core Web API
I più letti di oggi
- .NET Conference Italia 2018 - Milano
- Tutorial ASP.NET
- Seconda preview per i Dynamic Data Control 4.0
- Disponibile al download la versione finale di Mozilla Firefox 4
- Microsoft Security Bulletin MS02-044
- Shared Source Initiative per gli MVP
- Mono 1.1.10 per un po' di ASP.NET 2.0
- Webcast 'ASP.NET 2.0 HttpRuntime'