見出し画像

Langflow をCloudRunで動かしてみる

こんにちは。今回は、Langflow というLLMツールをGCPのマネージドコンピューティングサービスであるCloudRunにデプロイして動かしてみました。

Langflowとは

Langflowは、LangChainの機能をGUIで提供するツールで、ブラウザ上で視覚的に操作できます。ドラッグ&ドロップの簡単なインターフェースで、非エンジニアでも直感的に使いやすいのが利点です。

ソースコードはOSSとして公開されていて、誰でも無料で使うことができます。

似たようなサービスに Dify というサービスがあります。機能的にはDifyの方が充実しているのですが、Difyをデプロイしようとした場合、docker-composeが必要です。
一方で、こちらの Langflow は単一のdockerイメージでデプロイできることがわかったので、今回はCloudRunにデプロイをして実際に使ってみます。

実装

全コードはこちらで共有しています。
https://github.com/M0T0-2020/GCP-memorandum/tree/master/langflow-on-cr

Langflowでは、データストレージにデータベースや作成したサービス情報を保存します。保存先のデータストレージ先はデプロイ時の環境変数によって指定できるようになっています。

langflow をCloudRunにデプロイするには、 CloudRun上で永続的なボリュームを使えるようにすることが必要です。

そこで、CloudRunのボリュームマウントを使用して、GCSを永続的なデータストレージとして使用します。過去にも説明がありますが、CloudRunのボリュームマウントとは、dockerのボリュームマウント先としてGCSなどを使用できる機能です。

docker

Langflow のデプロイ時の設定を .env に保存します。
.env は公式のgithunの例を参考にして作成しました。

LANGFLOW_CONFIG_DIR を `/app/langflow-storage/db` として、こちらにログを書き出してもらうように設定します。
また、LANGFLOW_DATABASE_URL もそれに応じて、`sqlite:////app/langflow-storage/db/langflow.db` としています。

# docker/.env(抜粋)

# Config directory
# Directory where files, logs and database will be stored
# Example: LANGFLOW_CONFIG_DIR=~/.langflow
LANGFLOW_CONFIG_DIR="/app/langflow-storage/db"

# Save database in the config directory
# Values: true, false
# If false, the database will be saved in Langflow's root directory
# This means that the database will be deleted when Langflow is uninstalled
# and that the database will not be shared between different virtual environments
# Example: LANGFLOW_SAVE_DB_IN_CONFIG_DIR=true
LANGFLOW_SAVE_DB_IN_CONFIG_DIR=true

# Database URL
# Postgres example: LANGFLOW_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/langflow
# SQLite example:
LANGFLOW_DATABASE_URL=sqlite:////app/langflow-storage/db/langflow.db

この設定でdockerをデプロイして、Artifacts Registry にimageをアップしておきます。

terraform によるデプロイ

terraformを使って、cloudrunのデプロイを行います。

# terraform/main.tf (抜粋)

provider "google" {
  project = var.project
  region  = var.region
}

# GCSバケットの作成
resource "google_storage_bucket" "default" {
  name                        = var.storage_name
  location                    = var.region
  uniform_bucket_level_access = true
  # 実験なので、消せるようにする
  force_destroy               = true
}

# Cloud Run サービスの作成
resource "google_cloud_run_v2_service" "service" {
  depends_on          = [google_storage_bucket.default]
  name                = "langflow-test"
  location            = var.region
  # 実験なので、消せるようにする
  deletion_protection = false

  template {
    service_account = google_service_account.cloud_run_sa.email
    timeout         = "120s"
    containers {
      image = var.image_path
      volume_mounts {
        name       = var.volume_name
        mount_path = "/app/langflow-storage"
      }
      ports {
        container_port = 7860
      }
      resources {
        limits = {
          "memory" = "4Gi"
          "cpu"    = "6"
        }
      }
    }

    volumes {
      name = var.volume_name
      gcs {
        bucket    = google_storage_bucket.default.name
        read_only = false
      }
    }
    scaling {
      min_instance_count = 0
      max_instance_count = 1
    }
  }

  ingress = "INGRESS_TRAFFIC_ALL"
}

resource "google_cloud_run_v2_service_iam_member" "member" {
  project  = google_cloud_run_v2_service.service.project
  location = google_cloud_run_v2_service.service.location
  name     = google_cloud_run_v2_service.service.name
  role     = "roles/run.invoker"
  member   = "allUsers"
}

説明

`resource "google_storage_bucket" "default"` の部分で、マウント先にGCSを作成します。

`resource "google_cloud_run_v2_service" "service"` の部分で、CloudRunのデプロイを行なっています。
デプロイして後付けで微調整したことですが、サービスが重かったので、 timeout = "120s" に設定しています。また、メモリも4GiB、CPUコア数は6と少し高いスペックを指定しています。

今回は実験なので、 `ingress = "INGRESS_TRAFFIC_ALL"`で、invokerも "allUsers" 設定にしています。ただ、この設定だと誰でも見れてしまうので、IAPを付けるなどのユーザー制限も必要かと思います。

結果

デプロイ後、CloudRunのサーバーにアクセスするとこんな感じで、webページが見れました。

特に問題なく動作していた

GCSの方を確認すると、Langflow のデータが保存できていました。

サーバーが起動するとメモリに全てのデータをロード。
サーバーシャットダウン時にデータをストレージに保存するという挙動になっていました。GCSへのアクセス数は少なく、サーバーのメモリ負荷が重いという印象でした。

GCSのバケット内容

こんな感じで感じで無事、サービスを見ることが出来ました。
ただ、サービスをサクサク動かすには、少しインスタンスのスペックを上げる必要がありそうだなと思いました。使い方も常にサーバーを立てる想定なのかなと思います。

Langflowには作ったフローをjson化して、フロントエンドなしで処理をだけ実行できるので、ローカルで開発して処理だけをクラウドで動かすとかでもいいのかなと思いました。

以上です。ありがとうございました。


補足

invorker 設定を自分につけて、HTTP リクエストを送って回答を得ることも出来ました。

curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-identity-token)" \
    "<cloudrunのURL>" \
    -H 'Content-Type: application/json'\
  -H 'x-api-key: <サービス内で作成するtoken>'\
    -d '{"input_value": "こんにちは",
    "output_type": "chat",
    "input_type": "chat",
    "tweaks": {
  "ChatInput-mLYcE": {},
  "Prompt-IidU2": {},
  "ChatOutput-g1Upm": {}
}}'

返答 (一部)

"outputs":[
{
"inputs":{"input_value":"こんにちは"},
"outputs":[
{"results":{"message":{"text_key":"text","data":{"text":"Answer the user as if you were a pirate.\n\nUser: こんにちは\n\nAnswer: ",...

この記事が気に入ったらサポートをしてみませんか?