Oracle(OCI)ずくめでDifyしよう！

# はじめに
AI開発のプラットフォームであるDify。素晴らしいツールですよね。

https://dify.ai/jp

そんなDifyが「OCIで色々使えたらなぁ」っと横目で見ていたのですが、いつの間にか色々対応していたので試してみました！

Oracleずくめというタイトルの通り、
・OCI上のOracle Linuxインスタンスで、
・LLMにOCI GenAI(Cohere)を利用し、
・Vector StoreにOracle DB23ai(Container)
っという構成で組んでいきます。

「そもそもDifyってどんなことができるの？」という方は`早速アプリを作ってみよう`を見てみてください！
「へぇ、DifyでOracle使えるんだ」って思っていただいた方はぜひ`手順`をみて、OCIでDifyを使ってみてください！

# 本記事で記載する範囲
## くわしく言及しないこと
以下については、チュートリアルなど良い手順書がありますのでそちらをご案内いたします。
- OCIアカウントの取得方法
- OCIのVCNやインスタンス作成などの基本的な手順
- DocketやDocker Composeについて

説明すること
- コンピュートインスタンスでのDifyのセットアップ
- DifyでOCI GenAIやOracle DBの利用設定

# 必要なもの
- OCIのアカウント

# 手順
## VCN作成
以下のチュートリアルを参考に作成をしましょう。

https://oracle-japan.github.io/ocitutorials/beginners/creating-vcn/

Difyは80ポートでのアクセスが必要になるので、作成されたPublic SubnetのSecurity ListでIngress Ruleで許可しましょう。
Source CIDRは接続元のIPで絞れるなら絞りましょう。ここでは`0.0.0.0/0`としています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/68dd8113-252a-a635-6f9d-f5a83733b35b.png)


## インスタンス作成
以下のチュートリアルを参考に作成しましょう。

https://oracle-japan.github.io/ocitutorials/beginners/creating-compute-instance/

ShapeはデフォルトのVM.Standard.E4.Flexで1コア(OCPU)の12GBメモリで十分です。OSもデフォルトのOracle Linux8で、Boot Volのサイズもデフォルトの50GBでまずは良いでしょう。

## OS事前準備

### Dockerのインストール
```
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker opc
exit
```
もう一度ログインしましょう。


### docker-composeのインストール
```
sudo wget -O /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/v2.31.0/docker-compose-linux-x86_64
sudo chmod 755 /usr/local/bin/docker-compose
```

### difyのインストール

```
sudo dnf install -y git
git clone -b 0.13.1 https://github.com/langgenius/dify
cd dify/docker
cp .env.example .env
```

Vector StoreにOracle DBを使いたいので`.env`ファイル修正します。

```
vi .env
```

-  
    waviate以下を
    ```
    VECTOR_STORE=weaviate
    ```
    以下に
    ```
    VECTOR_STORE=oracle
    ```
    へ変更します。


以下コマンドで環境を立ち上げます。
```
docker-compose up -d
```

oracle dockerが展開されていることがわかります。
```
[opc@dify docker]$ docker-compose up -d
[+] Running 76/30
 ⠦ redis [⣿⣿⣿⣿⣿⣿] 117.2kB / 11.02MB Pulling                                                                                                                                                                                           95.7s
 ⠦ web [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 67.11MB / 105.5MB Pulling                                                                                                                                                                                       95.7s
 ⠦ ssrf_proxy [⣿⣿⣿] 70.36MB / 84.35MB Pulling                                                                                                                                                                                         95.7s
 ⠦ sandbox [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 141.8MB / 186.6MB Pulling                                                                                                                                                                                     95.7s
 ⠦ api Pulling                                                                                                                                                                                                                        95.7s
 ⠦ oracle [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 3.203GB / 3.214GB Pulling                                                                                                                                                                           95.7s
 ⠦ nginx [⣿⣿⣿⣿⣿⣿] 39.23MB / 43.85MB Pulling                                                                                                                                                                                           95.7s
 ⠦ db [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 96.79MB / 98.31MB Pulling                                                                                                                                                                                         95.7s
 ⠦ worker [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 900.3MB / 953.7MB Pulling
```

Oracle Linuxではfirewalldでポートを制御しているので、以下で80ポートを解放します。
```
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --reload
```
これでDifyにアクセスできるようになるはずです。

# OCI Gen AIの設定
早速ブラウザでDifyにアクセスしましょう。

```
http://<インスタンスのPublic IP>
```

正常に起動していれば以下の画面になるはずです。
以下のように項目を任意で記入してセットアップをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/c2c78697-3e18-994c-599c-6f0a33c68cc0.png)

以下の画面に遷移するので、上記で入力したメールアドレスとパスワードでサインインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/8ce83535-c20c-8a24-871c-bfb0ffef8104.png)

まず、LLMなどの利用するモデルを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/c2f5b5f6-a471-46f5-0106-ca3b352ca7a2.png)

モデルプロバイダーを選択し、したの方にスクロールすると`Oracle`がありますのでセットアップをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/85d3523a-d0ca-2b23-f5e4-0c26ad43ff28.png)

ここではOCIのAPI情報とAPI秘密鍵を入力します。
ここがちょっとややこしいので、以下を流れでAPIキーの取得とDifyへの入力形式へ変換を行なってください。

OCIコンソールから画面右上の人アイコンをクリックし、自身のメールアドレスまたはユーザー名をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/eb520edc-29dd-06a6-3a67-294aec074147.png)

画面が切り替わったら下へスクロールし、画面右側のResourcesから`API keys`をクリックし、`Add API key`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/574394e5-b4f0-f542-be2e-07ed773d734d.png)

Generate API key pairを選択し、Download private keyをクリックしてファイルをダウンロードし、Addをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/97c5c5ea-2966-bb1a-c65e-e6f21a70e963.png)

以下のpreviewが表示されるので`Copy`をクリックしてクリップボードにコピーして、メモ帳などに貼り付けて残しておきます。これでAPIキーの取得は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/70052ddf-596b-11aa-c015-baf2f0f4ba61.png)

続いてこのAPIキーの情報から先ほどのDifyの画面で登録する文字列を生成する必要があります。

ダウンロードしたAPI秘密鍵(ここではhogehoge.pemとしています)と以下のスクリプトをインスタンスにコピーして、user, fingerprint, tenancy を先ほどメモ帳に貼り付けた情報を記入します。
```
#!/bin/bash

#以下を書き換える
user="ocid1.user.oc1..hogehoge"
fingerprint="xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
tenancy="ocid1.tenancy.oc1..hogehoge"
pem_file_path="hogehoge.pem"

#以下は変更しない
compartment_ocid=$(oci-metadata |grep compartment | awk '{print $3}')
region="us-chicago-1"

combined_string="$user/$fingerprint/$tenancy/$region/$compartment_ocid"

encoded_combined_string=$(echo -n "$combined_string" | base64 --wrap=0)

echo "[Dify: oci api key config file's content]"
echo "$encoded_combined_string"

if [ ! -f "$pem_file_path" ]; then
    echo "PEM file not found: $pem_file_path"
    exit 1
fi

encoded_pem_content=$(base64 --wrap=0 "$pem_file_path")

echo
echo "[Dify: oci api key file's content]"
echo "$encoded_pem_content"
```

スクリプトを実行します。
```
sh code.sh
```

塗りつぶしておりますが、以下のような感じで二行表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/f477b9ec-c588-a33a-03e6-2349b1709847.png)


それぞれを以下に貼り付けて`保存`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/6c683fbb-02f0-a9c3-c4e0-940004caf824.png)

問題なければ以下のように登録されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/47434e98-2d8b-0352-c676-051e5f6b3044.png)

各モデルを有効、無効にできるので以下の2つのみ有効としておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/ce27df90-04a5-dc87-15c3-78b28ca64d99.png)

また`システムモデル設定`としてもそれぞれ登録しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/4630e5d0-4daa-ef75-d614-22fa898b1f35.png)


# 早速アプリを作ってみよう
ここでは`シンプルなチャット`と`RAGチャット`を作ってみましょう。

## チャット
画面上部の`スタジオ`から`最初から作成`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/801a2ec2-d196-a404-ea10-1ea7ab77b43e.png)

`チャットボット`を選択し、`基本`を選び、`アプリのアイコンと名前`に`OCI GenAI Chatbot`と入力して`作成する`をクリックしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/669d36e4-ef94-0b64-7cd4-9d5f51d2a022.png)

`デバッグとプレビュー`で動作確認をしましょう。ここでは以下を入力しています。
```
こんにちは！あなたの自己紹介をしてください 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/f54bf873-d838-babe-d5e9-129ff723a243.png)

問題なければ、以下のような回答が得られます。Coralと返ってきましたのでCohereのモデルであることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/5957fb06-ce92-897c-9cce-f4776d5df854.png)

あとは`公開する`をクリックし、`アプリを実行`をクリックすればチャットアプリの完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/f188eb0b-ecf3-69c9-9fc5-acd199fda060.png)

新たなページで以下のようなページが開くので、そのURLでアクセスして利用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/2bc86402-3951-c98a-0348-2f058510e46e.png)

先ほどと同じ質問をしてみます。同じような回答があり、問題なく動作していることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/715696c3-22bf-8a14-adb8-f8cf841d19a3.png)

## RAGチャット
続いてRAGを利用したチャットボットを作成しましょう。

その前にRAGを組み込んでいない上記で作成したチャットに以下のような質問をしてみました。
答えはRoCEv2なのですが、InfinibandとLLMモデルが持っている知識からそれらしい誤った回答をしてしまっています。
これから作成する`RAGチャット`では`Oracle DB`に入った正しい情報をもとに`RoCEv2`と回答できるアプリを作りましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/f634c50b-e222-3286-4b4a-bd25a2751bd1.png)

VectorStoreに入れる情報としては以下のBlogをPDFにしたものを利用します。
https://blogs.oracle.com/cloud-infrastructure/post/now-ga-largest-ai-supercomputer-oci-nvidia-h200

上記のブログには以下の情報があるのでこれを参照して正しい回答が得られることを期待します。
```
OCI’s custom-designed cluster network that uses RDMA over Converged Ethernet Version 2 (RoCE v2)
```


### ナレッジの作成

画面上部の`ナレッジ`をクリックし、`ナレッジを作成`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/5cb99c25-05bb-6cce-ba2c-58ab08e3188a.png)

`テキストファイルからインポート`を選択し、`アップロード`で先ほどのブログをPDFにしたファイルをアップロードし、`次へ`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/d918bea6-d47d-555f-35a6-b17806f226e4.png)

チャンク設定で、自動とカスタムがありますが、ここではカスタムを`選択`します。`最大チャンク長`を`128`にして、`チャンクのオーバーラップ`を`20`にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/b3824cf5-8935-d7ec-64a4-ca1855cc2eee.png)

`インデックスモード`は`高品質`として、`埋め込みモデル`は`cohere.embed-multilingual-v3.0`が選択されているので、そのままとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/9a1e7039-355f-4229-33dc-c069a542d2a3.png)


`検索設定`は`ハイブリッド検索`を選択し、`保存して処理`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/4bd737ad-bac0-33af-4bee-0f37cb4a2d56.png)

問題がなければ`埋め込み処理が完了しました`となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/5e222e7b-cfee-ca83-2be2-314a7a009701.png)


### RAGチャットの作成
続いて、上記ナレッジを利用したチャットを作成していきます。

先ほどと同様に画面上部の`スタジオ`から`最初から作成`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/66f89fb3-5a74-11ab-92dd-dd78f521866c.png)

ここも先ほどと同じように、`チャットボット`、`基本`を選択し、`名前`にRAGチャットボットと記入して`作成する`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/e18910db-6227-6213-b35e-d6b260c438e1.png)

以下の画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/1ffbd119-75ab-3e39-9997-d9789b67480f.png)

まず手順のところに以下を記入します。
```
- ユーザーの入力に回答するために、コンテキストの内容を検索した結果に忠実に回答を生成してください。
- あなたの事前知識で回答はしないでください。
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/28e0b1e2-4c7c-35ab-67e7-65ad8d9a8588.png)


続けて`コンテキスト`で`+追加`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/b179950e-566e-7898-4424-1e2a8ca010c1.png)

参照する知識が選択できるので、先ほど作成したナレッジを選択し、`追加`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/599324a3-759c-f546-6da9-b983df65ab93.png)

手順とコンテキストが設定できたので、これでRAGチャットの設定は完了です。
デバッグとプレビューでただのチャットボットでは回答できなかった以下の質問をします。
```
OCIのGPUクラスタのインターコネクトは何を採用していますか？
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/e2c134cc-58f6-337c-95d5-82326f72a20b.png)

RoCEv2と正しい回答を得られました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/57e12f18-aec9-761b-3b20-48d570c30a04.png)

あとは先ほどと同様に公開して利用することができます。

# 最後に
以上のようにDifyからOCI GenAI(Cohere)やOracle DB23aiを利用することができました。

ただ、実用に向けてはいくつか課題があることがわかっています。
- ナレッジの作成でチャンク設定を`自動`や`カスタム`でも`最大チャンク長`が大きいとナレッジの作成ができない(裏ではエラーが発生している)
- Oracle　DB23aiをContainerではなく、OCIのPaaSを使った構成方法の確認ができていない
- OCI GenAIの最新モデルへの追従ができていない
- OCI GenAIが大阪リージョンでリリースされたが、大阪リージョンでモデル追加するとエラーになる
などなど

今後、上記の調査を含めより良くOCIでDifyを利用する方法を確認していきたいと思います。