IBM Granite日本語版でLangchainを使ってみる

# はじめに
2024年2月29日にIBM watsonxにて生成タスク用に設計されたIBM独自の基盤モデルであるGraniteモデルシリーズのひとつとして、Granite日本語版モデル（granite-8b-japanese）がリリースされました。
プレスリリース: 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日本語版でLangchainのSequential Chainを使ってみたいと思います。

# Sequential Chainって？
Langchainの機能のひとつであるChainsを活用して、複数のプロンプトから回答を出力させることが可能になります。この記事の例の場合は「LLMにあるキーワードに関する質問をランダムに生成させる」→「その質問をLLMに回答させる」という流れを実装しています。

# 事前準備
watsonx.aiのLLMをpythonから呼び出すにはIBM Cloud API KeyとProject IDが必要になります。

### 1. watsonx.aiの環境準備
Granite日本語版はwatsonx.ai上で利用可能です。
以下を参考にしてwatsonx.aiを使えるようにしておきます。
[0からのIBM watsonx.aiのはじめかた](https://qiita.com/ironikot/items/a1ff1423c5c2e7c44876)

### 2. IBM Cloud API Keyの取得
以下の記事を参考にしてください。
[IBM Cloud APIKEYの作成(取得)方法](https://qiita.com/nishikyon/items/fa8b951267efbe911fe7)

### 3. Project IDの取得
Project IDはwatsonx.aiのプロジェクトから管理タブ→一般から参照することができます。
![スクリーンショット 2024-03-27 16.56.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738536/94c1edeb-f070-85fe-8c25-8921f5443f7b.png)


# スクリプト
スクリプトは以下のNotebookを参考にしました。
https://dataplatform.cloud.ibm.com/exchange/public/entry/view/c3dbf23a-9a56-4c4b-8ce5-5707828fc981?context=wx

Graniteに対応させたNotebookはgithubにアップロードしています。
https://github.com/hayateta/watson/blob/main/SequentialChain_granite_jp.ipynb

元のスクリプトではwatsonx.aiで使えるLLMのModel IDを取得するために以下のコードを実行するのですが、
```python:Use watsonx and LangChain to make a series of call
from ibm_watsonx_ai.foundation_models.utils.enums import ModelTypes

print([model.name for model in ModelTypes])
```
出力は以下のようになり、Granite日本語版のIDが出てきません。（なぜ？）
```python:出力
['FLAN_T5_XXL', 'FLAN_UL2', 'MT0_XXL', 'GPT_NEOX', 'MPT_7B_INSTRUCT2', 'STARCODER', 'LLAMA_2_70B_CHAT', 'LLAMA_2_13B_CHAT', 'GRANITE_13B_INSTRUCT', 'GRANITE_13B_CHAT', 'FLAN_T5_XL', 'GRANITE_13B_CHAT_V2', 'GRANITE_13B_INSTRUCT_V2', 'ELYZA_JAPANESE_LLAMA_2_7B_INSTRUCT']
```
IDがわからなかったので、直接model_id=ibm/granite-8b-japaneseと与えて、実行できるようにしました。
```python:SequentialChain_granite_jp
from langchain_ibm import WatsonxLLM

granite_jp_llm = WatsonxLLM(
    model_id="ibm/granite-8b-japanese",
    url=credentials["url"],
    apikey=credentials["apikey"],
    project_id=project_id,
    params=parameters
    )
```

また、元のコードではプロンプトが英語で書かれていたので日本語に修正しました。
```python:SequentialChain_granite_jp
from langchain import PromptTemplate

prompt_1 = PromptTemplate(
    input_variables=["topic"],
    template="""{topic}についてランダムな質問を生成してください。
                            質問: """
)
prompt_2 = PromptTemplate(
    input_variables=["question"],
    template="""次の質問に答えてください。: {question}
                            回答:""",
)
```
引数を与えます。この「IBM」と与えてみました。
```python:SequentialChain_granite_jp
qa.run("IBM")
```
実際にLLMに投げているプロンプトは
>IBMについてランダムな質問を生成してください。
>質問:

そして生成結果を元に

>次の質問に答えてください。: {LLMによってランダムに生成された質問}
>回答:

というプロンプトを投げています。

実際の出力は以下のようになりました。
```python:出力
> Entering new SimpleSequentialChain chain...
IBMは、コグニティブ・コンピューティング、クラウド・コンピューティング、モバイル・コンピューティング、
ソーシャル・コンピューティング、ビッグ・データ分析、セキュリティ、
およびモノのインターネット向けのオープン標準とテクノロジーの開発と促進を専門とする
アメリカの多国籍テクノロジー企業です。IBMの最も有名な製品は何ですか？
 Watson

> Finished chain.
' Watson'
```

# まとめ
質問がくどいような気がしますが、それっぽい質問と回答を生成することができました。
今回は質問生成→回答生成を実施しましたが、複雑な質問に対して、一度中間的な回答を生成して答えられるようにしたり、Custom Chainsというものを使って長い文書を分割して要約させたりといった使い方があるそうです。