LoginSignup
6
6

More than 3 years have passed since last update.

Watson AssistantからIBM Cloud functionsを使う時の考慮点

Last updated at Posted at 2018-10-17

初めに

本記事は、開発相談会#4 : IBM CloudFunction/Laravelでのディスカッション内容です。

サンプルアプリケーションについて

こちらで作成した、LaravelとWatson Assistantを連携したアプリケーションを使って検証をしています。
ソースコードはGithubで公開しています。

Watson AssistantからIBM Cloud Functionsを使うには…

使うだけであれば簡単です。
[公式のドキュメント](https://cloud.ibm.com/docs/assistant?topic=assistant-dialog-webhooksの力を借りることで、かなり簡単にWatson AssistantからIBM Cloud Functionsを使うことが出来るようになりました。

実際に使ってみると…

ただ、実際にユーザーアプリケーションからWatson Assistantを呼び出すにあたって、疑問:question:ポイントがありました。

IBM Cloud Functionsのキーを持たせる場所

IBM Cloud Functionsを呼び出す際には、credentialsというパラメータで、userpasswordを渡す必要があります。

下記の様に実際に呼び出すNodeでAPIキーを設定して呼び出すこともできますが、公式ドキュメントにも記載がある通り、コンテキストの一部として資格情報を渡すのが正解のようです。

資格情報を保護するために、資格情報は Watson Assistant ワークスペースに保管しないでください。
代わりに、コンテキストの一部としてクライアント・アプリケーションから渡してください。
メッセージ・コンテキストの $private セクション内にコンテキスト変数をネストすると、
この情報が Watson ログに保管されることを防止できます (例: `$private.my_credentials`)。

(contextをNodeで直接設定する方法)←本番でこれはNG:no_good:

{
  "context": {
    "private": {
      "my_credentials": {
        "user": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  },
  "output": {
    "generic": [
      {
        "values": [
          {
            "text": "どこの天気を知りたいですか?"
          }
        ],
        "response_type": "text",
        "selection_policy": "sequential"
      }
    ]
  }
}

IBM Cloud Functionsを呼び出すNodeの書き方

{
  "output": {
    "generic": [
      {
        "values": [
          {
            "text": ""
          }
        ],
        "response_type": "text",
        "selection_policy": "sequential"
      }
    ]
  },
  "actions": [
    {
      "name": "/enomotuProject_testSpace/getWeather",
      "type": "server",
      "parameters": {
        "location": "$repeat"
      },
      "credentials": "$private.my_credentials",
      "result_variable": "context.weather"
    }
  ]
}

PHPから呼び出すときのSample

<?php
namespace App\Services;

use GuzzleHttp\Client;

class CallWatsonAssistant{
    /**
     * Watson Assistantを呼び出すモジュール
     *
     * @param string $spokenWord ユーザーが入力した文字列
     * @param array $context watson assistantのcontextデータ
     * @return json Watson AssistantをCallした結果
     */
    public function call(string $spokenWord,array $context)
    {
        $context["private"] = ["my_credentials" => 
            [
                //ここは環境変数から取得
                "user"     => config('watson.icf_user'),
                "password" => config('watson.icf_password')
            ]
        ];

        $requestData  = json_encode(['input'=>['text'=>$spokenWord],'context'=>$context]);
        $headers = ['Content-Type' => 'application/json','Content-Length' => strlen($requestData)];
        $curlOpts = [
            CURLOPT_USERPWD        => config('watson.user_name').':'.config('watson.password'),
            CURLOPT_POSTFIELDS     => $requestData
        ];
        $path         = config('watson.workspace_id') . '/message?version=2018-07-10';
        $guzzleClient = new Client(['base_uri'=>'https://gateway-fra.watsonplatform.net/assistant/api/v1/workspaces/']);
        return $guzzleClient->request('POST',$path,['headers'=> $headers,'curl'=>$curlOpts])->getBody()->getContents();
    }
}

ただ、このままですとREST APIのレスポンスにIBM Cloud FunctionsのcontextにAPIキーが埋め込まれてしまう(下図参照)のでWebアプリから使う時には何らかの工夫が必要だと思います。
Request.png

私は下記の様にprivatecontextをクリアするNodeを持たせて、全てのNodeの最後はここにJump toするようにしています。
ただ、必ずJumptoを仕込む手間が面倒なのと、このJump toを忘れた時にAPIキーが外に出る恐れがあるので、より良い方法を模索中です:sweat_smile:
CleaCredentials.png

エラーハンドリングはどうするか?

何も判定していない状態では、ありえない住所を入力した場合に下記のようになってしまします。
5.PNG

ただ、実際のWebアプリケーションに返る値は正常値で、上記の例ですと「ほげほげの天気は」で文章が止まったままとなってしましまいます。
理想は「入力された地域が見つかりません」となることだと思いますが、このエラーハンドリングも掘り下げて考える必要があります。

CASE1 資格情報などが誤っており呼び出しに失敗する。

この場合は、公式ドキュメントにある通り、contextcloud_functions_call_errorが設定されます。
この時にはエラー内容をNodeに返してしまっても良いかもしれません。
ErrorSample1.PNG

CASE2 呼び出し自体には成功したがICF側でエラーとなった場合

様々な原因が考えられますが、可能な限りでIBM Cloud Function側でエラーの原因やメッセージなどをセットして返せると良いのでは、と思います。
というのも、ICF側で502等のステータスとなった場合には、returnしたcontextにはerrorという値のみが入ってくることになる為です。
ここも気を付ける点になりそうです。

おまけと宣伝

上記とは無関係ですが、勉強会の当日にはIBM様や@tokidaさんからIBM Cloud Functionに関する興味深い話を聞くことが出来ました。
箇条書きではありますが、IBM Cloud Functionsについて下記のメリットについて細かく聞くことが出来ました。

  1. 応答時間はCloud Foundryとほぼ同じ応答時間です!
  2. IBM Cloud FunctionsのSLAは99.95%です!
  3. dockerを使えばどのような言語でもサービスでも実装OK
  4. 必ずしもマイクロサービス的な使い方をする必要はない…が、1つのFunctionは60sまでしか動かないので注意。
  5. 最初からLog Analysysサービスと統合されているのですぐにログ管理ができる!
  6. 今のシステムの隙間を埋めるような使い方が可能。
    Apache Open Whiskはログ管理機能がない(IBM Cloud Functionsの優位性はここにある)

IBM Cloudを使ってみたい(もしくは実際に使った)けど、どう使ったらよいか分からない!という方は、是非、相談会に遊びに来てください。
次回の開催情報はこちらです。

6
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6