Erstellen einer Stateful-Fähigkeit für Alice in den serverlosen Funktionen von Yandex.Cloud und Python

Beginnen wir mit den Nachrichten. Gestern gab Yandex.Cloud den Start des serverlosen Computerdienstes Yandex Cloud Functions bekannt . Dies bedeutet: Sie schreiben nur den Code Ihres Dienstes (z. B. eine Webanwendung oder einen Chatbot), und die Cloud selbst erstellt und verwaltet virtuelle Maschinen dort, wo sie gestartet wird, und repliziert sie sogar, wenn die Last zunimmt. Es ist nicht notwendig zu denken, es ist sehr praktisch. Und die Gebühr geht nur während der Berechnung.


Einige zahlen jedoch möglicherweise überhaupt nicht. Dies sind die Entwickler von Alices externen Fähigkeiten , dh Chatbots, die in sie eingebaut sind. Jeder Entwickler kann eine solche Fähigkeit schreiben, hosten und registrieren, und ab heute müssen die Fähigkeiten nicht einmal mehr gehostet werden - laden Sie einfach ihren Code in Form der sehr serverlosen Funktion in die Cloud hoch .


Aber es gibt ein paar Nuancen. Erstens erfordert Ihr Haustiercode möglicherweise einige Abhängigkeiten, und das Abrufen in die Cloud ist nicht trivial. Zweitens muss jeder normale Chatbot den Status des Dialogs irgendwo speichern (daher Stateful). Wie geht das in einer serverlosen Funktion am einfachsten? Drittens, wie können Sie schnell und schmutzig eine Fertigkeit für Alice oder eine Art Bot mit einer Handlung ungleich Null schreiben? Über diese Nuancen in der Tat ein Artikel.


Bild

Moralisches Training


Für Ungeduldige: Ich sammle die erforderlichen Abhängigkeiten mit einer Make-Datei, bevor ich die Funktion in die Cloud hochlade, speichere den Status des Dialogs in Yandex Object Storage (es unterstützt die S3-API) und verwende zum Verwalten des Dialogs meine eigene Tgalice- Bibliothek. Das Ergebnis ist eine solche Demo-Fähigkeit. Schauen wir uns das jetzt genauer an.


Für ein bisschen weniger ungeduldig: Bevor ich in meine Geschichte über Schwierigkeiten eintauche, empfehle ich dringend, mit einer einfachen zu beginnen. Erstellen Sie nämlich eine Echolotfunktion für eine einzelne Datei, registrieren Sie sie und testen Sie sie in der Dialogs-Entwicklerkonsole. Details finden Sie im Cloud- Dialog- und Dokumentationsblog . Und erst dann weiter.


Wenn Sie sofort spüren möchten, wofür wir kämpfen, bitten Sie Alice, die Fähigkeit "IT-Horoskop " einzuschalten. Der folgende Dialog sollte stattfinden:


Alice: Hi! Sie sind in der Fähigkeit des Aishish Horoskops. Sagen Sie "Start", um herauszufinden, was die Sterne Ihnen versprechen.
Benutzer: Start
A: Bitte geben Sie Ihren Namen an.
Yu: Vasisuali
A: Jetzt sag mir das Jahr deiner Geburt. Nur vier Zahlen, nichts weiter.
Yu: Zweitens
A: Bitte versuchen Sie es erneut. Was ist das Jahr Ihrer Geburt - vier Ziffern.
U: 2002
A: Großartig! Nennen Sie jetzt den Monat Ihrer Geburt.
U: Februar
A: Großartig! Sagen Sie mir zum Schluss das Geburtsdatum - nur eine Zahl, nur ein oder zwei Ziffern.
U: 18
A: Danke, Vasisuali! Jetzt wissen wir: Sie sind 17 Jahre alt und Wassermann. Hier haben Sie natürlich Glück! Die Sterne sagen dir: , , .


Das Problem ist, dass Sie sich den Namen und das Geburtsdatum des Benutzers merken müssen, um auch einen so einfachen Dialog aufrechtzuerhalten. In einer Umgebung ohne Server ist dies nicht trivial. Speichern Sie den Kontext im RAM oder eine Datei auf der Festplatte funktioniert nicht, weil Yandex.Cloud kann die Funktion auf mehreren virtuellen Maschinen gleichzeitig ausführen und beliebig zwischen ihnen wechseln. Wir müssen eine Art externen Speicher verwenden. Die Objektspeicherung wurde als recht kostengünstige und unkomplizierte Speicherung direkt in Yandex.Cloud ausgewählt (d. H. Wahrscheinlich schnell). Als kostenlose Alternative können Sie beispielsweise ein kostenloses Stück trübe Monga irgendwo in der Ferne ausprobieren. 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 das Gehen in Object Storage, in MongoDB und in jeder anderen Datenbank oder jedem anderen Data Warehouse einige externe Abhängigkeiten benötigen, die Sie zusammen mit Ihrem Funktionscode in Yandex Functions hochladen müssen. Und ich würde es gerne bequem machen. Es ist sehr praktisch (wie Heroku), leider funktioniert es nicht, aber Sie können einen grundlegenden Komfort schaffen, indem Sie ein Skript zum Erstellen der Umgebung (make-file) schreiben.


Wie man eine Horoskop-Fähigkeit ausführt


  1. Bereiten Sie sich vor: Gehen Sie zu einem Linux-Computer. Im Prinzip können Sie wahrscheinlich auch mit Windows arbeiten, aber dann müssen Sie den Start der Make-Datei heraufbeschwören. In jedem Fall muss Python mindestens 3.6 installiert sein.
  2. Klonen Sie sich mit Github, einem Beispiel für eine Horoskop-Fähigkeit .
  3. Registrieren Sie sich in Y. Cloud: https://cloud.yandex.ru
  4. Erstellen Sie zwei Buckets für sich in Object Storage , benennen Sie sie mit einem beliebigen Namen {BUCKET NAME} und tgalice-test-cold-storage (dieser zweite Name ist jetzt in main.py meines Beispiels fest main.py ). Der erste Bucket wird nur für die Bereitstellung benötigt, der zweite - zum Speichern von Dialogzuständen.
  5. Erstellen Sie ein Dienstkonto , geben Sie ihm die editor Rolle und erhalten Sie die statischen Kreditkarten {KEY ID} und {KEY VALUE} - wir werden sie verwenden, um den Status des Dialogs aufzuzeichnen. All dies ist erforderlich, damit eine Funktion von Y. Cloud aus von Y. Cloud auf das Repository zugreifen kann. Eines Tages hoffe ich, dass die Autorisierung automatisch erfolgt, aber vorerst - also.
  6. (Optional) Installieren Sie die yc Befehlszeilenschnittstelle . Sie können eine Funktion über die Weboberfläche erstellen, aber die CLI ist insofern gut, als alle möglichen Innovationen schneller darin erscheinen.
  7. Jetzt können Sie tatsächlich die Abhängigkeitsassembly vorbereiten: Führen Sie sie an der Eingabeaufforderung in einem Ordner mit dem Beispiel " make all Fertigkeiten erstellen" aus. Eine Reihe von Bibliotheken (meistens, wie üblich, unnötig) werden im dist Ordner installiert.
  8. Gießen Sie im Objektspeicher (in den {BUCKET NAME} ) das im vorherigen Schritt erhaltene dist.zip Archiv ein. Falls gewünscht, können Sie dies über die Befehlszeile tun, z. B. über die AWS-CLI .
  9. Erstellen Sie eine serverlose Funktion über die Weboberfläche oder mit dem Dienstprogramm 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 geändert und veröffentlicht werden.



Was ist unter der Haube


Das Makefile enthält tatsächlich ein ziemlich einfaches Skript, um die Abhängigkeiten zu installieren und in das dist.zip Archiv zu stellen.


 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 ein paar einfache Werkzeuge, die in der tgalice Bibliothek tgalice . Das Ausfüllen von Benutzerdaten wird in der form.yaml- 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 Arbeit zum Parsen dieser Konfiguration und zum Berechnen des Endergebnisses wird von der Python-Klasse übernommen


 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 füllt die Basisklasse FormFillingDialogManager das "Formular" aus, und die Methode der handle_completed_form Klasse handle_completed_form gibt an, was zu tun ist, wenn es fertig ist.


Zusätzlich zu diesem Hauptfluss des Benutzerdialogs müssen Sie auch begrüßen, Hilfe zum Befehl "Hilfe" geben und die Fertigkeit zum Befehl "Beenden" freigeben. tgalice hat auch eine Vorlage dafür, so dass der gesamte Dialogmanager aus 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, alle seine Komponenten nacheinander auf den aktuellen Status des Dialogs anzuwenden, und wählt den ersten geeigneten aus.


Als Antwort auf jede Nachricht gibt der Dialogmanager ein Response , das weiter in Bare-Text oder in eine Nachricht in Alice oder Telegram konvertiert werden kann - je nachdem, wo der Bot gestartet wird. Es enthält auch den geänderten Status des Dialogs, der gespeichert werden muss. Eine andere Klasse, DialogConnector , beschäftigt sich mit dieser ganzen Küche. Das direkte Skript zum Starten der Fertigkeit für Yandex-Funktionen sieht also folgendermaßen 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 können, stellt der größte Teil dieses Codes eine Verbindung zur Object Storage S3-Schnittstelle her. Wie diese Verbindung direkt verwendet wird, kann im tgalice-Code nachgelesen werden .
In der letzten Zeile wird die Funktion alice_handler erstellt - die Funktion, die Yandex.Cloud beim Setzen des --entrypoint=main.alice_handler .


Das ist in der Tat alles. Makefiles für die Assembly, S3-ähnlicher Objektspeicher zum Speichern des Kontexts und die tgalice-Python-Bibliothek. 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 tgalice erstellen tgalice ? Der gesamte langweilige Code, der JSONs von der Anforderung zur Antwort und vom Speicher zum Speicher und umgekehrt überträgt, liegt darin. Es gibt auch eine reguläre Controller-Anwendung, eine Funktion zum Verstehen, wie „Februar“ wie „Februar“ ist, und eine andere NLU für die Armen. Nach meiner Vorstellung sollte dies bereits ausreichen, damit Sie Prototypen von Fähigkeiten in Yaml-Dateien skizzieren können, ohne sich von technischen Details ablenken zu lassen.


Wenn Sie eine ernstere NLU wünschen, können Sie Rasa oder DeepPavlov an Ihre Fähigkeiten anpassen. Um sie jedoch zu konfigurieren, benötigen Sie zusätzliche Tänze mit einem Tamburin, insbesondere auf Serverlosen. Wenn Sie überhaupt keine Lust zum Codieren haben, sollten Sie einen visuellen Konstruktor wie Aimylogic verwenden . Bei der Erstellung von Galice dachte ich an eine Art Zwischenpfad. Mal sehen, was passiert.


Nun, nehmen Sie am Chat der Entwickler ihrer Fähigkeiten teil , lesen Sie die Dokumentation und erstellen Sie wunderbare Fähigkeiten !

Source: https://habr.com/ru/post/de469723/


All Articles