DifyでVertex AIを使用する

## はじめに
DifyでVertex AIを使用するために試行錯誤したことを書き残しておきます。

### Difyとは
Difyとは、オープンソースのLLMアプリ開発プラットフォームです。ノーコードでRAGの構築などができます。
詳細は公式サイト等をご確認ください。

https://dify.ai/jp

https://qiita.com/KII437465127175/items/12cedc1d2a24f239b655

## 前提
DifyはSaaSとして利用もできますが、GitHubからソースコードをクローンしてローカル環境などで使用することも可能です。
今回はローカル環境での実行を前提としています。なお、ローカル環境にはDockerが使用できる環境も整っている想定です。

※なお、2024年7月14日時点での情報となります。

## 事前準備
### Difyの環境構築
以下のGitHubからソースコードをクローンします。

https://github.com/langgenius/dify

GitHubのREADMEに記載のように、以下のコマンドを実行することで環境構築・起動が可能です。
```zsh
cd docker
cp .env.example .env
docker compose up -d
```

起動が環境したら、http://localhost でアクセスできます。

### Vertex AI用のサービスアカウント準備
Vertex AIを使用できるサービスアカウントを[こちら](https://cloud.google.com/iam/docs/service-accounts-create?hl=ja)などを参考に準備して下さい。

ロールは適切なものを設定頂ければと思いますが、今回は[Vertex AI User](https://cloud.google.com/vertex-ai/docs/general/access-control?hl=ja#aiplatform.user)を設定しているものとします。
サービスアカウントは作成後、JSONキーファイルをダウンロードして下さい。

参考：

https://qiita.com/shunta_yoshida/items/1ba16c6dbfcc8e7921a9

## Difyによる設定
では、DifyでVertex AIを使用できるように設定していきます。

画面右上のユーザーアイコンのボタンから、[設定]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/6445a7cb-b686-6755-1ac2-59412e23ac11.png)

設定画面で[モデルプロバイダー]→[Google Cloud]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/208c89b7-8e80-3690-3a49-15f4f81c6f09.png)

セットアップ画面にて、[Project ID]には先ほどVertex AIのサービスアカウントを作成したGoogle CloudのプロジェクトIDを、[Location]には使用したいリージョンを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/bf6d49a0-9fe6-bcd4-6256-53793d3a205d.png)

[Service Account Key]には、事前準備で取得したJSONキーの情報を入力します。
ここで1点注意しなければならないのが、入力欄のプレースホルダーに記載があるように**base64エンコードした**文字列を入れる必要があります。
ですので、JSONキーファイルに記載されている**JSON形式のテキスト文字列全て**をbase64エンコード変換して、そのエンコードされた文字列を[Service Account Key]に貼り付けて下さい。

base64エンコードは以下のようなツールを使用できます。

https://develop.tools/base64-encoding/

:::note warn
Webアプリケーションの場合サーバー上に情報が保存されるリスクなどが存在しますので、キーファイルをbase64エンコードするツールはご自身で責任を持って選定して下さい。
:::

[Service Account Key]入力後、[保存]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/55dd7414-adb6-928e-842e-ac718df0f236.png)

設定がうまくいくと、[モデルプロバイダー]で使用できるモデルとしてGoogle Cloud(Vertex AI)が増えているのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/add990d7-e58d-a3c5-b3f9-ea940938fbe1.png)

## DifyでのVertex AIの使用
ここまでの手順で、DifyでVertex AIを使用する準備が整ったはずなのでGemini 1.5 Flashで試してみます。
~~が、筆者の環境では（2024年7月14日時点で）以下のようなエラーが発生してうまくいきませんでした。~~

:::note info
2024年10月3日時点で、以下のエラー原因のソースが修正されていることを確認しました。
:::

```
Run failed: Node LLM run failed: [vertex_ai] Bad Request Error, 400 User has requested a restricted HarmBlockThreshold setting BLOCK_NONE. You can get access either (a) through an allowlist via your Google account team, or (b) by switching your account type to monthly invoiced billing via this instruction: https://cloud.google.com/billing/docs/how-to/invoiced-billing.
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/a36ec533-3d6f-d1a5-f679-53eb984cc1c5.png)

エラーの原因は、Dify側で[安全性設定](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-attributes?hl=ja#safety_settings)に"BLOCK_NONE"を設定していることに起因しています。
[こちら](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-attributes?hl=ja#safety_settings)のページにも記載があるように、この設定は全てのユーザーが使用できるわけではありません。少なくとも、Google Cloudのデフォルト設定では使用できない認識です。
> 注: 「BLOCK_NONE」設定は制限付きフィールドで、一般提供のモデル バージョンのすべてのユーザーが使用できるわけではありません。詳しくは、このドキュメントの残りの部分をご覧ください。

エラー文言にも記載がありますが、このパラメータ(BLOCK_NONE)を使用するためには以下に記載の内容(許可リストの申請 or 請求書払いに変更)を実施しなければならず、少々面倒です。

https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-attributes?hl=ja#how_to_remove_automated_response_blocking_for_select_safety_attributes

なので今回はDifyのソースコード自体を修正して試してみることにしました。
[こちら](https://github.com/langgenius/dify/blob/main/api/core/model_runtime/model_providers/vertex_ai/llm/llm.py)の_generate()メソッド内のsafety_settingsパラメータをコメントアウトしてみました。
```py
        # safety_settings={
        #     HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
        #     HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
        #     HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
        #     HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
        # }

        google_model = glm.GenerativeModel(
            model_name=model,
            system_instruction=system_instruction
        )

        response = google_model.generate_content(
            contents=history,
            generation_config=glm.GenerationConfig(
                **config_kwargs
            ),
            stream=stream,
            # safety_settings=safety_settings,
            tools=self._convert_tools_to_glm_tool(tools) if tools else None
        )
```

この修正を実施後に再度試してみると、Gemini 1.5 Flashを使用できることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/5884a95c-b284-168c-fb7c-d5a1973cabfc.png)

## まとめ
DifyでVertex AIを試してみましたが、本記事公開時点でのDifyの仕様では使用できるユーザーがかなり限られると感じました。
今後BLOCK_NONEの制約が無くなったり等、使いやすくなったらまた色々試してみたいと思います。