How-to: So entwickelt man einen Skill für Amazons Alexa

Alexa Skill: Die ersten Schritte
Kommentare

Mit Echo und Echo Dot hat Amazon ein Tor zu einer vielversprechenden Technologie fürs Wohnzimmer geöffnet. Andere Firmen wie Google und Apple befinden sich mit ihren Produkten in den Startlöchern. Diese neuen Bereicherungen fürs Wohnzimmer fallen unter die Kategorie der Sprachassistenten und werden uns in Zukunft viele interessante Neuerungen bringen. Wir wollen im Folgendem einen Überblick bieten, wie man einen Skill für den Sprachassistenten von Amazon entwickelt.

Amazons Sprachassistentin Alexa mit Amazon Echo oder Amazon Echo Dot den Weg in unsere Wohnzimmer gefunden, und mit einem Alexa Skill kann man ihr noch mehr Tricks fürs Smarthome beibringen. Anders als bei sogenannten „Deep-Learning-Systemen“ haben Sprachassistenten wie Alexa oder Siri ein gutes Sprachverständnis, weil ihr Wortverständnis durch Anwendungen (Skills) eingegrenzt wird; es gibt keine grammatikalische oder kontextabhängige Analyse. Alexa ist zwar fähig über geringfügige Änderungen in den ihr bekannten Satzgefügen hinwegzusehen, jedoch nicht, Sätze aus ihrem Kontext heraus zu verstehen. Wie Alexas Sprachverständnis funktioniert, betrachten wir anhand eines einfachen Würfel-Skills – und entwickeln damit unseren ersten Alexa Skill. Das Beispielprojekt könnt ihr hier herunterladen.


Der Würfel-Skill ist einer der eher simpel gehaltenen Skills. Im Laufe dieses Artikels werden einige Schwachstellen der Sprachassistentin Alexa aufgedeckt – im Artikel Alexa Best Practices beschäftigen wir uns mit deutlich fortgeschritteneren Konzepten in der Skill-Entwicklung.
Übrigens: Das Beispielprojekt zum Artikel könnt ihr hier herunterladen.

Voraussetzung

Um einen Alexa Skill fürs Smarthome entwickeln zu können, bedarf es eines kostenlosen Amazon Developer Accounts. Der entsprechende Developer Account gibt Zugriff auf die sogenannte „Developer Console“, dem Herzstück jeglicher Entwicklung für Amazon-Produkte. Alexa hat hier ihren eigenen Bereich, unter der die Alexa-Skill-Entwicklung gestartet wird.

Alexa Skill

Der Entwickler hat hier die Möglichkeit auszuwählen, ob er mit dem „Alexa Skills Kit“ einen Skill entwickeln möchte oder mit dem „Alexa Voice Service“ (AVS) einem anderen Device Alexas Fähigkeiten verleiht. Für den AVS gibt es bereits fertige Beispielprojekte für z.B. den Raspberry Pi. Zu erwähnen ist allerdings, dass der AVS erst Anfang 2017 auf dem deutschen Markt nutzbar sein wird.

Die Fähigkeiten, die man Alexa verleiht, werden also als Skills bezeichnet. Entsprechend gibt es auch einen „Alexa Skill Store“.

Einen Alexa Skill erstellen

Das Erstellen eines Alexa Skill funktioniert in mehreren Schritten (Abb. 1). Im ersten Schritt werden per Webinterface allgemeine Informationen zum Skill angegeben. Der „Skill Type“ ist in unserem Falle „Custom Interaction Model“ – das ist die klassische Konfiguration von Alexa als Client, die auf Backendfunktionalität zugreift, um ihre Antwort mit den gewünschten Informationen anzureichern. Das „Smart Home Skill API“ bietet die Möglichkeit, für IOT Sprachinterfaces zu entwickeln, wie es sie auch z.B. unter Apples HomeKit gibt. Mit dem „Flash Briefing Skill API“ lassen sich mit wenig Aufwand z.B. RSS-Inhalte in Form von News verfügbar machen.

Die Sprache soll in unserem Fall Deutsch sein. „Name“ gibt an, unter welchem Namen der Skill in „Alexa Skill Store“ zu finden ist. Der „Invocation Name“ ist nun der Name, mit dem der der Nutzer den Skill auf dem Gerät aktiviert. Wenn wir unseren „Invocation Name“ also mit Würfel angeben, würde er mit „Alexa, öffne Würfel“ aktiviert werden können. Unter Global Fields kann noch angeben werden, ob sogenannte Intents für eine Audio-Player-Steuerung berücksichtigt werden sollen.

Das Erstellen eines Alexa Skill

Abb. 1: Das Erstellen eines Alexa Skills

Das Model

Im nächsten Schritt definieren wir das Schema für unseren Alexa Skill. Hier wird angegeben, was für Satztypen bzw. Intentionen es im Skill gibt und welche variablen Teile diese haben können. Variable Teile, sogenannte Slots, sind die Bereiche im Satz, mit denen der Nutzer etwas spezifiziert.

Grundsätzlich unterscheidet man bei der Kommunikation mit Alexa zwischen sogenannten „One-Shot-Models“ und „Dialog-Models“. Bei einem One-Shot-Model wird der Alexa Skill und seine Funktion in einem Schritt aktiviert. Bei einem Dialog-Model wird erst der Skill geöffnet und dann Funktionen ausgeführt; der Skill bleibt im letzteren Fall geöffnet, bis er explizit geschlossen wird. Ist der Skill im Dialog-Model geöffnet, ist es auch nicht mehr nötig, den Prefix „Alexa“ zu benutzen. Da wir uns innerhalb unseres Skills einen Status merken möchten, entscheiden wir uns also für ein Dialog-Model.

Wir möchten folgendes Schema realisieren:

Nutzer: „alexa, öffne würfel“
Alexa: „willkommen bei würfel“
Nutzer: „alexa, nutze einen acht seitigen würfel“
Alexa: „ich benutze jetzt einen acht seitigen würfel“
Nutzer: „würfel für mich“
Alexa: „ich habe eine 13 gewürfelt.“
Nutzer: „beenden“
Alexa: „auf wiedersehen“

Das Dialog-Schema

In Listing 1 sehen wir wie das Schema eines Dialogs aussehen kann. Schemata werden dem Skill in Form eines JSON übergeben. Das JSON besteht aus einer Array mit Intents, jeder Intent hat dabei einen Identifier und kann sogenannte Slots haben.

{
  "intents": [
    {
      "intent": "chooseDice",
      "slots": [
        {
          "name": "sides",
          "type": "AMAZON.NUMBER"
        }
      ]
    },
    {
      "intent": "rollDice"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    }
  ]
}

Das Intent mit der ID „chooseDice“ hat den Slot sides, rollDice hat keinen Slot. Es gibt auch vordefinierte Default-Intents, die genutzt werden können, um beispielsweise Alexa nach Hilfe zu Fragen oder den Alexa Skill zu beenden.

Anlegen des Intents

Im Bereich „Sample Utterances“ in Abbildung 2 gibt man anschließend alle Satzvariationen an, die Alexa verstehen können soll. Dabei bekommen die Sätze als Prefix den Identifier des jeweiligen Intents:

chooseDice nehme einen {sides} seitigen würfel.
chooseDice nehme einen würfel mit {sides} seiten.
chooseDice wähle einen würfel mit {sides} seiten. 

rollDice würfel für mich

Es werden alle Satzvariationen mit der jeweiligen Positionierung der Slots angegeben. Je mehr Variationen, um so flexibler wird Alexa auch in ihrem Sprachverständnis – so zumindest in der Theorie.

Die Pflege der Sprach-Samples

Abb. 2: Die Pflege der Satzvariationen

Mit Custom Slot Types können eigene Datentypen definieret werden. So könnte beispielsweise der Type „Farbe“ definiert werden, um alle möglichen Farben benennbar zu machen.

Entwicklung des Hosts

Sind Schema und Phrasen definiert, geht es weiter mit der Host-Programmierung. Amazon stellt für die Kommunikation mit Alexa für Java und Node.JS Frameworks zur Verfügung. Nutzt man andere Sprachen, muss das JSON-Request von Alexa ausgewertet und ein entsprechendes JSON-Response generiert werden, darauf wird an dieser Stelle aber nicht weiter eingegangen. Es ist jedoch prinzipiell möglich, jede beliebige Sprache für die Alexa-Backendentwicklung zu nutzen.

Alexa arbeitet grundsätzlich nur SSL-verschlüsselt. Möchte man also ein eigenes Backend hosten, ist ein Trusted-Zertifikat notwendig. Einzelheiten sind ausführlich in den Amazon-Dokumentationen zu finden.

Die bekanntesten deutschen Skills

Natürlich bietet Amazon bereits zahlreiche Skills für seine Sprachassistentin. Im Bereich der Reiseauskunft ist da natürlich der Skill der Deutschen Bahn zu erwähnen, der Auskunft über Abfahrtszeiten und Zugverbindungen gibt. Mit dem Skill von MyTaxi ist es möglich, sich mit einem simplen „Alexa, rufe mir ein Taxi“ ein MyTaxi an die Haustür zu ordern.
Zur sprachgesteuerten Bedienung im Smarthome gibt es Skills für die intelligente Heizungssteuerung tado, ebenso wie für Hue, ein WLAN-gesteuertes Beleuchtungssystem von Philips. Wer seine HomeMatic Devices mit Alexa steuern möchte, muss indes einiges an (Entwickler-)Arbeit investieren.
Erfreulich ist hingegen, dass man zum Radiohören gar keinen Skill benötigt: Das integrierte TuneIn findet zahllose Sender – egal ob Internetradio oder reguläre Sender.

Alexa mag AWS Lambda

Um unser Beispiel mit dem Alexa Skill möglichst einfach umsetzen zu können, nutzen wir als Hosting-Plattform AWS Lambda und als Entwicklungssprache Java. Lambda als Service im Amazon-Habitat arbeitet problemlos mit Alexa zusammen und spart einiges an Aufwand. So müssen wir uns nicht um SSL-Zertifikate oder die Administration von Servlet-Containern kümmern.

Als Grundlage für ein Projekt empfehlen wir, die Java-Beispiele von Amazon für AWS Lambda zu benutzen.

Das AlexaSkillsKit-Framework für Java

Generell wird das Request/Respond-Handling bei diesem Projekt zum Testen über einen embedded Jetty realisiert. Dem Jetty wird ein SpeechletServlet übergeben, welches wiederum ein Speechlet übergeben bekommt. Man kann also problemlos auch Unit Tests entwickeln; Lambda klinkt sich in den RequestStreamHandler des jeweiligen Projekts ein.

Kern des Backends für unseren Alexa Skill ist immer eine Klasse, die Speechlet implementiert. Speechlet ist ein Interface, das vier Callback-Methoden zur Verfügung stellt, die überschrieben werden müssen:

  • void onSessionStarted(SessionStartedRequest request, Session session) throws SpeechletException
    Wird aufgerufen, wenn unser Alexa Skill auf dem Echo aktiviert wird. In dieser Methode können Session-spezifische Dinge initialisiert und zurück in die Session geschrieben werden.
  • SpeechletResponse onLaunch(LaunchRequest request, Session session) throws SpeechletException
    Wird nach onSessionStarted aufgerufen und gibt die Möglichkeit für ein erstes Feedback von Alexa. Hier werden im Allgemeinen die Begrüßungstexte des Skills zurückgegeben.
  • SpeechletResponse onIntent(IntentRequest request, Session session) throws SpeechletException
    Ist der Callback, der die Interaktion mit dem Benutzer realisiert. Hier werden Intents und deren Slots übergeben und eine entsprechende Reaktion an Alexa zurückgegeben.
  • void onSessionEnded(SessionEndedRequest request, Session session) throws SpeechletException
    Wird bei der Beendigung einer Session aufgerufen. Hier ist die sinnvollste Stelle, um z.B. Userdaten zu persistieren, die länger als eine Session Gültigkeit haben sollen, wie beispielsweise Postleitzahlen, Favoriten oder ähnliches.

In Listing 3 sehen wir DiceSpeechlet als Implementierung des Speechlet-Interface, sowie die vier entsprechend überschriebenen Methoden. Interessant ist vor allem die onIntent-Callback-Funktion, da wir hier unsere Interaktionen implementiert haben. onIntent hat die beiden Übergabeparameter request und session von den Typen IntentRequest und Session.

IntentRequest beinhaltet neben einer Request ID auch das für uns wichtige Intent, welches wiederum einen Bezeichner und ggf. den gewählten Slot beinhaltet.

Wenn der Nutzer „alexa, nutze einen 20-seitigen Würfel“ sagt, wird also die onIntent-Callback-Funktion aufgerufen. Das Intent-Objekt, das wir aus dem Request bekommen, hat den Bezeichner „chooseDice“ und beinhaltet den Slot „sides“ mit dem Wert 20.

Über den Intent-Namen können wir nun gezielt reagieren und entsprechende Funktionen zur Würfelwahl usw. ausführen.

import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazon.speech.slu.Intent;
import com.amazon.speech.speechlet.IntentRequest;
import com.amazon.speech.speechlet.LaunchRequest;
import com.amazon.speech.speechlet.Session;
import com.amazon.speech.speechlet.SessionEndedRequest;
import com.amazon.speech.speechlet.SessionStartedRequest;
import com.amazon.speech.speechlet.Speechlet;
import com.amazon.speech.speechlet.SpeechletException;
import com.amazon.speech.speechlet.SpeechletResponse;
import com.amazon.speech.ui.PlainTextOutputSpeech;
import com.amazon.speech.ui.Reprompt;

public class DiceSpeechlet implements Speechlet {
  private static final Logger log = LoggerFactory.getLogger(DiceSpeechlet.class);
  private static final String SESSION_NUMBEROFSIDES = "diceNumberOfSides";
  private static final String INTENT_CHOOSE = "chooseDice";
  private static final String INTENT_ROLEDICE = "rollDice";
  private static final String SLOT_NUMBEROFSIDES = "sides";

  @Override
  public void onSessionStarted(final SessionStartedRequest request, final Session session) throws SpeechletException {
    log.info("onSessionStarted requestId={}, sessionId={}", request.getRequestId(), session.getSessionId());
    // Initial wird mit einem 6-seitigen Würfel gestartet
    session.setAttribute(SESSION_NUMBEROFSIDES, new Integer(6));
  }

  @Override
  public SpeechletResponse onLaunch(final LaunchRequest request, final Session session) throws SpeechletException {
    log.info("onLaunch requestId={}, sessionId={}", request.getRequestId(), session.getSessionId());
    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
    speech.setText("Willkommen bei Würfel.");
    return SpeechletResponse.newAskResponse(speech, createRepromptSpeech());
  }

  @Override
  public SpeechletResponse onIntent(final IntentRequest request, final Session session) throws SpeechletException {
    log.info("onIntent requestId={}, sessionId={}", request.getRequestId(), session.getSessionId());
    System.out.println("Session:"+session+ " Intent:"+request.getIntent().getName());
    String intentName = request.getIntent().getName();
    if (INTENT_CHOOSE.equals(intentName)) {
      return handleChooseDice(request.getIntent(), session);
    } else if (INTENT_ROLEDICE.equals(intentName)) {
      return handleRollDice(session);
    } else if ("AMAZON.HelpIntent".equals(intentName)) {
      return handleHelpIntent();
    } else if ("AMAZON.StopIntent".equals(intentName)) {
      return handleStopIntent();
    } else {
      throw new SpeechletException("Invalid Intent");
    }
  }

  @Override
  public void onSessionEnded(final SessionEndedRequest request, final Session session) throws SpeechletException {
    log.info("onSessionEnded requestId={}, sessionId={}", request.getRequestId(), session.getSessionId());
  }

  private SpeechletResponse handleRollDice(Session session) {
    int maxValue = (Integer) session.getAttribute(SESSION_NUMBEROFSIDES);
    int randomValue = new Random().nextInt(maxValue) + 1;
    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
    speech.setText("ich habe eine " + String.valueOf(randomValue) + " gewürfelt.");
    return SpeechletResponse.newAskResponse(speech, createRepromptSpeech());
  }

  private SpeechletResponse handleStopIntent() {
    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
    speech.setText("auf wiedersehen.");
    return SpeechletResponse.newTellResponse(speech);
  }

  private SpeechletResponse handleHelpIntent() {
    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
    speech.setText("bestimme wieviel seiten dein würfel hat oder würfle");
    return SpeechletResponse.newTellResponse(speech);
  }

  private SpeechletResponse handleChooseDice(Intent intent, Session session) {
    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
    if (intent.getSlot(SLOT_NUMBEROFSIDES).getValue() == null) {
      speech.setText("ich habe nicht verstanden wieviele seiten der würfel haben soll.");
    } else {
      Integer numberOfSides = Integer.valueOf(intent.getSlot(SLOT_NUMBEROFSIDES).getValue().toString());
      session.setAttribute(SESSION_NUMBEROFSIDES, numberOfSides);
      speech.setText("ich benutze jetzt einen " + numberOfSides.toString() + " seitigen würfel");
    }
    return SpeechletResponse.newAskResponse(speech, createRepromptSpeech());
  }

  private Reprompt createRepromptSpeech() {
    PlainTextOutputSpeech repromptSpeech = new PlainTextOutputSpeech();
    repromptSpeech.setText("ich habe dich nicht verstanden");
    Reprompt reprompt = new Reprompt();
    reprompt.setOutputSpeech(repromptSpeech);
    return reprompt;
  }
}

Die Session

Wurde ein Würfel gewählt, soll dieser bis zum Session-Ende oder der Wahl eines anderen Würfels aktiv bleiben. Das wird realisiert, indem wir die Anzahl der Seiten einfach in die Session schreiben. Dafür hat die Session eine Map, auf die über setAttribute und getAttribute zugegriffen werden kann. Der Inhalt der Map bleibt bis zum Ende der Session erhalten, da die Session immer wieder zwischen Alexa zum Backend weitergereicht wird.

Dies passiert allerdings nur, wenn unser SpeechletResponse mit newAskResponse zurückgegeben wird. newAksResponse sorgt dafür, dass die Session nicht beendet wird und Alexa aktiv auf Antwort wartet. Im Service-Response-JSON zeigt sich das dadurch, dass die Property shouldEndSession auf „false“ gesetzt wird.

Sollen größere Daten persistiert werden, sollte man das daher lokal tun und die Session-ID für die Zuordnung nutzen.

Audio-Feedback im Alexa Skill

Nachdem in die Session geschrieben wurde, wie viele Seiten der Würfel haben soll, soll Alexa dem Nutzer ein entsprechendes Audiofeedback geben.

Grundsätzlich gibt es zwei Möglichkeiten, Alexa Texte sprechen zu lassen. Die einfachste Methode ist, sie sogenannten Plaintext sprechen zu lassen. Das bedeutet, dass Alexa den vorgegebenen Text so liest, wie er übergeben wurde; ohne auf Besonderheiten zu achten. Eine andere Möglichkeit ist es, den zu sprechenden Text gezielt mit der Speech Synthesis Markup Language zu modellieren.

Haben wir z.B. eine Telefonnummer +49 40 6452312, würde Alexa die hinteren Ziffern als Zahl zusammenfassen: „Sechsmillionenvierhundertzweiundfünfzigtausendreihundertundzwöf“. Über solch eine Angabe würde man sich bestenfalls wundern, im schlechtesten Fall aber ärgern. Daher gibt es in der SSML Tags, die definieren, wie etwas (aus)gesprochen werden soll.

Möchten wir eine Telefonnummer als einzelne Ziffern gesprochen haben, würden wir die Ausgabe wie folgt modellieren:

<say-as interpret-as="telephone">+49 40 6452312</say-as>

Die SSML bietet viele Möglichkeiten, die Aussprache von Zahlen, Daten und Texten zu modellieren, aber auch ganz gezielt Texte in Lautschrift zu schreiben.

SpeechletResponse

Die Rückgabewerte der Callback-Funktionen onSessionStarted und onIntent sind vom Typ SpeechletResponse. In der SpeechletResponse kann festgelegt werden ob es sich um einen einfachen „tell“ handelt oder um einen „ask“. Der Unterschied ist, dass bei „tell“ die Session beendet wird und damit auch die Werte der Session verloren gehen. Nutzen wir „ask“, muss zusätzlich eine Phase übergeben werden, die Alexa spricht, sobald sie eine Antwort nicht versteht.

SpeechletResponse bietet neben der Rückgabe von Sprachausgaben auch sogenannte „Cards“. Cards sind visuelle Rückgabekomponenten, die auf der Alexa-App des Smartphones angezeigt werden. Hier unterscheidet man zwischen drei Typen von Cards: SimpleCard, StandardCard und LinkAccountCard.

SimpleCard und StandardCard sind für die Darstellung von Inhalten gedacht. SimpleCard kann einen Titel und Text-Content beinhalten, StandardCard zusätzlich ein Bild.

Die „Karten“ erscheinen in der Alexa-App, sobald Alexa Response von onSessionStarted oder onIntent bekommen hat, welche entsprechende Card enthalten ist.

Lambda-Deployment

Die Entwicklung eines einfachen Alexa Skill ist sehr überschaubar. Ist die Funktionalität implementiert, kann über ein Mavenbuild ein Jar für das Deployment unter Lambda erzeugt werden. Da AWS Lambda nur eine Möglichkeit ist, Backendfunktionalitäten für Alexa zur Verfügung zu stellen, wenn wir diesen Bereich auch nicht ausführlich erörtern.

Über mvn assembly:assembly -DdescriptorId=jar-with-dependencies package erstellen wir das Jar. Der Name des Jars wird vorher in der pom.xml festgelegt.

Der Upload des Jar erfolgt über die Lambda-Console. Dazu erstellen wir über Create a lambda function eine neue Funktion; ein Blueprint soll nicht genutzt werden. Im Configure triggers aus Abbildung 1 wählen wir „Alexa Skills Kit“ aus und gehen weiter zur Konfiguration der Funktion (Listing 3).

Hier wird der Funktionsname definiert, unter dem die Funktion in der Konsole zukünftig angezeigt werden soll. Da wir unser Skillbackend in Java entwickelt haben, wählen wir unter Runtime „Java 8“ aus. Lambda selbst greift auf einen speziellen Streamhandler zurück, dessen Package-Pfad wir unter Handler angeben müssen. Nun muss der Lamdafunktion noch das Recht zum Loggen gegeben werden. Dazu wählen wir unter Role „Create a custom role“ und anschließend die IAM-Rolle „lambda_basic_execution“. Mit Allow erzeugen wir diese Rolle (Abb. 3).

Konfiguration der Funktion

Abb. 3: Die Konfiguration der Funktion

Die Advanced Settings belassen wir auf den Default-Werten. Im nächsten Schritt gibt es eine Zusammenfassung und die Möglichkeit, die Funktion abschließend zu erstellen.
Wichtig ist für uns nun die ARN, ein eindeutiger Identifier, mit dem man im Amazon-Universum auf die Lambdafunktion zugreifen kann. Zurück in der Alexa-Developer-Konsole (Abb. 4) wählen wir nun unter Configuration den Service „Endpoint Type AWS Lambda“, selektieren „Europa“ und tragen unseren Lambda-Identifier ein. Auf Accountlinking können wir in unserem Beispiel verzichten.

Die Wahl des ARN

Abb. 4: Die Wahl des AWS Lambda ARN

Nun ist die Verbindung vom Alexa-Skill-Model zum Backend hergestellt. Im nächsten Schritt kann unter Test (Abb. 5) unser Skill direkt auf einem Echo oder Echo Dot getestet werden; alternativ kann der Simulator genutzt werden. Auf das Publishing wird hier nicht weiter eingegangen.

Test des Alexa Skills

Abb. 5: Der Test unseres Alexa Skill

Was beim Test sofort auffällt ist, dass Alexa die Satzphasen etwas „zu“ ungenau interpretiert. Alexa verhält sich ähnlich einem Expertensystem. In unserem Fall gibt es zwei Intents – wenn nun etwas gesagt wird, forciert die Logik, dass entweder der eine oder andere Intent gewählt wird. Sogar dann, wenn etwas völlig anderes gesagt wird. Das ist insofern nicht dramatisch, da wir wenigstens immer zu einem Ergebnis kommen.

Spaß mit Custom-Slots

Probieren wir ein wenig mit Custom-Slots herum, stellen wir fest, dass Alexa nicht nur die Werte zurückgibt, die wir definiert haben, sondern jegliche Begriffe, die sie versteht. Erzeugen wir einen Custom-Slot „userInput“, dessen Slot-Type nur den Wert „Lagerregal“ definiert und eine entsprechenden Phase „wiederhole {userInput}“, können wir austesten, wie Alexas allgemeines Wortverständnis ist. Sagen wir „wiederhole kindergarten“ wird der Slot Value „kindergarten“ zurückgegeben. Das teilweise schlechte Sprachverständnis zeigt schnell, wie wichtig Custom-Slots und deren Werte sind, um den Sprachschatz eines Skills zu erweitern.

Problematisch wird dieser Sachverhalt spätestens bei der Implementierung der Logik wie in unserem Beispiel. Ein Entwickler würde annehmen, dass ein Slot nur genau die Daten zurückgeben kann, die vorher definiert wurden. Daher ist unbedingt darauf zu achten, dass beliebige Texte als Slot-Value zurückgegeben werden können. Der Entwickler muss also selbst prüfen, ob es sich um einen Wert handelt, den er in seiner Programmlogik unterstützt.

Alexa wählt Intents

Wie Alexa passende Intents auswählt, lässt sich nur erahnen. Die Logik würde erst einmal vorgeben, dass wenn ein Intent einen Slot mit einem bestimmten Typ beinhaltet, dieser Intent auch nur dann erkannt wird, wenn auch ein Wert des Slot-Types erkannt wurde. Sagen wir aber „nehme einen blau seitigen würfel“, werden die definierten Werte des Slot-Types bei der Satzerkennung ignoriert. Alexa erkennt trotzdem den chooseDice-Intent. Doch dadurch, dass jeder Slot-Type fest definierte Werte hat, wird der Entwickler an dieser Stelle etwas verwirrt: Ein Intent mit Slot muss beim Callback nicht zwingend einen entsprechenden Slot-Value enthalten; den muss der Entwickler selbst abfangen. Das haben wir in unserem Beispiel jedoch nicht getan.

Probiert man ein wenig mit diesem Beispiel herum, wird man schnell feststellen, dass Alexa einfache Vektoren nutzt, um Intents zuzuordnen; in unserem Fall die Satzlänge und Zahlen. Nennt man eine Zahl, erkennt Alexa automatisch, dass es sich um das Intent mit dem Zahlenslot handeln muss. Nennt man einen kurzen Satz, wird Alexa immer für uns würfeln.

Diese Eigenheiten entschärfen sich natürlich mit der Komplexität des Models, da Alexa dann andere Vektoren zur Bestimmung des Intents nutzen muss.

Resümee und Aussichten

Eine weitere Eigenheit des Systems ist, dass es keine „freie“ Spracherkennung gibt. Die Sprachassistentin Alexa kann nur mit Dingen arbeiten, die sie auch kennt. Möchte ich für meine IOT-Anwendung im Smarthome die Farbe meines Lichts verändern können, muss ich Alexa alle möglichen Farben als Custom-Slot übergeben. Als Query-System auf eine Datenbank eignet sich Alexa also weniger.

Hier ist ein Umdenken gefragt. Wie können zukünftige Sprach-Interfaces den Nutzer effektiv durch Informationsbäume navigieren, ohne dass komplexe Befehle nötig werden? Abzusehen ist, dass hier zukünftig Mechanismen aus der Deep-Learning-Welt in einfache Sprachassistenten wie Alexa Einzug halten werden. Ein gutes Satzverständnis und komplexe Befehle werden mit der Komplexität der Aufgaben essenziell.

Bis dahin ist allerdings noch ein längerer Weg zu gehen und in der Zwischenzeit müssen Entwickler sehen, wie sie über geschickte Sprachinterfaces die Restriktionen des Sprachverständnisses kompensieren.

AlexaDice – das Beispielprojekt zum Artikel zum Download.


Der Würfel-Skill ist einer der eher simpel gehaltenen Skills. Im Laufe dieses Artikels werden einige Schwachstellen der Sprachassistentin Alexa aufgedeckt – im Artikel Alexa Best Practices beschäftigen wir uns mit deutlich fortgeschritteneren Konzepten in der Skill-Entwicklung.
Übrigens: Das Beispielprojekt zum Artikel könnt ihr hier herunterladen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -