Erstellung einer stateful Fähigkeit für Alice mit serverlosen Funktionen von Yandex.Cloud und Python

Beginnen wir mit den Neuigkeiten. Gestern hat Yandex.Cloud den Start eines serverlosen Rechenservices angekündigt. Yandex Cloud FunctionsDas bedeutet, dass Sie nur den Code Ihres Services (zum Beispiel einer Webanwendung oder eines Chatbots) schreiben und die Cloud automatisch die virtuellen Maschinen erstellt und verwaltet, auf denen er läuft, und sie sogar repliziert, wenn die Last steigt. Sie müssen sich um nichts kümmern, das ist sehr praktisch. Und es fallen nur Kosten für die tatsächlich genutzte Rechenzeit an.

Übrigens können einige sogar ganz kostenlos bleiben. Das sind die Entwickler externer Fähigkeiten von Alice, also die integrierten Chatbots. Jeder Entwickler kann einen solchen Skill schreiben, hosten und registrieren, und ab heute müssen die Skills nicht einmal mehr gehostet werden – es reicht aus, ihren Code in die Cloud als genau diese serverlose Funktion hochzuladen..

Es gibt jedoch einige Punkte zu beachten. Erstens könnte Ihr spezifischer Code Anforderungen an Abhängigkeiten haben, die in die Cloud integriert werden müssen – das ist kein triviales Unterfangen. Zweitens benötigt jeder vernünftige Chatbot einen Ort zur Speicherung des Dialogzustands (daher zustandsbehaftet); wie lässt sich dies am einfachsten in einer serverlosen Funktion umsetzen? Drittens, wie kann man schnell und unkompliziert eine Funktion für Alice oder irgendeinen Bot mit einer Minimum an Handlung erstellen? Über diese Punkte handelt der Artikel.

Erstellung einer stateful Fähigkeit für Alice mit serverlosen Funktionen von Yandex.Cloud und Python

Ethische Vorbereitung

Für die Ungeduldigen: Die benötigten Abhängigkeiten erstelle ich mit einer Make-Datei, bevor ich die Funktion in die Cloud lade. Den Dialogzustand speichere ich im Yandex Object Storage (das unterstützt das S3-API), und für das Dialogmanagement nutze ich meine eigene Bibliothek tgalice. Das Ergebnis ist ein so Demo-Skill. Lassen Sie uns das jetzt etwas detaillierter anschauen.

Für die etwas weniger Ungeduldigen: Bevor ich in meine Geschichte über die Herausforderungen eintauche, empfehle ich dringend, mit etwas Einfachem zu beginnen. Genauer gesagt, erstellen Sie eine einseitige Echo-Funktion, registrieren Sie sie und testen Sie sie in der Entwicklerkonsole von Dialogen; Details finden Sie im Dialogblog und Cloud-Dokumentation. Erst danach sollte man weitermachen.

Wenn Sie sofort spüren möchten, wofür wir hier kämpfen, fragen Sie Alice ‘aktiviere die Funktion „IT-Horoskop“‘. Es sollte ungefähr folgender Dialog stattfinden:

Alice: Hallo! Sie sind im Skill „IT-Horoskop“. Sagen Sie „Start“, um zu erfahren, was die Sterne Ihnen vorhersagen.
Benutzer: Start
A: Bitte nennen Sie mir Ihren Namen
B: Vassisualliy
A: Jetzt nennen Sie mir Ihr Geburtsjahr. Nur vier Ziffern, nichts weiter.
B: zwei
A: Bitte versuchen Sie es noch einmal. Nennen Sie mir Ihr Geburtsjahr – vier Ziffern.
B: 2002
A: Wunderbar! Nennen Sie mir nun den Monat Ihres Geburts.
B: Februar
A: Großartig! Schließlich nennen Sie mir das Datum Ihrer Geburt – nur die Zahl, insgesamt ein oder zwei Ziffern.
B: 18
A: Vielen Dank, Vassisualliy! Nun wissen wir: Sie sind 17 Jahre alt und Wassermann. Damit haben Sie echtes Glück! Die Sterne sagen Ihnen: was die Sterne sagen, erfahren Sie, indem Sie den Skill starten.

Das Problem ist, dass man für einen so einfachen Dialog den Namen und das Geburtsdatum des Benutzers im Gedächtnis behalten muss, was in einer serverlosen Umgebung nicht trivial ist. Kontext im Arbeitsspeicher oder in einer Datei auf der Festplatte zu halten, funktioniert nicht, da Yandex.Cloud die Funktion auf mehreren virtuellen Maschinen gleichzeitig ausführen und willkürlich zwischen ihnen wechseln kann. Man muss auf einen externen Speicher zurückgreifen. Objekt-Storage wurde als eine kostengünstige und einfache Lösung direkt in Yandex.Cloud gewählt (d.h. wahrscheinlich schnell). Als kostenlose Alternative könnte man beispielsweise ein kleines Stück nutzen. Cloud Mongo irgendwo weit weg. Sowohl für Object Storage (das die S3-Schnittstelle unterstützt) als auch für Mongo gibt es praktische Python-Bibliotheken.

Ein weiteres Problem ist, dass für den Zugang zu Object Storage, MongoDB oder anderen Datenbanken externe Abhängigkeiten benötigt werden, die zusammen mit dem Code Ihrer Funktion in Yandex Functions hochgeladen werden müssen. Es wäre schön, dies bequem zu machen. Ganz bequem (wie bei Heroku) wird es leider nicht möglich sein, aber ein gewisser Grundkomfort lässt sich schaffen, indem man ein Skript zur Erstellung der Umgebung (Makefile) schreibt.

Wie man einen Horoskop-Skill startet

  1. Vorbereitung: Melden Sie sich auf einem Linux-Rechner an. Prinzipiell sollte man auch mit Windows arbeiten können, aber bei der Ausführung des Makefiles könnte es etwas knifflig werden. In jedem Fall benötigen Sie eine installierte Python-Version von mindestens 3.6.
  2. Klone dir das von GitHub Beispiel für einen Horoskop-Skill.
  3. Registrieren Sie sich bei Yandex.Cloud: https://cloud.yandex.ru
  4. Erstellen Sie zwei Buckets in Object Storage, benennen Sie sie nach Belieben {BUCKET NAME} und tgalice-test-cold-storage (das zweite Name ist im Moment in main.py meinem Beispiel fest im Code verankert). Der erste Bucket wird nur für das Deployment benötigt, der zweite für die Speicherung der Dialogzustände.
  5. Erstellen Sie Dienstkonto, geben Sie ihm die Rolle editor, und erhalten Sie statische Anmeldeinformationen {KEY ID} und {KEY VALUE} — wir werden sie verwenden, um den Zustand des Dialogs aufzuzeichnen. Das ist notwendig, damit die Funktion von Я.Облака auf den Speicher von Я.Облака zugreifen kann. Irgendwann, hoffe ich, wird die Authentifizierung automatisch erfolgen, aber bis dahin — so.
  6. (Nicht zwingend) installieren eine Kommandozeilenoberfläche yc. Eine Funktion lässt sich auch über die Weboberfläche erstellen, aber das CLI ist vorteilhaft, da neue Funktionen hier schneller erscheinen.
  7. Jetzt können wir tatsächlich die Abhängigkeiten zusammenstellen: führen Sie in der Eingabeaufforderung aus dem Ordner mit dem Skill-Beispiel aus make all. Es werden viele Bibliotheken (hauptsächlich, wie üblich, unnötige) in den Ordner dist.
  8. manuell in den Object Storage (in den Bucket {BUCKET NAME}) das Archiv hochladen, das im vorherigen Schritt erstellt wurde dist.zip. Auf Wunsch kann dies auch aus der Eingabeaufforderung erfolgen, zum Beispiel mit AWS CLI.
  9. Erstellen Sie eine serverlose Funktion über die Weboberfläche oder unter Verwendung des Utilities yc. Für die Utility wird der Befehl so aussehen:

yc serverless function version create
    --function-name=horoscope
    --environment=AWS_ACCESS_KEY_ID={KEY ID},AWS_SECRET_ACCESS_KEY={KEY VALUE}
    --runtime=python37
    --package-bucket-name={BUCKET NAME}
    --package-object-name=dist.zip
    --entrypoint=main.alice_handler
    --memory=128M
    --execution-timeout=3s

Beim manuellen Erstellen der Funktion werden alle Parameter ähnlich ausgefüllt.

Jetzt können Sie die von Ihnen erstellte Funktion über die Entwicklertools testen, bevor Sie die Fähigkeit weiterentwickeln und veröffentlichen.

Erstellung einer stateful Fähigkeit für Alice mit serverlosen Funktionen von Yandex.Cloud und Python

Was steckt wirklich dahinter?

Die Make-Datei enthält tatsächlich ein ziemlich einfaches Skript zum Installieren von Abhängigkeiten und zum Verpacken in ein Archiv. dist.zip, ungefähr so:

mkdir -p dist/
pip3 install -r requirements.txt --target dist/
cp main.py dist/main.py
cp form.yaml dist/form.yaml
cd dist && zip --exclude '*.pyc' -r ../dist.zip ./*

Der Rest sind einige einfache Werkzeuge, die in eine Bibliothek gepackt sind. tgaliceDer Prozess zur Erfassung von Benutzerdaten wird durch die Konfiguration beschrieben. form.yaml:

form_name: 'horoskop_form'
start:
  regexp: 'start|beginnen'
  suggests:
    - Start
fields:
  - name: 'name'
    question: Bitte nennen Sie Ihren Namen.
  - name: 'year'
    question: Jetzt sagen Sie mir bitte das Jahr Ihrer Geburt. Nur vier Ziffern, nichts weiter.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Bitte versuchen Sie es erneut. Nennen Sie das Jahr Ihrer Geburt - vier Ziffern.
  - name: 'month'
    question: Wunderbar! Nennen Sie jetzt den Monat Ihrer Geburt.
    options:
      - Januar
      - Februar
      - März
      - April
      - Mai
      - Juni
      - Juli
      - August
      - September
      - Oktober
      - November
      - Dezember
    validate_message: Was Sie genannt haben, sieht nicht wie ein Monat aus. Bitte nennen Sie den Monat Ihrer Geburt, ohne andere Worte.
  - name: 'day'
    question: Ausgezeichnet! Nennen Sie mir schließlich das Datum Ihrer Geburt - nur die Zahl, maximal zwei Ziffern.
    validate_regexp: '[0123]?\d$'
    validate_message: Bitte versuchen Sie es erneut. Sie müssen die Zahl Ihres Geburtstags angeben (zum Beispiel: zwanzig); es sind ein oder zwei Ziffern nötig.

Die Analyse dieser Konfiguration und die Berechnung des endgültigen Ergebnisses übernimmt die Python-Klasse.

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'Januar': 'Steinbock',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Danke, {}! Jetzt wissen wir: Sie sind {} Jahre alt und Sie sind {}. n'
                 'Das ist Ihnen wirklich gelungen! Die Sterne sagen Ihnen: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

Genauer gesagt, die Basisklasse FormFillingDialogManager beschäftigt sich mit dem Ausfüllen des "Formulars", während die Methode der abgeleiteten Klasse handle_completed_form sagt, was zu tun ist, wenn es fertig ist.

Neben diesem Hauptdialogstrom muss der Benutzer auch begrüßt werden, eine Hilfe angeboten werden und der Skill muss bei dem Befehl "Ausgang" beendet werden. Dafür gibt es in tgalice auch eine Vorlage, weshalb der vollständige Dialogmanager aus Teilen zusammengesetzt ist:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='Auf Wiedersehen, besuchen Sie den Skill "IT-Horoskop" wieder!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager Es funktioniert einfach, indem es nacheinander versucht, alle seine Komponenten auf den aktuellen Status des Dialogs anzuwenden und die erste passende auszuwählen.

Als Antwort auf jede Nachricht gibt der Dialogmanager ein Python-Objekt zurück Response, das anschließend in reinen Text oder in eine Nachricht für Alice oder Telegram umgewandelt werden kann – je nachdem, wo der Bot läuft; es enthält auch den geänderten Zustand des Dialogs, der gespeichert werden muss. Um all dies kümmert sich eine weitere Klasse, DialogConnector, weshalb das direkte Skript zum Starten des Skills auf Yandex Functions folgendermaßen aussieht:

...
session = boto3.session.Session()
s3 = session.client(
    service_name='s3',
    endpoint_url='https://storage.yandexcloud.net',
    aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'],
    aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'],
    region_name='ru-central1',
)
storage = tgalice.session_storage.S3BasedStorage(s3_client=s3, bucket_name='tgalice-test-cold-storage')
connector = tgalice.dialog_connector.DialogConnector(dialog_manager=dm, storage=storage)
alice_handler = connector.serverless_alice_handler

Wie Sie sehen, erstellt der größte Teil dieses Codes eine Verbindung zur S3-Schnittstelle des Object Storage. Wie diese Verbindung genau genutzt wird, kann man im Code von tgalice.
Die letzte Zeile erstellt die Funktion alice_handler — genau die, die wir Yandex.Cloud gesagt haben, als wir den Parameter festlegten. --entrypoint=main.alice_handler.

Das ist im Wesentlichen alles. Makefiles für den Build, S3-ähnlicher Objektspeicher zur Speicherung des Kontexts und eine Python-Bibliothek. tgalice. Zusammen mit serverlosen Funktionen und der Ausdrücklichkeit von Python reicht das aus, um eine gesunde Fähigkeit zu entwickeln.

Vielleicht fragen Sie sich, warum es notwendig war, das zu erstellen. tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.

Wenn Sie eine ernsthaftere NLU wünschen, können Sie Ihrem Skill Rasa oder DeepPavlov, hinzufügen, aber für deren Einrichtung wird weitere Feinabstimmung benötigt, insbesondere bei serverless. Wenn Sie überhaupt nicht programmieren möchten, sollten Sie einen visuellen Baukasten wie Aimylogicverwenden. Als ich tgalice erstellte, dachte ich an einen Mittelweg. Mal sehen, was daraus wird.

Treten Sie jetzt dem Chat für Entwickler von Alice-ähnlichen Fähigkeitenbei, lesen Sie Dokumentation, und erstellen Sie großartige. Fähigkeiten!

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster