Oprettelse af en stateful færdighed for Alice ved hjælp af serverløse funktioner i Yandex.Cloud og Python

Lad os starte med nyhederne. I går annoncerede Yandex.Cloud lanceringen af ​​en serverløs computertjeneste Yandex Cloud-funktioner. Det betyder: du skriver kun koden til din tjeneste (for eksempel en webapplikation eller en chatbot), og skyen selv opretter og vedligeholder de virtuelle maskiner, hvor den kører, og replikerer dem endda, hvis belastningen stiger. Du behøver slet ikke tænke, det er meget praktisk. Og betalingen er kun for beregningstiden.

Nogle betaler dog måske slet ikke. Det er udviklerne Alices ydre færdigheder, altså chatbots indbygget i det. Enhver udvikler kan skrive, hoste og registrere en sådan færdighed, og fra i dag behøver færdighederne ikke engang at være vært - bare upload deres kode til skyen i formularen den samme serverløse funktion.

Men der er et par nuancer. For det første kan din pit-kode kræve nogle afhængigheder, og det er ikke-trivielt at trække dem ind i skyen. For det andet skal enhver normal chatbot gemme dialogens tilstand et sted (stateful derfor); Hvad er den nemmeste måde at gøre dette på i en serverløs funktion? For det tredje, hvordan kan du skrive en hurtig og beskidt færdighed til Alice eller endda en slags bot med et plot uden nul? Artiklen handler i virkeligheden om disse nuancer.

Oprettelse af en stateful færdighed for Alice ved hjælp af serverløse funktioner i Yandex.Cloud og Python

Moralsk forberedelse

Til de utålmodige: Jeg samler de nødvendige afhængigheder med en make-fil, før jeg uploader funktionen til skyen, jeg gemmer dialogens tilstand i Yandex Object Storage (den understøtter S3 API), og jeg bruger mit eget bibliotek til at styre dialogen tgalice. Til sidst viser det sig sådan demo færdighed. Lad os nu se på alt dette lidt mere detaljeret.

For de lidt mindre utålmodige, før du dykker ned i min historie om kompleksitet, anbefaler jeg stærkt at starte med noget simpelt. Nemlig, opret en enkelt-fil echobot-funktion, registrer og test den i Dialogs udviklerkonsol; detaljer - i Dialoger blog и Cloud dokumentation. Og først derefter starte.

Hvis du straks vil mærke, hvad vi kæmper for her, så spørg Alice 'aktivere færdigheden "IT-horoskop".'. En dialog svarende til følgende bør forekomme:

Alice: Hej! Du er i "IT Horoskop" færdigheden. Sig "Start" for at finde ud af, hvad stjernerne lover dig.
Bruger: Start
A: Angiv venligst dit navn
Yu: Vasisualiy
A: Fortæl mig nu dit fødselsår. Kun fire cifre, intet ekstra.
Yu: andet
A: Prøv venligst igen. Indtast dit fødselsår - fire cifre.
Yu: 2002
En stor! Navngiv nu din fødselsmåned.
Yu: februar
En stor! Fortæl mig endelig din fødselsdato - bare et tal, kun et eller to cifre.
Yu: 18
A: Tak, Vasisualiy! Nu ved vi: du er 17 år og vandmand. Nå, selvfølgelig er du heldig! Stjernerne fortæller dig: а что говорят звёзды, вы узнаете, запустив навык.

Problemet er, at for at opretholde selv en så simpel dialog, skal du huske brugerens navn og fødselsdato, og i et serverløst funktionsmiljø er dette ikke-trivielt. Det vil ikke være muligt at gemme konteksten i RAM eller som en fil på disk, pga Yandex.Cloud kan køre en funktion på flere virtuelle maskiner på samme tid og skifte mellem dem efter behag. Du bliver nødt til at bruge en form for ekstern lagring. Object Storage blev valgt som et ret billigt og ukompliceret lager direkte i Yandex.Cloud (dvs. sandsynligvis hurtigt). Som et gratis alternativ kan du prøve fx et gratis stykke Overskyet Monga et sted langt væk. Der er praktiske Python-indpakninger til både Object Storage (som understøtter S3-grænsefladen) og Mongo.

Et andet problem er, at for at få adgang til Object Storage, MongoDB og enhver anden database eller datalager, har du brug for nogle eksterne afhængigheder, der skal uploades til Yandex Functions sammen med din funktionskode. Og det vil jeg gerne gøre bekvemt. Desværre vil det ikke være helt praktisk (som på Heroku), men en vis grundlæggende komfort kan skabes ved at skrive et script til at bygge miljøet (lave fil).

Sådan starter du et horoskop

  1. Forbered dig: gå til en eller anden maskine med Linux. I princippet kan du sikkert også arbejde med Windows, men så skal du gøre noget magi med at starte makefilen. Og under alle omstændigheder skal du mindst have Python 3.6 installeret.
  2. Klon det fra Github eksempel på horoskopfærdigheder.
  3. Tilmeld dig i Y.Cloud: https://cloud.yandex.ru
  4. Skab dig selv to spande i Objektopbevaring, kald dem ved et hvilket som helst navn {BUCKET NAME} и tgalice-test-cold-storage (dette andet navn er nu hårdkodet ind main.py mit eksempel). Den første bucket er kun nødvendig til implementering, den anden - til at gemme dialogtilstande.
  5. skabe servicekonto, giv ham en rolle editor, og få statiske legitimationsoplysninger for det {KEY ID} и {KEY VALUE} — vi vil bruge dem til at registrere status for dialogen. Alt dette er nødvendigt for at en funktion fra Ya.Cloud kan få adgang til lageret fra Ya.Cloud. En dag håber jeg, at autorisation bliver automatisk, men indtil videre er det sådan.
  6. (Valgfrit) installere kommandolinjegrænseflade yc. Du kan også oprette en funktion gennem webgrænsefladen, men CLI'en er god, fordi alle mulige innovationer dukker hurtigere op i den.
  7. Nu kan du faktisk forberede afhængighedssamlingen: kør den på kommandolinjen fra mappen med færdighedseksemplet make all. En masse biblioteker (for det meste, som normalt, unødvendige) vil blive installeret i mappen dist.
  8. Hæld i objektopbevaring i hånden (i spanden {BUCKET NAME}) arkiv opnået i det foregående trin dist.zip. Hvis det ønskes, kan du gøre dette fra kommandolinjen, for eksempel ved at bruge AWS CLI.
  9. Opret en serverløs funktion via webgrænsefladen eller ved hjælp af et hjælpeprogram yc. For værktøjet vil kommandoen se sådan ud:

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

Når du opretter en funktion manuelt, udfyldes alle parametre på samme måde.

Nu kan den funktion, du har oprettet, testes gennem udviklerkonsollen, og derefter kan færdigheden forbedres og publiceres.

Oprettelse af en stateful færdighed for Alice ved hjælp af serverløse funktioner i Yandex.Cloud og Python

Hvad er der under motorhjelmen

Makefilen indeholder faktisk et ret simpelt script til at installere afhængigheder og lægge dem i et arkiv dist.zip, cirka sådan her:

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 ./*

Resten er et par enkle værktøjer pakket ind i et bibliotek tgalice. Processen med at udfylde brugerdata er beskrevet af konfigurationen 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: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

Arbejdet med at parse denne konfiguration og beregne det endelige resultat overtages af Python-klassen

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

Mere præcist, basisklassen FormFillingDialogManager beskæftiger sig med udfyldelse af "skemaet", og barneklassemetoden handle_completed_form fortæller hende, hvad hun skal gøre, når hun er klar.

Ud over denne hovedstrøm af dialog, skal brugeren også hilses, samt få hjælp ved hjælp af "hjælp"-kommandoen og frigivet fra færdigheden ved hjælp af "exit"-kommandoen. Til dette formål i tgalice Der er også en skabelon, så hele dialogmanageren består af stykker:

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 Det fungerer enkelt: det forsøger at anvende alle dets komponenter til den aktuelle tilstand af dialogen på skift og vælger den første passende.

Dialogmanageren returnerer et Python-objekt som et svar på hver besked. Response, som så kan konverteres til almindelig tekst eller til en besked i Alice eller Telegram - afhængigt af hvor botten kører; den indeholder også den ændrede tilstand af dialogen, der skal gemmes. Hele dette køkken varetages af en anden klasse, DialogConnector, så det direkte script til at starte en færdighed på Yandex Functions ser sådan ud:

...
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

Som du kan se, skaber det meste af denne kode en forbindelse til S3-grænsefladen i Object Storage. Du kan læse, hvordan denne forbindelse bruges direkte i tgalice kode.
Den sidste linje opretter funktionen alice_handler — den samme, som vi fortalte Yandex.Cloud at trække, når vi indstillede parameteren --entrypoint=main.alice_handler.

Det er alt, faktisk. Make-filer til assemblering, S3-lignende objektlagring til lagring af kontekst og et Python-bibliotek tgalice. Kombineret med Pythons serverløse funktioner og udtryksevne er dette nok til at udvikle en sund menneskelig færdighed.

Du kan spørge, hvorfor det var nødvendigt at oprette tgalice? Al den kedelige kode, der overfører JSON'er fra anmodning til svar og fra lager til hukommelse og tilbage, ligger i den. Der er også en almindelig kodeapplikation, en funktion til at forstå, at "februar" ligner "februar", og andre NLU for de fattige. Ifølge min idé skulle dette allerede være nok, så du kan skitsere prototyper af færdigheder i yaml-filer uden at blive for distraheret af tekniske detaljer.

Hvis du vil have en mere seriøs NLU, kan du knytte den til din færdighed Rasa eller DeepPavlov, men opsætning af dem vil kræve yderligere danse med en tamburin, især på serverløs. Hvis du slet ikke har lyst til at kode, bør du bruge en visuel konstruktør som Aimylogic. Da jeg oprettede tgalice, tænkte jeg på en form for mellemvej. Lad os se, hvad der kommer ud af dette.

Nå, vær med nu alice færdighedsudvikler chat, Læs dokumentation, og skabe vidunderlige færdigheder!

Kilde: www.habr.com

Tilføj en kommentar