こんにちは。エムスリーエンジニアリンググループのコンシューマチームに所属している園田です。 普段の業務では AWS やサーバーサイド、フロントエンドで遊んでいるのですが、最近はもっぱら OpenAI や Claude3 で遊んでます。
今回は、最近巷で話題の LLM ローコード構築ツールである Dify の OSS 版を AWS のマネージドサービスのみを使って構築してみました。
DifyとはオープンソースのLLMアプリ開発プラットフォームで、様々なLLMを使用してChatGPTのGPTsのようなものがノーコードで簡単に作れます。
引用元: DifyでSEO記事作成を試してみる|掛谷知秀
ローカル環境で Dify を構築する記事はたくさん見かけますが、AWS のマネージドサービスで構築する内容は見かけなかった*1ので公式リポジトリのローカル構築用 docker-compose.yaml を AWS に置き換えてみました。
最初に結論
一撃構築 Terraform テンプレートを公開しています。
VPC は作成済みの前提ですが、VPC さえ構築済みならすぐに Dify が使える状態です(ドメインがないので HTTP です)。
以降は Terraform の中身の解説です。
Dify コンポーネント紹介
ローカル環境で利用するための docker-compose.yaml には次の 9 つのサービスが定義されています。
- api
- worker
- web
- db
- redis
- weaviate
- sandbox
- ssrf_proxy
- nginx
かなり多いですね。このうち、Dify が提供しているコンテナイメージは api/worker, web, sandbox の 3 つのみです(api と worker は同じイメージ)。
- api と worker は Python のコンテナイメージで、エントリポイントで API モードなら
flask
、Worker モードならcelery
を起動しています。 - web は文字通り Web の UI で、Next で実装されています。Dify ではこの UI は console と呼ばれているようです。
- db は PostgreSQL で、アカウントや OpenAI など AI プロバイダーのクレデンシャル、ナレッジなどのメタデータを格納するためのデータストアとしての役割です。
- redis はキャッシュストアとしての役割と、Worker のメッセージブローカーとしての役割です(それぞれ db0, db1 を利用しています)。
- weaviate はオープンソースのベクターデータベースで、アップロードしたドキュメントなどのベクターデータを格納する役割です。
- sandbox について、ここだけ現時点では OSS ではないので確実なことは言えませんが、呼び出し元のソースコードを見る限りはワークフローのコード実行ノードを実行するためのサンドボックス環境のようです。
- ssrf_proxy は SSRF 対策のための Forward Proxy となる Squid です。SSRF の出口対策として送信パケットを制限するためのものです。ここの設定は初期状態では特段変わった制限はしていません。ドキュメントを見る限り、利用者ごとにここを個別にカスタマイズして使うそうです。こちらはなくても動作します。
- nginx はリバースプロキシで、web と api を同一のオリジンにマッピングするためのものでした。こちらもなくても動作します。
それぞれの依存関係は公式リポジトリにありますが、次のようになっています。
コンポーネントが多い割には依存関係はかなりシンプルです。ここで注目すべきは api と worker でボリュームを共有していることです。これは S3 や GCS に変更できます。
AWS による実装
Terraform ソースコードはこちら: GitHub - sonodar/dify-aws-terraform: Terraform template for Dify on AWS
以下はソースコードのおおまかな方針です。より詳細な解説などはソースコメントに記載してあります。
api / worker / sandbox
api と worker は ECS の Fargate タスクとして実装します。前述の api と worker の共有ボリュームですが、こちらは S3 バケットを利用します。 sandbox については、api からしか利用しないようなので api のサイドカーコンテナとして同一タスクに含めました。別タスクにしてしまうと接続のための NLB などが必要になってしまい、かなり複雑になります。 api と worker は直接通信しないので別々のタスクにして ECS サービスも別々にしています。
web
普通の Next アプリケーションなので、普通の ECS サービスとして構築しています。特筆すべきこととして、api の ECS サービスと web の ECS サービスは同じ ALB にアタッチされています(後述の nginx 参照)。
db / weaviate
db は Aurora PostgreSQL を使います。また、Dify はベクターデータベースの実装として pgvector
拡張をサポートしているため、weaviate
の代わりにベクターデータベースとしての役割も持たせます。
このあたりは大規模なシステムでは別個のインスタンスにしたほうがいいかもしれません。今回はもろもろ面倒なので Aurora Serverless にして両方の役割をもたせました。
redis
redis はそのまま ElastiCache Redis を使って構築しました。特筆すべき点として ElastiCache Redis では db0 しか使えない(db1 が使えない)ので celery のブローカーも db0 に相乗りしています。こちらもちゃんとやるなら別途インスタンスを追加したほうがいいかもしれません。最初クラスターモードで構築したら celery で MOVED のエラーが出たのでクラスター無効で構築しています。
ssrf_proxy
SSRF 対策の Forward Proxy はいったんなしで構築しました。利用者が制限可能な場合や、ライトにやるなら SecurityGroup や VPC Endpoint を運用に応じてカスタマイズするので十分だと思います。一般公開したり、ちゃんとやるなら Firewall Manager や IDS/IPS を導入することになると思います。
nginx
こちらは ALB を利用しています。役割としてはパスごとにプロキシ先を web か api かに振り分けているだけなので、ALB Listener Rule の path pattern で対象のターゲットグループを分岐しています。
まとめ
マネージドサービスのみを使って Dify を AWS 上に構築できました。 OpenAI の登場によりニューラルネットワークなど AI の専門知識がなくても誰でも気軽に LLM を利用できるようになりました。 それからまだ 1 年ほどしか経っていないにも関わらず今度は RAG や Agent をローコードで構築をするためのツールが発展してきました。
パブリッククラウドの登場によってインフラ知識がなくてもサービスを構築できるようになったのと同様に、AI の知識がなくても LLM サービスを構築できるようになったのは素晴らしいですね。
We are hiring
エムスリーでは OpenAI や Bedrock などの AI プラットフォームを活用しています。LLM を活用したバックエンドの構築に興味がある方、ぜひ一緒に働きませんか。軽く話を聞いてみるだけでも OK ですので、ぜひともカジュアル面談をお申し込みください!
エンジニア採用情報はこちら!
インターン応募はこちら!
*1:Amazon Lightsail で構築する記事はいくつかありましたが