Alexaスキル開発をはじめた人がハマりがちなこと

投稿者: | 2018年12月8日

この記事はFujitsu Advent Calendar 2018の8日目のエントリーです。
まずは恒例のお約束を。本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。…仕事にできたら面白いんですけど、まだまだです。

はじめに

自分は今年2018年の8月から趣味のAlexaスキル開発をはじめ、現在2本のスキルを公開中です。開発をはじめて約4カ月間でハマったことを振り返って、まとめてみます。なお、以下はすべてAlexaスキル開発ではスタンダードな、Node.jsとLambdaの組み合わせについての記載となります。

また、2018/12/5開催の勉強会「SIerIoTLT vol.13」の登壇資料は、本記事から一部抜粋して作成しました。

SDKの選択

Node.js用SDKは現在V2が最新ですが、まだV1とV2の両方が開発に使われていると思われます。V1とV2は大まかにいうと下記の様な特徴があります。


実装パターンSDKのサイズサポート
V1シンプル新機能実装は保証されない
V2効率的大(機能限定版有)最新

V2は標準SDKのサイズが大きく、そのままではLambdaのインラインエディタでの開発ができません。開発はローカルPCで行ない、ソースとSDK一式をzipファイル化してLambdaにアップロードする必要がありました。そのため、スキルを構成する基本的な要素を学ぶような入門にはインラインエディタが使えるV1が向いていると考えていました。

しかし、先日のAWS re:Inventでリリースされた「Lambda Layer」を使い、SDKのようなモジュールをプログラム本体と別に管理することで、プログラム本体の編集にインラインエディタが使えるようになりました。すでにクラスメソッドさんで検証記事が公開されています。今後は入門時からV2を使うのが良さそうです。

8秒ルール

公式の「スマートホームスキルAPIのメッセージリファレンス」によれば、ユーザーが発話しAlexa音声サービスからLambda関数へリクエストが発行されてから8秒以内に、何らかのレスポンスをAlexa音声サービスへ返す必要があります。これがいわゆる「8秒ルール」です。8秒ルールにはリクエストやレスポンス自体の通信時間も含まれるため、Lambda関数自体には6~7秒でタイムアウトするように設定し、超過した場合はエラーが発行されるようにしています。

ただ、処理自体が重い、外部APIのレスポンス時間の上限が7秒を超えるといった場合があります。こういった場合は、その処理を別のLambda関数として定義して子プロセスとして実行(invoke)し、処理終了までは「時間がかかっています、続けますか?」などと場を繋ぐ必要があります。

また、外部APIのレスポンス自体は高速でも、リトライを考慮しないといけない場合は、タイムアウト時間とリトライ回数を調整する必要があります。

Alexa音声サービスの仕様

ビルトインスロットはユーザーの発話を正規化しLambda関数に渡してくれる便利な仕組みです。ですが、実装上の制約がツライときがあります。例えば、AMAZON.NUMBER では負の数を取得できません。そのため符号のスロットを定義し、組み合わせて使うことになります。

スロットの定義例

ところでこのAMAZON.NUMBER、仕様上「ゼロ(〇、零)」を認識できるはずなのですが、自分で発話しても開発コンソールのテストツールで手入力しても認識されないのはなぜだろう?(謎)

これに限らず、音声認識と音声合成を司るAlexa音声サービスは内部で常に改善がされているようで、認識結果や精度が突然変わったりします。そのため、一度リリースしたスキルも時々確認が必要です。

データ永続化の罠

サーバレス型サービスであるLambdaは、クライアント接続においてセッション管理を行いません。しかし実装上で困らないよう、AlexaのSDKにはデータ永続化の仕組みが2つ用意されています。

セッションの間だけ保持されるのがSession Attributeです。Alexa音声サービスとLambda関数の間でやりとりするリクエスト/レスポンスメッセージのJSONファイルにデータを埋め込み、持ち続けることで実現しています。

セッションが切れてもデータが保持されるのがPersistant Attributeです。これはAWSのNoSQL型データベースDynamoDBをAlexaのSDKから呼びだして使えるようになっています。異なるクライアント間でデータが参照できないなど、開発者にとって使いやすい形で提供されています。が、ここに一つ罠、というか仕様上の落とし穴があります。

DynamoDBのテーブル生成には10秒前後の時間がかかります。テーブル生成を行った直後、テーブル参照用オブジェクトを生成するgetPersistanceAttribute関数を呼びだした場合にnullを返却してくれればいいのですが、この関数は一見正常な(でも実在しない)オブジェクトを返してきます。そのため、それを使って保存したデータを参照しようとした瞬間、エラーで落ちます。同じプログラムでも2回目以降の実行ではテーブルの生成が行われないため、エラーは発生しません。非常にわかりにくいです。

結論、テーブル生成のリードタイムを想定して実装なりフローなりで回避するしかありません。おそらくAWS開発者にとっては常識なのでしょう、世にある様々なサンプル(例:こことか)でも、この点には触れられていないのがほとんどです。

スキル公開申請のコツ

スキル内の発話内容や公開申請時の説明文などでは「スキル」と「アプリ」を区別することが大切です。Echoなどで動作するアプリケーション本体が「スキル」、Android/iOSのスマホにインストールしているのが「アプリ」です。ですが、審査員によってはこの違いを分かっておらず、おかしなNGを出される場合があるので注意が必要です。この場合は、コメントなりで説明を頑張るしかありません。

また当然ですが、申請時のテスト手順はなるべく詳しく書く方が良いです。以下は、実際の申請でリジェクト原因となったものです。

  1. インテントを付けて呼び出してもスキル名での起動と同じになる場合:すなわち「(呼び出し名)を開いて、○○して」と発話しても「○○して」の動作を行なわず、意図的に「(呼び出し名)を開いて」と同じ動作としている場合。この場合、テスト手順に「初期化に時間がかかる」などの理由を添えた上で「あえてそのような動作にしている」旨を明記します。
  2. 書籍の表紙画像など著作物を利用する場合:この場合、利用許諾がされている旨をURLなど添えて明記します。

また、申請内容によっては実装での注意が必要です。例えば所在地の国コードを取得するような実装を含むと、仮に申請時にスキル公開国を「日本のみ」としても、テストでは様々の国でスキルを利用されることを想定したテストが実施されます。そのため、実装上で「日本」以外の国コードが来た場合の処理を記述しておく必要があります。

外部APIは仕様変更に気を付けろ

Alexaスキルの機能を充実させるためには外部APIとの連携は必須です。ただ、外部サービスである以上Alexaのサービスとは無関係に変更されることがあり、スキル公開後もずっと注意しておく必要があります。

自分の場合、Amazon.co.jpのアフィリエイト用API(Product Advertising API)を使っているのですが、スキル公開後に利用規約が変更され、呼び出し回数の制限が厳しくなってしまいました。変更前は10~0.1回/秒だったのが、変更後は10~0回/秒となり、最悪の場合はスキルが全く動作しなくなる可能性が出ています。同じアマゾンなんだからお目こぼししてほしい所ですが難しそうなので、別のAPIを探すことになりそうです。

おわりに

色々と書きましたが、現在スマートスピーカー関連で日本語ドキュメントが広く揃っているのはAmazon Alexaです(LINE Clovaも充実してます)。決済機能が提供されたり、UXの自由度も増したりとキャッチアップが大変ですが、これからも引き続きスキル開発を楽しんで行きたいと思います。

おまけ:自作スキルへのリンクです。ご興味のある方はどうぞ↓

みんなの図書館」公立図書館蔵書の貸出状況を調べられます。

イコールテン!」ワーキングメモリを鍛える系の暗算ゲーム。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください