素人がチームを盛り上げるDiscordボットをDifyで作ってみた

# はじめに
[技術チャレンジ部](https://challenge-club.connpass.com/)のとも(Tomo)です。チームTPACで[自動運転AIチャレンジ2024](https://www.jsae.or.jp/jaaic/2024ver/summary/)に[参加中](https://www.jsae.or.jp/jaaic/2024ver/contest/)です。
チームTPACの参加メンバーを盛り上げるべく、DifyでDiscordのボットを作ってみました。
…と言ってもこちらの記事を実行しただけ(記事を書かれた方、ありがとうございます!)。

https://note.com/jolly_dahlia842/n/n058c486b2e96

せっかくなので、AI経験0な素人の私がつまづいたところ、チーム盛り上げに効きそう点などを交えてお伝えできればと思います。
素人なので、変なことを言っていたらすいません!

# きっかけ
たまたま生成AIのワークショップに参加する機会があり、そこでDifyを使ったAIアプリケーションのデモがありました。
また、[技術チャレンジ部のLT会](https://challenge-club.connpass.com/event/320786/)で、Difyを使ったAIアプリケーションで新生活をスタートされた方のお話を聞きました(感動!)。
TPACはチームも大きくなって、メンバーと大会を盛り上げていきたい!
AIアプリケーションで盛り上げ、もしかしたら私にもできるのでは…?

# 環境
PC環境は、自動運転AIチャレンジに使用している環境そのものを使いました。
- PC: [ZBOX E](https://qiita.com/air-gh/items/d0721ec05abdab28fe01)
- OS: Ubuntu 22.04 Desktop
- モデルプロバイダー: OpenAI

# 構成要素
- Discord: エンドユーザーのUIとなるグループチャットアプリ。APIサービスあり
- OpenAI API: AIアプリケーションの中核となるLLMのAPIサービス。Difyから使用
- Dify: AIアプリケーションを簡単に作れるプラットフォーム。APIサービスあり
- Pythonスクリプト: DiscordとDifyをつなぐスクリプト。DiscordとDifyのAPIを使用

# OpenAIでのAPIキーの作成
- OpenAIにログインし、APIを選択。ChatGPTとは別…とは知らなかったくらいの素人です
- 画面右上のSettings -> Billing -> Add to credit balanceで課金。ChatGPTとは別課金…とは知らなかったくらいの素人です
- 画面左上のDefault prject -> Create projectで、プロジェクトを作成
- 作成したプロジェクトを選択し、画面左のAPI keys -> 画面右上のCreate new secret keyで、プロジェクトのAPIキーを作成し、メモ
- 各種パラメーターは一旦デフォルトのまま

# Dify
## Difyのインストール
自動運転AIチャレンジ2024の環境構築にて、[Dockerのインストール](https://automotiveaichallenge.github.io/aichallenge-documentation-2024/setup/docker.html)を行っているため、これをこのまま活用し、docker compose上のself hostedな運用としました。
インストールは、[公式手順](https://docs.dify.ai/getting-started/install-self-hosted/docker-compose)をそのまま実行しました。迷う点はありませんでした。

- githubからDifyをclone
- dify/dockerで.env.exampleを.envにコピー
- docker compose up -dで起動

気分的に、.env.exampleに入っていたデフォルトっぽいパスワードは、.envにてランダム生成したものに変更しました。

## モデルプロバイダーの設定
WebブラウザーでDifyにアクセスし、画面右上の自分のアイコン -> 設定 -> 画面左のモデルプロバイダーで、OpenAIを選択、セットアップで先ほどメモしたOpenAIのAPIキーを入力し、OpenAIのモデルを有効化しました。緑ランプが点灯すれば有効化完了。新しめのDifyなら(?)噂のgpt-4o-miniも使用できるようです。

## チャットボットの作成
WebブラウザーでDifyにアクセスし、以下を実施しました。
- チャットボット -> テンプレートから、チャットボットを作成。テンプレートはどれが良いかわからなかったものの、Knowledge Retreival + Chatbotであれば、本大会独自の知識も埋め込めるかなと思い、選択
- 色々試した結果、Knowledge Retreivalは後回しにしようと判断、一旦Knowledge Retreivalのブロックを削除し、STARTとLLMを直接接続
- LLMブロックでは、モデルにgpt-4o-miniを選択。SYSTEMからは、Knowlegdを与える`<context>〜</context>`のくだりを削除。SYSTEMには日本語で「高度な命令」をこのような感じで設定(ここがボットのキャラクターの味付けに)

![dify.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764521/33e54700-b81e-6e17-252c-d2da03942272.png)

- デバッグとプレビューで質問すると、いい感じでアツい回答が得られたので、画面右上の「公開する」ボタンでチャットボットを公開

ここまでが一瞬すぎて笑ってしまうほどでした。

チャットボットができたので、画面左のAPIアクセス -> 画面右上のAPIキーで、新しいシークレットキーを生成し、メモしておきます。

# Discordでのボットの作成
Difyはワークショップで見たのでなんとなく感覚が分かっていましたが、Discordのボット作成は未知の世界。改めて[こちらの記事](https://note.com/jolly_dahlia842/n/n058c486b2e96)を読みながら以下を実施しました。

- Discord Developer PortalのMy Applicationsから、New Applicationでアプリケーションを作成。アイコンも設定できるので、TPACのアイコンを設定。ボットっぽくなる気がしてきました
- 作ったアプリケーション(ボットのアイコン)を選択し、BotのReset Tokenでトークンを取得し、メモ。また、Presence IntentとMessage Content Intentを有効化。これは、画面下にあるたくさんのチェックボックスではなく、画面中程のスライドスイッチでした。ちょっと迷子になりました
- OAuth2のOAuth2 URL Generatorで、画面下のたくさんのチェックボックスからbotを選択し、画面を下にスクロールして現れるGenerated URLをコピーし、ブラウザでアクセス。ここもちょっと迷子になりました
- Generated URLにアクセスして現れる認証画面では「サーバーに追加」部分に追加したいサーバーが現れるはずですが、現れず。Discordサーバーにボットを追加できる権限を持っていなかったようです。Discordのサーバー管理者に権限を追加してもらって、改めてDiscordサーバーにボットを追加。結果、テキストチャンネルの一般に、ボットのtpacさんが現れました、わーい!

後で分かったのですが、プライベートチャンネルでボットを使うには、そのチャンネルのロールが必要そうです。作成したボットにロールを付与しました。

# DiscordとDifyをつなぐPythonスクリプトの作成
Pythonアプリケーションも、[こちらの記事](https://note.com/jolly_dahlia842/n/n058c486b2e96)のPythonアプリケーションをそのまま使用させていただきました。
Pythonスクリプトは、Difyに対してもDiscordに対しても、クライアントとして動作するようです。ポートフォワーディングが不要なので、一般のご家庭でも動作が容易な接続形態かと思います。
.envにDifyとDiscordのAPIキーを設定した上で、Pythonスクリプトを実行します。

```.env
TOKEN="Discordのトークン"
DIFY_API_KEY="DifyのAPIキー"
```

何点かつまづきポイントがありました。

## pipでの依存Pythonパッケージのインストール
自動運転AIチャレンジ2024では[pip環境も設定される](https://automotiveaichallenge.github.io/aichallenge-documentation-2024/setup/docker.html)ため、これをそのまま活用しました。
結果的に`pip install aiohttp discord python-dotenv`が必要でした。
最初、`pip install dotenv`で失敗していたのですが、`python-dotenv`だと成功しました。

## Discordからのボット呼び出し名の変更
デフォルトではDiscordから`!chat`でボットが呼び出せます。これを`!tpac`に変える方法をChatGPTに聞いたところ、以下のようにすればよいとのことで、実際動作しました。
```:python
@client.command(name='tpac')
```

# Discordからのボットの呼び出し
絵文字も交えた応援メッセージがアツい!

![discord-chat-bot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764521/bd00b3c6-f730-84d8-7988-fb3424bbe4fb.png)

# ここが良かった!
- 自分が疑問に思ったことと、AIからの応答の両方が、チーム全体と共有できる
  - 他のメンバーが言葉にできていなかった疑問や思いに対して寄り添ったり、新たな気づきにつながる可能性
- gpt-4o-miniの応答の速さと、普段使いのアプリケーション上のボットの組み合わせが、ユーザー体験の向上につながる
- ボットのキャラクターの味付けを、Dify上にて自然言語で簡単に設定できる

# 今後に向けて
## 長い応答が途切れる
あとちょっと、というところで会話が途切れる場合があります。
DifyのLLMブロックのモデルを押すと、Max Tokensという設定があり、これがデフォルトで512になっていたので、768にして様子をみようと思います。
<img width="350" alt="max-tokens.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764521/4765bb31-b722-780d-2180-bb1e012094da.png">

## ナレッジの活用
Difyでは、外部からナレッジを注入できます。本大会に特化した知識での応答もできそうです。
実際、元々のテンプレートにあったKnowledge Retrievalを使って、こんな応答が得られました。
チャンクの切り方の工夫やRerankerを用いて、精度を上げられればと思っています。
![knowledge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764521/64d2ecd8-05d7-7b2d-859e-4e2cfc4abc65.png)

### FirecrawlのためのDockerネットワーク設定
LinuxのDockerで、DifyのコンテナからFirecrawlのコンテナのAPIへアクセスするURLにhost.docker.internalを使用するには、extra_hostsで"host.docker.internal:host-gateway"を指定する必要がありそうです。
これをDifyのどのサービスに適用すればよいか(どのサービスからFirecrawlにアクセスするか)、調べられていません。
とりあえずdocker-compose.override.yamlにて適当に複数指定したら動作したのですが、絞り込めればと思っています。

## Slack化
本大会ではSlackが活用されているため、Slack化もしたいと思っています。
ほぼ同じタイミングで、[こちらの記事](https://qiita.com/soyaoki/items/407b83a36cf0a59d3e1f)が公開となりました! しかもSlack編!
是非参考にさせていただき、大会を盛り上げていければと思っています!