ゼロから始めるAIシステム開発 #16 「DifyでBedrockと連携」

## DifyでBedrockを使うには
Difyを使ったチャットボットアプリのお仕事をいただいた。デモで使ったLLMはChatGPTだがクライアントはAWSを契約済みなので本実装はBedrockを使うことになりそうである。こういうケースは頻発しそうなのでつまづいた点などをまとめておく。
チャットボットの構成は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/6550106d-4c0c-4443-a9f7-1eb5afb6a17f.png)

Difyはクラウド版とセルフホスト版があるが今回はクラウド版を想定。セルフホスト版はIAMロールの設定などが必要になるがクラウド版では不要。
## AWS側の準備
### 使用したいモデルを有効化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/689adabc-22df-430e-81b9-fd6d7520f1f1.png)
「モデルアクセス」→使いたいモデルの「リクエスト可能」をクリック→「モデルアクセスをリクエスト」→モデルアクセスを編集の画面で「次へ」→「送信」
### アクセスキーとシークレットキーを作成
コンソールホームから「IAM」→「ユーザー」→ユーザーを選択or作成→AmazonBedrockFullAccess ポリシーをアタッチ
→セキュリティ認証情報のタグから「アクセスキーを作成」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/ee4fe324-4d48-4268-a7d2-a7568eea741e.png)
これは作成済みの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/a1e74d4f-d1a6-40b5-a3c3-7d26b4955965.png)
この画面は「サードパーティーサービス」を選択し「次へ」
進めてアクセスキーとシークレットアクセスキーを入手し、それらをDifyに貼り付ける。
## Dify側の設定
「設定」から「モデルプロバイダー」を選択、「Amazon Bedrock」を見つけてインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/66123c8f-1387-46ed-9699-b06186da9be1.png)
↓の画像はインストール済みのスクショ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/fb3c20a1-a192-4666-aa5e-5de4dedf8b51.png)
セットアップ画面で以下を入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/04588401-4322-4fd5-9488-b90405728a07.png)
|項目| 入力内容 |
|:-:|:-:|
|Access Key|先ほど作成したアクセスキーID |
|Secret Access Key|先ほどのシークレットキー|
|AWS Region|Bedrockのリージョン（例：us-east-1）|
|Bedrock Endpoint URL|例：https://bedrock-runtime.us-east-1.amazonaws.com|
|Available Model Name|例：amazon.nova-micro-v1:0|
|Bedrock Proxy URL|Difyクラウドユーザーの場合は空欄でOK|
## 使用するLLMについて
Available Model Nameのところに入力すべきLLMのモデルIDはAWSの公式ドキュメントで公開されている。今回の実装時、最初にAnthropic社のClaudeを使おうとしたが、チャットへの反応時に以下のエラーが発生。
```
Run failed: [bedrock] Error: PluginInvokeError: {"args":{"description":"[models] Error: AccessDeniedException: You invoked an unsupported model or your request did not allow prompt caching. See the documentation for more information."},"error_type":"InvokeError","message":"[models] Error: AccessDeniedException: You invoked an unsupported model or your request did not allow prompt caching. See the documentation for more information."}
```
### 原因：Difyの「Prompt Caching」設定に非対応のモデルを使っている
BedrockでClaude3系モデルを使う場合はprompt caching（プロンプトのキャッシュ） を許可するという処理が必要らしい。DifyがBedrockと連携する際、リクエストのヘッダーに bedrock-runtime:cache を含める必要があるが、これは**Dify側で暗黙的に処理されており、クラウド版では明示的に操作することができない**ので現状では解決不能とのこと。
### Amazon Novaシリーズを使用
いろいろ試してみたが結局Claude系モデルではうまくいかなかったのでモデルを変更することに。**Amazon Nova**シリーズで成功。Novaは低コスト低レイテンシーのMicro、マルチモーダル対応のLiteとProがあるが、今回のユースケースでは簡単なQ&AがメインなのでMicroを選択。利用料金はなんとGPT-4oやClaude3.5 Sonnetの**約100分の1。** 回答性能は**MMLU**（知識と推論能力のベンチマーク）で**35％ほど落ちてしまう**が一般的なチャットボットに求められる性能としては十分だと思われる。
### LLMの回答比較
同じプロンプトを使った構成でChatGPTとNovaMicroを比較してみる。
・ChatGPT-4o使用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/09130fd8-cc2b-437c-95d4-97ea3f1c63a5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/abdc0673-32dc-4348-8ef1-b1675728e50a.png)

・Bedrock（Amazon Nova Micro）使用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/cb19227c-72d8-48f1-9ed7-617205386a69.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885923/3e7eb1b1-bd29-46a2-b3ae-156546b1251a.png)

・ChatGPTのほうは「引用した箇所を正確に表記して」というプロンプトに従って青いラインの段落で表記してくれている。NovaMicroのほうはそれがない。
・さらにNovaMicroのほうは納品書のことを聞いているのに入金処理についての回答が混ざっている。
・ChatGPTのほうが受け答えがシンプルな印象。NovaMicroのほうはマニュアル外質問への回答も無駄に丁寧。
・両者とも「ポップアップが表示され～」という回答をしているがマニュアルによればポップアップが出るのは別の処理のところなのでどちらも検索箇所が混線している？

結論として性能差を感じるといえば感じるが、プロンプトやチャンクのオーバーラップ設定などの工夫によってどうにかできるかもしれない。マニュアルの複雑さにもよるがユーザー体験としてはNovaMicroで大きく損なわれるということはなさそう。