在 Yandex.Cloud 和 Python 的無服務器功能上為 Alice 創建有狀態技能

我們先從新聞說起。 昨天 Yandex.Cloud 宣布推出無服務器計算服務 Yandex 雲功能。 這意味著:您只需編寫服務的代碼(例如,Web 應用程序或聊天機器人),雲本身會在其運行的地方創建和維護虛擬機,甚至在負載增加時復制它們。 你根本不用考慮,非常方便。 並且付款僅適用於計算時間。

然而,有些人可能根本不付錢。 這些是開發商 愛麗絲的外在技能,即內置的聊天機器人。 任何開發人員都可以編寫、託管和註冊這樣的技能,從今天開始,技能甚至不需要託管——只需以以下形式將他們的代碼上傳到雲端即可 相同的無服務器功能.

但有一些細微差別。 首先,您的寵物代碼可能需要一些依賴項,將它們拖到雲中並不是一件容易的事。 其次,任何正常的聊天機器人都需要將對話的狀態存儲在某處(因此是有狀態的); 如何以最簡單的方式在無服務器功能中做到這一點? 第三,如何為 Alice 甚至某種具有非零情節的機器人編寫快速而骯髒的技能? 關於這些細微差別,其實有文章。

在 Yandex.Cloud 和 Python 的無服務器功能上為 Alice 創建有狀態技能

道德準備

對於不耐煩的人:我在將函數上傳到雲之前使用 makefile 收集必要的依賴項,將對話框的狀態存儲在 Yandex 對象存儲中(它支持 S3 API),並使用我自己的庫來管理對話框 特加利斯。 結果發現 這樣 演示技能。 現在讓我們更詳細地分析這一切。

對於不太耐心的人,在深入研究我的複雜故事之前,我強烈建議從簡單的開始。 即創建一個單文件echobot函數,在Dialog開發者控制台中註冊並測試; 詳細信息 - 在 博客對話 и 雲文檔。 然後才開始。

如果你想立即感受到我們為何而戰,就去問愛麗絲吧。開啟技能“IT占星”'。 應進行以下對話:

愛麗絲:你好! 您處於“IT 占星”技能中。 說“開始”,看看星星向您承諾了什麼。
用戶:開始
答:請說出您的姓名。
於:瓦西蘇利
A:現在告訴我你的出生年份。 只有四位數,僅此而已。
於:第二
答:請再試一次。 註明您的出生年份 - 四位數。
於:2002年
一個了不起的! 現在說出您的出生月份。
於:二月
一個了不起的! 最後,告訴我你的出生日期——只是一個數字,只是一兩位數字。
於:18年
答:謝謝你,瓦西蘇爾! 現在我們知道:你今年17歲,你是水瓶座。 當然,你很幸運! 星星告訴你 а что говорят звёзды, вы узнаете, запустив навык.

問題是,即使要維護這樣一個簡單的對話框,您也需要記住用戶的姓名和出生日期,而在無服務器環境中,這並不是一件小事。 將上下文存儲在 RAM 中或作為磁盤上的文件是行不通的,因為Yandex.Cloud可以同時在多個虛擬機上運行該功能,並在它們之間任意切換。 您必須使用某種外部存儲。 對象存儲被選為直接在 Yandex.Cloud 中相當便宜且簡單的存儲(也就是說,可能很快)。 作為免費的替代方案,您可以嘗試例如免費的作品 多雲蒙吉 在很遠的某個地方。 對象存儲(支持 S3 接口)和 Mongo 都有方便的 Python 包裝器。

另一個問題是,為了訪問對象存儲、MongoDB 和任何其他數據庫或數據存儲,您需要一些外部依賴項,您需要將這些依賴項與函數代碼一起上傳到 Yandex Functions。 我想舒服地做這件事。 它非常方便(就像在heroku上一樣),可惜它不起作用,但是您可以通過編寫腳本來構建環境(make文件)來創建一些基本的舒適感。

如何開始占星技能

  1. 準備好:轉到裝有 Linux 的機器。 原則上,您也可以使用 Windows,但是您必須啟動 makefile。 無論如何,您至少需要安裝 3.6 版本的 Python。
  2. 從 github 克隆 占星技能的例子.
  3. 在Ya.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。 您還可以通過 Web 界面創建函數,但 CLI 很好,因為各種創新都可以更快地出現在其中。
  7. 事實上,現在您可以準備依賴項的組裝:從包含技能示例的文件夾中在命令行上運行 make all。 一堆庫(大部分是不必要的)將安裝在該文件夾中 dist.
  8. 將筆填充到對象存儲中(放入桶中 {BUCKET NAME}) 上一步獲得的存檔 dist.zip。 如果需要,您還可以從命令行執行此操作,例如使用 命令行界面.
  9. 通過 Web 界面或使用實用程序創建無服務器函數 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

手動創建函數時,所有參數都以相同的方式填充。

現在您創建的功能可以通過開發者控制台進行測試,然後最終確定並發布技能。

在 Yandex.Cloud 和 Python 的無服務器功能上為 Alice 創建有狀態技能

引擎蓋下有什麼

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。 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: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

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 告訴她準備好後該做什麼。

除了這個主要的對話流程之外,還必須向用戶打招呼,並在“幫助”命令上提供幫助,並在“退出”命令上釋放技能。 為此在 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 Functions 上啟動技能的直接腳本如下所示:

...
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 接口的連接。 這個連接是如何直接使用的,可以閱讀 在 tgalice 代碼中.
最後一行創建一個函數 alice_handler - 我們在設置參數時命令拉取 Yandex.Cloud 的那個 --entrypoint=main.alice_handler.

事實上,僅此而已。 用於構建的 Makefile、用於上下文存儲的類似 S3 的對象存儲以及一個 Python 庫 tgalice。 再加上Python的無服務器特性和表現力,這足以培養一個健康人的技能。

您可能會問為什麼需要創建 tgalice? 所有將 JSON 從請求傳輸到響應、從存儲傳輸到內存並返回的無聊代碼都在其中。 還有一個常規應用程序,一個用於理解“二月”與“二月”類似的功能,以及其他針對窮人的 NLU。 按照我的想法,這應該已經足夠能夠在 yaml 文件中勾勒出技能原型,而不會被技術細節過多分散注意力。

如果你想要更嚴肅的 NLU,你可以將其運用到你的技能中 Rasa深巴甫洛夫,但設置它們需要額外用手鼓跳舞,尤其是在無服務器上。 如果您根本不想編碼,您應該使用視覺類型構造函數 愛美樂。 在創建 tgalice 時,我想到了某種中間路徑。 讓我們看看發生了什麼。

嗯,現在加入 Aliy技能開發者聊天, 讀 文件並創造出令人驚嘆的 技能!

來源: www.habr.com

添加評論