推論エンジンとモデルの関係を整理する|llama.cpp・vLLM・TensorRT-LLMの使い分け
はじめに
前回、社内知恵袋(ShineosQA)をOllama + Open WebUIからllama.cpp直接実行へ全面書き直した話を書きました。その反響といっしょに、こんな質問を社内外からいただくようになりました。
- 「なぜllama.cppなんですか?サーバで動かすならvLLMの方が速いのでは?」
- 「TensorRT-LLMというNVIDIA公式のものもありますが、あれはどんなときに使うんですか?」
- 「そもそも“推論エンジン”と“モデル”って、何が違うんですか?」
ちょうど社内の技術共有会でこのテーマを話す機会があったので、その内容を記事として整理したのが本記事です。 「モデルとエンジンの関係」「3つのエンジンのアーキテクチャ上の違い」「どう選ぶか」 の3点を、図と表で説明します。エンジン選びは一度決めると構成全体に影響するので、コードを書き始める前に押さえておきたい話です。
前提:モデルと推論エンジンは「別物」である
モデルとは「重みの塊」で、単体では何もできない
LLMの中身を突き詰めると、学習で確定した膨大な数値(重み)の集合です。Transformerアーキテクチャという「設計図」に沿った層の数やAttentionの構造、語彙数といった構造情報(config)、テキストを数値の列に変換するトークナイザ、そして重み——この3点セットになって初めて「モデル」として扱えます。
ただし、モデルはそれ単体では何もしてくれません。Excelファイルを開くアプリがないとただのデータであるのと同じで、重みをメモリにロードして「次の1トークンを予測する行列計算」をひたすら実行してくれる装置が別に必要です。それが 推論エンジン(推論ランタイム) です。
たとえばChatGPTのようなサービスは、大雑把に書くと次の積み重ねでできています。
つまり「どのモデルを使うか」と「どのエンジンで動かすか」は独立した選択で、その2つをつなぐのがモデル形式(と、モデルのアーキテクチャへの対応)です。ここが今回の主題です。
音楽にたとえると分かりやすいです。モデルは「マスターデータ(楽曲)」で、エンジンは「再生装置」。同じ曲でも、CDプレーヤーで聴くならCD-Rに焼く必要があるし、スマホに入れるならファイル形式を合わせる必要がある。再生装置が違えば、求められる媒体の形式も違う——これが、llama.cppにはGGUF、vLLMやTensorRT-LLMにはsafetensors(HF形式)と「エンジンごとに渡すモデルの形式が違う」ように見える正体です。なお、vLLMとTensorRT-LLMは同じsafetensorsを使い、TensorRT-LLMはそれをGPU向けにビルドする点だけが異なります。
KVキャッシュ:エンジンの腕の見せどころ
エンジンごとの違いを理解する鍵がKVキャッシュです。LLMはテキストを1トークンずつ生成しますが、そのたびに「ここまでの文脈」をAttention計算用に保持しています。これがKVキャッシュで、性質として、
- サイズがコンテキスト長に比例して大きくなる(層数・ヘッド数にも比例)
- 同時アクセスが増えると、リクエスト数ぶんだけKVキャッシュが必要になる
というものがあります。つまりエンジンの個性とは、 「限られたGPUメモリにKVキャッシュをどう詰め込むか」「待ち時間をどう減らして複数リクエストを1つのバッチでさばくか」 の設計に集約されます。このあと出てくるPagedAttentionや継続バッチングは、すべてこの2つの問いへの答えです。
3つのエンジン:アーキテクチャで見ると何が違うか
llama.cpp:「どこでも動く」単体ランタイム
- C/C++だけで書かれた、依存の少ない単体の推論エンジン
- 動く場所が広い:CPU(x86/ARMのSIMD最適化)、Apple Silicon(Metal)、NVIDIA/AMD GPU(CUDA/Vulkan/ROCm)
- モデル形式はGGUF。重み・トークナイザ・設定を1ファイルに同梱し、量子化済みで配布される
- llama-serverというOpenAI互換のHTTPサーバを同梱(ShineosQA v2はこれを子プロセスとして実行)
- 量子化の種類が非常に豊富(Q4_K_M、IQ4_XSなど)で、少ないメモリに収める工夫が随所にある
強みはポータビリティです。GPUがなくても動くので、「支給PCの8GBメモリで動かしたい」「アプリに同梱して配布したい」「CIでも動かしたい」という用途では最有力です。半面、GPUサーバで大人数の同時リクエストをさばく用途では、後述のvLLMなどにスループットで及ばないことが多い(バッチングの設計思想が違う)です。
vLLM:「サーバでさばく」ためのエンジン
- 研究機関発祥のOSSで、現在はコミュニティ主体で活発に開発。Python(PyTorch)ベース
- 動く場所はNVIDIA GPUが中心(AMDやTPU、CPUなども対応範囲を広げている)
- モデル形式はHugging Face形式(safetensors)をほぼそのままロード。AWQ/GPTQ/FP8などの量子化版もそのまま使える
- キーとなる技術が2つ:
- PagedAttention:KVキャッシュを、OSの仮想メモリがページ単位で管理するのと同じ発想で細かく分割・再利用する。断片化によるメモリの無駄を潰し、同一GPUに収められる同時リクエスト数を大きく増やす
- 継続バッチング(continuous batching):生成の完了したリクエストをバッチから抜けさせ、新しいリクエストを都度参加させる。バッチを固定して回す方式と比べ、GPUの稼働率が下がらない
- OpenAI互換APIサーバ(
vllm serve)を内蔵
「1台のGPUサーバに、社内の何十人もが同時に質問してくる」構成で真価を出します。金融業の社内マニュアルAIの記事では、Qwen3-14B(AWQ 4bit)をvLLMで運用しました。
TensorRT-LLM:「そのGPUのための専用機」をビルドする
- NVIDIA公式のLLM推論最適化ライブラリ
- 最大の特徴は、モデルをそのまま実行せず、対象のGPUアーキテクチャ向けに最適化した実行形式(TensorRT engine)にビルド(コンパイル)して使うこと。演算の融合(カーネル融合)、FP8/INT4といった低精度フォーマットへの変換、GPUのメモリ階層に合わせた配置まで、ビルド時に決め打ちで行う
- 継続バッチング(NVIDIAの呼び方ではin-flight batching)やPagedAttention相当のKVキャッシュ管理も備えており、手法レベルではvLLMと重なる。違いは「特定ベンダーのハードに固定して、限界まで最適化するか」
- サービングはTriton Inference Serverと組み合わせるのが定番で、OpenAI互換サーバ(
trtllm-serve)も同梱されている
同一ハードウェアなら3者の中で最も速いことが多い一方、NVIDIA GPU専用で、モデルやGPU構成を変えるたびにビルドが絡み、バージョン管理も重くなります。「環境を固定できる・性能を限界まで絞りたい・それに見合う運用工数をかけられる」場合の選択肢です。
比較表
| 観点 | llama.cpp | vLLM | TensorRT-LLM |
|---|---|---|---|
| 開発主体 | OSSコミュニティ | 研究発祥のOSSコミュニティ | NVIDIA(公式) |
| 実装 | C/C++単体 | Python(PyTorchベース) | NVIDIA最適化ライブラリ |
| モデル形式 | GGUF(1ファイル・量子化済み) | safetensors(HF形式) | HF形式をGPU向けにビルド |
| 動く環境 | CPU・Mac・GPUと広い | GPUサーバ中心 | NVIDIA GPU専用 |
| 得意なこと | ポータビリティ・量子化の豊富さ | 同時多数アクセスのスループット | 固定環境での最高性能 |
| 運用の重さ | ほぼゼロ依存・軽い | Python環境の管理が必要 | ビルドとバージョン固定が重い |
| 向くシーン | デスクトップ常駐・エッジ配布 | 社内APIサーバ・本番サービス | 性能上限を絞り切る専門環境 |
使い分け:何を軸に決めるか
軸は4つ
- どこで動かすか:利用者のPC・エッジ・Macならllama.cppにほぼ収束。GPUサーバならvLLMかTensorRT-LLM
- 同時リクエスト数:1人〜数人ならllama.cppで十分。数十〜数百ならPagedAttentionと継続バッチングが効く領域
- レイテンシか、スループットか:1リクエストの体感速度なら「小さいモデル+llama.cpp」でも戦える。総さばき数ならサーバ向けエンジン
- 運用コスト:llama.cppは依存がほぼゼロ。vLLMはPython環境の管理。TensorRT-LLMはビルドとバージョン固定まで含めた専門運用
ShineosQAでの判断を振り返ると
この軸に当てはめると、ShineosQAがllama.cppだった理由が整理できます。
- 動かす場所は「非エンジニアの支給PC」。GPUなし・メモリ8〜16GBが前提 → llama.cpp
- 同時アクセスは「そのPCを使っている1人」 → PagedAttentionも継続バッチングも不要
- 要求は「CPUでも数秒で最初の1文字」 → モデルを大きくするより、量子化とプロンプトキャッシュの効くllama.cpp
- 配布要件は「ダブルクリックで入る・インストーラ約200MB」 → Pythonランタイムごと同梱する構成は厳しく、C/C++単体が合致
逆に、「社内のGPUサーバ1台を、100人の部署で共有する」なら答えは変わります。この構成ならvLLMが第一候補になり、「サーバがNVIDIA GPUで固定できる・レイテンシ要求がシビア」ならTensorRT-LLMを検討、です。エンジンに優劣はなく、どこで・誰が・どう使うかで答えが変わる——これが本記事で一番伝えたいことです。
Ollama・LM Studioの位置づけ
補足として。OllamaやLM Studioは、実体はllama.cppベースの 「モデル管理・配布の便利ツール」です。llama.cppの前に立って、モデルのダウンロード管理やAPIの形を整えている仲介層で、ShineosQA初代(v1)がOllamaを使っていたのはこのおかげです。そしてv2で「仲介層のやることは自前で書けるから、llama.cppに直行した」というのが前回の記事の話でした。つまり「Ollama vs llama.cpp」はエンジン同士の比較ではなく、「エンジン+管理ツール」か「エンジン素」か の比較です。
成長パスとして考える
- 第1段階:デスクトップ・少人数 → llama.cpp。既存PCのまま始められる
- 第2段階:利用が回り、同時アクセスが増えた → GPUサーバ+vLLM
- 第3段階:ボトルネックがGPU性能そのものになった → TensorRT-LLMで最適化
「最初から最強の構成」を目指さなくても、モデルは同じものを使い回しながら、エンジンだけ載せ替えていくのが現実的な成長パスです。形式の壁(GGUFかsafetensorsか)さえ意識しておけば、モデル選びの検証資産は引き継げます。
補足:Hugging Faceからモデルを入手する
ここからは補足です。上の話を実践するとき、モデルの入手元になるのがHugging Face Hubです。GitHubのモデル版のような場所で、モデルカード(用途・ライセンス・ベンチマーク)と、重み・トークナイザのファイル一式が公開されています。ShineosQAで使っているQwen3もbge-m3も、ここから取得しています。
形式の見分け方
| 形式 | 中身 | 主に使うエンジン | 量子化 |
|---|---|---|---|
| safetensors(HF形式) | 重み(fp16/bf16中心)+config.json・tokenizer.jsonなどのファイル群 | vLLM、TensorRT-LLM | そのまま、またはAWQ/GPTQ/FP8版 |
| GGUF | 重み+トークナイザ+設定を1ファイルに同梱 | llama.cpp(Ollama・LM Studioも) | Q4_K_M・IQ4_XSなど豊富 |
モデルページの「Files and versions」を見ると形式はすぐ分かります。
-
*.safetensors+config.json+tokenizer.jsonが並んでいたらsafetensors(HF形式)。vLLM・TensorRT-LLM向け -
*.ggufが量子化レベルごとに並んでいたらGGUF。llama.cpp向け - リポジトリ名やファイル名に
AWQ/GPTQ/FP8が付いていたら、量子化済みHF形式。vLLMでそのまま動く
GGUFのファイル名(Q4_K_M、IQ4_XSなど)は量子化レベルの表記で、数字はビット幅を表し、小さいほど圧縮率が高くサイズが小さい反面、品質が落ちるリスクが上がると読みます。ただし_S/_M/_Lの違いや、重要度を考慮するIQ系では同じビット幅でも品質が変わるため、数字だけで単純比較はできません。実用上はQ4_K_Mあたりが定番のバランスポイントで、ShineosQAでもIQ4_XSを採用する前に複数構成で品質検証をしました。
ダウンロードの方法
方法は大きく3つあります。
1. ブラウザでダウンロード:モデルページのFilesから個別に取得。手軽ですが、大きなモデルや多数のファイルには不向きです。
2. HF公式CLI(hfコマンド):実務ではこれが定番です。レジュームにも対応しています。
pip install -U "huggingface_hub[cli]"
# GGUFを量子化レベルで絞って取得(llama.cpp向け)
hf download Qwen/Qwen3-4B-GGUF --include "*Q4_K_M*.gguf" --local-dir ./models
# HF形式をリポジトリごと取得(vLLM向け)
hf download Qwen/Qwen3-4B --local-dir ./models/qwen3-4b
(huggingface-cli downloadという旧コマンド名も同じものです。)
3. エンジン側の自動ダウンロード:vLLMはHugging FaceのリポジトリIDを指定すると、初回に自動でダウンロードしてキャッシュします。llama.cppはGGUFファイルを直接指定する方式なので、この指定方法の違いがちょうど「エンジンと形式の関係」そのものです。
# 同じQwen3-4Bでも、エンジンによって"指定するもの"が違う
llama-server -m ./models/Qwen3-4B-Q4_K_M.gguf --port 8080 # llama.cpp: GGUFファイルのパス
vllm serve Qwen/Qwen3-4B --port 8000 # vLLM: Hugging FaceのリポジトリID
なお、vLLMもvllm serve ./models/qwen3-4bのようにローカルパスを指定できます。上で--local-dirに落としたものをそのまま使いたい場合は、この形でパスを渡します。
--local-dirを付けない場合、ダウンロードしたモデルはローカルキャッシュ(~/.cache/huggingface/hub。Windowsでもユーザーディレクトリ以下)に蓄積され、2回目以降は通信なしで起動できます。逆にキャッシュが肥大化しやすいので、上の例のように--local-dirで配置先を明示して管理するのがおすすめです(--local-dir指定時はキャッシュを経由せず、指定したディレクトリへ直接配置されます)。
入手時に確認したい4つのこと
- ライセンス:モデルカードに必ず書かれています。Apache-2.0やMITのような緩いものから、商用利用に条件が付くものまであるので、社内利用や製品組込みの前に確認を
- 量子化レベル:GGUFならどの量子化にするか。迷ったらQ4_K_Mから始めて、品質が気になったら1段上げる
- 対応アーキテクチャ:モデルが新しすぎると、エンジン側の対応がまだのことがある。「どのバージョンから対応」は各エンジンのリリースノートで確認
- 同一性の検証:配布物が意図したものかの確認として、ShineosQAの初回起動DLウィザードでもSHA256検証を入れています。特に「自社アプリに同梱して配布する」場合はやっておいて損がありません
まとめ
- モデルは重みの塊、推論エンジンはそれを実行する装置。2つをつなぐのはモデル形式(GGUF / safetensors)とアーキテクチャ対応
- llama.cppは「どこでも動く」単体ランタイム。クライアントPC・エッジ・配布アプリに強い
- vLLMは「サーバでさばく」エンジン。PagedAttentionと継続バッチングで同時アクセスのスループットを出す
- TensorRT-LLMは「NVIDIA GPU固定で限界まで最適化」。最速を狙える代わりに、ビルドと運用が重い
- 使い分けの軸は「どこで・何人が・どんな性能を・どれだけの運用コストで」
- モデルの入手はHugging Faceから。形式の読み方・ライセンス・量子化・検証の4点に注意
- エンジンに優劣はない。ShineosQAがllama.cppなのは、要件に対する答えがそうだったから。GPUサーバ×多数アクセスなら、答えはvLLMになる
前回のShineosQA記事を読んで「なぜllama.cppなのか」が気になった人の疑問が、この記事で整理できていたら嬉しいです。同じモデルでもエンジンを変えられますし、逆にエンジンを決めたら形式も合わせて決める必要があります。「モデル選び」と「エンジン選び」をセットで考えるのが、ローカルLLM運用の第一歩です。
💡 社内Q&A・ローカルLLM導入のご相談は、以下よりお気軽にお問い合わせください。
参考
- Shineos/shineos-qa-assistant(GitHub)
- ローカルRAG環境を非エンジニアに届ける(当ブログ・前編)
- OllamaとOpen WebUIで作るRAG環境(当ブログ)
- 社外APIが使えない金融業での社内マニュアル問い合わせAI(当ブログ)
- ローカルLLM構築のハードウェア選定ガイド(当ブログ)
- llama.cpp(GitHub)
- vLLM(GitHub)
- TensorRT-LLM(GitHub)
- GGUFフォーマット(ggml docs)
- PagedAttention論文(Efficient Memory Management for LLM Serving with PagedAttention)
- Hugging Face Hub Docs
Discussion