การสร้างทักษะ stateful สำหรับ Alice บนฟังก์ชันไร้เซิร์ฟเวอร์ของ Yandex.Cloud และ Python

เริ่มจากข่าวกันก่อน เมื่อวานนี้ Yandex.Cloud ประกาศเปิดตัวบริการคอมพิวเตอร์แบบไร้เซิร์ฟเวอร์ ฟังก์ชั่นยานเดกซ์คลาวด์. ซึ่งหมายความว่า: คุณเขียนโค้ดสำหรับบริการของคุณเท่านั้น (เช่น เว็บแอปพลิเคชันหรือแชทบอท) และคลาวด์เองก็สร้างและบำรุงรักษาเครื่องเสมือนที่มันทำงานอยู่ และแม้แต่จำลองพวกมันหากโหลดเพิ่มขึ้น ไม่ต้องคิดเลย สะดวกมาก และการชำระเงินเป็นเพียงเวลาคำนวณเท่านั้น

แต่บางคนอาจจะไม่จ่ายเลย เหล่านี้คือนักพัฒนา ทักษะภายนอกของอลิซนั่นคือมีแชทบอทติดตั้งอยู่ภายใน นักพัฒนาคนใดก็ตามสามารถเขียน โฮสต์ และลงทะเบียนทักษะดังกล่าวได้ และตั้งแต่วันนี้ ทักษะดังกล่าวไม่จำเป็นต้องโฮสต์ด้วยซ้ำ เพียงอัปโหลดโค้ดของพวกเขาไปยังคลาวด์ในแบบฟอร์ม ฟังก์ชันไร้เซิร์ฟเวอร์เดียวกัน.

แต่มีความแตกต่างเล็กน้อย ประการแรก Pit Code ของคุณอาจต้องมีการขึ้นต่อกัน และการลากมันเข้าไปในคลาวด์นั้นไม่ใช่เรื่องเล็กน้อย ประการที่สอง แชทบอตปกติใดๆ จำเป็นต้องจัดเก็บสถานะของบทสนทนาไว้ที่ไหนสักแห่ง (ดังนั้นจึงมีสถานะ); วิธีที่ง่ายที่สุดในการทำเช่นนี้ในฟังก์ชันไร้เซิร์ฟเวอร์คืออะไร ประการที่สาม คุณจะเขียนทักษะที่รวดเร็วและสกปรกให้กับอลิซหรือแม้แต่บอทบางประเภทที่มีพล็อตเรื่องที่ไม่เป็นศูนย์ได้อย่างไร? บทความนี้เกี่ยวกับความแตกต่างเหล่านี้จริงๆ

การสร้างทักษะ stateful สำหรับ Alice บนฟังก์ชันไร้เซิร์ฟเวอร์ของ Yandex.Cloud และ Python

การเตรียมคุณธรรม

สำหรับผู้ที่ใจร้อน: ฉันรวบรวมการขึ้นต่อกันที่จำเป็นด้วย makefile ก่อนที่จะอัปโหลดฟังก์ชันไปยังคลาวด์ ฉันจัดเก็บสถานะของกล่องโต้ตอบใน Yandex Object Storage (รองรับ S3 API) และฉันใช้ไลบรารีของตัวเองเพื่อจัดการกล่องโต้ตอบ ทากาลิซ. ในที่สุดปรากฎว่า เช่น ทักษะการสาธิต ทีนี้มาดูรายละเอียดทั้งหมดนี้กันดีกว่า

สำหรับผู้ที่ใจร้อนน้อยกว่าเล็กน้อย ก่อนที่จะเจาะลึกเรื่องราวของฉันเกี่ยวกับความซับซ้อน ฉันขอแนะนำให้เริ่มต้นด้วยสิ่งที่เรียบง่าย กล่าวคือ สร้างฟังก์ชัน echobot ไฟล์เดียว ลงทะเบียนและทดสอบในคอนโซลนักพัฒนา Dialogs รายละเอียด-เข้า บล็อกบทสนทนา и เอกสารเกี่ยวกับคลาวด์. และจากนั้นก็เริ่มต้น

หากคุณต้องการสัมผัสทันทีว่าเรากำลังต่อสู้เพื่ออะไรที่นี่ ถามอลิซ 'เปิดทักษะ “ดวงไอที”'. บทสนทนาที่คล้ายกับสิ่งต่อไปนี้ควรเกิดขึ้น:

อลิซ: สวัสดี! คุณอยู่ในทักษะ “ดวงไอที” พูดว่า "เริ่ม" เพื่อดูว่าดวงดาวสัญญาอะไรกับคุณ
ผู้ใช้: เริ่มต้น
ตอบ: กรุณาระบุชื่อของคุณ
ยู: วาซิซัวลี่
ตอบ: ตอนนี้บอกฉันปีเกิดของคุณ เพียงสี่หลักไม่มีอะไรพิเศษ
ยู: สอง
ตอบ: โปรดลองอีกครั้ง ป้อนปีเกิดของคุณ - ตัวเลขสี่หลัก
ยู: 2002
ดี! ตอนนี้ตั้งชื่อเดือนเกิดของคุณ
ยู: กุมภาพันธ์
ดี! สุดท้ายนี้ บอกวันเกิดของคุณมาให้ฉันหน่อย แค่ตัวเลข เพียงหนึ่งหรือสองหลักเท่านั้น
ยู: 18
ตอบ: ขอบคุณ Vasisualiy! ตอนนี้เรารู้แล้ว: คุณอายุ 17 ปีและเป็นชาวราศีกุมภ์ แน่นอนว่าคุณโชคดี! ดวงดาวบอกคุณว่า: а что говорят звёзды, вы узнаете, запустив навык.

ปัญหาคือเพื่อรักษาบทสนทนาง่ายๆ ไว้ คุณต้องจำชื่อผู้ใช้และวันเกิด และในสภาพแวดล้อมของฟังก์ชันไร้เซิร์ฟเวอร์ นี่ไม่ใช่เรื่องเล็กน้อย จะไม่สามารถจัดเก็บบริบทใน RAM หรือเป็นไฟล์บนดิสก์ได้เนื่องจาก Yandex.Cloud สามารถเรียกใช้ฟังก์ชันบนเครื่องเสมือนหลายเครื่องพร้อมกันและสลับระหว่างเครื่องเหล่านั้นได้ตามต้องการ คุณจะต้องใช้ที่จัดเก็บข้อมูลภายนอกบางประเภท Object Storage ได้รับเลือกให้เป็นพื้นที่เก็บข้อมูลที่ค่อนข้างถูกและไม่ซับซ้อนโดยตรงใน Yandex.Cloud (เช่น อาจเร็ว) เพื่อเป็นทางเลือกฟรี คุณสามารถลองชิ้นส่วนฟรีได้ เมฆมากมองก้า ที่ไหนสักแห่งที่ห่างไกล มีตัวห่อ Python ที่สะดวกสำหรับทั้ง Object Storage (รองรับอินเทอร์เฟซ S3) และ Mongo

ปัญหาอีกประการหนึ่งคือในการเข้าถึง Object Storage, MongoDB และฐานข้อมูลหรือที่เก็บข้อมูลอื่น ๆ คุณต้องมีการอ้างอิงภายนอกบางอย่างที่ต้องอัปโหลดไปยังฟังก์ชัน Yandex พร้อมกับโค้ดฟังก์ชันของคุณ และฉันก็อยากจะทำสิ่งนี้ตามสะดวก น่าเสียดายที่มันไม่สะดวกอย่างสมบูรณ์ (เช่น Heroku) แต่ความสะดวกสบายขั้นพื้นฐานบางอย่างสามารถสร้างขึ้นได้โดยการเขียนสคริปต์เพื่อสร้างสภาพแวดล้อม (สร้างไฟล์)

วิธีเปิดสกิลดูดวง

  1. เตรียมพร้อม: ไปที่เครื่องบางเครื่องที่ใช้ Linux โดยหลักการแล้ว คุณอาจทำงานกับ Windows ได้เช่นกัน แต่คุณจะต้องใช้เวทย์มนตร์บางอย่างในการเปิด makefile และไม่ว่าในกรณีใด คุณจะต้องติดตั้ง Python 3.6 เป็นอย่างน้อย
  2. โคลนมันจาก Github ตัวอย่างทักษะดูดวง.
  3. ลงทะเบียนใน Y.Cloud: https://cloud.yandex.ru
  4. สร้างถังสองใบให้กับตัวเอง การจัดเก็บวัตถุเรียกพวกเขาด้วยชื่อใดก็ได้ {BUCKET NAME} и tgalice-test-cold-storage (ชื่อที่สองนี้ถูกฮาร์ดโค้ดไว้แล้ว main.py ตัวอย่างของฉัน) ที่เก็บข้อมูลแรกจำเป็นสำหรับการปรับใช้เท่านั้น ส่วนที่สอง - เพื่อจัดเก็บสถานะกล่องโต้ตอบ
  5. สร้าง บัญชีบริการมอบบทบาทให้เขา editorและรับข้อมูลประจำตัวแบบคงที่ {KEY ID} и {KEY VALUE} — เราจะใช้เพื่อบันทึกสถานะของบทสนทนา ทั้งหมดนี้จำเป็นเพื่อให้ฟังก์ชันจาก Ya.Cloud สามารถเข้าถึงที่เก็บข้อมูลจาก Ya.Cloud ฉันหวังว่าสักวันหนึ่งการอนุญาตจะกลายเป็นแบบอัตโนมัติ แต่ตอนนี้มันเป็นอย่างนั้น
  6. (ไม่บังคับ) ติดตั้ง อินเตอร์เฟซบรรทัดคำสั่ง yc. คุณยังสามารถสร้างฟังก์ชันผ่านเว็บอินเตอร์เฟสได้ แต่ CLI นั้นดีเพราะนวัตกรรมทุกประเภทจะปรากฏเร็วขึ้น
  7. ตอนนี้คุณสามารถเตรียมแอสเซมบลีการพึ่งพาได้จริง: รันบนบรรทัดคำสั่งจากโฟลเดอร์พร้อมตัวอย่างทักษะ make all. ไลบรารีจำนวนมาก (ส่วนใหญ่ตามปกติไม่จำเป็น) จะถูกติดตั้งในโฟลเดอร์ dist.
  8. เทลงใน Object Storage ด้วยมือ (ลงในถัง {BUCKET NAME}) ไฟล์เก็บถาวรที่ได้รับในขั้นตอนก่อนหน้า dist.zip. หากต้องการ คุณสามารถทำได้จากบรรทัดคำสั่ง เช่น การใช้ AWS CLI.
  9. สร้างฟังก์ชันแบบไร้เซิร์ฟเวอร์ผ่านทางเว็บอินเตอร์เฟสหรือใช้ยูทิลิตี yc. สำหรับยูทิลิตี้ คำสั่งจะมีลักษณะดังนี้:

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

เมื่อสร้างฟังก์ชันด้วยตนเอง พารามิเตอร์ทั้งหมดจะถูกกรอกในลักษณะเดียวกัน

ขณะนี้คุณสามารถทดสอบฟังก์ชันที่คุณสร้างขึ้นได้ผ่านแผงควบคุมสำหรับนักพัฒนาซอฟต์แวร์ จากนั้นจึงปรับปรุงและเผยแพร่ทักษะได้

การสร้างทักษะ stateful สำหรับ Alice บนฟังก์ชันไร้เซิร์ฟเวอร์ของ Yandex.Cloud และ Python

อะไรอยู่ภายใต้ประทุน

จริงๆ แล้ว makefile มีสคริปต์ที่ค่อนข้างง่ายสำหรับการติดตั้งการขึ้นต่อกันและนำไปไว้ในไฟล์เก็บถาวร dist.zipประมาณนี้:

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

ที่เหลือคือเครื่องมือง่ายๆ สองสามอย่างที่รวมอยู่ในห้องสมุด tgalice. กระบวนการกรอกข้อมูลผู้ใช้อธิบายไว้ในการกำหนดค่า 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: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

งานแยกวิเคราะห์การกำหนดค่านี้และการคำนวณผลลัพธ์สุดท้ายถูกยึดครองโดยคลาส Python

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

คลาสพื้นฐานอย่างแม่นยำยิ่งขึ้น FormFillingDialogManager เกี่ยวข้องกับการกรอก "แบบฟอร์ม" และวิธีการเรียนคลาสย่อย handle_completed_form บอกเธอว่าต้องทำอะไรเมื่อเธอพร้อม

นอกเหนือจากบทสนทนาหลักนี้แล้ว ผู้ใช้ยังต้องได้รับการทักทาย ตลอดจนให้ความช่วยเหลือโดยใช้คำสั่ง "help" และออกจากทักษะโดยใช้คำสั่ง "exit" เพื่อจุดประสงค์นี้ใน tgalice นอกจากนี้ยังมีเทมเพลตด้วย ดังนั้นตัวจัดการกล่องโต้ตอบทั้งหมดจึงประกอบด้วยส่วนต่างๆ:

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 มันใช้งานได้ง่าย: พยายามนำส่วนประกอบทั้งหมดไปใช้กับสถานะปัจจุบันของบทสนทนาตามลำดับ และเลือกอันแรกที่เหมาะสม

ตัวจัดการไดอะล็อกส่งคืนอ็อบเจ็กต์ Python เป็นการตอบกลับแต่ละข้อความ Responseซึ่งสามารถแปลงเป็นข้อความธรรมดาหรือเป็นข้อความใน Alice หรือ Telegram - ขึ้นอยู่กับตำแหน่งที่บอททำงานอยู่ นอกจากนี้ยังมีสถานะที่เปลี่ยนแปลงของบทสนทนาที่ต้องบันทึก ห้องครัวทั้งหมดนี้ได้รับการจัดการโดยอีกชั้นเรียนหนึ่ง DialogConnectorดังนั้นสคริปต์โดยตรงสำหรับการเปิดตัวทักษะในฟังก์ชัน Yandex มีลักษณะดังนี้:

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

อย่างที่คุณเห็น โค้ดส่วนใหญ่นี้สร้างการเชื่อมต่อกับอินเทอร์เฟซ S3 ของ Object Storage คุณสามารถอ่านวิธีการใช้การเชื่อมต่อนี้โดยตรงได้ ในรหัส tgalice.
บรรทัดสุดท้ายสร้างฟังก์ชัน alice_handler — อันเดียวกับที่เราบอกให้ Yandex.Cloud ดึงเมื่อเราตั้งค่าพารามิเตอร์ --entrypoint=main.alice_handler.

นั่นคือทั้งหมดจริงๆ Makefiles สำหรับแอสเซมบลี, Object Storage ที่มีลักษณะคล้าย S3 สำหรับการจัดเก็บบริบท และไลบรารี Python tgalice. เมื่อรวมกับฟังก์ชันแบบไร้เซิร์ฟเวอร์และการแสดงออกของ Python ก็เพียงพอแล้วในการพัฒนาทักษะของมนุษย์ที่ดี

คุณอาจถามว่าทำไมถึงจำเป็นต้องสร้าง tgalice? โค้ดที่น่าเบื่อทั้งหมดที่ถ่ายโอน JSON จากคำขอไปยังการตอบกลับ และจากที่เก็บข้อมูลไปยังหน่วยความจำและด้านหลังอยู่ในนั้น นอกจากนี้ยังมีการใช้รหัสปกติ ฟังก์ชันทำความเข้าใจว่า "กุมภาพันธ์" คล้ายกับ "กุมภาพันธ์" และ NLU อื่นๆ สำหรับคนยากจน ตามความคิดของฉัน นี่น่าจะเพียงพอแล้วเพื่อให้คุณสามารถร่างต้นแบบทักษะในไฟล์ yaml ได้โดยไม่ต้องสนใจรายละเอียดทางเทคนิคมากเกินไป

หากคุณต้องการ NLU ที่จริงจังกว่านี้ คุณสามารถแนบไปกับทักษะของคุณได้ รสา หรือ ดีพพาฟลอฟแต่การตั้งค่าจะต้องมีการเต้นเพิ่มเติมด้วยแทมบูรีน โดยเฉพาะบนเซิร์ฟเวอร์ไร้เซิร์ฟเวอร์ หากคุณไม่อยากเขียนโค้ดเลย คุณควรใช้ Visual Constructor เช่น ไอมีโลจิก. เมื่อสร้าง tgalice ฉันคิดถึงเส้นทางกลางบางอย่าง มาดูกันว่ามีอะไรเกิดขึ้นบ้าง

เอาล่ะเข้าร่วมด้วย แชทนักพัฒนาทักษะอลิซ, อ่าน เอกสารและสร้างสิ่งมหัศจรรย์ ทักษะ!

ที่มา: will.com

เพิ่มความคิดเห็น