watsonx Assistant + Discovery + watsonx.ai 連携による生成系AIの活用（Granite日本語版）

[watsonx Assistant](https://www.ibm.com/jp-ja/products/watsonx-assistant)から[Watson Discovery](https://www.ibm.com/jp-ja/cloud/watson-discovery)に取り込まれたデータを検索して、[watsonx.ai](https://www.ibm.com/jp-ja/products/watsonx-ai)の生成AIで回答を作成する手順です。
2024年2月末にIBMから[Granite日本語版のLLM](https://jp.newsroom.ibm.com/2024-02-27-IBM-launches-Granite-Japanese-built-on-trusted-data-to-accelerate-Japanese-clients-adoption-of-generative-AI)が提供されたので、ここではGranite日本語版の利用手順を確認しました。

[watsonx Assistantのスターターキット](https://github.com/watson-developer-cloud/assistant-toolkit/tree/master/integrations/extensions/starter-kits/language-model-conversational-search#language-model-conversational-search-starter-kit)では、カスタム拡張機能を使用して外部 REST API にアクセスするために必要なテンプレートを提供しています。
ここではDiscoveryとwatsonx.aiのAPIを呼び出して、Assistantから生成AIを利用する手順を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/d036e67b-1ffe-d6e4-12f3-6e0ce697c485.png)


## Assistantの作成

最初に新しい空のアシスタントを作成します。
[新しい Watson Assistant](https://cloud.ibm.com/docs/watson-assistant?topic=watson-assistant-welcome-new-assistant)を使用する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/5d3b5500-330b-574a-2060-d8e712bbe270.png)
Assistant name: ここでは「watsonxx」としています。
Assistant language: スターターキットを利用するため、言語はEnglishを指定します。

## Discoveryカスタム拡張
Watson Assistant のカスタム拡張機能を使用して Watson Discovery で情報検索をした内容を利用します。
### Discoveryの情報を取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/32fb82ed-feac-b5cd-e2fa-930d678ad389.png)
Assistantのカスタム拡張でDiscoveryを利用する際にはDiscovery側の「**API鍵**」「**URL**」「**Project ID**」が必要です。
**API鍵**と**URL**はDiscoveryのリソース情報に表示される資格情報からコピーします。
**Project ID**はDiscoveryで検索対象のデータを取り込んであるプロジェクトを開き、Integrate and deploy の API Information の Project ID をコピーしておきます。

### Discoveryのカスタム拡張機能を作成

:::note info
**watson-discovery-query-openapi.json**ファイルを以下からダウンロードします
https://github.com/watson-developer-cloud/assistant-toolkit/blob/master/integrations/extensions/starter-kits/watson-discovery/watson-discovery-query-openapi.json
:::

東京リージョンを選択できるように、watson-discovery-query-openapi.json の servers に以下の行を箇所を追加して保存します。
```diff_json
"servers": [
+    {
+      "url": "https://jp-tok.ml.cloud.ibm.com",
+      "description": "watsonx.ai Tokyo"
+    },
    {
      "url": "https://us-south.ml.cloud.ibm.com",
      "description": "watsonx.ai v1-beta"
    }
  ],
```

モデルパラメーターのデコード(greedyかsampling)を選択できるようにする場合は以下も追加します
```diff_json
"parameters": {
  "type": "object",
    "properties": {
+      "decoding_method": {
+      "type": "string",
+      "description": "greedy か Sample を指定します",
+      "example": "sample"
+      },
```
Watson Assistant のメニューから「Integration」を選択
Extensionsにある「Build custom extension」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/dd0f1a13-37b9-91e0-667f-b713454a09b0.png)
- Assistant のメニューから[Integration]を選択
- Extensionsにある [Build custom extension] をクリック
- [Next]をクリック
- Extension name (例:Discovery) を入力して[Next]をクリック
- Import OpenAPIで、先ほど編集して保存した __"watson-discovery-query-openapi.json"__ を指定して[Next]をクリック
- [Finish] をクリック

### Discoveryカスタム拡張機能の追加
Watson Assistant のメニューから「Integration」を選択
Extensionsの前ページで作成したカタログ(Discovery)の[Add]をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/62a3d5fe-30aa-265c-3f89-7866c006b5cd.png)
- 作成したカタログDiscoveryの[Add]をクリック
- [Next]をクリック
- Extension name (例:Discovery) を入力して[Next]をクリック
- Discoveryの情報を入力
*Authentication type:* **Basic auth**
*Username:* **apikey**
*Password:* **[DiscoveryのAPI鍵]**
*discovery_url:* **[DiscoveryのURL]から"http://"を除いた値**
- [Next] をクリック
- [Finish] をクリック
- [Close] をクリック

## watsonx.aiカスタム拡張：
Watson Assistant のカスタム拡張機能を使用して watsonx の生成AIを利用できるようにします。
### IBM Cloudの情報を取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/b142c184-75a2-cb1c-142b-4f78b10a440b.png)
Assistantのカスタム拡張でwatsonx.aiを利用する際には、IBM Cloudの「APIキー」と、watsonx.aiの「プロジェクトID」が必要になります。
API鍵はこちらの記事[「IBM Cloud APIKEYの作成(取得)方法」](https://qiita.com/nishikyon/items/fa8b951267efbe911fe7)を参考に取得します。
プロジェクトIDはwatsonx.aiの画面からコピーをしておきます。

### watsonxのカスタム拡張機能を作成
:::note info
**watsonx-openapi.json**ファイルを以下からダウンロードします
https://github.com/watson-developer-cloud/assistant-toolkit/blob/master/integrations/extensions/starter-kits/language-model-watsonx/watsonx-openapi.json
:::
Watson Assistant のメニューから「Integration」を選択
Extensionsにある「Build custom extension」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/ed9814e8-2a0d-e3b3-0b00-5c81219cfc7f.png)
- Assistant のメニューから[Integration]を選択
- Extensionsにある [Build custom extension] をクリック
- [Next]をクリック
- Extension name (例:watsonx) を入力して[Next]をクリック
- Import OpenAPIで、"watsonx-openapi.json" を指定して[Next]をクリック
- [Finish] をクリック

### watsonカスタム拡張機能の追加
Watson Assistant のメニューから「Integration」を選択
Extensionsのカタログに追加されたwatsonxにある[Add]をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/7f45c4a5-3472-1946-55ad-c4131993b8d2.png)
- 作成したwatsonxの[Add]をクリック
- [Next]をクリック
- watsonx.aiの情報を入力
*Authentication type:* **Oauth 2.0**
*Grant type:* **Custom apikey**
*apikey:* **[取得済みのIBM Cloud API鍵]**
*Client authentication:* **Send as Body**
*Header prefix:* **Bearer**
*Servers:* __https://jp-tok.ml.cloud.ibm.com__（東京リージョン）
- [Next] をクリック
- [Finish] をクリック
- [Close] をクリック

## Assistant アクションの作成

:::note info
**discovery-watsonx-actions.json**ファイルを以下からダウンロードします
https://github.com/watson-developer-cloud/assistant-toolkit/blob/master/integrations/extensions/starter-kits/language-model-conversational-search/discovery-watsonx-actions.json
:::

Watson Assistant のメニューから「Actions」を選択
[Global settings]（右上の歯車マーク）をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/3cbe40e3-ca51-1e1c-5bf8-6e0430249468.png)
- Assistantの[Actions]をクリック
- [Global settings]をクリックして一番右の[Upload/Download]を選択
- Upload で、__"discovery-watsonx-actions.json"__ を指定して[Upload]をクリック
- [Upload and replace] をクリック
*登録済みのアクションは置き換えられて使えなくなります
- [Close] をクリック
3つのアクションが作成されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/43ed85e5-0da9-631d-ce2f-b1265e8d2c2c.png)

### 「Invoke watsonx generation API」がエラーになっている場合
-  Assistantの[Actions]をクリック
-  “Created by you”にある [Invoke watsonx generation API] をクリック
-  Step 1 の “And then” にある “Edit extension” をクリック
-  Optional parameters をクリックして
以下の図のように登録します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/50ac50e3-5b5f-27bc-9277-5c9d744990e5.png)

- [Apply] をクリック

エラー表示がなくなっていることを確認します

### Assistant 変数の指定
Watson Assistant のメニューから[Variables] - [Created by you] を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/bb2ac90a-6b9e-4060-c8e5-0fae3158b9a5.png)
変数の初期値を設定します

必須：
_discovery_project_id:_ **[DiscoveryのプロジェクトID]**
_watsonx_project_id:_ **[watsonx.aiのプロジェクトID]**
_model_id_: **使用する言語モデル**

:::note info
使用する言語モデルは、日本語が扱える以下のモデルの中から指定します
**ibm/granite-8b-japanese**
**elyza/elyza-japanese-llama-2-7b-instruct**
**meta-llama/llama-2-70b-chat**
**meta-llama/llama-2-13b-chat**
:::

その他必要に応じて変更します
_model_parameters_max_new_tokens_: 最大トークン数
_model_parameters_min_new_tokens_: 最小トークン数
_model_parameters_repetition_penalty_: 反復ペナルティ
_model_parameters_stop_sequences_: シーケンスの停止

#### デコード方式(greedyかsampling)を追加
Watson Assistant のメニューから[Variables] - [Created by you] を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/ffbf224a-56a4-8236-2c05-ec3f7aa2f812.png)
- [New variable +]をクリック
- 以下の情報を入力
Name: __decoding_method__
Type: __Any__
Initial value: __greedy__
*ここでは”greedy”としていますが、Samplingを利用する場合は”sample”と入力します

- [Save] をクリックして保存


### Assistant で動作確認
Discoveryには生成AIに関連する「IBMソリューションブログ」を取り込み、
Assistantで作成したチャットから、生成AIに関する質問をしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/21464d9d-4c53-154d-7c2e-69aa8f864c91.png)
日本語も扱える llama-2-70b-chat を使用すると日本語の質問に対しても期待する結果が得られます。

## [参考]Assistantからwatsonx.aiに渡される情報
上記の例で Assistant から watsonx.ai に渡されたプロンプトは下記の通りです。
参考とする例はタイトルと文書を日本語で与えて、指示(命令ステートメント)は英語で行なっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/40b09954-7098-eecc-40c4-b55f8e6c79de.png)
watsonx.ai からAssistant に返された結果は下記の通りです。
例として与えられた文書と指示に対して、生成された文書が返ってきてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/c7d29a7c-d053-2fdd-89c1-abd29c61bddf.png)

## 【Tips】IBMの言語モデル（Granite日本語版）を利用する際のプロンプト変更
watsonx.aiへのプロンプトは、Generate Answer(アクション)の model_input で指示を与えています。Graniteモデルを使用する場合、モデルに適してプロンプトに変更する必要があります。
Step5で model_input の指示を右の例のように変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/37e57302-8546-6d9e-71d3-0676655c4909.png)

Granite用プロンプトとして model_input を下記の内容に変更します。プロンプトは目的に合わせて修正します。
```text
("### System:
あなたは誠実で優秀なAIアシスタントです。ユーザーの指示に可能な限り正確に従ってください。

### User:
以下の文書を読んでQuestionに回答してください。与えられた文書では回答できない場合は「回答がない」と述べてください。
").concat(
${passages}

).concat("\n\n<Question>").concat(
${query_text}

).concat("</Qustion>\n\n### Assistant:")
```

## 【Tips】応答結果に元文書のリンクを表示する
＊Discoveryのコレクション作成時にファイルをアップロードしている場合はこの方法を使えません。WebやICOSなどのデータをクロールした場合に利用できる方法です

[Actions] - [Variables - Created by you] の [New variable +] から "links" を追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/6a72e836-9d42-08f6-6bc2-c60ec87cc952.png)
Name: __links__
Type: __Free text__

[Actions] - [All items - Created by you] の [Generate answer] を選択
Step 1 で links を初期化します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/660c396c-10b1-479a-1b76-f88c9d8a866d.png)

Step 2 で links にDiscoveryの検索結果からurlをセットします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/59c59212-1c4a-659d-f467-af71e55e771d.png)
```:Expression の値は以下の通りです
__${search_results}.get(0).metadata.source.url + "\n"__
```
Step 3と4 で links にDiscoveryの検索結果からurlを追加でセットします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/87ffb531-0ef4-5a2b-7026-af2508cd2c04.png)
```:Expression の値はそれぞれ以下の通りです
Step 3: 
${links}. concat(${search_results}.get(1).metadata.source.url) + "\n"
Step 4:
${links}. concat(${search_results}.get(2).metadata.source.url)
```

Step 10 で表示項目に links を追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/2a3cae5a-212f-0378-91f4-7253e5ada6c9.png)
```:Assistana says の内容は以下の通りです
${model_response} <hr>参考文書${links} 
```
生成AIが参考にしたファイルへのリンクが表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/d97938e2-3a10-62d1-90d7-b49cb19e0397.png)

## 【Tips】 Discovery検索結果のパラメータ変更
Discoveryから取得する検索結果は、Search(アクション)内のステップ3で条件を変更できます。
・count= 3（初期値は3件の検索結果を取得、別の値に変更できます）
・passages.characters= 250（パッセージとして取得する長さを変更できます）
・passages.fields= ["text"]（パッセージを抽出するフィールドで、別のフィールドに変更可能）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/8dbe6340-442e-822e-9136-37050adb93d2.png)

## 最後に
社内文書など独自のデータを対象にして生成系AIを利用する方法として、検索拡張生成(RAG)が注目されています。今回は情報抽出にWatson Discoveryを利用することで、独自データから回答作成をするチャットボットをノーコードで作成できることが確認できました。Actionを日本語化したりプロンプトを修正することでさらに使い勝手の良いチャットになることが期待できます。

---
# 参考情報
**Language Model Conversational Search starter kit（Watson Assistant Toolkit）**
https://github.com/watson-developer-cloud/assistant-toolkit/tree/master/integrations/extensions/starter-kits/language-model-conversational-search#language-model-conversational-search-starter-kit