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

> オープンな言語モデルを社内の GPU サーバーで動かし、OpenAI 互換の API として使う手順。vLLM 0.31 の導入、日本語モデルの起動、2 枚の GPU への分割、メモリの設定、--api-key だけに頼らない守り方まで、コマンドとコードで示す。

- URL: https://weaveai.jp/journal/vllm-inference-server-on-premises/
- カテゴリ: AI最新技術
- 公開: 2026-10-08 / 更新: 2026-10-08
- 執筆: weaveAI 編集部（株式会社サオス）

社内に言語モデルを置くなら、推論サーバーには vLLM を使い、OpenAI 互換の API として社内のアプリから呼ぶ形が、2026年10月時点で一番手間が少ない構成です。アプリ側は接続先の URL を変えるだけで、クラウドの API と社内のモデルを切り替えられます。この記事では、日本語を強化したオープンモデルを 1〜2 枚の GPU で動かし、外から守るところまでを組みます。どの大きさのモデルにどれだけのメモリが要るかは [ローカルLLMは製造現場に置けるか](https://weaveai.jp/journal/local-llm-on-the-factory-floor/) に書いたので、ここでは手順に絞ります。

## 構成

```text
社内アプリ（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 に対応しています。

```bash
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 に分割するときに共有メモリが要るため）。

```bash
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 での起動方法が書かれています。

```bash
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 の接続先を変えるだけで呼べます。

```python
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 系のモデルでは、サーバー側でまとめて切ることもできます（文書の例）。

```bash
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 の設定は次のようになります（証明書や認証の方式は社内の決まりに合わせてください）。

```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
