Erstellen eines zustandsbehafteten Skills für Alice auf den serverlosen Funktionen von Yandex.Cloud und Python

Beginnen wir mit den Nachrichten. Gestern gab Yandex.Cloud die Einführung eines Serverless-Computing-Dienstes bekannt Yandex Cloud-Funktionen. Das bedeutet: Sie schreiben nur den Code Ihres Dienstes (z. B. einer Webanwendung oder eines Chatbots), und die Cloud selbst erstellt und verwaltet virtuelle Maschinen, auf denen sie ausgeführt wird, und repliziert sie sogar, wenn die Last steigt. Sie müssen überhaupt nicht nachdenken, es ist sehr praktisch. Und die Zahlung erfolgt nur für die Zeit der Berechnungen.

Manche Menschen zahlen jedoch möglicherweise überhaupt nicht. Das sind die Entwickler Alices externe Fähigkeiten, das heißt, darin integrierte Chatbots. Jeder Entwickler kann einen solchen Skill schreiben, hosten und registrieren. Ab heute müssen Skills nicht einmal mehr gehostet werden – laden Sie einfach ihren Code im Formular in die Cloud hoch die gleiche serverlose Funktion.

Aber es gibt ein paar Nuancen. Erstens erfordert Ihr Haustiercode möglicherweise einige Abhängigkeiten, und es ist nicht einfach, diese in die Cloud zu ziehen. Zweitens muss jeder normale Chatbot den Status des Dialogs irgendwo speichern (also zustandsbehaftet); Wie geht das am einfachsten in einer serverlosen Funktion? Drittens: Wie kann man einen Quick-and-Dirty-Skill für Alice oder sogar eine Art Bot mit einer Handlung ungleich Null schreiben? Über diese Nuancen eigentlich der Artikel.

Erstellen eines zustandsbehafteten Skills für Alice auf den serverlosen Funktionen von Yandex.Cloud und Python

moralische Vorbereitung

Für Ungeduldige: Ich sammle die notwendigen Abhängigkeiten mit einem Makefile, bevor ich die Funktion in die Cloud hochlade, ich speichere den Status des Dialogs im Yandex Object Storage (es unterstützt die S3-API) und ich verwende meine eigene Bibliothek, um den Dialog zu verwalten tgalice. Als Ergebnis stellt sich heraus solche Demo-Skill. Und jetzt analysieren wir das alles etwas genauer.

Für die etwas weniger Ungeduldigen empfehle ich dringend, einfach anzufangen, bevor ich in meine komplexe Geschichte eintauche. Erstellen Sie nämlich eine Echobot-Funktion für eine einzelne Datei, registrieren und testen Sie sie in der Dialog-Entwicklerkonsole. Details - in Blog-Dialoge и Cloud-Dokumentation. Und erst dann anfangen.

Wenn Sie sofort spüren möchten, wofür wir kämpfen, fragen Sie Alice.Schalte den Skill „IT-Horoskop“ ein'. Es soll folgender Dialog stattfinden:

Alice: Hallo! Sie befinden sich im Skill „IT-Horoskop“. Sagen Sie „Start“, um herauszufinden, was die Sterne Ihnen versprechen.
Benutzer: Start
A: Bitte geben Sie Ihren Namen an.
Yu: Vasisualy
A: Sagen Sie mir jetzt Ihr Geburtsjahr. Nur vier Ziffern, mehr nicht.
Yu: Zweiter
A: Bitte versuchen Sie es erneut. Geben Sie Ihr Geburtsjahr an – vierstellig.
Yu: 2002
Ein großer! Nennen Sie nun den Monat Ihrer Geburt.
Yu: Februar
A: Ausgezeichnet! Sagen Sie mir abschließend Ihr Geburtsdatum – nur eine Zahl, nur ein oder zwei Ziffern.
Yu: 18
A: Danke, Vasisual! Jetzt wissen wir: Du bist 17 Jahre alt und ein Wassermann. Hier haben Sie natürlich Glück! Die Sterne sagen es dir а что говорят звёзды, вы узнаете, запустив навык.

Das Problem besteht darin, dass Sie sich den Namen und das Geburtsdatum des Benutzers merken müssen, um selbst einen so einfachen Dialog aufrechtzuerhalten. In einer serverlosen Umgebung ist dies nicht trivial. Es funktioniert nicht, den Kontext im RAM oder als Datei auf der Festplatte zu speichern, weil Yandex.Cloud kann die Funktion auf mehreren virtuellen Maschinen gleichzeitig ausführen und beliebig zwischen diesen wechseln. Sie müssen eine Art externen Speicher verwenden. Object Storage wurde als relativ kostengünstiger und einfacher Speicher direkt in Yandex.Cloud ausgewählt (also wahrscheinlich schnell). Als kostenlose Alternative können Sie beispielsweise ein kostenloses Stück ausprobieren Bewölkter Mongi Irgendwo weit entfernt. Sowohl Object Storage (es unterstützt die S3-Schnittstelle) als auch Mongo verfügen über praktische Python-Wrapper.

Ein weiteres Problem besteht darin, dass Sie für den Zugriff auf Object Storage, MongoDB und andere Datenbanken oder Datenspeicher einige externe Abhängigkeiten benötigen, die Sie zusammen mit Ihrem Funktionscode in Yandex Functions hochladen müssen. Und ich möchte es bequem machen. Es ist völlig praktisch (wie bei Heroku), leider funktioniert es nicht, aber Sie können einen grundlegenden Komfort schaffen, indem Sie ein Skript schreiben, um die Umgebung zu erstellen (Datei erstellen).

So starten Sie die Horoskop-Fähigkeit

  1. Machen Sie sich bereit: Gehen Sie zu einem Computer mit Linux. Prinzipiell kann man wohl auch mit Windows arbeiten, allerdings muss man dann mit dem Start des Makefiles zaubern. Und in jedem Fall benötigen Sie mindestens 3.6 installiertes Python.
  2. Von Github klonen Beispiel für eine Horoskop-Fähigkeit.
  3. Registrieren Sie sich in Ya.Cloud: https://cloud.yandex.ru
  4. Erstellen Sie sich zwei Eimer Objektspeicher, nenne sie bei irgendeinem Namen {BUCKET NAME} и tgalice-test-cold-storage (Dieser zweite Vorname ist jetzt fest einprogrammiert main.py mein Beispiel). Der erste Bucket wird nur für die Bereitstellung benötigt, der zweite dient zum Speichern von Dialogzuständen.
  5. Schaffen Dienstkonto, gib ihm eine Rolle editor, und erhalten Sie statische Anmeldeinformationen dafür {KEY ID} и {KEY VALUE} - Wir werden sie nutzen, um den Stand des Dialogs festzuhalten. Dies alles wird benötigt, damit die Funktion von Ya.Cloud auf den Speicher von Ya.Cloud zugreifen kann. Ich hoffe, dass die Autorisierung eines Tages automatisch erfolgt, aber vorerst – so.
  6. (Optional) installieren Befehlszeilenschnittstelle yc. Sie können eine Funktion auch über das Webinterface erstellen, aber die CLI ist gut, weil darin alle möglichen Neuerungen schneller erscheinen.
  7. Jetzt können Sie tatsächlich die Zusammenstellung der Abhängigkeiten vorbereiten: Führen Sie sie in der Befehlszeile aus dem Ordner mit dem Skill-Beispiel aus make all. Im Ordner werden eine Reihe von Bibliotheken (meistens wie üblich unnötig) installiert dist.
  8. Füllen Sie es mit Stiften in den Objektspeicher (in einen Eimer). {BUCKET NAME}) das im vorherigen Schritt erhaltene Archiv dist.zip. Auf Wunsch können Sie dies auch über die Kommandozeile erledigen, zum Beispiel mit AWS-CLI.
  9. Erstellen Sie eine serverlose Funktion über die Weboberfläche oder mithilfe des Dienstprogramms yc. Für das Dienstprogramm sieht der Befehl folgendermaßen aus:

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 einer Funktion werden alle Parameter auf die gleiche Weise gefüllt.

Jetzt kann die von Ihnen erstellte Funktion über die Entwicklerkonsole getestet und anschließend finalisiert und veröffentlicht werden.

Erstellen eines zustandsbehafteten Skills für Alice auf den serverlosen Funktionen von Yandex.Cloud und Python

Was steckt unter der Haube?

Das Makefile enthält tatsächlich ein ziemlich einfaches Skript zum Installieren von Abhängigkeiten und zum Ablegen dieser Abhängigkeiten in einem Archiv. dist.zip, etwas wie das:

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 besteht aus ein paar einfachen Werkzeugen, verpackt in einer Bibliothek tgalice. Der Vorgang zum Ausfüllen der Benutzerdaten wird in der Konfiguration beschrieben form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'старт|нач(ать|ни)'
  suggests:
    - Старт
fields:
  - name: 'name'
    question: Пожалуйста, назовите своё имя.
  - name: 'year'
    question: Теперь скажите мне год вашего рождения. Только четыре цифры, ничего лишнего.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Пожалуйста, попробуйте ещё раз. Назовите год вашего рождения - четыре цифры.
  - name: 'month'
    question: Замечательно! Теперь назовите месяц вашего рождения.
    options:
      - январь
     ...
      - декабрь
    validate_message: То, что вы назвали, не похоже на месяц. Пожалуйста, назовите месяц вашего рождения, без других слов.
  - name: 'day'
    question: Отлично! Наконец, назовите мне дату вашего рождения - только число, всего одна или две цифры.
    validate_regexp: '[0123]?d$'
    validate_message: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

Die Python-Klasse übernimmt die Arbeit, diese Konfiguration zu analysieren und das Endergebnis zu berechnen

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'январь': 'Козерог',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Спасибо, {}! Теперь мы знаем: вам {} лет, и вы {}. n'
                 'Вот это вам, конечно, повезло! Звёзды говорят вам: {}'.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“ und der Methode der untergeordneten Klasse handle_completed_form sagt, was zu tun ist, wenn sie bereit ist.

Zusätzlich zu diesem Hauptdialogfluss muss der Benutzer auch begrüßt werden und beim Befehl „Hilfe“ Hilfe geben und beim Befehl „Beenden“ aus dem Skill entlassen werden. Dafür in tgalice Es gibt auch eine Vorlage, sodass der gesamte Dialogmanager aus mehreren Teilen besteht:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='До свидания, приходите в навык "Айтишный гороскоп" ещё!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager funktioniert einfach: Es versucht, nacheinander alle seine Komponenten auf den aktuellen Status des Dialogs anzuwenden und wählt die erste relevante aus.

Als Antwort auf jede Nachricht gibt der Dialogmanager ein Python-Objekt zurück Response, der dann in Klartext oder in eine Nachricht in Alice oder Telegram umgewandelt werden kann – je nachdem, wo der Bot läuft; Es enthält auch den geänderten Status des Dialogs, der gespeichert werden muss. Die ganze Küche wird von einer anderen Klasse betreut, DialogConnector, also sieht das direkte Skript zum Starten eines Skills auf Yandex Functions so aus:

...
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, stellt der größte Teil dieses Codes eine Verbindung zur Object Storage S3-Schnittstelle her. Wie diese Verbindung direkt genutzt wird, können Sie nachlesen im Tgalice-Code.
Die letzte Zeile erstellt eine Funktion alice_handler - derjenige, den wir angewiesen haben, Yandex.Cloud abzurufen, als wir den Parameter festgelegt haben --entrypoint=main.alice_handler.

Das ist eigentlich alles. Makefiles zum Erstellen, S3-ähnlicher Objektspeicher zur Kontextspeicherung und eine Python-Bibliothek tgalice. Zusammen mit den serverlosen Funktionen und der Ausdruckskraft von Python reicht dies aus, um die Fähigkeiten eines gesunden Menschen zu entwickeln.

Sie fragen sich vielleicht, warum Sie etwas erstellen müssen tgalice? Darin steckt aller langweiliger Code, der JSONs von der Anfrage zur Antwort und vom Speicher zum Speicher und zurück überträgt. Es gibt auch eine reguläre Anwendung, eine Funktion zum Verständnis, dass „Februar“ dem „Februar“ ähnelt, und andere NLU für die Armen. Meiner Vorstellung nach sollte dies bereits ausreichen, um Skill-Prototypen in Yaml-Dateien skizzieren zu können, ohne sich zu sehr von technischen Details ablenken zu lassen.

Wenn Sie eine ernsthaftere NLU wünschen, können Sie diese an Ihre Fähigkeiten anpassen Rasa oder DeepPavlov, aber der Aufbau erfordert zusätzliches Tanzen mit einem Tamburin, insbesondere auf Serverless. Wenn Sie überhaupt keine Lust zum Codieren haben, sollten Sie den visuellen Typkonstruktor verwenden Aimylogik. Bei der Erstellung von Tgalice habe ich über eine Art Zwischenpfad nachgedacht. Mal sehen was passiert.

Nun, jetzt machen Sie mit Aliy Skills-Entwickler-Chat, lesen Dokumentationund Erstaunliches schaffen навыки!

Source: habr.com

Kommentar hinzufügen