Finora abbiamo utilizzato GPT per implementare una chat, ma in alcuni casi vorremmo invece sfruttarlo per avere delle risposte "strutturate" a partire da un input generico. Consideriamo l'esempio che abbiamo visto finora: siamo in grado di creare una ChatHistory persistente, salvata su database, ma abbiamo lasciato un punto "aperto", ossia la definizione del titolo, che al momento contiene solo un placeholder.
L'obiettivo è di usare GPT per generare questo titolo ma, dato che si tratterà di un'interrogazione a sé stante e, soprattutto, "una tantum", invece che usare ChatCompletionService, sfrutteremo direttamente l'oggetto Kernel per eseguire il prompt.
Come prima cosa, quindi, dobbiamo registrarlo nell'IoC container di ASP.NET Core:
builder.Services.AddTransient<Kernel>();
Non dobbiamo configurare alcuna stringa di connessione o chiave, perché sfrutterà automaticamente quanto già impostato per ChatCompletionService.
A questo punto possiamo aggiungere un nuovo metodo al nostro controller, che si occuperà di generare e impostare il titolo:
private async Task SetTitleAsync(ChatSession session) { if (session.Title != "Placeholder Title") { // title was already set previously return; } string prompt = "Determine the title of the following conversation in a single JSON property named 'Title': " + JsonSerializer.Serialize(session.History.Skip(1)); var settings = new AzureOpenAIPromptExecutionSettings() { ResponseFormat = "json_object" }; var response = await _kernel.InvokePromptAsync(prompt, new KernelArguments(settings)); var title = JsonDocument.Parse(response.ToString()).RootElement.GetProperty("Title").GetString(); if (!string.IsNullOrEmpty(title)) { session.Title = title; } }
Questo metodo accetta una ChatSession come parametro, e verifichiamo inizialmente che il titolo sia ancora il placeholder iniziale e non sia stato già reimpostato.
Successivamente creiamo un semplice prompt per GPT, in cui chiediamo di restituire una risposta di tipo JSON con una proprietà Title. A questo prompt alleghiamo poi l'intera serializzazione della history, escludendo però il system message, così che il titolo venga generato solo a partire dall'effettiva conversazione.
Un aspetto importante da sottolineare è l'uso di AzureOpenAIPromptExecutionSettings, e in particolare della proprietà ResponseFormat, che abbiamo impostato a "json_object". Questo parametro ha l'effetto di forzare GPT a restituire un risultato JSON, evitando risposte del tipo "Certamente, ecco il tuo JSON: .." che inevitabilmente creerebbero problemi alla nostra logica di deserializzazione. Attenzione a un requisito non immediatamente ovvio: il prompt deve contenere la parola "JSON", non basta limitarsi a impostare ResponseFormat!
Proprio grazie a questo constraint, possiamo effettuare il parsing diretto della risposta tramite JsonDocument, recuperare il titolo e assegnarlo alla nostra ChatSession.
A questo punto non ci resta che invocare questo metodo durante la Action per rispondere a un messaggio utente:
public async IAsyncEnumerable<string> PostMessage(int sessionId, [FromBody] string message) { var session = await _dbContext.ChatSession.FindAsync(sessionId); // .. altro codice qui .. session.History.AddAssistantMessage(responseMessage); await SetTitleAsync(session); _dbContext.Entry(session).State = EntityState.Modified; await _dbContext.SaveChangesAsync(); }
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Bloccare l'esecuzione di un pod in mancanza di un'artifact attestation di GitHub
.NET Aspire per applicazioni distribuite
Migliorare i tempi di risposta di GPT tramite lo streaming endpoint in ASP.NET Core
Introduzione alle Container Queries
Collegare applicazioni server e client con .NET Aspire
Referenziare un @layer più alto in CSS
Effettuare il log delle chiamate a function di GPT in ASP.NET Web API
Esporre i propri servizi applicativi con Semantic Kernel e ASP.NET Web API
.NET Conference Italia 2024
Generare un hash con SHA-3 in .NET
Ordinare randomicamente una lista in C#
Utilizzare il trigger SQL con le Azure Function