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
Integrare modelli AI in un workflow di GitHub
Self-healing degli unit test con Copilot in GitHub
Gestire codice JavaScript con code splitting e lazy loading
Integrare un servizio esterno con .NET Aspire
Le cron expression di un workflow di GitHub
Eseguire query in contemporanea con EF
Ricevere notifiche sui test con Azure Load Testing
Autenticazione di git tramite Microsoft Entra ID in Azure DevOps
Recuperare le subissue e il loro stato di completamento in GitHub
Utilizzare Locust con Azure Load Testing
Importare repository da Bitbucket a GitHub Enterprise Cloud
DevSecOps per .NET: dalla teoria alla pratica


