−25%

Windows 年払い、10月31日まで。 プランを見る

EQVPS
始める

Langfuse 用 VPS:AI エージェントが何をしたかを見る

Langfuse をセルフホストし、無人で動くエージェントの LLM 呼び出しとツール実行をすべてトレース。検証済みの Docker Compose、実測 RAM、最適なプラン。

深夜 3 時に誰も見ていないところで動くエージェントの価値は、あとから何をしたのかを再構成できるかどうかで決まります。「一晩でトークンを 38 $ 分使った」は最悪の朝です。「検索ツールが空のページを返し、プランナーが 400 回リトライしたせいで 38 $ を使った」は、昼食前に直せるバグです。後者の文を書くにはトレースが要ります。

Langfuse は LLM 呼び出し、プロンプト、ツール実行、トークン数、レイテンシをひとつずつ記録し、クリックでたどれるツリーとして表示します。セルフホストすれば、顧客データや API の出力、ときには紛れ込んだ秘密情報まで含むプロンプトと応答が、他人のダッシュボードではなく自分で管理するサーバーにとどまります。

動かし続けるためのコスト

Langfuse v4 は小さなバイナリひとつではなく、6 つのコンテナです。Web アプリ、バックグラウンドの worker、Postgres、イベント用の ClickHouse、Redis、ファイル用の MinIO。テストサーバーに入れてみたところ、空のプロジェクトで約 3.5 GB の RAM を使っていました。増えていくのは ClickHouse で、送った span はすべてそこに入ります。

負荷プラン
数個のエージェント、数週間分のトレースMedium-IP:6 vCPU、6 GB、45 GB(月額 $20)
エージェント群、数か月分の履歴Pro プラン、RAM 32 GB から — お問い合わせ

これより小さいプランでもインストールはできますが、ClickHouse と worker が同時にメモリを欲しがった瞬間に苦しくなります。私なら 6 GB を下回るものは選びません。

エージェントはどこにいますか? 別のマシンで動くなら、専用の IPv4 付きプランを選んでください。エージェントには HTTPS のエンドポイントが必要で、NAT プランでは送信元アドレスが自分専用ではなく、外部から届くのは SSH ポートだけです。エージェントがこのサーバー自身で動くなら、Langfuse をインターネットに出す必要はありません。試すだけなら NAT の Medium(月額 $12)で十分です。ロケーションはドイツとフィンランドの 2 か所で、空き状況は注文時に表示されます。自分ではなくエージェントに近いほうを選んでください。サーバーの支払いは暗号資産で、KYC は不要です。

インストール

新しく作った Ubuntu 24.04 または Debian 12 のサーバーで、root として作業します。まず Docker:

curl -fsSL https://get.docker.com | sh

次に Langfuse。compose ファイルのデフォルト値ではなく、本物のシークレットを使います:

git clone --depth 1 https://github.com/langfuse/langfuse.git
cd langfuse

PG=$(openssl rand -hex 16); MINIO=$(openssl rand -hex 16)
cat > .env <<EOF
NEXTAUTH_URL=https://langfuse.example.com
NEXTAUTH_SECRET=$(openssl rand -hex 32)
SALT=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$PG
DATABASE_URL=postgresql://postgres:$PG@postgres:5432/postgres
CLICKHOUSE_PASSWORD=$(openssl rand -hex 16)
MINIO_ROOT_PASSWORD=$MINIO
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=$MINIO
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=$MINIO
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=$MINIO
REDIS_AUTH=$(openssl rand -hex 16)
TELEMETRY_ENABLED=false
EOF
chmod 600 .env

このうち 2 つのパスワードは対になっています。Postgres のパスワードは DATABASE_URL の中にも入り、MinIO のパスワードは 3 行の S3_..._SECRET_ACCESS_KEY と一致している必要があります。そのため、それぞれをひとつの変数から取っています。

ここに落とし穴があります。compose ファイルは Web アプリをポート 3000、MinIO を 9090 で全インターフェースに公開し、Docker が公開したポートは ufw をすり抜けます。両方を localhost に縛り、入口をリバースプロキシだけにします:

sed -i 's/- 3000:3000/- 127.0.0.1:3000:3000/; s/- 9090:9000/- 127.0.0.1:9090:9000/' docker-compose.yml
docker compose up -d
curl -s http://127.0.0.1:3000/api/public/health

最後のコマンドは {"status":"OK", ...} を表示するはずです。初回起動ではデータベースのマイグレーションが走ります。私たちのテストでは、コンテナが起動してから約 15 秒でヘルスチェックが通りました。

前段に HTTPS

langfuse.example.com をサーバーの IP に向けてから:

apt install -y caddy
cat > /etc/caddy/Caddyfile <<'EOF'
langfuse.example.com {
    reverse_proxy 127.0.0.1:3000
}
EOF
systemctl reload caddy
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable

証明書は Caddy が自分で取得します。サイトを開いてアカウントを作り(これが最初の組織になります)、プロジェクトを追加して、その公開鍵と秘密鍵をコピーします。

そのあとは扉を閉めておきましょう。Langfuse は AUTH_DISABLE_SIGNUP を理解しますが、標準の compose ファイルはこれを web コンテナに渡さないので、langfuse-web の下に 1 行追加が必要です:

sed -i 's|^      NEXTAUTH_SECRET: \(.*\)$|      NEXTAUTH_SECRET: \1\n      AUTH_DISABLE_SIGNUP: ${AUTH_DISABLE_SIGNUP:-false}|' docker-compose.yml
echo "AUTH_DISABLE_SIGNUP=true" >> .env
docker compose up -d

これ以降、登録しようとすると «Sign up is disabled» が返ります。チームメンバーはプロジェクトの中から追加します。

エージェントからトレースを送る

Python SDK は関数をラップし、入れ子の呼び出しは入れ子の span になります:

python3 -m venv venv && . venv/bin/activate
pip install langfuse
export LANGFUSE_PUBLIC_KEY=pk-lf-...
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_BASE_URL=https://langfuse.example.com
from langfuse import get_client, observe

langfuse = get_client()  # LANGFUSE_* 変数を読み込む

@observe(name="fetch-prices")
def fetch_prices(pair: str) -> dict:
    return {"pair": pair, "bid": 64210.5}

@observe(name="nightly-agent-run")
def run() -> str:
    data = fetch_prices("BTC/USDT")
    return f"done: {data['pair']}"

print(run())
langfuse.flush()  # 短いスクリプトはバックグラウンド送信が終わる前に終了してしまう

LANGFUSE_BASE_URL を省略しないでください。これがないと SDK は黙ってすべてを Langfuse のクラウドに送り、そこにはあなたの鍵が存在しないので、空のダッシュボードを眺めることになります。

span が届いたかをターミナルから確認するには:

curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
  "$LANGFUSE_BASE_URL/api/public/v2/observations?limit=5"

v4 では、古いエンドポイント /api/public/traces は events-only モードについてのエラーを返します。これは想定どおりの動作で、インストールが壊れているわけではありません。実際のエージェントでも、LLM 呼び出しと各ツールを同じようにラップします。さらに Langfuse には主要な LLM SDK やエージェントフレームワーク向けの連携があるので、あちこちにデコレーターを付けなくても、import を 1 行変えるだけで済むことがよくあります。

注意して見ておくこと

  • ディスク。 ClickHouse と MinIO は送ったものをすべて保存します。容量がどこに使われたかは docker system df -v でわかります。長いプロンプトと応答をトレースすると、Medium-IP の 45 GB は数年ではなく数週間で埋まります。月に一度は確認し、手狭になったら 400 GB 以上の Pro プランをお問い合わせください。
  • アップデート。 compose ファイルはメジャーバージョン(:4)を固定しています。docker compose pull && docker compose up -d でその範囲内の修正が入ります。メジャーバージョンを上げる前には changelog を読んでください。トレースのエンドポイントが消えたのは、まさに v4 でした。
  • バックアップ。 大事なものは Docker ボリュームにあります。Postgres にはユーザー、プロジェクト、鍵、ClickHouse と MinIO にはトレースそのもの。定期的にサーバーの外へコピーしてください。

月 $20 の価値はあるでしょうか? エージェントがそれ以上のトークン代を使っているなら(無人のエージェントの多くはそうです)、トークンの行き先がわかることは、ループが初めて暴走したその日に元が取れます。1 日 1 回動くだけの小さなエージェントには、どれも必要ありません。ログファイルとトークンカウンターで十分です。

関連記事

デプロイの準備はできましたか?暗号通貨で支払い、KYC不要 — 約1分でオンライン。

今すぐデプロイ →

FAQ

セルフホストの Langfuse にはどれくらい RAM が必要ですか?

私たちのテストサーバーでは、Langfuse v4 は web、worker、Postgres、ClickHouse、Redis、MinIO の 6 コンテナで動き、空のプロジェクトで約 3.5 GB の RAM を使いました。ClickHouse は送信する span ごとに大きくなります。数個のエージェントなら Medium-IP(RAM 6 GB、ディスク 45 GB)で余裕をもって動きます。数か月分の履歴を持つエージェント群全体には Pro プランが必要で、こちらはお問い合わせで提供しています。

Langfuse に専用の IP アドレスは必要ですか?

エージェントが別の場所で動き、インターネット経由でトレースを送る場合だけです。エージェントには HTTPS のエンドポイントが必要ですが、NAT プランが外部から受け付けるのは SSH ポートだけです。エージェントが同じサーバー上にあるなら、Langfuse は localhost のままでよく、ダッシュボードは SSH トンネルで開けます。その場合は NAT の Medium プランで足ります。

コードは動くのに、ダッシュボードが空のままです。なぜですか?

ほとんどの場合、LANGFUSE_BASE_URL が設定されていません。これがないと SDK はすべてを Langfuse 自身のクラウドへ送り、そこにはセルフホストの鍵が存在しないため、あなたのサーバーには何も届きません。変数に自分のアドレスを設定してください。

/api/public/traces がエラーを返します。インストールが壊れていますか?

いいえ。Langfuse v4 は events-only モードで動作し、このエンドポイントは無効になっています。データは /api/public/v2/observations から読んでください。私たちもこの呼び出しでテスト用の span が届いたことを確認しました。

知らない人がインスタンスに登録できないようにするには?

Langfuse は AUTH_DISABLE_SIGNUP を読みますが、標準の docker-compose.yml はこの変数を web コンテナに渡さないため、.env に書くだけでは効きません。langfuse-web の environment に 1 行追加し(コマンドは下にあります)、自分のアカウントを作ったあとで true にすると、以降の登録には «Sign up is disabled» が返ります。

コメント

まだコメントはありません。最初になりましょう。

コメントを残す

コメントは表示される前にモデレートされます。