Een stateful vaardigheid creëren voor Alice met behulp van serverloze functies van Yandex.Cloud en Python

Laten we beginnen met het nieuws. Gisteren kondigde Yandex.Cloud de lancering aan van een serverloze computerservice Yandex Cloud-functies. Dit betekent: jij schrijft alleen de code voor jouw dienst (bijvoorbeeld een webapplicatie of een chatbot), en de Cloud creëert en onderhoudt zelf de virtuele machines waarop deze draait, en repliceert deze zelfs als de belasting toeneemt. Je hoeft helemaal niet na te denken, het is erg handig. En de betaling geldt alleen voor de rekentijd.

Sommigen betalen echter misschien helemaal niet. Dit zijn de ontwikkelaars De externe vaardigheden van Alice, dat wil zeggen, chatbots die erin zijn ingebouwd. Elke ontwikkelaar kan zo'n vaardigheid schrijven, hosten en registreren, en vanaf vandaag hoeven de vaardigheden niet eens meer gehost te worden - upload gewoon de code naar de cloud in het formulier dezelfde serverloze functie.

Maar er zijn een paar nuances. Ten eerste vereist uw pitcode mogelijk enkele afhankelijkheden, en het slepen ervan naar de cloud is niet triviaal. Ten tweede moet elke normale chatbot de status van de dialoog ergens opslaan (dus stateful); Wat is de gemakkelijkste manier om dit te doen in een serverloze functie? Ten derde: hoe kun je een quick-and-dirty-vaardigheid voor Alice schrijven, of zelfs een soort bot met een plot dat niet nul is? Het artikel gaat in feite over deze nuances.

Een stateful vaardigheid creëren voor Alice met behulp van serverloze functies van Yandex.Cloud en Python

Morele voorbereiding

Voor de ongeduldigen: ik verzamel de nodige afhankelijkheden met een makefile voordat ik de functie naar de cloud upload, ik sla de status van het dialoogvenster op in Yandex Object Storage (het ondersteunt de S3 API) en ik gebruik mijn eigen bibliotheek om het dialoogvenster te beheren tgalice. Uiteindelijk blijkt het dergelijk demo-vaardigheid. Laten we dit alles nu wat gedetailleerder bekijken.

Voor degenen die wat minder ongeduldig zijn, raad ik je ten zeerste aan om, voordat je in mijn verhaal over complexiteit duikt, met iets eenvoudigs te beginnen. Maak namelijk een echobot-functie met één bestand, registreer en test deze in de Dialogs-ontwikkelaarsconsole; details - in Dialogenblog и Cloud-documentatie. En pas dan beginnen.

Als je meteen wilt voelen waar we hier voor strijden, vraag het dan aan Alice'schakel de vaardigheid “IT-horoscoop” in'. Er zou een dialoog moeten plaatsvinden die lijkt op de volgende:

Alice: Hallo! Je beheerst de vaardigheid “IT Horoscoop”. Zeg 'Start' om erachter te komen wat de sterren je beloven.
Gebruiker: Begin
Antwoord: Gelieve uw naam te vermelden
Yu: Vasualiy
A: Vertel mij nu uw geboortejaar. Slechts vier cijfers, niets extra's.
Yu: tweede
A: Probeer het opnieuw. Voer het geboortejaar in (vier cijfers).
Ja: 2002
Een geweldige! Noem nu uw geboortemaand.
Yu: Februari
Een geweldige! Vertel me ten slotte je geboortedatum - slechts een getal, slechts een of twee cijfers.
Ja: 18
A: Bedankt, Vasisualiy! Nu weten we het: je bent 17 jaar oud en een Waterman. Nou ja, natuurlijk heb je geluk! De sterren vertellen je: а что говорят звёзды, вы узнаете, запустив навык.

Het probleem is dat je, om zelfs maar zo'n eenvoudige dialoog te kunnen voeren, de naam en geboortedatum van de gebruiker moet onthouden, en in een serverloze functieomgeving is dit niet triviaal. Het zal niet mogelijk zijn om de context in RAM of als bestand op schijf op te slaan, omdat Yandex.Cloud kan een functie tegelijkertijd op meerdere virtuele machines uitvoeren en naar wens tussen deze machines schakelen. Je zult een soort externe opslag moeten gebruiken. Objectopslag werd gekozen als een redelijk goedkope en ongecompliceerde opslag rechtstreeks in Yandex.Cloud (dat wil zeggen waarschijnlijk snel). Als gratis alternatief kun je bijvoorbeeld een gratis stukje proberen Bewolkt Monga ergens ver weg. Er zijn handige Python-wrappers voor zowel Object Storage (die de S3-interface ondersteunt) als Mongo.

Een ander probleem is dat je voor toegang tot Object Storage, MongoDB en elke andere database of gegevensopslag een aantal externe afhankelijkheden nodig hebt die samen met je functiecode naar Yandex Functions moeten worden geüpload. En ik wil dit graag gemakkelijk doen. Helaas zal het niet helemaal handig zijn (zoals op Heroku), maar wat basiscomfort kan worden gecreëerd door een script te schrijven om de omgeving te bouwen (bestand maken).

Hoe je een horoscoopvaardigheid start

  1. Bereid je voor: ga naar een machine met Linux. In principe kun je waarschijnlijk ook met Windows werken, maar dan zul je wat magie moeten doen met het starten van het makefile. En in ieder geval moet je minimaal Python 3.6 geïnstalleerd hebben.
  2. Kloon het vanuit Github voorbeeld van horoscoopvaardigheid.
  3. Registreren in Y.Cloud: https://cloud.yandex.ru
  4. Schep voor jezelf twee emmers in Object Opslag, noem ze bij welke naam dan ook {BUCKET NAME} и tgalice-test-cold-storage (deze tweede naam is nu hardgecodeerd main.py mijn voorbeeld). De eerste bucket is alleen nodig voor implementatie, de tweede om dialoogstatussen op te slaan.
  5. Creëren servicerekening, geef hem een ​​rol editoren verkrijg er statische referenties voor {KEY ID} и {KEY VALUE} – we zullen ze gebruiken om de stand van de dialoog vast te leggen. Dit alles is nodig zodat een functie van Ya.Cloud toegang kan krijgen tot de opslag van Ya.Cloud. Ik hoop dat autorisatie op een dag automatisch zal worden, maar voorlopig is het zo.
  6. (Optioneel) installeren opdrachtregelinterface yc. Je kunt ook via de webinterface een functie aanmaken, maar de CLI is goed omdat daarin sneller allerlei innovaties verschijnen.
  7. Nu kunt u de afhankelijkheidsassemblage daadwerkelijk voorbereiden: voer deze uit op de opdrachtregel vanuit de map met het vaardigheidsvoorbeeld make all. Een aantal bibliotheken (meestal, zoals gewoonlijk, onnodig) zullen in de map worden geïnstalleerd dist.
  8. Giet het met de hand in de objectopslag (in de emmer). {BUCKET NAME}) archief verkregen in de vorige stap dist.zip. Indien gewenst kunt u dit vanaf de opdrachtregel doen, bijvoorbeeld met behulp van AWS CLI.
  9. Creëer een serverloze functie via de webinterface of met behulp van een hulpprogramma yc. Voor het hulpprogramma ziet de opdracht er als volgt uit:

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

Wanneer u handmatig een functie aanmaakt, worden alle parameters op dezelfde manier ingevuld.

Nu kan de functie die u hebt gemaakt worden getest via de ontwikkelaarsconsole, en vervolgens kan de vaardigheid worden verbeterd en gepubliceerd.

Een stateful vaardigheid creëren voor Alice met behulp van serverloze functies van Yandex.Cloud en Python

Wat zit er onder de motorkap

De makefile bevat eigenlijk een vrij eenvoudig script voor het installeren van afhankelijkheden en het plaatsen ervan in een archief dist.zip, ongeveer zo:

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

De rest bestaat uit een paar eenvoudige hulpmiddelen, verpakt in een bibliotheek tgalice. Het proces van het invullen van gebruikersgegevens wordt beschreven door de config 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: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

Het werk van het parseren van deze configuratie en het berekenen van het eindresultaat wordt overgenomen door de Python-klasse

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

Om precies te zijn, de basisklasse FormFillingDialogManager behandelt het invullen van het “formulier” en de kindklassemethode handle_completed_form vertelt haar wat ze moet doen als ze er klaar voor is.

Naast deze hoofdstroom van dialoog moet de gebruiker ook worden begroet, hulp krijgen met het commando “help” en van de vaardigheid worden losgelaten met het commando “exit”. Voor dit doel in tgalice Er is ook een sjabloon, dus de hele dialoogmanager bestaat uit delen:

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 Het werkt eenvoudig: het probeert al zijn componenten beurtelings toe te passen op de huidige staat van de dialoog en selecteert de eerste geschikte.

De dialoogmanager retourneert een Python-object als antwoord op elk bericht. Response, die vervolgens kan worden omgezet in platte tekst, of in een bericht in Alice of Telegram - afhankelijk van waar de bot draait; het bevat ook de gewijzigde staat van de dialoog die moet worden bewaard. Deze hele keuken wordt afgehandeld door een andere klas, DialogConnector, dus het directe script voor het starten van een vaardigheid op Yandex Functions ziet er als volgt uit:

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

Zoals u kunt zien, creëert het grootste deel van deze code een verbinding met de S3-interface van Object Storage. Hoe deze verbinding direct wordt gebruikt, leest u hier in tgalice-code.
De laatste regel maakt de functie alice_handler – dezelfde die we Yandex.Cloud vertelden om te trekken toen we de parameter instelden --entrypoint=main.alice_handler.

Dat is eigenlijk alles. Makefiles voor montage, S3-achtige Object Storage voor het opslaan van context en een Python-bibliotheek tgalice. Gecombineerd met de serverloze functies en expressiviteit van Python is dit voldoende om een ​​gezonde menselijke vaardigheid te ontwikkelen.

Je kunt je afvragen waarom het nodig was om te creëren tgalice? Alle saaie code die JSON's overbrengt van verzoek naar antwoord en van opslag naar geheugen en terug, zit erin. Er is ook een reguliere codetoepassing, een functie om te begrijpen dat "Februari" vergelijkbaar is met "Februari", en andere NLU voor de armen. Volgens mijn idee zou dit al voldoende moeten zijn, zodat je prototypes van vaardigheden in yaml-bestanden kunt schetsen zonder al te veel afgeleid te worden door technische details.

Als je een serieuzere NLU wilt, kun je deze aan je vaardigheden koppelen Rasa of Diep Pavlov, maar voor het opzetten ervan zijn extra dansen met een tamboerijn nodig, vooral op serverless. Als je helemaal geen zin hebt om te coderen, moet je een visuele constructor zoals amylogic. Bij het maken van tgalice dacht ik aan een soort tussenpad. Laten we kijken wat hiervan komt.

Nou, doe dan mee Alice Skills-ontwikkelaarchat, lezen de documentatie, en creëer prachtig vaardigheden!

Bron: www.habr.com

Voeg een reactie