Conversational Language Understanding (CLU), en funktion i Azure AI Language, är den uppdaterade versionen av LUIS.
Mer information om stöd för språktolkning i Bot Framework SDK finns i Förstå naturligt språk.
Möjligheten att förstå vad användaren menar konversationsmässigt och kontextuellt kan vara en svår uppgift, men kan ge roboten en mer naturlig konversationskänsla. Language Understanding (LUIS) är en molnbaserad API-tjänst som gör att du kan göra just detta så att roboten kan känna igen avsikten med användarmeddelanden, tillåta mer naturligt språk från användaren och bättre dirigera konversationsflödet.
Det här avsnittet beskriver hur du lägger till LUIS i ett flygbokningsprogram för att identifiera olika avsikter och entiteter som ingår i användarindata.
Kommentar
Bot Framework JavaScript-, C#- och Python-SDK:erna fortsätter att stödjas, men Java SDK dras tillbaka med slutligt långsiktigt stöd som slutar i november 2023.
Befintliga robotar som skapats med Java SDK fortsätter att fungera.
Det här exemplet på kärnroboten visar ett exempel på en flygbokningsapp på flygplatsen. Den använder en LUIS-tjänst för att identifiera användarindata och returnera den mest identifierade LUIS-avsikten.
Språkmodellen innehåller tre avsikter: Book Flight, Canceloch None. LUIS använder dessa avsikter för att förstå vad användaren menade när de skickar ett meddelande till roboten. Språkmodellen definierar också entiteter som LUIS kan extrahera från användarens indata, till exempel ursprunget eller målflygplatsen.
Efter varje bearbetning av användarindata DialogBot sparar du det aktuella tillståndet för både UserState och ConversationState. När all nödvändig information har samlats in skapar kodningsexemplet en bokningsreservation för demoflyg. I den här artikeln ska vi ta upp LUIS-aspekterna i det här exemplet. Det allmänna flödet i exemplet är dock:
OnMembersAddedAsync anropas när en ny användare är ansluten och visar ett välkomstkort.
OnMessageActivityAsync anropas för varje användarindata som tas emot.
Modulen OnMessageActivityAsync kör lämplig dialogruta via Run dialogtilläggsmetoden. Sedan anropar huvuddialogrutan LUIS-hjälpen för att hitta avsikten med den mest poänggivande användaren. Om den främsta avsikten för användarindata returnerar "BookFlight" fyller hjälpverktyget i information från användaren som LUIS returnerade. Därefter startar BookingDialoghuvuddialogrutan , som hämtar ytterligare information efter behov från användaren, till exempel:
Origin den ursprungliga staden
TravelDate datumet då flygresan skulle bokas
Destination målstaden
Efter varje bearbetning av användarindata dialogBot sparar du det aktuella tillståndet för både userState och conversationState. När all nödvändig information har samlats in skapar kodningsexemplet en bokningsreservation för demoflyg. I den här artikeln ska vi ta upp LUIS-aspekterna i det här exemplet. Det allmänna flödet i exemplet är dock:
onMembersAdded anropas när en ny användare är ansluten och visar ett välkomstkort.
OnMessage anropas för varje användarindata som tas emot.
Modulen onMessage kör mainDialog, som samlar in användarindata.
Sedan anropar huvuddialogrutan LUIS-hjälpen FlightBookingRecognizer för att hitta avsikten med den mest poänggivande användaren. Om den främsta avsikten för användarindata returnerar "BookFlight" fyller hjälpverktyget i information från användaren som LUIS returnerade.
När svaret är tillbaka mainDialog bevaras information för användaren som returneras av LUIS och startar bookingDialog. bookingDialog hämtar ytterligare information efter behov från användaren, till exempel
destination målstaden.
origin den ursprungliga staden.
travelDate datum då flygresan skulle bokas.
Efter varje bearbetning av användarindata DialogBot sparar du det aktuella tillståndet för både UserState och ConversationState.
När all nödvändig information har samlats in skapar kodningsexemplet en bokningsreservation för demoflyg.
I den här artikeln ska vi ta upp LUIS-aspekterna i det här exemplet. Det allmänna flödet i exemplet är dock:
onMembersAdded anropas när en ny användare är ansluten och visar ett välkomstkort.
onMessageActivity anropas för varje användarindata som tas emot.
Modulen onMessageActivity kör lämplig dialogruta via run dialogtilläggsmetoden. Sedan anropar huvuddialogrutan LUIS-hjälpen för att hitta avsikten med den mest poänggivande användaren. Om den främsta avsikten för användarindata returnerar "BookFlight" fyller hjälpverktyget i information från användaren som LUIS returnerade. Därefter startar BookingDialoghuvuddialogrutan , som hämtar ytterligare information efter behov från användaren, till exempel:
Origin den ursprungliga staden
TravelDate datumet då flygresan skulle bokas
Destination målstaden
Efter varje bearbetning av användarindata DialogBot sparar du det aktuella tillståndet för både user_state och conversation_state. När all nödvändig information har samlats in skapar kodningsexemplet en bokningsreservation för demoflyg. I den här artikeln ska vi ta upp LUIS-aspekterna i det här exemplet. Det allmänna flödet i exemplet är dock:
on_members_added_activity anropas när en ny användare är ansluten och visar ett välkomstkort.
on_message_activity anropas för varje användarindata som tas emot.
Modulen on_message_activity kör lämplig dialogruta via run_dialog dialogtilläggsmetoden. Sedan anropas LuisHelper huvuddialogrutan för att hitta avsikten med den mest poänggivande användaren. Om den främsta avsikten för användarindata returnerar "BookFlight" fyller hjälpfunktionen i information från användaren som LUIS returnerade. Därefter startar BookingDialoghuvuddialogrutan , som hämtar ytterligare information efter behov från användaren, till exempel:
På sidan Konversationsappar i LUIS väljer du Importera och sedan Importera som JSON.
I dialogrutan Importera ny app:
Välj filen FlightBooking.json i mappen CognitiveModels i exemplet.
Ange FlightBooking som valfritt namn på appen och välj Klar.
Webbplatsen kan visa Hur du skapar en effektiv LUIS-app och Uppgradera dina sammansatta entitetsdialogrutor . Du kan stänga dessa dialogrutor och fortsätta.
Träna appen och publicera sedan appen i produktionsmiljön .
Mer information finns i LUIS-dokumentationen om hur du tränar och publicerar en app.
Varför använda entiteter
LUIS-entiteter gör det möjligt för roboten att förstå händelser utöver standard avsikter. På så sätt kan du samla in ytterligare information från användarna, så att din robot kan ställa frågor och svara mer intelligent. Tillsammans med definitioner för de tre LUIS-avsikterna "Book Flight", "Cancel" och "None" innehåller filen FlightBooking.json också en uppsättning entiteter som "From.Airport" och "To.Airport". Dessa entiteter gör det möjligt för LUIS att identifiera och returnera ytterligare information som finns i användarens ursprungliga indata när de begär en ny resebokning.
Hämta värden för att ansluta till luis-appen
När luis-appen har publicerats kan du komma åt den från din robot. Du måste registrera flera värden för att få åtkomst till LUIS-appen inifrån roboten. Du kan hämta den informationen med hjälp av LUIS-portalen.
Hämta programinformation från LUIS.ai-portalen
Inställningsfilen (appsettings.json.enveller config.py) fungerar som platsen för att samla alla tjänstreferenser på ett och samma ställe. Informationen du hämtar läggs till i den här filen i nästa avsnitt.
Lägg till den information som krävs för att komma åt LUIS-appen, inklusive program-ID, redigeringsnyckel och region i appsettings.json filen. I föregående steg hämtade du dessa värden från din publicerade LUIS-app. API-värdnamnet ska vara i formatet <your region>.api.cognitive.microsoft.com.
Lägg till den information som krävs för att komma åt LUIS-appen, inklusive program-ID, redigeringsnyckel och region i .env filen. I föregående steg hämtade du dessa värden från din publicerade LUIS-app. API-värdnamnet ska vara i formatet <your region>.api.cognitive.microsoft.com.
Lägg till den information som krävs för att komma åt LUIS-appen, inklusive program-ID, redigeringsnyckel och region i application.properties filen. I föregående steg hämtade du dessa värden från din publicerade LUIS-app. API-värdnamnet ska vara i formatet <your region>.api.cognitive.microsoft.com.
Lägg till den information som krävs för att komma åt LUIS-appen, inklusive program-ID, redigeringsnyckel och region i config.py filen. I föregående steg hämtade du dessa värden från din publicerade LUIS-app. API-värdnamnet ska vara i formatet <your region>.api.cognitive.microsoft.com.
Kontrollera att NuGet-paketet Microsoft.Bot.Builder.AI.Luis är installerat för projektet.
För att ansluta till LUIS-tjänsten hämtar roboten den information som du lade till i appsetting.json-filen. Klassen FlightBookingRecognizer innehåller kod med dina inställningar från appsetting.json-filen och frågar LUIS-tjänsten genom att anropa RecognizeAsync metoden.
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 Innehåller logiken för att extrahera Från, Till och TravelDate. Den utökar den partiella klass FlightBooking.cs som används för att lagra LUIS-resultat vid anrop FlightBookingRecognizer.RecognizeAsync<FlightBooking> från 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];
}
För att använda LUIS måste projektet installera botbuilder-ai npm-paketet.
För att ansluta till LUIS-tjänsten använder roboten den information som du har lagt till i .env filen. Klassen flightBookingRecognizer.js innehåller den kod som importerar inställningarna från .env filen och frågar LUIS-tjänsten genom att anropa recognize() metoden.
dialogrutor/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;
}
}
Logiken för att extrahera Från, Till och TravelDate implementeras som hjälpmetoder i flightBookingRecognizer.js. Dessa metoder används efter anrop flightBookingRecognizer.executeLuisQuery() från mainDialog.js
Se till att com.microsoft.bot.bot-ai-luis-v3-paketet har lagts till i din pom.xml-fil.
För att ansluta till LUIS-tjänsten hämtar roboten den information som du lade till i filen application.properties. Klassen FlightBookingRecognizer innehåller kod med dina inställningar från filen application.properties och frågar LUIS-tjänsten genom att anropa recognize metoden.
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 Innehåller logiken för att extrahera Från, Till och TravelDate och anropas från MainDialog.java för att avkoda resultatet av Luis-frågeresultatet.
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;
}
Kontrollera att PyPI-paketet botbuilder-ai är installerat för projektet.
För att ansluta till LUIS-tjänsten använder roboten den information som du har lagt till i config.py filen. Klassen FlightBookingRecognizer innehåller den kod som importerar inställningarna från config.py filen och frågar LUIS-tjänsten genom att anropa recognize() metoden.
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)
Logiken för att extrahera från, till och travel_date implementeras som hjälpmetoder från LuisHelper klassen i luis_helper.py. Dessa metoder används efter anrop LuisHelper.execute_luis_query() från main_dialog.py
hjälp/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
LUIS har nu konfigurerats och anslutits för din robot.
I emulatorn skriver du ett meddelande som "resa till Paris" eller "åka från Paris till Berlin". Använd alla yttranden som finns i filen FlightBooking.json för att träna avsikten "Book flight".
Om den främsta avsikten som returneras från LUIS matchar "Boka flyg" kommer roboten att ställa fler frågor tills den har tillräckligt med information lagrad för att skapa en resebokning. Då returneras den här bokningsinformationen tillbaka till din användare.
Nu återställs logiken för kodroboten och du kan fortsätta att skapa fler bokningar.
Ytterligare information
Mer information om LUIS finns i LUIS-dokumentationen: