清水理史の「イニシャルB」

ローコードLLMアプリ開発環境「Dify」を使って、SynologyのNAS上で動くAIチャットを作る

 「Dify」は、オープンソースで開発が進められているローコードのLLMアプリ開発プラットフォームだ。特定の知識を基に回答させるRAGや、特定の役割を演じるアシスタントなどを手軽に作成できるほか、会話の中で条件を判断し、自動的に分岐処理するチャットフローも手軽に作成できる。

 今回は、SynologyのNASでDifyを稼働させ、チャット中のやりとりから、Q&A検索・外部API呼び出し・Google検索から適切な回答方法を自動的に判断するフローを作ってみた。

作成したチャットフロー

SNSで話題になったDify

 チャットアプリを特定用途向けにカスタマイズしたい場合、もっとも手軽なのはOpenAIのカスタムGPTやCopilotのCopilot GPTを利用することだろう。例えば、QA文書を登録して特定の手続きについて回答させたり、あらかじめ指定した指示(プロンプト)で特定の役割を演じさせたり、ウェブ検索やコード、外部APIなどのツールを活用させたりできる。

 「Dify」も、こうした特定用途向けの生成AIアプリを作成するためのプラットフォームだ。

 一時期、SNSなどで話題になったので知っている人も少なくないかもしれないが、Difyの特徴は、更新が頻繁なこと、日本語がサポートされていること、機能が充実している点となる。例えば、5月13日にOpenAIから最新モデルのGPT-4oがリリースされたが、その数日後にリリースされたバージョン0.6.8でDifyでもGPT-4oがサポートされた。

いち早く、GPT-4oに対応

 似たようなソリューションとして、以前、本コラムでローコード開発プラットフォームの「bn」やワークフロー自動化ツールの「n8n」を紹介したことがあるが、個人的な印象としては、DifyはRAGとワークフロー関連の機能が充実しているのが印象的だ。

 具体的には、「ナレッジ」として文書を与える際の前処理段階でテキストから連続するスペースやタブを置換したり、URLやメールアドレスなどを削除したりできる。また、ベクトル検索と全文検索を組み合わせたハイブリッド検索が可能で、さらに外部のリランクモデルを利用して検索結果の候補となる文章を並べ替えて精度を上げることなどもできる。

RAGの詳細な設定が可能。ベクトルデータベースも一緒に提供される

 さらに、本稿執筆時点(2024年5月)ではベータ版となるが、条件によって処理を分岐させるワークフロー(チャットフロー)が利用できる。Copilot Studioほど高度ではないが、キーワードによって特定処理に振り分けるチャットボットなども作れる。

チャットフローを作成可能
カスタムGPTやCopilot GPTのようにコンテキストやツールを指定して作成することもできる

 本格的な利用には有料のクラウドサービスの利用を検討したいが、以下のサイトから一部機能制限がある「SANDBOX」プランを無料で試すことができるうえ、Dockerなどで自前のPCやサーバー環境で利用することもできるので、試してみるといいだろう。

▼Difyの利用を始める
https://dify.ai/jp

手っ取り早く使ってみたいなら、クラウド版のSANDBOXで試せる

Synology DS716+でDifyを動かす

 今回は、自前の環境でDifyを稼働させた。

 利用したのはSynologyのNAS「DS716+」だ(2015年発売の製品で、現在は代理店でも販売終了しているようだ)。動かすだけなら、Windows PCのDocker Desktop環境や一般的なLinux環境を用意した方が楽だが、DSM 7.2でSynology NASのDocker環境が使いやすくなったので、検証も兼ねて動作させてみた。DS716+以外でも、DSM 7.2のContainer Managerが利用できれば、同様の操作で利用可能なはずだ。

 以下の、Difyを動かすまでの手順を紹介するが、ポイントは2つある。1つは、動作に必要なフォルダーを手動で作成すること、もう1つは、Difyのウェブインターフェースにアクセスするためのポート番号を変更することだ。

Container Managerに進化し、docker-composeを読み込めるようになった

STEP 1:Gitリポジトリからファイルをダウンロードする

 まずは、NASに展開するためのDifyのファイルを取得する。本来は、SSHで接続してGitでクローンするのが簡単なのだが、今回はシンプルにZIPでファイルを取得して、NAS上に展開した。以下のサイトの「Code」(緑色のプルダウン)から「Download Zip」を選択してファイルをダウンロードする。

▼ファイルのダウンロード
langgenius/dify(GitHub)

今回はZIPでダウンロード

STEP 2:ファイルを展開する

 Synology NASの「File Station」を利用して、ダウンロードしたZIPファイルをNASの「docker」フォルダーにコピーし、ZIPを展開しておく。これで、「dify-main」というフォルダーが作成される。

NASに転送して展開する

STEP 3:フォルダーを作成する

 次にDockerコンテナから接続されるデータ保管用のフォルダーを作成する。今回のようにNASを利用する場合、権限の関係で自動的にフォルダーを作成できないので、あらかじめ作成しておく。

 具体的には、「/docker/dify-main/docker/volumes/」に、次の4つのフォルダーを作成しておく(sandboxとssrf_proxyはZIP展開時に作成済み)。

app/storage
db/data
redis/data
weaviate

コンテナに接続するフォルダーを作成する

STEP 4:ポート番号を変更する

 続いて、docker composeで利用する設定ファイルを書き換える。「/docker/dify-main/docker/」にある「docker-compose.yaml」ファイルをダウンロードし、ファイルの最後の方に記述されている「The nginx reverse proxy.」のブロックにある「ports」の値を「80:80」から「5080:80」などに書き換える。

 Difyは、標準ではポート80で接続を待ち受けるが、このポートはSynology NASのウェブステーションでウェブページを公開するためのポートとして予約済みなので、5080など別のポートに変更しておく。

 なお、「5080:80」の後ろ(「:」以降)の「80」は、転送先のコンテナ内部のポート番号なので変更する必要はない。前(「:」より前)のSynology NASで待ち受けるポート番号だけ変更しておく。

 「docker-compose.yaml」ファイルを更新したら、元の場所にコピーしておく(以前のファイルは別のファイル名などでバックアップしておくと安心)。

ポート番号を変更しておく

STEP 5:プロジェクトとしてコンテナを起動する

 最後に、Synology NASの「Container Manger」を利用してコンテナを起動する。DSM 7.2以降からDocker関連の管理アプリが「Container Manager」に変更され、docker-compose.yamlファイルを読み込めるようになった。

 「プロジェクト」で「作成」を開き、「パス」で「/docker/dify-main/docker/」フォルダーを指定すると、書き換えたdocker-compose.yamlファイルが検出されるので「既存のdocker-compose.ymlを使用してプロジェクトを作成」を選択する。

 docker-compose.yamlが読み込まれ内容が表示されるので、ポート番号を確認しておく(ここで、STEP 4で解説したポート番号の変更を行ってもいい)。

 今回はWeb Stationのウェブポータルを利用した中継は利用しないので、設定せずにそのまま「次へ」で進み、「完了」をクリックすると、docker-compose.yamlの内容に従って、イメージの取得やコンテナの稼働などの処理が自動的に実行される。

docker-compose.yamlファイルがあるフォルダーを指定してプロジェクトを作成

STEP 6:Difyにアクセスする

 しばらくすると自動的にコンテナが稼働するので、「http://[NASのIPアドレス]:5080」のように、末尾にdocker-compose.yamlで書き換えたポート番号を指定してアクセスすればDifyの画面にアクセスできる。

 初回は管理者アカウントの作成画面になるので、メールアドレスやパスワードなどを設定しておこう。

「http://NASのIPアドレス:指定したポート番号」でアクセスできる

STEP 7:APIキーを設定する

 起動したら、利用する生成AIサービスのAPIキーを設定しておく。右上のユーザー名をクリックし、「設定」から「モデルプロバイダー」を選び、利用するモデルのAPIキーを設定しておく。

利用する生成AIサービスのAPIキーを設定しておく

 いろいろなモデルが利用可能で、ローカルモデルなども利用できるが、とりあえずはOpenAIを登録しておくことをおすすめする。これだけで、RAG用のEmbeddingモデルなども含めて、一通りのことが可能になる。

 なお、冒頭で少し触れたが、RAGで検索された文書のチャンクを再評価するリランクを利用する場合は、「cohere」のAPIも登録しておく必要がある。レートリミットがあるFreeプランでも利用できるので、登録しておくといいだろう。

RAGでリランクモデルを利用する場合はcohereにも登録しておく

テンプレートを試しながら使い方をマスターしよう

 Difyの使い方だが、この手のツールの「あるある」ではあるが、ドキュメントを読み込むよりも、手を動かして試行錯誤しながら慣れる方が早い。もちろん、ドキュメントも存在するが、現状は英語となる。

▼Difyのドキュメントや利用例紹介サイト
Creating Dify Apps

 テンプレートとして、いくつかのアプリが用意されているので、それを見ながら確認する方が簡単だ。例えば、チャットフローであれば、「Question Classifier+Knowledge+Chatbot」がわかりやすい。

テンプレートを試してみるのが手っ取り早い

 基本的には、ブロックを並べ、前のブロックの出力を変数として活用しながら、各ブロックで処理を実行させていくという流れになる。

 例えば、上記テンプレートの「LLM」ブロックは、「コンテキスト」として「KnowledgeRetrieval/result Arreay[Object]」が指定されている。これは、前の「Knowledge Retrieval」ブロックの出力結果を指す。

LLMブロックでコンテキストとして、前のブロックの出力が参照されている

 実際に動かしてみよう。このテンプレートを動かすには、まず「ナレッジ」に文書を登録する必要がある。

 「ナレッジ」の「知識を作成」で、知識のベースとなるファイルをドラッグする。

 利用する文書にもよるが、個人的には「チャンク設定」で「カスタム」を選択し、「セグメント識別子」を「¥n¥n」にすることをおすすめする。本稿もそうだが、最近の文書は段落ごとに改行が入ることが多いので、「¥n¥n」と改行2つを指定しておくと段落ごとにチャンクを分割できる。

 また、cohereのAPIを登録済みの場合は、「検索設定」で「ハイブリッド検索」を選択し、「再ランクモデル」で「rerank-multilingual-v3.0」を選択しておくといいだろう。

文章をチャンクで分割。識別子を「¥n¥n」にしておくと段落ごとに1行空いている文書などを意味単位で分割しやすい
検索方式として、全文検索+ベクトル検索のハイブリッドを利用可能。検索結果の候補を並べ替えるリランクも設定できる

 ナレッジを用意できたら、「Knowledge Retrieval」ブロックの「知識」に登録したナレッジを登録し、さらに「Question Classifier」の「クラス1」の質問を「Question related to ●●」のように登録したナレッジに合ったものに変更しておく。

 これで、「デバッグとプレビュー」から、ナレッジに関する質問をすると、フローのブロックが一つずつ実行されながら回答される様子を確認できる。なお、ナレッジとClassifierブロックが適切に設定されていないと、分岐が思い通りにならないので、注意が必要だ。

ナレッジを登録し、質問分類器(Question Classifier)でキーワードを設定
デバッグとプレビューで試せる。質問内容によってフローが分岐していることを確認できる

テンプレートをベースに拡張する

 最後に、もう少し、複雑な例を紹介しておく。

 ひとつずつ説明すると長くなるので、概要のみ紹介しておく。例は出版社のチャットボットをイメージしたものとなる。最初に、質問内容が特定の書籍の内容(サンプルでは青空文庫の「走れメロス」の内容)についての質問なのか、本のデータについての質問なのか、その他の質問なのかを判断し、もしも、本の内容についての質問ならナレッジから回答する。

作った例

 書籍のデータについての質問だった場合は、入力フォームを用意しておき、ISBNコードが入力されていればOpenBD(オープンな書誌情報データベース)のAPIを利用してISBNコードで検索し、フリーワード検索ならGoogle Book Search APIを利用してタイトルや内容などを検索する。

 最後に「今日の東京の天気は?」などのように、その他の質問の場合は、GoogleSearchを呼び出して検索結果から、トップの結果のウェブサイトの内容を読み込み、それを要約して表示する。

 このフローのポイントは、GoogleSearchの出力結果からURLを取り出す処理をLLMに任せている点だ。GoogleSearchの出力結果は、Markdown形式のタイトルとURLのリストとなる。通常は、ここからURLを取り出すコードを書く必要があるが、LLMブロックを間に入れて、先頭のURLのみを取り出すという処理を生成AIに任せている。

前のブロックの出力から、特定の値を取り出したり、結果を整形したりするのに生成AIを利用できる

 API料金が発生するので効率的とは言えないが、コードを書かなくて済むのがメリットだ。同様に、LLMにコードを作成させてCode Interpreterで実行させたいケースでも、間にLLMブロックを入れて、生成AIの回答メッセージや「’’’」などの記号を省き、コードのみを出力結果の変数に入れることなどもできる。

知識として登録した内容についての質問(今回は「走れメロス」)への回答
外部APIを使用して、ISBNコードやキーワードに合った書籍を検索
その他の質問はGoogle Searchを利用して検索

 一応、以下にサンプルファイルを用意しておくが、Difyにインポートしても、そのままでは動かない。現状のDifyでは、エクスポートされたファイルに「ナレッジ」や「ツール(今回の例ではAPI呼び出し用のカスタムツール)」が含まれないからだ。

 カスタムツール用のスキーマはテキストファイルとして含めておくが、カスタムツールは自分で作成する必要があるうえ、フローのブロックや変数なども、複数修正する必要がある。参考程度に考えてほしい。

▼サンプルファイルのダウンロード
sample.zip(4920Byte)

まだ発展途上のツールだ

 このように、なかなか面白いツールではあるが、まだ発展途上という印象が強い。前述したエクスポートの問題もあるが、本稿執筆時点のバージョンではHTTPSの証明書のエラーが発生する場合があり、カスタムツールで外部のHTTPSのAPIを呼び出す際に、特定のサイトにアクセスできないエラーもあった。

 現時点では「お試し」感が強いが、詳細なRAGやチャットフローなどを体験してみたい場合は、触ってみることをおすすめする。

清水 理史

製品レビューなど幅広く執筆しているが、実際に大手企業でネットワーク管理者をしていたこともあり、Windowsのネットワーク全般が得意ジャンル。最新刊「できるWindows 11」ほか多数の著書がある。