vLLM で社内に LLM 推論サーバーを立てる:OpenAI 互換 API・量子化・複数 GPU

社内に言語モデルを置くなら、推論サーバーには vLLM を使い、OpenAI 互換の API として社内のアプリから呼ぶ形が、2026年10月時点で一番手間が少ない構成です。アプリ側は接続先の URL を変えるだけで、クラウドの API と社内のモデルを切り替えられます。この記事では、日本語を強化したオープンモデルを 1〜2 枚の GPU で動かし、外から守るところまでを組みます。どの大きさのモデルにどれだけのメモリが要るかは ローカルLLMは製造現場に置けるか に書いたので、ここでは手順に絞ります。
構成
社内アプリ(OpenAI SDK)
│ HTTPS(社内 LAN)
▼
nginx(リバースプロキシ) … 使うパスだけ通す・認証・流量制限・記録
│ http://127.0.0.1:8000
▼
vLLM(vllm serve) … OpenAI 互換 API、GPU 2 枚に分割
│
▼
GPU × 2(例:24GB × 2)
vLLM は外に直接出しません。理由は最後の「守り方」で説明します。
1. 導入
2026年10月時点の最新は vLLM 0.31.0(10月5日公開)です。動くのは Linux だけで、Windows では WSL を使います。Python は 3.10〜3.13 に対応しています。
uv venv --python 3.12 --seed
source .venv/bin/activate
uv pip install vllm --torch-backend=auto
0.31.0 から、PyPI の配布物と Docker イメージの既定が CUDA 13.0 になりました。GPU のドライバが古くて CUDA 13 に対応していない場合は、CUDA 12.9 版の Docker イメージ(vllm/vllm-openai:v0.31.0-cu129)を使います。導入の文書にはまだ「CUDA 12.9 でビルド」と書かれている箇所があるので、リリースノートの表を正としてください。
Docker で動かす場合は、公式文書の例にならって次のようにします。モデルの保存先をホストと共有し、--ipc=host を付けます(複数 GPU に分割するときに共有メモリが要るため)。
docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=$HF_TOKEN" \
-p 127.0.0.1:8000:8000 \
--ipc=host \
vllm/vllm-openai:v0.31.0 \
--model tokyotech-llm/Qwen3-Swallow-32B-RL-v0.2-AWQ-INT4
文書の例では -p 8000:8000 と latest タグですが、ここでは外から直接つながらないよう 127.0.0.1 に限り、版も固定しています。
2. モデルを選んで起動する
例には、東京科学大学と産業技術総合研究所の Qwen3 Swallow の 32B を 4 ビット(AWQ)に量子化したものを使います。Apache 2.0 で、モデルカードに vLLM での起動方法が書かれています。
vllm serve tokyotech-llm/Qwen3-Swallow-32B-RL-v0.2-AWQ-INT4 \
--reasoning-parser qwen3 \
--tensor-parallel-size 2 \
--max-model-len 32768 \
--served-model-name swallow-32b \
--host 127.0.0.1 --port 8000 \
--api-key "$VLLM_API_KEY"
それぞれの意味は次のとおりです。
| 指定 | 意味 |
|---|---|
--reasoning-parser qwen3 | 思考型モデルの「考えた過程」を、回答の本文と分けて返す。モデルカードの指定どおり |
--tensor-parallel-size 2 | モデルを 2 枚の GPU に分けて載せる。既定は 1 |
--max-model-len 32768 | 1 回に扱える長さ(入力と出力の合計)。モデルカードは 32,768 以下を勧めている |
--served-model-name | API で指定するモデル名。省略すると Hugging Face のリポジトリ名になる |
--api-key | /v1 などの下のパスに鍵を求める(後述のとおり、これだけでは守れない) |
このモデルのファイルは約 19GB(2026年10月時点の Hugging Face の表示)なので、重みだけなら 24GB の GPU 1 枚にも載りますが、長い文脈と同時処理の分のメモリ(KV キャッシュ)を考えると、24GB × 2 枚か 48GB 以上の 1 枚が現実的です。これはファイルの大きさからの見積もりで、モデルカードに書かれている数字ではありません。
GPU 同士が NVLink でつながっていない機材(例:L40S)では、vLLM の文書はテンソル並列ではなくパイプライン並列(--pipeline-parallel-size)を使うよう勧めています。
モデルを小さくしたい場合は、同じ Swallow の 8B(tokyotech-llm/Qwen3-Swallow-8B-RL-v0.2)があり、モデルカードは vLLM で主に検証したと書いています。
3. 社内アプリから呼ぶ
vLLM は OpenAI 互換の API(/v1/chat/completions、/v1/responses、/v1/models など)を出すので、OpenAI の Python SDK の接続先を変えるだけで呼べます。
import os
from openai import OpenAI
client = OpenAI(
base_url="https://llm.example.local/v1", # nginx の URL
api_key=os.environ["VLLM_API_KEY"],
)
res = client.chat.completions.create(
model="swallow-32b", # --served-model-name で付けた名前
messages=[
{"role": "system", "content": "あなたは製造現場の品質担当を手伝うアシスタントです。"},
{"role": "user", "content": "外観検査で見つかったクラックの、よくある原因を3つ挙げてください。"},
],
)
print(res.choices[0].message.content)
思考型モデルを --reasoning-parser 付きで動かしていると、考えた過程は本文とは別の項目(モデルカードの例では message.reasoning)に入ります。画面に出すのは content だけにします。
考える過程そのものが不要なら、Qwen3 系のモデルでは、サーバー側でまとめて切ることもできます(文書の例)。
vllm serve Qwen/Qwen3-8B \
--reasoning-parser qwen3 \
--default-chat-template-kwargs '{"enable_thinking": false}'
なお、vLLM は既定で、モデルのリポジトリにある generation_config.json の生成設定(温度など)を使います。自分で決めたい場合は --generation-config vllm を付けます。
4. メモリの設定
うまく起動しない、途中で落ちる、というときに見る設定です。
| 設定 | 既定(0.31.0) | 調整の考え方 |
|---|---|---|
--gpu-memory-utilization | 0.92 | vLLM がその GPU のメモリをどこまで使うか。同じ GPU で他のプロセスも動かすなら下げる |
--max-model-len | モデルの設定から自動 | 長いほど KV キャッシュが要る。業務で使う長さに絞るとメモリが空く |
--max-num-seqs | 70GiB 未満の GPU では 256 | 同時に処理する数の上限。下げるとメモリが空く |
--enable-prefix-caching | 有効 | 同じ前置き(システムプロンプトなど)の計算を使い回す |
--enforce-eager | 無効 | CUDA グラフを使わない。メモリは空くが遅くなる |
--gpu-memory-utilization の既定は、よく引用される 0.9 ではなく 0.92 です(0.31.0 のソースコードで確認)。
量子化の方式は、GPU の世代で使えるものが違います。vLLM の対応表では、AWQ は Turing から Hopper まで使えますが、8 ビット浮動小数点(FP8)の量子化済みモデルは Ada と Hopper の世代だけです。また 0.31.0 で、読み込み時に FP8 に量子化する指定が --quantization fp8 から --quantization fp8_per_tensor に変わりました。古い手順書をそのまま使うと動かないので注意してください。
5. 守り方:--api-key だけに頼らない
vLLM の文書は、--api-key が守るのは /v1、/v2、/inference、/cohere の下のパスだけで、同じサーバーの他の多くのパス(たとえば /invocations は /v1 と同じ推論を行う)は認証なしで開いている、と明記しています。そのうえで、--api-key だけに頼らず、使うパスだけを通すリバースプロキシの後ろに置くことを勧めています。
最小の nginx の設定は次のようになります(証明書や認証の方式は社内の決まりに合わせてください)。
limit_req_zone $binary_remote_addr zone=llm:10m rate=5r/s;
server {
listen 443 ssl;
server_name llm.example.local;
ssl_certificate /etc/nginx/certs/llm.crt;
ssl_certificate_key /etc/nginx/certs/llm.key;
location = /v1/chat/completions {
limit_req zone=llm burst=10;
proxy_pass http://127.0.0.1:8000;
proxy_buffering off; # ストリーミングの応答をためずに流す
proxy_read_timeout 300s; # 長い生成で切れないように
}
location = /v1/models {
proxy_pass http://127.0.0.1:8000;
}
location / {
return 404; # それ以外のパスは外に出さない
}
}
ほかに、文書は次のことも挙げています。
- 1 回のリクエストで生成する数(
n)の上限を、環境変数VLLM_MAX_N_SEQUENCESで小さくする(既定は 16384。文書の例は 64 や 128) - 本番で
VLLM_SERVER_DEV_MODE=1を設定しない - 複数台に分けて動かす場合、サーバー間の通信は既定で暗号化されないので、専用のネットワークに閉じる
社内に置くとデータは外に出ませんが、社内の誰でも何にでも使える状態にすると、機密の図面を誰が読ませたかが分からなくなります。nginx の記録と、どのアプリにどの鍵を渡したかの管理は、最初から用意しておくのが安全です。
出典
- vLLM「Release v0.31.0」(2026年10月5日) https://github.com/vllm-project/vllm/releases/tag/v0.31.0
- vLLM「Installation(GPU)」 https://docs.vllm.ai/en/latest/getting_started/installation/gpu/
- vLLM「Quickstart」 https://docs.vllm.ai/en/latest/getting_started/quickstart/
- vLLM「Using Docker」 https://docs.vllm.ai/en/latest/deployment/docker/
- vLLM「vllm serve」(CLI リファレンス) https://docs.vllm.ai/en/latest/cli/serve/
- vLLM「Parallelism and Scaling」 https://docs.vllm.ai/en/latest/serving/parallelism_scaling/
- vLLM「Online Serving(OpenAI 互換サーバー)」 https://docs.vllm.ai/en/latest/serving/online_serving/
- vLLM「Conserving Memory」 https://docs.vllm.ai/en/latest/configuration/conserving_memory/
- vLLM「Quantization」 https://docs.vllm.ai/en/latest/features/quantization/
- vLLM「Reasoning Outputs」 https://docs.vllm.ai/en/latest/features/reasoning_outputs/
- vLLM「Security」 https://docs.vllm.ai/en/latest/usage/security/
- vLLM ソースコード(0.31.0)cache.py https://github.com/vllm-project/vllm/blob/v0.31.0/vllm/config/cache.py
- Hugging Face「tokyotech-llm/Qwen3-Swallow-32B-RL-v0.2-AWQ-INT4」 https://huggingface.co/tokyotech-llm/Qwen3-Swallow-32B-RL-v0.2-AWQ-INT4
- Hugging Face「tokyotech-llm/Qwen3-Swallow-8B-RL-v0.2」 https://huggingface.co/tokyotech-llm/Qwen3-Swallow-8B-RL-v0.2
- OpenAI「openai-python」 https://github.com/openai/openai-python


