Aggiungere la comprensione del linguaggio naturale al bot
Articolo
SI APPLICA A: SDK v4
Nota
Language Understanding (LUIS) verrà ritirato il 1° ottobre 2025.
A partire dal 1° aprile 2023, non sarà possibile creare nuove risorse LUIS.
Una versione più recente di Language Understanding è ora disponibile come parte del linguaggio di intelligenza artificiale di Azure.
CLU (Conversational Language Understanding), una funzionalità del linguaggio di intelligenza artificiale di Azure, è la versione aggiornata di LUIS.
Per altre informazioni sul supporto per la comprensione del linguaggio in Bot Framework SDK, vedere Comprensione del linguaggio naturale.
La capacità di riconoscere ciò che l'utente intende a livello di conversazione e di contesto può essere un'attività difficile, ma può offrire al bot un'esperienza di conversazione più naturale. Language Understanding (LUIS) è un servizio API basato sul cloud che consente di creare una conversazione più naturale in modo tale che il bot riesca a riconoscere la finalità dei messaggi utente, rendendo più naturale il linguaggio per l'utente stesso, e indirizzi in modo migliore il flusso della conversazione.
Questo argomento descrive la procedura per aggiungere LUIS a un'applicazione di prenotazione di voli e riconoscere diverse finalità ed entità contenute nell'input utente.
Nota
Gli SDK JavaScript, C# e Python di Bot Framework continueranno a essere supportati, ma Java SDK verrà ritirato con il supporto finale a lungo termine che termina a novembre 2023.
I bot esistenti creati con Java SDK continueranno a funzionare.
Questo esempio di bot di base mostra un esempio di un'applicazione di prenotazione di voli. Usa un servizio LUIS per riconoscere l'input utente e restituire la principale finalità LUIS riconosciuta.
Il modello linguistico ha tre finalità: Book Flight, Cancele None. LUIS userà queste finalità per comprendere cosa intende l'utente quando invia un messaggio al bot. Il modello linguistico definisce anche le entità che LUIS può estrarre dall'input dell'utente, ad esempio l'origine o l'aeroporto di destinazione.
Dopo ogni elaborazione dell'input utente, DialogBot salva lo stato corrente di UserState e ConversationState. Dopo aver raccolto tutte le informazioni necessarie, l'esempio di codifica crea una prenotazione demo di prenotazione dei voli. In questo articolo verranno illustrati gli aspetti LUIS di questo esempio. Tuttavia, il flusso generale dell'esempio è:
Quando un nuovo utente si connette e visualizza una scheda di benvenuto, viene effettuata una chiamata a OnMembersAddedAsync.
Per ogni input utente ricevuto, viene effettuata una chiamata a OnMessageActivityAsync,
Il modulo OnMessageActivityAsync esegue il dialogo appropriato tramite il metodo di estensione del dialogo Run. Il dialogo principale chiama quindi l'helper LUIS per trovare la finalità dell'utente con il punteggio più alto. Se la finalità con il punteggio massimo per l'input dell'utente restituisce "BookFlight", l'helper compila le informazioni dell'utente restituite da LUIS. Successivamente, il dialogo principale avvia BookingDialog, che acquisisce eventuali informazioni aggiuntive necessarie all'utente, ad esempio:
Origin: la città di origine
TravelDate: la data per cui prenotare il volo
Destination: la città di destinazione
Dopo ogni elaborazione dell'input utente, dialogBot salva lo stato corrente di userState e conversationState. Dopo aver raccolto tutte le informazioni necessarie, l'esempio di codifica crea una prenotazione demo di prenotazione dei voli. In questo articolo verranno illustrati gli aspetti LUIS di questo esempio. Tuttavia, il flusso generale dell'esempio è:
Quando un nuovo utente si connette e visualizza una scheda di benvenuto, viene effettuata una chiamata a onMembersAdded.
Per ogni input utente ricevuto, viene effettuata una chiamata a OnMessage,
Il onMessage modulo esegue , che raccoglie l'input mainDialogdell'utente.
Il dialogo principale chiama quindi l'helper LUIS FlightBookingRecognizer per trovare la finalità dell'utente con il punteggio più alto. Se la finalità con il punteggio massimo per l'input dell'utente restituisce "BookFlight", l'helper compila le informazioni dell'utente restituite da LUIS.
Dopo aver ricevuto una risposta, mainDialog mantiene le informazioni per l'utente restituite da LUIS e avvia bookingDialog. bookingDialog acquisisce altre informazioni dell'utente, se necessario, ad esempio
destination: la città di destinazione.
origin: la città di origine.
travelDate: la data per cui prenotare il volo.
Dopo ogni elaborazione dell'input utente, DialogBot salva lo stato corrente di UserState e ConversationState.
Dopo aver raccolto tutte le informazioni necessarie, l'esempio di codifica crea una prenotazione demo di prenotazione dei voli.
In questo articolo verranno illustrati gli aspetti LUIS di questo esempio. Tuttavia, il flusso generale dell'esempio è:
Quando un nuovo utente si connette e visualizza una scheda di benvenuto, viene effettuata una chiamata a onMembersAdded.
Per ogni input utente ricevuto, viene effettuata una chiamata a onMessageActivity,
Il modulo onMessageActivity esegue il dialogo appropriato tramite il metodo di estensione del dialogo run. Il dialogo principale chiama quindi l'helper LUIS per trovare la finalità dell'utente con il punteggio più alto. Se la finalità con il punteggio massimo per l'input dell'utente restituisce "BookFlight", l'helper compila le informazioni dell'utente restituite da LUIS. Successivamente, il dialogo principale avvia BookingDialog, che acquisisce eventuali informazioni aggiuntive necessarie all'utente, ad esempio:
Origin: la città di origine
TravelDate: la data per cui prenotare il volo
Destination: la città di destinazione
Dopo ogni elaborazione dell'input utente, DialogBot salva lo stato corrente di user_state e conversation_state. Dopo aver raccolto tutte le informazioni necessarie, l'esempio di codifica crea una prenotazione demo di prenotazione dei voli. In questo articolo verranno illustrati gli aspetti LUIS di questo esempio. Tuttavia, il flusso generale dell'esempio è:
Quando un nuovo utente si connette e visualizza una scheda di benvenuto, viene effettuata una chiamata a on_members_added_activity.
Per ogni input utente ricevuto, viene effettuata una chiamata a on_message_activity,
Il modulo on_message_activity esegue il dialogo appropriato tramite il metodo di estensione del dialogo run_dialog. La finestra di dialogo principale chiama LuisHelper quindi per trovare la finalità dell'utente con punteggio superiore. Se la finalità con il punteggio più alto per l'input dell'utente restituisce "BookFlight", la funzione helper compila le informazioni dell'utente restituite da LUIS. Successivamente, il dialogo principale avvia BookingDialog, che acquisisce eventuali informazioni aggiuntive necessarie all'utente, ad esempio:
Nella pagina App di conversazione in LUIS selezionare Importa, quindi Importa come JSON.
Nella finestra di dialogo Importa nuova app :
Scegliere il file FlightBooking.json nella cartella CognitiveModels dell'esempio.
Immettere FlightBooking come nome facoltativo dell'app e selezionare Fine.
Il sito può visualizzare Come creare un'app LUIS efficace e Aggiornare le finestre di dialogo delle entità composite. È possibile ignorare questi dialoghi e continuare.
Eseguire il training dell'app, quindi pubblicare l'app nell'ambiente di produzione .
Per altre informazioni, vedere la documentazione di LUIS su come eseguire il training e pubblicare un'app.
Perché usare le entità
Le entità LUIS consentono al bot di comprendere gli eventi oltre le finalità standard. In questo modo è possibile raccogliere informazioni aggiuntive dagli utenti, in modo che il bot possa porre domande e rispondere in modo più intelligente. Insieme alle definizioni per le tre finalità LUIS 'Book Flight', 'Cancel' e 'None', il file FlightBooking.json contiene anche un set di entità come 'From.Airport' e 'To.Airport'. Queste entità consentono a LUIS di rilevare e restituire le informazioni aggiuntive contenute nell'input originale dell'utente quando ha richiesto una nuova prenotazione di viaggio.
Ottenere i valori per connettersi all'app LUIS
Dopo aver pubblicato l'app LUIS, è possibile accedere all'app dal proprio bot. È necessario registrare diversi valori per accedere all'app LUIS dall'interno del bot. È possibile recuperare tali informazioni usando il portale LUIS.
Recuperare le informazioni sull'applicazione dal portale LUIS.ai
Il file di impostazioni (appsettings.json, .env o config.py) riunisce tutti i riferimenti del servizio in un'unica posizione. Le informazioni recuperate verranno aggiunte a questo file nella sezione successiva.
Con l'app LUIS pubblicata aperta, selezionare la scheda MANAGE (Gestione).
Selezionare la scheda Impostazioni sul lato sinistro e registrare il valore visualizzato per ID applicazione come <YOUR_APP_ID>.
Selezionare Risorse di Azure e quindi Risorsa previsione. Registrare il valore visualizzato per Location come <YOUR_REGION> e Primary Key come <YOUR_AUTHORING_KEY>.
In alternativa, è possibile usare l'area e la chiave primaria per la risorsa di creazione.
Aggiungere le informazioni necessarie per accedere all'app LUIS, inclusi l'ID applicazione, la chiave di creazione e l'area nel appsettings.json file. Nel passaggio precedente questi valori sono stati recuperati dall'app LUIS pubblicata. Il nome host dell'API deve essere nel formato <your region>.api.cognitive.microsoft.com.
Aggiungere le informazioni necessarie per accedere all'app LUIS, inclusi l'ID applicazione, la chiave di creazione e l'area nel .env file. Nel passaggio precedente questi valori sono stati recuperati dall'app LUIS pubblicata. Il nome host dell'API deve essere nel formato <your region>.api.cognitive.microsoft.com.
Aggiungere le informazioni necessarie per accedere all'app LUIS, inclusi l'ID applicazione, la chiave di creazione e l'area nel application.properties file. Nel passaggio precedente questi valori sono stati recuperati dall'app LUIS pubblicata. Il nome host dell'API deve essere nel formato <your region>.api.cognitive.microsoft.com.
Aggiungere le informazioni necessarie per accedere all'app LUIS, inclusi l'ID applicazione, la chiave di creazione e l'area nel config.py file. Nel passaggio precedente questi valori sono stati recuperati dall'app LUIS pubblicata. Il nome host dell'API deve essere nel formato <your region>.api.cognitive.microsoft.com.
Assicurarsi che per il progetto sia installato il pacchetto NuGet Microsoft.Bot.Builder.AI.Luis.
Per connettersi al servizio LUIS, il bot esegue il pull delle informazioni aggiunte al file di appsetting.json. La classe FlightBookingRecognizer contiene il codice con le impostazioni dal file appsetting.json ed esegue una query sul servizio LUIS chiamando il metodo RecognizeAsync.
FlightBookingRecognizer.cs
public class FlightBookingRecognizer : IRecognizer
{
private readonly LuisRecognizer _recognizer;
public FlightBookingRecognizer(IConfiguration configuration)
{
var luisIsConfigured = !string.IsNullOrEmpty(configuration["LuisAppId"]) && !string.IsNullOrEmpty(configuration["LuisAPIKey"]) && !string.IsNullOrEmpty(configuration["LuisAPIHostName"]);
if (luisIsConfigured)
{
var luisApplication = new LuisApplication(
configuration["LuisAppId"],
configuration["LuisAPIKey"],
"https://" + configuration["LuisAPIHostName"]);
// Set the recognizer options depending on which endpoint version you want to use.
// More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
var recognizerOptions = new LuisRecognizerOptionsV3(luisApplication)
{
PredictionOptions = new Bot.Builder.AI.LuisV3.LuisPredictionOptions
{
IncludeInstanceData = true,
}
};
_recognizer = new LuisRecognizer(recognizerOptions);
}
}
// Returns true if luis is configured in the appsettings.json and initialized.
public virtual bool IsConfigured => _recognizer != null;
public virtual async Task<RecognizerResult> RecognizeAsync(ITurnContext turnContext, CancellationToken cancellationToken)
=> await _recognizer.RecognizeAsync(turnContext, cancellationToken);
public virtual async Task<T> RecognizeAsync<T>(ITurnContext turnContext, CancellationToken cancellationToken)
where T : IRecognizerConvert, new()
=> await _recognizer.RecognizeAsync<T>(turnContext, cancellationToken);
}
FlightBookingEx.cs contiene la logica per estrarre From, To e TravelDate, estende la classe parziale FlightBooking.cs usata per archiviare i risultati di LUIS quando si chiama FlightBookingRecognizer.RecognizeAsync<FlightBooking> da MainDialog.cs.
CognitiveModels\FlightBookingEx.cs
// Extends the partial FlightBooking class with methods and properties that simplify accessing entities in the luis results
public partial class FlightBooking
{
public (string From, string Airport) FromEntities
{
get
{
var fromValue = Entities?._instance?.From?.FirstOrDefault()?.Text;
var fromAirportValue = Entities?.From?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault();
return (fromValue, fromAirportValue);
}
}
public (string To, string Airport) ToEntities
{
get
{
var toValue = Entities?._instance?.To?.FirstOrDefault()?.Text;
var toAirportValue = Entities?.To?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault();
return (toValue, toAirportValue);
}
}
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
public string TravelDate
=> Entities.datetime?.FirstOrDefault()?.Expressions.FirstOrDefault()?.Split('T')[0];
}
Per usare LUIS, è necessario installare il pacchetto npm botbuilder-ai per il progetto.
Per connettersi al servizio LUIS, il bot usa le informazioni aggiunte al .env file. La classe flightBookingRecognizer.js contiene il codice che importa le impostazioni dal file .env ed esegue una query sul servizio LUIS chiamando il metodo recognize().
dialogs/flightBookingRecognizer.js
class FlightBookingRecognizer {
constructor(config) {
const luisIsConfigured = config && config.applicationId && config.endpointKey && config.endpoint;
if (luisIsConfigured) {
// Set the recognizer options depending on which endpoint version you want to use e.g v2 or v3.
// More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
const recognizerOptions = {
apiVersion: 'v3'
};
this.recognizer = new LuisRecognizer(config, recognizerOptions);
}
}
get isConfigured() {
return (this.recognizer !== undefined);
}
/**
* Returns an object with preformatted LUIS results for the bot's dialogs to consume.
* @param {TurnContext} context
*/
async executeLuisQuery(context) {
return await this.recognizer.recognize(context);
}
getFromEntities(result) {
let fromValue, fromAirportValue;
if (result.entities.$instance.From) {
fromValue = result.entities.$instance.From[0].text;
}
if (fromValue && result.entities.From[0].Airport) {
fromAirportValue = result.entities.From[0].Airport[0][0];
}
return { from: fromValue, airport: fromAirportValue };
}
getToEntities(result) {
let toValue, toAirportValue;
if (result.entities.$instance.To) {
toValue = result.entities.$instance.To[0].text;
}
if (toValue && result.entities.To[0].Airport) {
toAirportValue = result.entities.To[0].Airport[0][0];
}
return { to: toValue, airport: toAirportValue };
}
/**
* This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
* TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
*/
getTravelDate(result) {
const datetimeEntity = result.entities.datetime;
if (!datetimeEntity || !datetimeEntity[0]) return undefined;
const timex = datetimeEntity[0].timex;
if (!timex || !timex[0]) return undefined;
const datetime = timex[0].split('T')[0];
return datetime;
}
}
La logica per estrarre From, To e TravelDate viene implementata come metodi helper all'interno di flightBookingRecognizer.js. Questi metodi vengono usati dopo la chiamata a flightBookingRecognizer.executeLuisQuery() da mainDialog.js
Assicurarsi che il pacchetto com.microsoft.bot.bot-ai-luis-v3 venga aggiunto al file pom.xml.
Per connettersi al servizio LUIS, il bot esegue il pull delle informazioni aggiunte al file application.properties. La FlightBookingRecognizer classe contiene codice con le impostazioni del file application.properties ed esegue una query sul servizio LUIS chiamando recognize il metodo .
FlightBookingRecognizer.java
/**
* The constructor of the FlightBookingRecognizer class.
*
* @param configuration The Configuration object to use.
*/
public FlightBookingRecognizer(Configuration configuration) {
Boolean luisIsConfigured = StringUtils.isNotBlank(configuration.getProperty("LuisAppId"))
&& StringUtils.isNotBlank(configuration.getProperty("LuisAPIKey"))
&& StringUtils.isNotBlank(configuration.getProperty("LuisAPIHostName"));
if (luisIsConfigured) {
LuisApplication luisApplication = new LuisApplication(
configuration.getProperty("LuisAppId"),
configuration.getProperty("LuisAPIKey"),
String.format("https://%s", configuration.getProperty("LuisAPIHostName"))
);
// Set the recognizer options depending on which endpoint version you want to use.
// More details can be found in
// https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
LuisRecognizerOptionsV3 recognizerOptions = new LuisRecognizerOptionsV3(luisApplication);
recognizerOptions.setIncludeInstanceData(true);
this.recognizer = new LuisRecognizer(recognizerOptions);
}
}
/**
* Runs an utterance through a recognizer and returns a generic recognizer result.
*
* @param turnContext Turn context.
* @return Analysis of utterance.
*/
@Override
public CompletableFuture<RecognizerResult> recognize(TurnContext turnContext) {
return this.recognizer.recognize(turnContext);
}
FlightBookingRecognizer.cs Contiene la logica da cui estrarre From, To e TravelDate e viene chiamato da MainDialog.java per decodificare i risultati del risultato della query Luis.
FlightBookingRecognizer.java
/**
* Gets the From data from the entities which is part of the result.
*
* @param result The recognizer result.
* @return The object node representing the From data.
*/
public ObjectNode getFromEntities(RecognizerResult result) {
String fromValue = "", fromAirportValue = "";
if (result.getEntities().get("$instance").get("From") != null) {
fromValue = result.getEntities().get("$instance").get("From").get(0).get("text")
.asText();
}
if (!fromValue.isEmpty()
&& result.getEntities().get("From").get(0).get("Airport") != null) {
fromAirportValue = result.getEntities().get("From").get(0).get("Airport").get(0).get(0)
.asText();
}
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
ObjectNode entitiesNode = mapper.createObjectNode();
entitiesNode.put("from", fromValue);
entitiesNode.put("airport", fromAirportValue);
return entitiesNode;
}
/**
* Gets the To data from the entities which is part of the result.
*
* @param result The recognizer result.
* @return The object node representing the To data.
*/
public ObjectNode getToEntities(RecognizerResult result) {
String toValue = "", toAirportValue = "";
if (result.getEntities().get("$instance").get("To") != null) {
toValue = result.getEntities().get("$instance").get("To").get(0).get("text").asText();
}
if (!toValue.isEmpty() && result.getEntities().get("To").get(0).get("Airport") != null) {
toAirportValue = result.getEntities().get("To").get(0).get("Airport").get(0).get(0)
.asText();
}
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
ObjectNode entitiesNode = mapper.createObjectNode();
entitiesNode.put("to", toValue);
entitiesNode.put("airport", toAirportValue);
return entitiesNode;
}
/**
* This value will be a TIMEX. And we are only interested in a Date so grab the first result and
* drop the Time part. TIMEX is a format that represents DateTime expressions that include some
* ambiguity. e.g. missing a Year.
*
* @param result A {link RecognizerResult}
* @return The Timex value without the Time model
*/
public String getTravelDate(RecognizerResult result) {
JsonNode datetimeEntity = result.getEntities().get("datetime");
if (datetimeEntity == null || datetimeEntity.get(0) == null) {
return null;
}
JsonNode timex = datetimeEntity.get(0).get("timex");
if (timex == null || timex.get(0) == null) {
return null;
}
String datetime = timex.get(0).asText().split("T")[0];
return datetime;
}
Assicurarsi che per il progetto sia installato il pacchetto PyPI botbuilder-ai.
Per connettersi al servizio LUIS, il bot usa le informazioni aggiunte al config.py file. La classe FlightBookingRecognizer contiene il codice che importa le impostazioni dal file config.py ed esegue una query sul servizio LUIS chiamando il metodo recognize().
flight_booking_recognizer.py
class FlightBookingRecognizer(Recognizer):
def __init__(self, configuration: DefaultConfig):
self._recognizer = None
luis_is_configured = (
configuration.LUIS_APP_ID
and configuration.LUIS_API_KEY
and configuration.LUIS_API_HOST_NAME
)
if luis_is_configured:
# Set the recognizer options depending on which endpoint version you want to use e.g v2 or v3.
# More details can be found in https://docs.microsoft.com/azure/cognitive-services/luis/luis-migration-api-v3
luis_application = LuisApplication(
configuration.LUIS_APP_ID,
configuration.LUIS_API_KEY,
"https://" + configuration.LUIS_API_HOST_NAME,
)
self._recognizer = LuisRecognizer(luis_application)
@property
def is_configured(self) -> bool:
# Returns true if luis is configured in the config.py and initialized.
return self._recognizer is not None
async def recognize(self, turn_context: TurnContext) -> RecognizerResult:
return await self._recognizer.recognize(turn_context)
La logica per estrarre i valori di From, To e travel_date viene implementata come metodi helper della classe LuisHelper all'interno di luis_helper.py. Questi metodi vengono usati dopo la chiamata a LuisHelper.execute_luis_query() da main_dialog.py
helpers/luis_helper.py
class LuisHelper:
@staticmethod
async def execute_luis_query(
luis_recognizer: LuisRecognizer, turn_context: TurnContext
) -> (Intent, object):
"""
Returns an object with preformatted LUIS results for the bot's dialogs to consume.
"""
result = None
intent = None
try:
recognizer_result = await luis_recognizer.recognize(turn_context)
intent = (
sorted(
recognizer_result.intents,
key=recognizer_result.intents.get,
reverse=True,
)[:1][0]
if recognizer_result.intents
else None
)
if intent == Intent.BOOK_FLIGHT.value:
result = BookingDetails()
# We need to get the result from the LUIS JSON which at every level returns an array.
to_entities = recognizer_result.entities.get("$instance", {}).get(
"To", []
)
if len(to_entities) > 0:
if recognizer_result.entities.get("To", [{"$instance": {}}])[0][
"$instance"
]:
result.destination = to_entities[0]["text"].capitalize()
else:
result.unsupported_airports.append(
to_entities[0]["text"].capitalize()
)
from_entities = recognizer_result.entities.get("$instance", {}).get(
"From", []
)
if len(from_entities) > 0:
if recognizer_result.entities.get("From", [{"$instance": {}}])[0][
"$instance"
]:
result.origin = from_entities[0]["text"].capitalize()
else:
result.unsupported_airports.append(
from_entities[0]["text"].capitalize()
)
# This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop
# the Time part. TIMEX is a format that represents DateTime expressions that include some ambiguity.
# e.g. missing a Year.
date_entities = recognizer_result.entities.get("datetime", [])
if date_entities:
timex = date_entities[0]["timex"]
if timex:
datetime = timex[0].split("T")[0]
result.travel_date = datetime
else:
result.travel_date = None
except Exception as exception:
print(exception)
return intent, result
Eseguire l'esempio in locale nel computer. Se sono necessarie istruzioni, vedere il file per l'esempio README C#, l'esempio JS o l'esempio Python.
Nell'emulatore digitare un messaggio come "travel to paris" o "going from paris to berlin". Usare qualsiasi espressione disponibile nel file FlightBooking.json per eseguire il training della finalità "Book flight".
Se la finalità principale restituita da LUIS viene risolta in "Prenota volo", il bot chiederà altre domande fino a quando non dispone di informazioni sufficienti archiviate per creare una prenotazione di viaggio. A quel punto, restituirà le informazioni su questa prenotazione all'utente.
A questo punto, la logica del bot del codice verrà reimpostata e sarà possibile continuare a creare altre prenotazioni.
Informazioni aggiuntive
Per altre informazioni su LUIS, vedere la documentazione di LUIS: