Gestione dello stato

SI APPLICA A: SDK v4

Lo stato all'interno di un bot segue gli stessi paradigmi delle moderne applicazioni Web e Bot Framework SDK fornisce alcune astrazioni per semplificare la gestione dello stato.

Come con le app Web, un bot è intrinsecamente senza stato. Una istanza diversa del bot può gestire un determinato turno della conversazione. Per alcuni bot, questa semplicità è preferibile: il bot può funzionare senza informazioni aggiuntive o le informazioni necessarie sono garantite all'interno del messaggio in ingresso. Per altri utenti, lo stato (ad esempio dove la conversazione ha lasciato o i dati ricevuti in precedenza sull'utente) è necessario per il bot per avere una conversazione utile.

Perché è necessario lo stato?

Il mantenimento dello stato consente al bot di avere conversazioni più utili, ricordando alcuni dati su un utente o una conversazione. Se ad esempio ci sono già state conversazioni con un utente, è possibile salvare le informazioni di tale utente per non doverle chiedere di nuovo. Lo stato conserva i dati più a lungo del turno corrente, in modo che il bot mantenga le informazioni nel corso di una conversazione a più turni.

Poiché riguarda i bot, esistono alcuni livelli da usare: il livello di archiviazione, la gestione dello stato (contenuta nello stato del bot nel diagramma seguente) e le funzioni di accesso alle proprietà di stato. Questo diagramma illustra parti della sequenza di interazione tra questi livelli, con le frecce piene che rappresentano una chiamata al metodo e le frecce tratteggiate che rappresentano la risposta, con o senza un valore restituito.

Diagramma sequenza che illustra come viene caricato, memorizzato nella cache e archiviato ogni turno.

Il flusso di questo diagramma viene spiegato nelle sezioni seguenti con dettagli per ognuno di questi livelli.

Livello di archiviazione

A partire dal back-end, in cui le informazioni sullo stato vengono effettivamente archiviate, è il livello di archiviazione. Questo può essere pensato come archiviazione fisica, ad esempio in memoria, Azure o un server di terze parti.

Bot Framework SDK include alcune implementazioni per il livello di archiviazione:

  • L'archiviazione in memoria implementa l'archiviazione in memoria a scopo di test. L'archiviazione dei dati in memoria è destinata solo ai test locali perché questa risorsa di archiviazione è volatile e temporanea. I dati vengono cancellati ogni volta che viene riavviato il bot.
  • L'archivio BLOB di Azure si connette a un database di oggetti di Archiviazione BLOB di Azure.
  • L'archiviazione partizionata Azure Cosmos DB si connette a un database NoSQL Cosmos DB partizionato.

Importante

La classe CosmosDbStorage è stata deprecata. I contenitori originariamente creati con CosmosDbStorage non hanno impostato alcuna chiave di partizione e sono stati assegnati la chiave di partizione predefinita di "/_partitionKey".

I contenitori creati con l'archiviazione Cosmos DB possono essere usati con l'archiviazione partizionata di Cosmos DB. Per altre informazioni, vedere Partizionamento in Azure Cosmos DB.

Si noti anche che, a differenza dell'archiviazione legacy di Cosmos DB, l'archiviazione partizionata di Cosmos DB non crea automaticamente un database all'interno dell'account Cosmos DB. È necessario creare manualmente un nuovo database, ma ignorare manualmente la creazione di un contenitore poiché CosmosDbPartitionedStorage creerà il contenitore.

Per istruzioni su come connettersi ad altre opzioni di archiviazione, vedere Scrivere direttamente nell'archivio.

Gestione dello stato

La gestione dello stato automatizza la lettura e la scrittura dello stato del tuo bot nel livello di archiviazione sottostante. Lo stato viene archiviato sotto forma di proprietà di stato, che sono in effetti coppie chiave-valore che il bot può leggere e scrivere attraverso l'oggetto di gestione dello stato senza preoccuparsi dell'implementazione specifica sottostante. Tali proprietà di stato definiscono il modo in cui queste informazioni vengono archiviate. Quando ad esempio si recupera una proprietà definita come classe o oggetto specifici, la struttura dei dati è nota.

Queste proprietà di stato sono raggruppate in "bucket" con ambito, ovvero semplici raccolte che consentono di organizzare tali proprietà. L'SDK include tre di questi "bucket":

  • Stato dell'utente
  • Stato della conversazione
  • Stato privato della conversazione

Tutti questi bucket sono sottoclassi della classe bot state, che possono essere derivate per definire altri tipi di bucket con ambiti diversi.

Questi bucket predefiniti hanno come ambito una specifica visibilità, a seconda del bucket:

  • Lo stato dell'utente è disponibile in ogni turno in cui il bot conversa con quell'utente in quel canale, indipendentemente dalla conversazione
  • Lo stato della conversazione è disponibile in qualsiasi turno in una conversazione specifica, indipendentemente dall'utente, ad esempio nelle conversazioni di gruppo
  • L'ambito dello stato privato della conversazione si estende alla conversazione e all'utente specifici

Suggerimento

Sia lo stato dell'utente che lo stato della conversazione hanno un ambito basato sul canale. La stessa persona che usa diversi canali per accedere al bot è considerata un utente diverso per ogni canale, con uno stato utente distinto.

Le chiavi utilizzate per ciascuno di questi bucket predefiniti sono specifiche dell'utente, della conversazione o di entrambi. Quando si imposta il valore della proprietà di stato, la chiave viene definita internamente, con informazioni contenute nel contesto di turno per assicurarsi che ogni utente o conversazione venga inserito nel bucket e nella proprietà corretti. Nello specifico, le chiavi vengono definite come segue:

  • Lo stato dell'utente crea una chiave usando gli elementi ChannelId e From.Id, ad esempio {Activity.ChannelId}/users/{Activity.From.Id}#YourPropertyName
  • Lo stato della conversazione crea una chiave usando gli elementi ChannelId e Conversation.Id, ad esempio {Activity.ChannelId}/conversations/{Activity.Conversation.Id}#YourPropertyName
  • Lo stato privato della conversazione crea una chiave usando gli elementi ChannelId, From.Id e Conversation.Id, ad esempio {Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#YourPropertyName

Quando usare ogni tipo di stato

Lo stato della conversazione è utile per monitorare il contesto della conversazione, ad esempio:

  • Se il bot ha posto una domanda all'utente e di quale domanda si trattava
  • Qual è l'argomento attuale della conversazione, o quale era l'ultimo

Lo stato dell'utente è utile per tenere traccia delle informazioni sull'utente, come ad esempio:

  • Informazioni utente non critiche, come nome e preferenze, un'impostazione di allarme o una preferenza di avviso
  • Informazioni sull'ultima conversazione che l'utente ha avuto con il bot
    • Ad esempio, un bot di assistenza prodotti potrebbe tenere traccia dei prodotti per i quali l'utente ha posto domande.

Lo stato privato della conversazione è utile per i canali che supportano conversazioni di gruppo, ma in cui si vuole tenere traccia di informazioni specifiche dell'utente e della conversazione. Se ad esempio si ha un bot per dispositivi risponditori nelle aule scolastiche:

  • Il bot potrebbe aggregare e visualizzare le risposte degli studenti per una determinata domanda.
  • Il bot potrebbe aggregare i risultati di ogni studente e inviarli in privato allo studente stesso alla fine della sessione.

Per i dettagli sull'uso di questi bucket predefiniti, vedere l'articolo sugli stati.

Connessione a più database

Se il bot deve connettersi a più database, creare un livello di archiviazione per ogni database. È possibile scegliere di usare più database se il bot raccoglie informazioni con sicurezza, concorrenza o posizione dati diverse.

Per ogni livello di archiviazione, creare gli oggetti di gestione dello stato necessari per supportare le proprietà di stato.

Funzioni di accesso alle proprietà di stato

Le funzioni di accesso alle proprietà di stato vengono usate per leggere o scrivere una delle proprietà di stato e fornire metodi get, set e delete per accedere alle proprietà di stato da un turno. Per creare una funzione di accesso è necessario specificare il nome della proprietà, di solito quando si inizializza il bot. È quindi possibile usare la funzione di accesso per ottenere e manipolare quella proprietà dello stato del bot.

Le funzioni di accesso consentono all'SDK di ottenere lo stato dall'archivio sottostante e di aggiornare automaticamente la cache di stato del bot. La cache di stato è una cache locale gestita dal bot che archivia automaticamente l'oggetto stato, consentendo operazioni di lettura e scrittura senza accedere all'archivio sottostante. Se non è già nella cache, chiamando il metodo get della funzione di accesso è possibile recuperare lo stato e inserirlo nella cache. Dopo il recupero, la proprietà di stato può essere manipolata esattamente come una variabile locale.

Il metodo delete della funzione di accesso rimuove la proprietà dalla cache e la elimina anche dall'archivio sottostante.

Importante

Per la prima chiamata al metodo get di una funzione di accesso è necessario specificare un metodo factory per creare l'oggetto, se ancora non esiste nello stato. Se non viene specificato alcun metodo factory, si otterrà un'eccezione. I dettagli sull'uso di un metodo factory sono disponibili nell'articolo sugli stati.

Per rendere persistenti le modifiche apportate alla proprietà di stato ottenuta dalla funzione di accesso, è necessario aggiornare la proprietà nella cache di stato. Questa operazione può essere eseguita chiamando il metodo set della funzione di accesso, che imposta il valore della proprietà nella cache e lo rende disponibile se è necessario leggerlo o aggiornarlo più avanti nel turno. Per rendere tali dati effettivamente persistenti nell'archivio sottostante, e quindi renderli disponibili dopo il turno corrente, è necessario salvare lo stato.

Funzionamento dei metodi della funzione di accesso alla proprietà di stato

I metodi di accesso rappresentano il modo principale con cui il bot interagisce con lo stato. Il funzionamento di ognuno e l'interazione dei livelli sottostanti sono descritti di seguito:

  • Il metodo get della funzione di accesso:
    • La funzione di accesso richiede la proprietà dalla cache di stato.
    • Se la proprietà si trova nella cache, la restituisce. In caso contrario, la proprietà si ottiene dall'oggetto di gestione dello stato. Se non è ancora in stato, usare il metodo factory fornito nella chiamata get delle funzioni di accesso.
  • Il metodo set della funzione di accesso:
    • Aggiorna la cache di stato con il nuovo valore della proprietà.
  • Il metodo save changes dell'oggetto di gestione dello stato:
    • Verifica le modifiche alla proprietà nella cache di stato.
    • Scrive tale proprietà nella risorsa di archiviazione.

Stato nelle finestre di dialogo

La libreria dei dialoghi usa una funzione di accesso della proprietà dello stato del dialogo, definita sullo stato della conversazione del bot, per mantenere il posto di un dialogo nella conversazione. La proprietà dello stato del dialogo consente anche a ogni finestra di dialogo di archiviare informazioni temporanee tra turni.

Le finestre di dialogo adattive hanno una struttura di ambito di memoria più elaborata, che semplifica l'accesso ai risultati della configurazione e del riconoscimento, tra le altre cose. Gestione finestre di dialogo usa gli oggetti di gestione dello stato della conversazione e utente per fornire questi ambiti di memoria.

Per informazioni sulla libreria dei dialoghi, vedere l'articolo della raccolta dialoghi.

Salvataggio dello stato

Quando si chiama il metodo set della funzione di accesso per registrare lo stato aggiornato, la proprietà di stato non è ancora stata salvata nell'archiviazione permanente, ma solo nella cache di stato del bot. Per salvare nello stato permanente eventuali modifiche presenti nella cache di stato è necessario chiamare il metodo save changes dell'oggetto di gestione dello stato, disponibile nell'implementazione della classe di stato bot indicata in precedenza (ad esempio stato dell'utente o stato della conversazione).

La chiamata al metodo salva modifiche per un oggetto di gestione dello stato (ad esempio i bucket menzionati in precedenza) salva tutte le proprietà nella cache di stato configurate fino a quel punto per tale bucket, ma non per gli altri bucket che potrebbero essere presenti nello stato del bot.

Suggerimento

Lo stato del bot implementa un comportamento di precedenza dell'ultima scrittura, in base al quale l'ultima scrittura si sovrappone allo stato scritto in precedenza. Questo comportamento può essere adatto per molte applicazioni, ma ha implicazioni in particolare negli scenari di scalabilità orizzontale in cui può essere in gioco un certo livello di concorrenza o latenza.

Se è presente middleware personalizzato che potrebbe aggiornare lo stato dopo il completamento del gestore dei turni, prendere in considerazione la gestione dello stato nel middleware.

Risorse aggiuntive