Watson Assistantの新しいプラン「Plus」と月次ユーザー数課金(MCU)導入のご紹介

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/a783d51c-84a7-c67d-3c0a-d25625e85216.png)

# TL;DR

- 2018/11/28にWatson Assistantに[**Plusプラン**が追加](https://console.bluemix.net/docs/services/assistant/release-notes.html#release-notes)されました
    - Plusプランでは、今までPremiumプランでないと使えなかった機能がお得に使えます
    - (2019/2/13) Plusプランの30日間トライアルも利用可能になっています
- **PlusとPremium**の課金の考え方が**Monthly Conversing User (MCU) metric**に変更されました。従来はAPI Call数での課金でしたが、MCUでは「月当りに実際に会話したユーザーの数」での課金になります
    - １ユーザーは月に何回会話しても(=APIをコールしても)1ユーザーとしてカウントされます
    - ユニーク・ユーザーを識別するために、API要求時にUSERIDをセットしていただく必要があります
    - 結果的にMCUに対応するために若干の**アプリ変更が必要になる場合**がありますのでご注意ください 
- :triangular_flag_on_post:  (2020/04/02) **2020/4/1からPlusプランの最小ユーザー数が10,000→1,000に引き下げ！1,000ユーザー/120USD・月よりお使いいただけます！** 価格が[カタログ](https://cloud.ibm.com/catalog/services/watson-assistant)に掲載され、**セルフサービスで購入できるようになった**ので、当記事も併せてアップデートしました。

# はじめに
こんにちわ！石田です。Watson Assistantの[Release Note](https://console.bluemix.net/docs/services/assistant/release-notes.html#release-notes)によると、2018/11/28付けで以下の2点が発表されました。

- **Plusプランの追加**
- **Monthly Conversing User (MCU)ベースの課金体系**

課金の話はQiitaにそぐわないのは承知しておりますが、新しいプランの利点を享受するためにはプログラムに手を入れる必要がありそうなので、そのへんを技術記事として書きます。（プラン＝契約やお金にからむ話なので、以下は個人的な理解=非公式情報とご認識ください. 万が一間違ってても責任とれないんで　:sweat_smile:)

~~:triangular_flag_on_post: (2018/12/06更新) [Release Note](https://console.bluemix.net/docs/services/assistant/release-notes.html#release-notes)によると、2018/12/01付でDialogノードの上限数がLiteプラン=100、Standard=500に**引き下げられました**。新しい制限に抵触される場合は半年の移行猶予期間があります。くわしくは[Release Note](https://console.bluemix.net/docs/services/assistant/release-notes.html#release-notes)をご参照ください。~~
:triangular_flag_on_post: (2018/12/18更新) 上記Dialog数の上限Standard=500の上限が撤回されたようです。（ヨカッタ。。:relieved:）[Release Note](https://console.bluemix.net/docs/services/assistant/release-notes.html#release-notes)から記述が削除されています。よってスタンダードプランは100,000のまま、無償のライトプランは250,000→100に引き下げとなりました。くわしくは[こちら](https://console.bluemix.net/docs/services/assistant/dialog-build.html#dialog-node-limits)を。
:triangular_flag_on_post: (2019/2/13更新) **Plusプランの30日間トライアルが可能**になりました。現時点では基本、IBM担当者経由でのリクエストですが、近々セルフサービスでお試しいただけるよう準備中、とのこと。ご興味があるお客様はぜひ営業担当者にお声かけください。[こちらの記事](https://medium.com/ibm-watson/build-an-assistant-that-your-users-will-actually-want-to-use-49f1c0bdf6a1)もどうぞ。

# Plusプランって何?

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108535/faa4114d-5116-2790-a0f3-fe0839dc2655.png)

すでにAssistantのカタログにPlusプランの記載があります。プランと価格は[こちら](https://cloud.ibm.com/catalog/services/watson-assistant)にて。要は1,000ユーザーあたり120USD/月と非常にリーズナブルになってます。

ちなみに[Watson Assistant Pricing](https://www.ibm.com/cloud/watson-assistant/pricing/)のページには各プラン別の機能比較があります。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108535/7a2d5762-0726-fc96-0554-936ef23f5296.png)

その他営業面で聞いてる話では以下（あくまでご参考。正確には営業担当者まで）
- １つの発注で開発・テスト・本番の３つのインスタンスが用意されます
- ロケーションはデータセンターを指定できます。ただし上記３つは同じ場所である必要があります
- 課金は本番に対してのみ、です

## Plusプランが出てきた背景(Why)

聞いてる話では以下です。

- 環境を共有するスタンダード・プランと環境を占有するPremiumプランの間に価格差がありすぎる
- API Call数による課金はお客様からみると、「事前にどのくらい使うものか」の見積もりが難しい/予算上限を超えたら困る、などのご不安がある→ユーザー数でカウントすればAPI Call数よりは予測しやすい
- Premiumプラン限定の最新機能が増えてきた。この辺の利点をもっとお得に使ってもらいたい

上記のような背景から**①ユーザー数ベースの課金体系　②従来、Premiumプラン限定だった機能をリーズナブルに使えるようにする**　プランとしてPlusプランができたようです。

## Plusプランで使えるようになる上位機能( What )

カタログ上、現時点では下記３つが記載されています。

| 機能 | ドキュメントへのリンク | 私の記事での簡単な紹介 |その他|
|:---|:---:|:---:|:---|
| Disambiguation | [Link](https://console.bluemix.net/docs/services/assistant/dialog-runtime.html#disambiguation) | [Link](https://qiita.com/ishida330/items/ae7277598cd3e08fc3a2#crown-pluspremium%E9%99%90%E5%AE%9A--disambiguation) |  |
| Intent Recommendations | [Link](https://console.bluemix.net/docs/services/assistant/intents.html#intent-recommendations) | [Link](https://qiita.com/ishida330/items/ae7277598cd3e08fc3a2#crown-pluspremium%E9%99%90%E5%AE%9A--intent-recommendations) | Beta / :us: 英語のみ |
| Intent Conflict Detection | [Link](https://console.bluemix.net/docs/services/assistant/intents.html#conflict-intents) | [Link](https://qiita.com/ishida330/items/ae7277598cd3e08fc3a2#crown-pluspremium%E9%99%90%E5%AE%9A-intent-conflict-resolution) |  |


## 課金の考え方は？MCUって何？( How Much )

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/a783d51c-84a7-c67d-3c0a-d25625e85216.png)

今後作られるインスタンスでのPlusとPremiumの課金は**Monthly Conversing User (MCU)**ベースになります。(Liteとスタンダードは従来とおりのAPI Call数で変わりません。)

ドキュメントの「[user-based plans](https://console.bluemix.net/docs/services/assistant/services-information.html#user-based-plans)」に以下の記載があります。

>They measure usage by the number of unique users who interacted with the assistant during a specified timeframe.
(一定の期間内にアシスタントと対話をしたユニークなユーザーの数をもって利用を計測する)

つまりMCUとは「その月に**実際にWatson Assistantと対話をした識別可能な（ユニークな）ユーザー数**」をベースにした課金です。事前に「対話するかもしれないユーザーの見込み数」で契約するのではなく、実際に対話した実績数を測定します。

上記を計測するためにはWatson Assistant側で各ユーザーを一意に識別できる必要があります。そのために、アプリケーションが発行するAPIの中で「誰からのリクエストか」=アプリ側で何らかのユニークなユーザーIDをセットしていただくのが基本・推奨となります。(後述しますがユーザーIDのセットは「おススメ」ですが「オプション」であって「必須」ではありません。平たく言えば「何度もAPI呼ぶときに、ユーザーIDで紐つけしておけば、１ユーザーとカウントしてくれる。そうでない場合は暗黙ユーザーと認識し、その場合は各々が別ユーザーと認識されるため、集計カウント時にユーザー数が実際より多くカウントされ、損をする」だけです。具体的なセット方法は後述します。)

以下、図を使ってご説明します。
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/bcd32a36-af01-9161-29f3-9a2782192ad7.png)
【前提】
:one:　ユーザーAさんのWatson Assistantとの対話状況を１ケ月の期間で考えます
:two:   それらは複数回の対話からなるものでしょう。(例:対話=機器修理の相談、なんらかの質問など）
:three: 各々の対話は一連のやりとり=複数回の/message API Callからなるものでしょう

つまり月あたりで 「Aさん(USERID):対話=1:M」「１つの対話:API Call=1:N」という関係です。この状況で

- API利用時にアプリでお約束とおりにAさんのUSERIDを**セットした上で**会話する(:one:)のであれば、実績の集計時には一連の会話は同一ユーザー=Aさんのものと判別できます。その場合、Aさんが当月に1回会話しても、100回会話しても1ユーザー=1MCUと数えます(同一ユーザーで利用頻度が高い場合は、お得ですね）
- とはいえ一般消費者や匿名ユーザーからの利用などユニークなユーザーIDを決められない(Anonymousな)場合もあるでしょう。その場合はユーザーIDをセットしなくても結構です。ただしその場合は一回の会話(:two:)を１MCUと数えます。    
    - 要はUSERIDを**セットせずに**利用した場合は暗黙ユーザー扱いとなり、会話の都度、1MCUと数えます。実体として同じAさんであっても、月に3回会話したら3MCU=3人分とカウントされます。
- 上記の「会話」(:two:)はアプリケーションのAPI利用時のContext情報でConversaion_ID(V1)やSessionID(V2)をきちんと使っている場合に適用される集計ルールです。(以下、例外的かなとも思いますが) V1 APIでContextを使っていないコーディングをされている場合は、/messageの都度、異なるConversaion_IDが生成されます＝集計時に一連の会話が別のものと認識されてしまうので、/messageの実行数だけMCUがカウントされてしまいます。

## Plusプラン vs Standardプラン(私見)

Plusプランはユーザー課金でありStandardプランはAPI Call数課金です。ユーザー数や１ユーザー当りのAPI Call数などにより損得が変わると思いますので一概に「どちらが得」とはいえませんし、無理に移行する必要もないのですが、**長期的にはPlusプラン推し**なのかな、とは思います。

- 当然ながら、ユーザー数や利用頻度が極端に少ない場合などは従来型のStandard プランのほうが（0.2525円×n回Callで済むので）お安く済むでしょう
- サーチスキル(Discovery統合)など、今後の機能追加の予定でPlusプラン以上のみのものもあるので、最新の便利機能を求めるならPlusプランでしょう
- ~~Plusプランは最低10,000ユーザーからなので「結構高いのかな」と思われるかもしれませんが、（Qiitaには価格は書きませんが）10,000ユーザー分でも驚くようなお値段ではありません。社内向けのアプリなど「10,000ユーザーもいないからな～」と躊躇されたなら、営業担当者に価格を聞いてみることをお勧めします。~~
- (2020/04/02) Plusプランは最低1,000ユーザーからになりました。

|  | Standardプラン | Plusプラン|
|:---|:---:|:---:|
| 課金の単位 | API Call数/月| MCU |
| 価格 | 0.0025USD/API Call | 120USD/1000 Auth.User/Month |
| 最低要件| なし| 1,000ユーザー分～ |
| スキル数上限　| 20 | 50 | 
| Dialogノード数[^2]　| 500 | 100,000 |

[^2]: 2018/012/1のリリースによると、Dialogノード数の上限がLite=100、Standard=500に変更になってます。半年の凍結期間があるので、もし上記制限に抵触する場合は2019/6/1までに上位プランへの移行もしくはアプリ分割などの対応をお願いします。上記期限を越えるとノードに追加が一切できなくなるそうです。

# アプリでMCUに対応するには？( How )

以上、Plusプランのユーザー課金の利点を享受してお得に使うなら、アプリケーション側でのユーザーIDのセットなどの対応が必要なことをご説明してきました。ここからは具体的にコーディグについてご紹介します。(Pythonで書きますが他の言語でも同じです）

## サマリー
:blue_book: [User-based plans](https://console.bluemix.net/docs/services/assistant/services-information.html#plans)をサマリーします。説明がややこしいのでフローチャートにしました。

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/bde277f8-9ab5-790a-a0b0-1270db137e91.png)

先般、記事「[Watson Assistant API V1/V2の違い](https://qiita.com/ishida330/items/6dcdb664e4724e27764d)」でご紹介したのですが、現在Watson AssistantはV1とV2の２種類のAPIがあります。そのどちらを使うか（現在使っているか）で対応内容が変わってきます。

:one: :two: 業務的に各利用者にユニークなユーザーIDを割り当てられる場合は、/messageのContext=でV1/V2各々のAPI Referenceで指定されているデータ項目をセットすればいいだけです[^1]

[^1]: 単なる思考実験/ネタですが、仮に全リクエストで同一のユーザーIDを設定した場合、「１ユーザー分」で済むのでしょうかネ。。。まあ最小が1,000ユーザー分ですし、遵法精神に則った紳士淑女である皆様はそんなことはしないとは思いますけれど。。:smile:

:three: :four: ユーザーIDが設定されていないので、１回の会話を一人の(暗黙)ユーザーとして扱います。各々の「会話」はV1 APIではConversation_IDで識別できます。このConversation_IDは会話の開始時にWatson Assistantから割振られContextにセットされてアプリケーションに渡ってきます。V1のAPIでは一連の/message呼び出し時にContextを受け取り（必要なら中身を更新し）次回の/message呼び出しでWatson AssistantにContextを送り返すのはユーザー・アプリケーションの責任です。アプリケーションがConxextの中にセットされたConversation_IDを変更せずに再度送信してくれているなら、Watson Assistantはそれらのやりとりを1暗黙ユーザーと認識してくれます。( :three: の場合) ここでややこしい話ですが、が、Context=の利用自体は厳密にはオプション(任意）です。通常は一連の流れで会話するのでContextを使っているはずです。とはいえ**レアケースでしょうが**、アプリケーションによってはContext=を一切使ってない可能性がありえます。(またはContext=自体は使っているがConversation_IDを意図せず潰してしまっているケースもあるでしょう）( :four: の場合) その場合は毎回の/messageで異なるConversation_IDが生成されるので**/message実行の数だけ暗黙ユーザーがカウントされてしまう**ことになります。（要は、レアケースでしょうがお気をつけください、ということです）
:five: V2 APIの場合でもユーザーIDが設定されていなければ、１回の会話を一人の(暗黙)ユーザーとして扱います。各々の「会話」はV2 APIではSession_IDで識別します。
V2 APIにおいてはSessionの利用は必須であり、V1の :three: :four: の時のようなユーザーアプリのコードでのContext=指定有無による違いは発生しえません。普通にV2のお作法に沿ってコーディングしてあればオーケーです。


## :one: V1 APIでUSER_IDをセット
:blue_book: [V1 API Reference - /message](https://console.bluemix.net/apidocs/assistant#get-response-to-user-input)

/messageのContext=で以下をセットします
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/893827a6-211c-ca95-469d-40518cd1764e.png)

<details><summary>サンプル</summary><div>

```python
import json
from watson_developer_cloud import AssistantV1

iam_apikey = 'xxxxxxxx'
workspace_id = 'xxxxxxxx'
assistant = AssistantV1(
    iam_apikey=iam_apikey,
    version='2018-07-10')

my_context ={}
def message(input):
    response = assistant.message(
        workspace_id=workspace_id,
        input={'text': input},
        context=my_context
        ).get_result()
    print('{0}'.format('-'*30))
    #print(response)
    print(json.dumps(response, indent=2, ensure_ascii=False))
    return response

# user_idをセット
my_context["metadata"] = {'user_id': 'ishida330'}
# 当件と直接関係ないが名前が空白ではよくないのでユーザー変数をセット
my_context["myname"] = "ISHIDA"
response = message('')
# 受け取ったcontextを保管
my_context = response["context"]

response = message('hello')
response = message('thanks')
response = message('bye')

```
```json:response
------------------------------
{
  "intents": [],
  "entities": [],
  "input": {
    "text": ""
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "Hi, ISHIDA   . May I help you?"
      }
    ],
    "text": [
      "Hi, ISHIDA   . May I help you?"
    ],
    "nodes_visited": [
      "Opening"
    ],
    "log_messages": []
  },
  "context": {
    "metadata": {
      "user_id": "ishida330"
    },
    "myname": "ISHIDA",
    "conversation_id": "671fccd4-4312-402f-a3e6-7d149ba851fc",
    "system": {
      "initialized": true,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 1,
      "dialog_request_counter": 1,
      "_node_output_map": {
        "Opening": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "no_reservation": true
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "General_Greetings",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "hello"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "hello! Mr.ISHIDA "
      }
    ],
    "text": [
      "hello! Mr.ISHIDA "
    ],
    "nodes_visited": [
      "node_13_1502484041694"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "671fccd4-4312-402f-a3e6-7d149ba851fc",
    "system": {
      "initialized": true,
      "dialog_request_counter": 2,
      "dialog_turn_counter": 2,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "_node_output_map": {
        "Opening": [
          0
        ],
        "node_13_1502484041694": {
          "0": [
            0
          ]
        }
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "metadata": {
      "user_id": "ishida330"
    },
    "no_reservation": true,
    "myname": "ISHIDA"
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "Thanks",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "thanks"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "You're welcome, Mr.ISHIDA . Just let me know if you need anything else"
      }
    ],
    "text": [
      "You're welcome, Mr.ISHIDA . Just let me know if you need anything else"
    ],
    "nodes_visited": [
      "node_2_1468243505617"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "671fccd4-4312-402f-a3e6-7d149ba851fc",
    "system": {
      "initialized": true,
      "dialog_request_counter": 2,
      "dialog_turn_counter": 2,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "_node_output_map": {
        "Opening": [
          0
        ],
        "node_2_1468243505617": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "metadata": {
      "user_id": "ishida330"
    },
    "no_reservation": true,
    "myname": "ISHIDA"
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "Goodbye",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "bye"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "So long, Mr.ISHIDA "
      }
    ],
    "text": [
      "So long, Mr.ISHIDA "
    ],
    "nodes_visited": [
      "node_12_1468329566917"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "671fccd4-4312-402f-a3e6-7d149ba851fc",
    "system": {
      "initialized": true,
      "dialog_request_counter": 2,
      "dialog_turn_counter": 2,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "_node_output_map": {
        "Opening": [
          0
        ],
        "node_12_1468329566917": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "metadata": {
      "user_id": "ishida330"
    },
    "no_reservation": true,
    "myname": "ISHIDA"
  }
}

```
</div></details>

## :two: V2 APIでUSER_IDをセット
:blue_book: [V2 API Reference - /message](https://console.bluemix.net/apidocs/assistant-v2#send-user-input-to-assistant)
/messageのContext=で以下をセットします
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/68b772bf-274a-bac1-e28c-ba20aef04370.png)

<details><summary>サンプル</summary><div>

```python
import json
from watson_developer_cloud import AssistantV2

assistant_id = 'xxxxxxxx'
iam_apikey='xxxxxxxx',

assistant = AssistantV2(
    iam_apikey=iam_apikey,
    version='2018-11-08')
session_id = assistant.create_session(assistant_id).get_result()
print(json.dumps(session_id, indent=2))
#########################
# Message
#########################
my_context={}
def message(session_id, input):

    response = assistant.message(
        assistant_id,
        session_id,
        input={'text': input,
            'options': {'return_context': True}
        },
        context=my_context
        ).get_result()
    print('{0}'.format('-'*30))
    print(json.dumps(response, indent=2, ensure_ascii=False))
    return response

# user_idをセット
my_context.update({"global":{"system":{"user_id":"ishida330"}}})
# 当件とは直接関係ないが名前が空白ではよくないのでユーザー変数をセット
my_context.update({"skills":{"main skill":{"user_defined":{"myname":"ISHIDA"}}}})

print(json.dumps(my_context, indent=2, ensure_ascii=False))
response = message(session_id["session_id"],"")
response = message(session_id["session_id"],"hello")
response = message(session_id["session_id"],"thanks")
response = message(session_id["session_id"],"bye")

assistant.delete_session(assistant_id, session_id["session_id"]).get_result()

```

```json:response
{
  "session_id": "bc9f0306-c7fa-4d37-ad40-4e83c48d7c51"
}
{
  "global": {
    "system": {
      "user_id": "ishida330"
    }
  },
  "skills": {
    "main skill": {
      "user_defined": {
        "myname": "ISHIDA"
      }
    }
  }
}
------------------------------
{
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "Hi, ISHIDA   . May I help you?"
      }
    ],
    "intents": [],
    "entities": []
  },
  "context": {
    "global": {
      "system": {
        "turn_count": 1,
        "user_id": "ishida330"
      }
    },
    "skills": {
      "main skill": {
        "user_defined": {
          "myname": "ISHIDA",
          "no_reservation": true
        }
      }
    }
  }
}
------------------------------
{
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "hello! Mr.ISHIDA "
      }
    ],
    "intents": [
      {
        "intent": "General_Greetings",
        "confidence": 1
      }
    ],
    "entities": []
  },
  "context": {
    "global": {
      "system": {
        "turn_count": 2,
        "user_id": "ishida330"
      }
    },
    "skills": {
      "main skill": {
        "user_defined": {
          "myname": "ISHIDA",
          "no_reservation": true
        }
      }
    }
  }
}
------------------------------
{
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "You're welcome, Mr.ISHIDA . Just let me know if you need anything else"
      }
    ],
    "intents": [
      {
        "intent": "Thanks",
        "confidence": 1
      }
    ],
    "entities": []
  },
  "context": {
    "global": {
      "system": {
        "turn_count": 3,
        "user_id": "ishida330"
      }
    },
    "skills": {
      "main skill": {
        "user_defined": {
          "myname": "ISHIDA",
          "no_reservation": true
        }
      }
    }
  }
}
------------------------------
{
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "So long, Mr.ISHIDA "
      }
    ],
    "intents": [
      {
        "intent": "Goodbye",
        "confidence": 1
      }
    ],
    "entities": []
  },
  "context": {
    "global": {
      "system": {
        "turn_count": 4,
        "user_id": "ishida330"
      }
    },
    "skills": {
      "main skill": {
        "user_defined": {
          "myname": "ISHIDA",
          "no_reservation": true
        }
      }
    }
  }
}

```

</div></details>


## :three: V1 APIでユーザーIDはセットしないがContext=を利用

Conversaion_IDは会話の開始時にContextの先頭にセットされてアプリケーションに渡ってきます。V1 APIではこれを保管して毎回送り返してください。

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/2303d7ae-2c60-85ed-033b-4f5a4b448619.png)

<details><summary>サンプル</summary><div>

```python
import json
from watson_developer_cloud import AssistantV1

iam_apikey = 'xxxxxxxx'
workspace_id = 'xxxxxxxx'
assistant = AssistantV1(
    iam_apikey=iam_apikey,
    version='2018-07-10')

my_context ={}
def message(input):
    response = assistant.message(
        workspace_id=workspace_id,
        input={'text': input},
        context=my_context
        ).get_result()
    print('{0}'.format('-'*30))
    #print(response)
    print(json.dumps(response, indent=2, ensure_ascii=False))
    return response

# user_idをセット
my_context["metadata"] = {'user_id': 'ishida330'}
# 当件と直接関係ないが名前が空白ではよくないのでユーザー変数をセット
my_context["myname"] = "ISHIDA"
response = message('')
# 受け取ったcontextを保管
my_context = response["context"]

response = message('hello')
response = message('thanks')
response = message('bye')
```

```json:response
------------------------------
{
  "intents": [],
  "entities": [],
  "input": {
    "text": ""
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "Hi, ISHIDA   . May I help you?"
      }
    ],
    "text": [
      "Hi, ISHIDA   . May I help you?"
    ],
    "nodes_visited": [
      "Opening"
    ],
    "log_messages": []
  },
  "context": {
    "metadata": {
      "user_id": "ishida330"
    },
    "myname": "ISHIDA",
    "conversation_id": "26cc8c22-a904-46bc-b843-37aa1e4660ff",
    "system": {
      "initialized": true,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 1,
      "dialog_request_counter": 1,
      "_node_output_map": {
        "Opening": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "no_reservation": true
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "General_Greetings",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "hello"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "hello! Mr.ISHIDA "
      }
    ],
    "text": [
      "hello! Mr.ISHIDA "
    ],
    "nodes_visited": [
      "node_13_1502484041694"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "26cc8c22-a904-46bc-b843-37aa1e4660ff",
    "system": {
      "initialized": true,
      "_node_output_map": {
        "Opening": [
          0
        ],
        "node_13_1502484041694": {
          "0": [
            0
          ]
        }
      },
      "dialog_turn_counter": 2,
      "dialog_request_counter": 2,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "no_reservation": true,
    "metadata": {
      "user_id": "ishida330"
    },
    "myname": "ISHIDA"
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "Thanks",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "thanks"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "You're welcome, Mr.ISHIDA . Just let me know if you need anything else"
      }
    ],
    "text": [
      "You're welcome, Mr.ISHIDA . Just let me know if you need anything else"
    ],
    "nodes_visited": [
      "node_2_1468243505617"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "26cc8c22-a904-46bc-b843-37aa1e4660ff",
    "system": {
      "initialized": true,
      "_node_output_map": {
        "Opening": [
          0
        ],
        "node_2_1468243505617": [
          0
        ]
      },
      "dialog_turn_counter": 2,
      "dialog_request_counter": 2,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "no_reservation": true,
    "metadata": {
      "user_id": "ishida330"
    },
    "myname": "ISHIDA"
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "Goodbye",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "bye"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "So long, Mr.ISHIDA "
      }
    ],
    "text": [
      "So long, Mr.ISHIDA "
    ],
    "nodes_visited": [
      "node_12_1468329566917"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "26cc8c22-a904-46bc-b843-37aa1e4660ff",
    "system": {
      "initialized": true,
      "_node_output_map": {
        "Opening": [
          0
        ],
        "node_12_1468329566917": [
          0
        ]
      },
      "dialog_turn_counter": 2,
      "dialog_request_counter": 2,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "no_reservation": true,
    "metadata": {
      "user_id": "ishida330"
    },
    "myname": "ISHIDA"
  }
}
```


</div></details>


## :four: V1 APIでユーザーIDはセットせずContext=を利用していない

非常にレアケースかと思いますが、この場合は会話の開始時に渡ってくるContextを毎回捨てているわけです。この場合は「一連の会話」になりませんので、「一問一答」型のアプリになります。

<details><summary>サンプル</summary><div>


```python
import json
from watson_developer_cloud import AssistantV1

iam_apikey = 'xxxxxxxx'
workspace_id = 'xxxxxxxx'
assistant = AssistantV1(
    iam_apikey=iam_apikey,
    version='2018-07-10')

my_context={}
def message(input):
    response = assistant.message(
        workspace_id=workspace_id,
        input={'text': input}
        ).get_result()
    print('{0}'.format('-'*30))
    #print(response)
    print(json.dumps(response, indent=2, ensure_ascii=False))
    return response

# 当件と直接関係ないが名前が空白ではよくないのでユーザー変数をセット
my_context["myname"] = "ISHIDA"
response = message('')
response = message('hello')
response = message('thanks')
response = message('bye')

```
:warning:  conversation_idが/messageを呼ぶ都度、変わっている点にご注目ください

```json
------------------------------
{
  "intents": [],
  "entities": [],
  "input": {
    "text": ""
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "Hi,    . May I help you?"
      }
    ],
    "text": [
      "Hi,    . May I help you?"
    ],
    "nodes_visited": [
      "Opening"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "51a53ff7-2b51-44ef-bf9a-47a72cdfcf3f",
    "system": {
      "initialized": true,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 1,
      "dialog_request_counter": 1,
      "_node_output_map": {
        "Opening": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "no_reservation": true
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "General_Greetings",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "hello"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "hello! Mr. "
      }
    ],
    "text": [
      "hello! Mr. "
    ],
    "nodes_visited": [
      "node_13_1502484041694"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "9e8ad600-0879-4065-9898-82dff5c19d58",
    "system": {
      "initialized": true,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 1,
      "dialog_request_counter": 1,
      "_node_output_map": {
        "node_13_1502484041694": {
          "0": [
            0
          ]
        }
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    }
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "Thanks",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "thanks"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "You're welcome, Mr. . Just let me know if you need anything else"
      }
    ],
    "text": [
      "You're welcome, Mr. . Just let me know if you need anything else"
    ],
    "nodes_visited": [
      "node_2_1468243505617"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "3f73bb8c-e7c2-4d64-a4e5-6be6eb6c4aa9",
    "system": {
      "initialized": true,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 1,
      "dialog_request_counter": 1,
      "_node_output_map": {
        "node_2_1468243505617": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    }
  }
}
------------------------------
{
  "intents": [
    {
      "intent": "Goodbye",
      "confidence": 1
    }
  ],
  "entities": [],
  "input": {
    "text": "bye"
  },
  "output": {
    "generic": [
      {
        "response_type": "text",
        "text": "So long, Mr. "
      }
    ],
    "text": [
      "So long, Mr. "
    ],
    "nodes_visited": [
      "node_12_1468329566917"
    ],
    "log_messages": []
  },
  "context": {
    "conversation_id": "878083b5-0e47-4283-ae38-a8000f462371",
    "system": {
      "initialized": true,
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 1,
      "dialog_request_counter": 1,
      "_node_output_map": {
        "node_12_1468329566917": [
          0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    }
  }
}

```

</div></details>


## :five: V2 APIでUSER_IDをセットしない

この場合は普通にSession単位で暗黙ユーザーとして扱われます。
サンプルコードは[こちら](https://qiita.com/ishida330/items/6dcdb664e4724e27764d#v2%E3%81%AE%E6%99%82)と同じです。


以上です。いますぐの移行は無いにしても、色々な魅力のあるPlusプランをぜひご検討くださいませ。