メインコンテンツへスキップ
友田 陽大
Llama・オープンウェイトLLM
Llama
vLLM
生成AI
GPU
MLOps
セルフホスト
Python

vLLM で Llama を本番セルフホストする:高スループット推論サーバ運用記

Llama を自前GPUで本番運用するための vLLM 実践ガイド。連続バッチとPagedAttentionでスループットを最大化し、FP8量子化・テンソル並列で詰め、OpenAI互換エンドポイントとして提供。ヘルスチェック・可観測性・オートスケール・グレースフルドレイン・Bedrockフォールバック・ネットワーク隔離まで、落ちない推論基盤の作り方を実コードで。

公開日
読了時間
9分
著者
友田 陽大
シェア

この記事のゴール

Llama を本番投入する全体像で「自前運用なら vLLM」と書きました。本稿はその実装の runbook です。データを外に出せない・1リクエスト単価を最小化したい・微調整した重みを動かしたい——そんな要件で Llama を自分のGPUで、落ちずに、速く動かすための全工程を実コードで示します。

ゴールは、vllm serve を叩けることではなく、**ヘルスチェック・可観測性・オートスケール・回復性・セキュリティを備えた“本番の推論基盤”**を組めることです。

信頼性の開示:GPU を本番で回す難しさ(スループット・障害・コスト)は、動画AIローカライズ基盤で実際に踏んだ領域です。本稿のコマンド・フラグは公式(vLLM Blog: Llama 4vLLM Recipes)に基づきます。スループットの実数は環境依存・要ベンチです。


なぜ vLLM なのか

自前サーブの勝敗は「GPU をどれだけ遊ばせないか(実効スループット)」で決まります。vLLM はここに最適化されています。

  • PagedAttention:KVキャッシュを OS の仮想メモリのようにページ管理し、断片化を抑えてより多くの同時リクエストを載せる。
  • 連続バッチ(continuous batching):到着したリクエストを動的に束ねて処理。1件が終わる前に次を詰めるので、GPU が空転しない。これがセルフホストの損益分岐を直接動かす。
  • OpenAI 互換サーバ:8000/v1 を提供。本番コードを一切変えずに向け先だけ差し替えられる。

サーブする:Scout を FP8 × テンソル並列で

公式 recipe に沿った最小の本番コマンドです。FP8 量子化で VRAM を圧縮し、テンソル並列で複数 GPU に分散します。

# Llama 4 Scout(FP8)を 2GPU にテンソル並列、KVキャッシュもFP8で文脈を稼ぐ
vllm serve meta-llama/Llama-4-Scout-17B-16E-Instruct-FP8 \
  --tensor-parallel-size 2 \
  --kv-cache-dtype fp8 \
  --max-model-len 500000 \
  --gpu-memory-utilization 0.90 \
  --port 8000
  • --tensor-parallel-size 2:重みとKVを2GPUに分割。台数は VRAM とモデルで決める。
  • --kv-cache-dtype fp8:KVキャッシュをFP8化。使える文脈長が実質的に伸び、スループットも改善(精度劣化は実用上小さい)。
  • --max-model-len:実効上限。Scout は本来 10M だが、VRAM とレイテンシの現実で絞る。青天井にしない。
  • --gpu-memory-utilization:確保率。上げすぎると OOM、低すぎると同時実行が減る。

🔧 ハマりどころ:FP8 は H100/H200/Ada/Blackwell など対応GPUが前提。非対応GPUだと起動失敗かフォールバックで遅くなる。nvidia-smi で世代を、起動ログで実際の dtype を必ず確認。

立ち上がれば、そのまま OpenAI クライアントで叩けます

import OpenAI from "openai";
// 本番コードは無改修。baseURL を自前エンドポイントに向けるだけ。
const llm = new OpenAI({ baseURL: "http://llama-internal:8000/v1", apiKey: "internal" });
const r = await llm.chat.completions.create({
  model: "meta-llama/Llama-4-Scout-17B-16E-Instruct-FP8",
  messages: [{ role: "user", content: "RAGの再ランキングを2行で" }],
});

コンテナ化:再現可能なイメージにする

本番は手作業の pip install で再現性を失います。イメージに固めるのが原則です。

# Dockerfile — vLLM の公式イメージを基盤に、モデルは実行時にマウント/取得
FROM vllm/vllm-openai:latest

# モデルIDと並列数は環境変数で外出し(イメージは1つ、構成は差し替え)
ENV MODEL_ID=meta-llama/Llama-4-Scout-17B-16E-Instruct-FP8 \
    TP_SIZE=2

# ヘルスチェック:/health が 200 を返すまでトラフィックを入れない
HEALTHCHECK --interval=15s --timeout=5s --start-period=600s --retries=10 \
  CMD curl -fsS http://localhost:8000/health || exit 1

ENTRYPOINT ["sh", "-c", \
  "vllm serve $MODEL_ID --tensor-parallel-size $TP_SIZE --kv-cache-dtype fp8 --port 8000"]

--start-period を長め(モデルロードは数分かかる)に取るのが地味だが重要。ロード中に unhealthy 判定で再起動ループに陥る事故を防ぎます。


可観測性:vLLM は最初からメトリクスを出す

vLLM は Prometheus 形式のメトリクス/metrics に出します。これを取り込めば、スループット・待ち行列・GPUキャッシュ使用率・TTFT/TPOTが可視化でき、「いつスケールすべきか」を数字で判断できます。

# 監視で見るべき主要メトリクス(例)
# vllm:num_requests_running     … 実行中リクエスト数(飽和の指標)
# vllm:num_requests_waiting     … 待ち行列(増え続けるならスケール)
# vllm:gpu_cache_usage_perc     … KVキャッシュ使用率(高止まりは限界)
# vllm:time_to_first_token_*    … 体感レイテンシ
curl -s http://localhost:8000/metrics | grep -E "num_requests|gpu_cache_usage"

num_requests_waiting継続的に積み上がるなら容量不足のサイン。ここをトリガにGPUノードをオートスケールします。可観測性の設計思想はOpenTelemetry の記事に揃えてください(メトリクス・ログ・トレースの相関、PII非出力)。


オートスケールとグレースフルドレイン

GPU は高価なので、需要に追従させます。同時に、スケールインや更新で処理中のリクエストを切らないことが品質です。

  • スケールアウト判断num_requests_waiting / キュー滞留時間をトリガに、GPUノードを増やす。コールドスタート(モデルロード数分)を見込み先回りで増やす。
  • グレースフルドレイン:終了シグナルを受けたら新規受付を止め、処理中を完走させてから落とす。ロードバランサのレディネスを先に落とし、preStop で待つ。
# k8s(抜粋):レディネスで安全に出し入れし、preStop で在庫を捌いてから落とす
readinessProbe:
  httpGet: { path: /health, port: 8000 }
  periodSeconds: 10
lifecycle:
  preStop:
    exec: { command: ["sh", "-c", "sleep 30"] } # 在庫リクエストの完走待ち
terminationGracePeriodSeconds: 120

回復性:自前ノードの障害を全体障害にしない

セルフホストは落ちる前提で設計します。クライアント側にタイムアウト・リトライ・フォールバックを持たせ、自前ノードが死んでもBedrockに逃がして止めない

// lib/llama-client.ts — 自前vLLM優先、ダメならBedrockへフォールバック(止めない)
import OpenAI from "openai";

const selfHosted = new OpenAI({ baseURL: process.env.VLLM_URL, apiKey: "internal", timeout: 30_000 });

export async function generate(prompt: string): Promise<{ text: string; via: "self" | "bedrock" }> {
  try {
    const r = await selfHosted.chat.completions.create({
      model: "meta-llama/Llama-4-Scout-17B-16E-Instruct-FP8",
      messages: [{ role: "user", content: prompt }],
    });
    return { text: r.choices[0]?.message.content ?? "", via: "self" };
  } catch (err) {
    // タイムアウト/接続不可/5xx は“正常系”として吸収し、マネージドへ退避する。
    const text = await viaBedrock(prompt); // Converse API 実装は別関数に分離(SRP)
    return { text, via: "bedrock" };
  }
}

連鎖障害を防ぐには、フォールバック側にもサーキットブレーカーを入れて殺到を止めます(リトライ/バックオフ/サーキットブレーカー)。


セキュリティ:推論エンドポイントは「公開しない」

vLLM の OpenAI 互換サーバはそれ自体に強い認証がありませんインターネットに直接晒さないのが大前提です。

  • ネットワーク隔離:private subnet / VPC に置き、外部から直接到達できないようにする。
  • 前段に認証ゲートウェイ:API Gateway / リバースプロキシで認証・レート制限・監査ログを担う。アプリは内部DNSで叩く。
  • データ非送出:そもそもセルフホストの動機は「外に出さない」こと。ログにもプロンプト本文(PII)を残さない——メタデータだけ記録する。
  • 入力検証:プロンプトも外部入力。長さ上限・スキーマ検証を境界で行う(型安全の規律)。

負荷試験:本番前に「どこで折れるか」を知る

スループットとレイテンシは推測せず計測します。同時実行を段階的に上げ、num_requests_waiting が跳ね TTFT が劣化する点=飽和点を見つけ、そこから1ノードあたりの安全な同時実行数を決めます。

# vLLM 同梱のベンチで実効スループットを測る(数値は環境依存・要実測)
python -m vllm.entrypoints.benchmarks.benchmark_serving \
  --backend openai --base-url http://localhost:8000 \
  --model meta-llama/Llama-4-Scout-17B-16E-Instruct-FP8 \
  --num-prompts 500 --request-rate 20

ここで得た実効スループットを、コスト記事の式に入れて初めて、セルフホストの損益分岐が数字で出ます。


よくある質問(FAQ)

Q. Ollama と vLLM はどう違う? A. Ollama はローカル開発・単機・お手軽vLLM は本番の高スループット。連続バッチで多数同時を捌くのは vLLM。開発は Ollama、本番は vLLM、と使い分けます(ピラー記事のセルフホスト章)。

Q. 何台のGPUが要る? A. モデル・量子化・文脈長次第。Scout(FP8) は少数GPUのテンソル並列が現実的。まず1ノードで負荷試験し、num_requests_waiting が飽和する点から逆算して台数を決めます。

Q. 文脈長 10M を設定していい? A. できますがVRAMとレイテンシが破綻します。--max-model-len実際に必要な長さに絞るのが本番の鉄則。長文脈は --kv-cache-dtype fp8 と併せて現実的な範囲で。

Q. ファインチューニングした重みも動かせる? A. はい。LoRAをマージした重みvllm serve の対象にすれば、特化モデルをそのまま本番提供できます。

Q. マネージド(Bedrock)と比べて運用は重い? A. 重いです。スケール・障害・更新・監視を自前で持つ分、定常大量でコストが見合うときに選ぶべき。少量・変動はBedrockが正解です。


まとめ

vLLM の serve は1行ですが、本番の推論基盤はその外側にあります。

  1. 連続バッチ × FP8 × テンソル並列でスループットを最大化する。
  2. ヘルス/メトリクス/オートスケール/ドレインで落ちない・切らない。
  3. クライアント側のフォールバックで自前障害を全体障害にしない。
  4. 隔離+認証ゲート+データ非送出で守る。
  5. 負荷試験の実数コスト式に入れて損益分岐を出す。

プライベートで可観測・回復性のある Llama 推論基盤を、負荷試験とコスト試算まで含めて構築します。GPU 本番運用の実績をご覧のうえご相談ください。一人 × 生成AIで、速く・安く・安全に。

出典・公式リソース

※ フラグ・スループット・GPU要件は更新・実測依存です。実装前に一次情報と自社ベンチで確認してください。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

AI動画ローカライズ・リップシンク基盤

ケーススタディを見る