ローカルLLM本番投入でハマった話|量子化・マルチGPU・コスト削減の実録2026

月300万超のAPI費用とセキュリティ問題が重なり、ローカルLLM本番移行を決断。vLLM・llama.cppで実際に踏んだ量子化の落とし穴やマルチGPU構成のトラブルを赤裸々に共有します。

先日、チームのML基盤を大幅に刷新して、ようやくローカルLLMがまともにプロダクションで動くようになった。正直、去年の時点では「ローカルLLMはまだ玩具だな」と半ば諦めていたんだけど、2026年に入ってモデルの量子化品質・推論ランタイムの成熟度・GPUメモリ効率が一気に実用ラインを超えてきた実感がある。

Gemma 3系・Qwen3・Llama 4系モデルをvLLM + llama.cppで本番投入するまでの試行錯誤、量子化の選び方、マルチGPU構成時のトラブル、コスト比較まで、自分たちが実際に踏んだ轍を共有したい。API経由でクラウドLLMを使ってる人も「切り替えられるかも」と思えるくらい状況は変わってきてると思う。

同じくローカルLLM周辺で試行錯誤してる人には、以前書いたLoRAファインチューニング6ヶ月の実録も読んでもらえると、モデル適応の全体像が掴みやすいと思う。

なぜ今ローカルLLMに本腰を入れたか

きっかけはシンプルで、OpenAI APIのコストと、社内データをクラウドに送ることへの経営層からのプレッシャーが両方同時にきたことだ。月のAPI請求が300万円を超えたあたりで「ここで一回構成を見直さないとまずい」という話になった。

セキュリティ観点では、SOC2審査でCloudTrailとConfig設計が泥沼になった実録でも書いたように、外部APIへのデータ送信は監査証跡の管理が複雑になる。社内ドキュメントを扱うRAGパイプラインでは特に問題になりやすい。

それと、2025年後半からモデル品質が本当に変わった。EQ-Bench・MMLU・HumanEvalの各ベンチマークでローカルで動く70B級モデルがGPT-4クラスに肉薄してきて、「これ実用的じゃないか?」という認識が社内でも広まっていた。コスト・セキュリティ・品質の三拍子が揃ったタイミングで動かない理由がなくなった、という感じだ。

2026年のモデル選定と量子化の現実

最初にやったのがモデルと量子化フォーマットの選定で、ここで正直かなり時間を使った。

現時点でうちのチームが本番で使っているのは以下の3モデルだ:

  • Qwen3-72B(Q4_K_M):コーディング支援・ドキュメント要約
  • Gemma 3 27B(Q6_K):多言語対応・日本語ドキュメント処理
  • Llama 4 Scout(Q4_0):軽量・低レイテンシが求められる用途

量子化の選び方、これが最初に迷うポイントだと思う。llama.cppのGGUFフォーマットは今や選択肢が多すぎて逆に辛い。個人的には「まずQ4_K_Mを試して、精度が足りなければ上げる」という順番で攻めるのがいちばんストレスが少なかった。

量子化メモリ使用量品質劣化推論速度用途
Q2_K最小大きい最速検証・デモのみ
Q4_0中程度速い低優先タスク
Q4_K_M小さいやや速い本番バランス型
Q5_K_M中大非常に小標準精度優先タスク
Q6_Kほぼなしやや遅い日本語など繊細な用途
Q8_0なし(実用上)遅いベースライン比較用

Q4_K_MとQ5_K_Mの品質差を実際に測ってみたところ、日本語生成では体感で分かるくらい差があった。英語のコード生成はQ4_K_Mで十分なんだけど、日本語の文章生成はQ6_K以上を使わないとアウトプットが微妙になる場面が多かった。これは想定外で、最初は「英語より日本語のほうが語彙が少ないから大丈夫でしょ」と甘く見ていた。

実際に計測したスループット(H100 SXM5 × 2枚構成):

xychart-beta
  title "量子化別スループット(tokens/sec) - Qwen3-72B"
  x-axis ["Q4_0", "Q4_K_M", "Q5_K_M", "Q6_K", "Q8_0"]
  y-axis "tokens/sec" 0 --> 120
  bar [98, 87, 74, 62, 41]

Q4_K_Mが実用上の「コスパ最強帯」というのはデータ的にも明らかで、Q8_0との差は倍以上ある。まだ完全に最適化しきれていない部分はあるが、まずはここを基準に考えるのが正解だと思う。

推論ランタイムの選定:vLLM vs llama.cpp vs Ollama

ランタイムの選択でかなり悩んだ。今の構成はユースケースによって使い分けている。「一つで全部賄おう」という発想を早めに捨てたのが良かった。

flowchart TB
  subgraph Client["クライアント層"]
    A[社内Webアプリ]
    B[Slack Bot]
    C[RAGパイプライン]
  end

  subgraph LB["Load Balancer (Nginx + upstream動的切替)"]
    D[Router]
  end

  subgraph Inference["推論サーバー層"]
    subgraph vLLM_Cluster["vLLM Cluster(高スループット)"]
      E[vLLM Worker 1\nQwen3-72B Q4_K_M]
      F[vLLM Worker 2\nLlama 4 Scout Q4_0]
    end
    subgraph LlamaCPP["llama.cpp サーバー(低レイテンシ)"]
      G[llama-server\nGemma3 27B Q6_K]
    end
    subgraph Ollama_Dev["Ollama(開発・検証環境)"]
      H[Ollama Instance\n各種モデル]
    end
  end

  subgraph GPU["GPU層"]
    I[H100 SXM5 × 2\nTensor Parallel]
    J[RTX 4090 × 1\n単体推論]
    K[RTX 4090 × 1\n開発用]
  end

  A --> D
  B --> D
  C --> D
  D -->|バッチ・並列| E
  D -->|低レイテンシ優先| G
  D -->|Llama4軽量系| F
  E --> I
  F --> I
  G --> J
  H --> K

各ランタイムを実際に本番で使った感想をまとめると:

vLLM 0.9.x系(2026年5月時点)

PagedAttentionとcontinuous batchingの恩恵が大きく、同時接続が多いユースケースでは圧倒的だ。うちの社内チャットツール連携(Slack Bot経由で1日数千リクエスト)はvLLMなしでは成立しなかった。ただ、セットアップが素直じゃない部分がある。特にマルチGPUのTensor Parallelism設定で最初ハマった。

# vLLM起動コマンド(本番で使ってる構成)
python -m vllm.entrypoints.openai.api_server \
  --model /models/qwen3-72b-q4_k_m.gguf \
  --tensor-parallel-size 2 \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.90 \
  --enable-chunked-prefill \
  --max-num-batched-tokens 8192 \
  --port 8000

--gpu-memory-utilizationは最初0.95にしてOOMが頻発した。0.90で安定している。このあたりは環境によって違うと思うので、最初は保守的な値から始めることをすすめる。

llama.cpp(llama-server)

シングルリクエストの低レイテンシが必要な場面ではいまだにllama.cppが強い。Gemma 3 27Bを日本語ドキュメント処理に使っているが、TTFT(Time to First Token)がvLLMより一貫して速い。

# llama-server 起動設定
llama-server \
  --model /models/gemma3-27b-q6_k.gguf \
  --n-gpu-layers 999 \
  --ctx-size 16384 \
  --n-parallel 4 \
  --flash-attn \
  --port 8001

--flash-attnフラグ、2026年時点では安定して有効にできるようになった。去年まではたまに挙動が怪しかったが、今は問題ない。地味に嬉しい改善だ。

Ollama

開発・検証環境での使い勝手は圧倒的に良い。本番には使っていないが、エンジニアが手元でモデルを試すためのインターフェースとしては最高だと思う。プロンプト設計のイテレーションが爆速で回せる。プロンプト設計の構造化についての記事でも書いたが、試行錯誤の初期段階はOllamaで回すのが一番効率がいい。

マルチGPU構成で踏んだハマりどころ

H100 × 2枚のTensor Parallel構成で、最初の2週間はほぼハマりっぱなしだった。「GPUが2枚あれば2倍速くなる」という単純な話じゃないことを身をもって学んだ。主なトラブルを共有する。

NVLink確認の重要性

Tensor Parallelismは原則としてNVLink接続が前提だ。PCIeだとGPU間通信がボトルネックになって、シングルGPUより遅くなることもある。

# NVLink状態確認
nvidia-smi nvlink --status -i 0

# 出力例(NVLink有効な場合)
GPU 00000000:3B:00.0
         Link 0: <Active>
         Link 1: <Active>
         ...

うちの環境はHGXボードでNVLinkが有効だったが、別のプロジェクトで使っているPCIe接続のRTX 4090 × 2構成ではTP=2にしたら逆に遅くなった経験がある。GPUトポロジーの確認は必須だ。

CUDA_VISIBLE_DEVICESとプロセスアフィニティ

複数モデルを同一ホストで動かすとき、CUDA_VISIBLE_DEVICESで明示的に分離しないと干渉する。

# vLLM(GPU 0,1を使用)
CUDA_VISIBLE_DEVICES=0,1 python -m vllm.entrypoints.openai.api_server \
  --tensor-parallel-size 2 ...

# llama-server(GPU 2を使用)
CUDA_VISIBLE_DEVICES=2 llama-server ...

これをやらずに同じGPUをvLLMとllama-serverが取り合って謎のクラッシュが発生した。原因特定に半日溶かした。エラーメッセージが全然ヒントにならなくて本当に辛かった。

実際のレイテンシ推移(本番導入後3ヶ月)

xychart-beta
  title "P95レイテンシ推移(ms) - 社内チャットbot用途"
  x-axis ["Week1", "Week2", "Week4", "Week6", "Week8", "Week10", "Week12"]
  y-axis "P95 Latency (ms)" 0 --> 3000
  line [2800, 2400, 1900, 1600, 1450, 1380, 1320]

Week1〜2の高さはチューニング中の値で、chunked prefillの有効化とGPUメモリ使用率の調整でWeek4以降は落ち着いてきた。今はP95で1.3秒前後で安定している。最初の2週間と比べると半分以下になったので、チューニングの効果は確かにあった。

コスト比較:クラウドLLM vs ローカルLLM

これが経営層を一番説得できた資料なので、実際の数字を出す。

比較軸OpenAI GPT-4oローカルLLM(H100×2)備考
月額コスト約320万円約45万円(サーバー償却含)月300万token想定
レイテンシ(P50)800ms680msうちのユースケース
データプライバシー外部送信あり完全内部完結監査対応で重要
モデル更新自動(制御不可)任意タイミング再現性担保できる
カスタムファインチューニング費用高・制限あり自由LoRA適用済み
障害時リスクAPI障害に依存自前管理が必要運用コスト発生

月のコスト差が275万円。サーバー初期費用がH100 × 2で約800万円だったので、単純回収は3ヶ月を切る計算になる。もちろんこれは運用負荷・エンジニアの工数を含んでいないので実際はもう少しかかるけど、それでも投資対効果は十分あった。スライド一枚でこの表を見せたら、会議室の空気が変わったのを覚えている。

ただし、誤解してほしくないのは「ローカルLLMが常に正解」ではないということだ。うちでも最先端の推論能力が必要な研究系タスクはOpenAI o3を継続して使っている。使い分けが正解だと思う。

監視・運用体制で実際にやっていること

ローカルLLMの運用で地味に大変なのが監視だ。APIサービスと違ってSLAを自分たちで担保しなければならない。これが想定より工数を食った正直なところで、「動かすこと」と「安定して動かし続けること」は全然別の話だった。

現在の監視スタック:

sequenceDiagram
  participant Client
  participant Router as Nginx Router
  participant vLLM
  participant Prometheus
  participant Grafana
  participant Slack

  Client->>Router: リクエスト
  Router->>vLLM: 転送
  vLLM->>Client: レスポンス
  vLLM-->>Prometheus: メトリクス収集(/metrics)
  Prometheus-->>Grafana: 可視化
  Grafana-->>Slack: アラート通知
  note over Prometheus: GPU使用率・キュー深度<br/>TTFT・スループット監視

vLLMは/metricsエンドポイントでPrometheusメトリクスを吐いてくれる。特に監視しているのは:

  • vllm:num_requests_waiting:キュー詰まりの検知
  • vllm:gpu_cache_usage_perc:KVキャッシュ枯渇の予兆
  • vllm:time_to_first_token_seconds:P95レイテンシ

KVキャッシュ使用率が85%を超えたらアラートを出す設定にしている。これを超えるとスループットが急激に落ちる経験をした。閾値の設定は経験則に近いが、80〜85%あたりが現実的なラインだと思う。

llama-serverはPrometheusネイティブ対応ではないので、カスタムエクスポーターを書いた。正直これが地味に面倒で、vLLMとllama.cppで監視コードが分離してしまっているのは今も課題として残っている。誰かいい解決策を持っていたら教えてほしい。

RAGパイプラインとの統合についてはRAG本番運用1年で痛感した実録が参考になると思う。特にチャンキング戦略とベクトル検索の部分はローカルLLM構成と組み合わせることが多いので、セットで読んでおくと良い。

まとめ

2026年時点のローカルLLM本番運用を実際にやってみて、重要だと思ったポイントを整理する。

  1. 量子化はQ4_K_Mをベースラインにする:日本語など精度が重要な用途はQ6_K以上。コードはQ4_K_Mで十分なケースが多い。

  2. ランタイムはユースケースで使い分ける:高スループットが必要ならvLLM、低レイテンシシングルリクエストならllama.cpp、開発・検証はOllama。全部を一つで賄おうとしない。

  3. マルチGPU構成はNVLinkの確認が最初のステップ:PCIe接続でTensor Parallelismを使っても恩恵が得られないケースがある。

  4. 監視はPrometheus + Grafanaでvllm:num_requests_waitingとKVキャッシュ使用率を必ず監視する:これを怠るとキュー詰まりで無音障害が起きる。

  5. コスト回収は思ったより早い:うちのケースでは3ヶ月以内に初期投資を回収できる試算になった。ただし運用工数を忘れずにカウントすること。

次のアクションとして、まず手元で試したい人はOllamaをインストールしてollama run qwen3:14bから始めるのが一番早い。14Bクラスならゲーミング用のRTX 4070 Ti(16GB VRAM)でもQ4_K_Mが動く。「本当にローカルで動くんだ」という体験から始めると、その後の技術選定の解像度が上がると思う。

皆さんのチームではローカルLLMの検討はどこまで進んでますか?「まだクラウドAPIで十分」という判断も全然ありだと思うし、逆に「もっと早く移行すればよかった」という声も聞く。ユースケース次第で答えが変わる領域なので、ぜひコメントや@での共有を聞かせてほしい。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事