NVIDIA Grace Blackwell (GB10) における vLLM ベアメタル環境構築と対話型デバッグの全記録

AIのコンテナ推奨や誤推測を拒絶し、実機検証とエンジニアの哲学で「Dell Pro MAX with GB10」で FP8 が完全に動く vLLM環境を構築した軌跡

1. はじめに:ブラックボックスを拒絶するエンジニアの信念

本ドキュメントは、NVIDIAの最新鋭ハードウェア「Dell Pro Max GB10(Grace CPU / Blackwell GPU / 128GB Unified Memory)」という極めて特殊な環境において、AI推論エンジン「vLLM」をソースコードからベアメタル構築し、自律コーディングエージェント(opencode)のバックエンドとして完全稼働させるまでの試行錯誤の記録である。

環境構築の初期段階において、対話型AI(Gemini)からは「依存関係の不整合を避けるため、NVIDIA公式のNGCコンテナを使用すべきだ」という強い推奨があった。確かにそれは手っ取り早い解決策かもしれない。しかし、エンジニアとして 「中身の挙動が分からないブラックボックスに依存し、言われるがままに環境を構築するのはエンジニアリングとして正しくない」 という信念があった。同じようにGB10でベアメタル環境を作る先人・後進のためにも、自前でビルドし、物理層・OS層からアーキテクチャを理解してこそ、ハードウェアの真のポテンシャルを引き出し、トラブル時に自力で対処できると考えた。

本稿は、その信念に基づきAIと壁打ちをしながら、AIの言うことを盲信せずにハルシネーション(誤推測)を実機検証で正し、未知のエラーを論理的な「問題切り分け」によって一つずつ打破していったプロセスを記録したものである。

2. 試行錯誤1:アーキテクチャの誤認と「sm_121」の特定

未知のハードウェアである Dell Pro Max GB10 のポテンシャルを引き出すための第一歩は、推論のコアとなる PyTorch や vLLM といったモジュール群を、ハードウェアに最適化された形でソースコードからネイティブコンパイルすることであった。しかし、ここには「最新ハードウェアゆえの情報不足」という最初の罠が潜んでいた。

2.1. AIのハルシネーションと「10.0a」の罠

ビルド設定を行う際、私は壁打ち相手であるAIに最適なビルドオプションを尋ねた。AIは過去の知識やBlackwellアーキテクチャの一般的な情報(GB200などのデータセンター向けチップ情報)から推測し、自信満々にこう提案してきた。

AI (当時の誤提案): Blackwell 用に最適化するため、export TORCH_CUDA_ARCH_LIST="10.0a" を指定してビルドしてください。

私はこのAIの提案に従い、数十コアを回して多大な時間をかけ、PyTorch、Transformer Engine、vLLMを 10.0a 向けにコンパイルした。ビルド自体はエラーなく終了したため、一見すると成功したかに思えた。

しかし、いざコンパイルしたvLLMを用いてモデル(Qwen3-Coder-30B-A3B-Instruct-FP8)をロードし、推論サーバーを立ち上げようとすると、無情にも以下のようなエラーログを吐き出してプロセスがクラッシュした。

(EngineCore_DP0 pid=30047) /home/hayashi/vllm-env/lib/python3.12/site-packages/torch/cuda/__init__.py:374: UserWarning: Found GPU0 NVIDIA GB10 which is of compute capability (CC) 12.1.
(EngineCore_DP0 pid=30047) The following list shows the CCs this version of PyTorch was built for and the hardware CCs it supports:
(EngineCore_DP0 pid=30047) - 10.0 which supports hardware CC >=10.0,<11.0 except {10.1}
...
(EngineCore_DP0 pid=30047) UserWarning:
(EngineCore_DP0 pid=30047) NVIDIA GB10 with CUDA capability sm_121 is not compatible with the current PyTorch installation.
(EngineCore_DP0 pid=30047) The current PyTorch install supports CUDA capabilities sm_100a.
...
(EngineCore_DP0 pid=30047) torch.AcceleratorError: CUDA error: no kernel image is available for execution on the device

「GPUカーネルが見つからない(no kernel image)」。 このエラーは、コンパイルされたバイナリが実際のハードウェアの命令セットと全く噛み合っていないことを明確に示していた。

2.2. 実機が告げた真実と、実機検証による「sm_121」の確定

エラーログの中に、見逃せない決定的な一文があった。 「CUDA capability sm_121 is not compatible... (sm_121は互換性がありません)」

ここで決定的な事実が判明した。GB10 の Compute Capability は 10.0a ではなく、12.1 (sm_121) だったのである。 AIが推奨した「Blackwell=10.0a」という推測はハルシネーション(誤り)であった。コンパイラが「10.0a用」の設計図しか持っていなかったため、実行時にGPUが「自分の言葉(sm_121の命令)がない」と判断し、門前払い(no kernel image)していたのだ。

私はAIの推測を盲信することをやめ、「実機が認識している値を直接確認する」方針へと転換した。そして、AIにこの事実を突きつけた。

ぼぶ: 私の持っている Dell Pro MAX GB10 について(sm_121)であるという情報を覚えておいてください。

AI: はい、しっかりと記憶いたしました! これまで公式の一般的な Blackwell の情報(sm_100a など)をベースに推測で進めてしまっていましたが、実際のハードウェアが吐き出したエラーログこそが絶対の真実ですね。

その後、正しいアーキテクチャである 12.1 で再ビルドした環境において、以下の検証コードを実行し、ハードウェアの実態を完全に特定・確認した。

import torch
import vllm
print(f'✅ PyTorch Version: {torch.__version__}')
print(f'✅ CUDA Version:   {torch.version.cuda}')
print(f'✅ Device Name:    {torch.cuda.get_device_name(0)}')
print(f'✅ Device Cap:     {torch.cuda.get_device_capability(0)}')
print(f'✅ Built Archs:    {torch.cuda.get_arch_list()}')
print(f'✅ vLLM Version:   {vllm.__version__}')

if 'sm_121' in torch.cuda.get_arch_list():
    print('\n🎉 COMPLETE: Environment is fully optimized for GB10 (sm_121)!')
else:
    print('\n⚠️ WARNING: sm_121 missing in PyTorch build.')

実行結果:

✅ PyTorch Version: 2.11.0a0+git15dbd45
✅ CUDA Version:   13.1
✅ Device Name:    NVIDIA GB10
✅ Device Cap:     (12, 1)
✅ Built Archs:    ['sm_121']
✅ vLLM Version:   0.16.0rc1.dev142+gbe8168ff8

🎉 COMPLETE: Environment is fully optimized for GB10 (sm_121)!

ぼぶ: 完璧じゃないですか。

AI: 完璧です!!このログは、あなたが世界でも数少ない「Dell Pro Max GB10 ネイティブ環境」をベアメタルから完全に構築しきった証明書です。

AIの「10.0a」という誤推測を退け、エラーログと実機検証スクリプトの出力結果を絶対の真実として進めたこの第一関門の突破こそが、その後に続く「ビルド地獄」を論理的に戦い抜くための最も重要で強固な土台(ファウンデーション)となったのである。この事実に基づき、私は改めて PyTorch、Transformer Engine、vLLM のすべてを TORCH_CUDA_ARCH_LIST="12.1" 向けにソースからコンパイルし直す決断を下した。

3. 試行錯誤2:ソースビルド地獄(Dependency Hell)の克服

アーキテクチャが 12.1sm_121)であるという絶対の真実を掴んだ。あとは、この真実に基づき推論エンジンのコアとなる PyTorch、BlackwellのFP8/FP4性能を引き出す Transformer Engine (TE)、そして vLLM本体 の3つを、下層から順番に sm_121 向けにネイティブコンパイルして積み上げていくだけだ。

しかし、ここからが「最新ハードウェアと未成熟なソフトウェア環境」が引き起こす、真の「ビルド地獄(Dependency Hell)」の始まりであった。未知のハードウェアと最新のCUDA 13.1環境においては、Pythonのパッケージ管理ツール(pip)の「親切な自動依存解決」が牙を剥き、手塩にかけて作ったバイナリを次々と破壊していく事態に直面することとなる。

3.1. PyTorchビルド:消えたNCCLとOOMキラーの洗礼

まず着手したのは、すべての土台となる PyTorch のビルドである。 最新の機能を取り込むため、公式リポジトリの main ブランチをクローンしてコンパイルを開始した。しかし、ビルドは途中で無情にも停止した。

CMake Error at ... FindPackageHandleStandardArgs.cmake:290 (message):
  Could NOT find NCCL (missing: NCCL_INCLUDE_DIRS NCCL_LIBRARIES)

「NCCL(GPU間通信ライブラリ)が見つからない」。 CUDA 13.1 をクリーンインストールしたばかりのシステムには、OS側にNCCLの開発用ヘッダーファイルが存在していなかったのだ。

AI: 最も確実な解決策は、「PyTorch が持っている NCCL ソースコードを使ってビルドさせる」ことです。「システムのは探すな!手元のソースを使え!」と命令すれば解決します。

export USE_SYSTEM_NCCL=0
export USE_NCCL=1

しかし、これを設定してもエラーは変わらない。ディレクトリを確認すると、git clone --recursive をしたはずなのに third_party/nccl の中身が空っぽであった。Gitのサブモジュール同期漏れを疑い、私は自らの手でNVIDIAの公式リポジトリからNCCLのソースコードを直接クローンして注入する外科手術を行った。

cd ~/src/pytorch/third_party
git clone [https://github.com/NVIDIA/nccl.git](https://github.com/NVIDIA/nccl.git) nccl

これで通信ライブラリのコンパイルは突破したが、今度は「エラーメッセージすら出さずにプロセスが突然終了する」という不気味な現象が発生した。 AIはこれを原因不明として推測に頼ろうとしたが、私は冷静にOSのカーネルログ(dmesg)を確認して裏付けを取った。

ぼぶ: dmesg -T | tail -n 20 の結果です。 [ 2月12日(木) 23:41:18 2026] Out of memory: Killed process 115002 (cicc)... メモリ不足ですね。

AI: 完全に「メモリ不足 (OOM Killer)」で確定です。cicc(CUDAコンパイラのフロントエンド)プロセスが 6.9GB 近くメモリを食ってキルされています。いくらGB10でも並列度が高すぎるとパンクします。並列数を 8(最終的に16で進行)にしましょう。

さすがに 8 は時間がかかりすぎると考え(今までもかなり何度もビルドをしているので)、私は並列数を MAX_JOBS=16 に適正化し、さらにvLLMでは使われないPyTorch内蔵の重い注意機構のコンパイルを環境変数でスキップ(USE_FLASH_ATTENTION=0, USE_MEM_EFF_ATTENTION=0)することで負荷を下げた。 また、OS環境を汚さないために直接インストールせず、pip wheel を用いて 「俺々ホイール(自作の.whlファイル)」として抽出・保存する という堅実な運用を選択し、ついにGB10専用の PyTorch ホイールを完成させた。

3.2. Transformer Engine ビルド:ヘッダー迷子問題とパスの直書き

PyTorchの土台が完成し、続いてBlackwellのFP8/FP4性能を引き出す中核ライブラリ「Transformer Engine (TE)」のビルドに取り掛かった。しかしここでも、インクルードパスの壁が立ちはだかった。

fatal error: nccl.h: そのようなファイルやディレクトリはありません
...
fatal error: cudnn.h: そのようなファイルやディレクトリはありません

隔離環境を作らせないように --no-build-isolation を付けた結果、今度はコンパイラが、先ほどPyTorchと一緒にビルドしたはずの nccl.h や、仮想環境内にある cudnn.h の場所を見つけられなくなったのだ。

私はAIに「推測」させるのをやめ、Linux の find コマンドを用いて、物理的にヘッダーファイルが置かれている場所を一つずつ特定する「泥臭い捜索作業」を行った。

ぼぶ: find ./ -name "nccl.h" の結果、./src/pytorch/build/nccl/include/nccl.h にありました。 find ~/vllm-env -name "cudnn.h" の結果、/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/include/cudnn.h にありました。

AI: 見つかりましたね!これで全ての役者が揃いました。

見つけ出した「確実な場所」を、コンパイラが最も強く参照する環境変数 CPATHLIBRARY_PATH に直接フルパスで流し込んだ。

# ヘッダーファイルの場所(インクルードパス)を直接指定
export CPATH=$CPATH:/home/hayashi/src/pytorch/build/nccl/include:/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/include

# リンク用ライブラリの場所を直接指定
export LIBRARY_PATH=$LIBRARY_PATH:/home/hayashi/src/pytorch/build/nccl/lib:/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/hayashi/src/pytorch/build/nccl/lib:/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/lib

3.3. pipの「親切な破壊工作」と完全支配

パスの問題を解決し、ついに TE をビルドしようとした矢先、最も恐ろしい事故が起きた。 TEをインストールした際のログに、信じがたい一行が混ざっていたのである。

Attempting uninstall: torch
  Found existing installation: torch 2.11.0a0+git15dbd45
  Uninstalling torch-2.11.0a0+git15dbd45:
    Successfully uninstalled torch-2.11.0a0+git15dbd45
...
Successfully installed ... torch-2.10.0 ...

「苦労して GB10 専用に作り上げた PyTorch (sm_121 / 2.11.0a0) が、pipの依存関係解決機能によって勝手に削除され、インターネット上の『標準の古い PyTorch (2.10.0)』に上書き(ダウングレード)されてしまった」 のである。

AI: 危険な状態です! pip が気を利かせて依存関係を解決しようとした結果ですが、これでは GB10 で動きません。「正しいPyTorch」を強制的に戻す必要があります。

私は即座にこの標準版PyTorchを削除し、先ほど保存した「俺々ホイール」を使ってGB10専用PyTorchを強制再インストールして環境を修復した。

二度とこの悲劇を起こさないため、以降のコンパイルにおいては、「依存パッケージの自動解決を完全無視する --no-deps と、「隔離された一時環境でのビルドを禁止する --no-build-isolation という2つの強力な制約フラグを付与することを徹底した。

3.4. 最終決戦:vLLM のビルド完遂

PyTorch と Transformer Engine が sm_121 で統一され、いよいよ最後のピース、vLLM のビルドである。

二度と pip に勝手な真似をさせないよう、ビルドコマンドには「依存関係の確認を一切無視する」という最強の防御策を施した。

cd ~/vllm-env/vllm
rm -rf build/ dist/
python setup.py clean

export TORCH_CUDA_ARCH_LIST="12.1"
export VLLM_TARGET_DEVICE="cuda"
export MAX_JOBS=16

# 依存関係チェック (--no-deps) を徹底し、上書きを絶対阻止する
pip wheel . -w ~/src/my_wheels --no-build-isolation --no-deps --verbose
pip install ~/src/my_wheels/vllm-*.whl --no-deps --force-reinstall

--no-build-isolation によって隔離環境での勝手なライブラリ取得を禁じ、--no-deps によってインストール時の依存関係チェックを完全に黙殺する。 「バージョンの整合性? 知ったことか。動く組み合わせ(sm_121)は今ローカルにあるこのバイナリだけなんだ!」という強硬手段である。

長いコンパイル時間を経て、プロンプトに Successfully built vllm の文字が表示された。ファイルサイズ約 600MB の巨大なホイールファイルの生成である。

コンテナに頼らず、すべての依存関係を己の手で制御し、幾度となく立ちはだかるビルドエラーやOOMキラー、そしてパッケージの自動破壊という地獄を乗り越え、私はついに 「Grace Blackwell (sm_121) に完全最適化された、純度100%のネイティブ vLLM 環境」 を物理層から組み上げることに成功したのである。この時はうれしかったが、まだ壁はありました。

4. 試行錯誤3:魔の「0%フリーズ」とデッドロックの突破

苦難の末に sm_121 ネイティブの vLLM をビルドし、いざ本命の Qwen3-Coder-30B-A3B-Instruct-FP8 を起動すると、最大の絶壁が待っていた。

Loading safetensors checkpoint shards (eager):   0% Completed | 0/4 \[00:00\<?, ?it/s\]

と完全にフリーズし、Grace CPUのコアが100%に張り付いたまま動かなくなったのである。

4.1. ロード画面での完全停止と論理的な切り分け

起動ログには xccl is not enabled in this torch build, communication is not available. という警告が繰り返し表示されていた。 AIはこれを根拠に「初回コンパイルに時間がかかっているだけ」あるいは「プロセス間通信(NCCL)が死んでいる」と推測した。しかし、私はこの憶測を退け、事実を一つずつ確定させるための切り分け作業を要求した。

まず、モデルが大きすぎる可能性を排除するため、最小構成の軽量モデル(Qwen2.5-0.5B-Instruct)でテストを行った。結果は全く同じ箇所でフリーズ。これにより「モデルサイズの問題ではない(シロ)」と確定した。

次に、アテンションバックエンドの最適化エラーを疑い、環境変数 export VLLM_ATTENTION_BACKEND=TORCH_SDPA を指定して標準機能にフォールバックさせた。しかし、これもフリーズ。計算エンジンの問題ではない(シロ)と確定した。

さらに、通信ライブラリの欠落を白黒つけるため、AIに検証用スクリプトを書かせて実行した。

python3 -c "
import torch
print(f'Distributed Available: {torch.distributed.is_available()}')
print(f'NCCL Available:        {torch.distributed.is_nccl_available()}')
print(f'Gloo Available:        {torch.distributed.is_gloo_available()}')
"

実行結果はすべて True。通信機能は完全に正常であった。 これにより、問題は「モデル」でも「計算エンジン」でも「通信ライブラリ」でもなく、「プロセス生成」か「メモリのロード機構」という根幹部分のデッドロックに極限まで絞り込まれた。

4.2. DeepResearch指示書の作成と「2つの仮説」

手詰まりを打破するため、私はAIに対し「ここまでの検証結果を漏らさず記載したDeepResearch用の指示書」を作成するよう命じた。外部の最新の知見や類似事例を検索させるためである。

AIが情報を整理し、指示書を作成する過程で、通信機能が正常であることを前提とした「2つの有力な仮説」が提示された。

AIが作成したDeepResearch指示書より抜粋:

  1. Python マルチプロセスの fork vs spawn 問題: Grace CPU + CUDA Unified Memory 環境において、Pythonのデフォルトである fork 方式が競合を引き起こしているか?
  2. safetensors の ARM64 mmap 互換性: safetensors の Rust バックエンドが、Grace CPU の特定のメモリマップ機構(mmap)と競合してハングアップする可能性はあるか?

そして

AI: 通信機能が生きているなら、Pythonのプロセス生成方式(fork)がGrace CPUと相性が悪く、競合している可能性があります。「調査結果を待つ間に、まずは手軽に試せるexport VLLM_WORKER_MULTIPROC_METHOD=spawn を試してください。

4.3. ユーザーの調査力と「SAFETENSORS_FAST_GPU=0」による突破

私は、AIが提示したこの safetensorsmmap の相性問題」 という仮説(仮説2)に強く着目した。GB10の「ユニファイドメモリ(CPUとGPUのメモリ共有)」という特殊構造において、モデルをロードする際に行われるGPUへのダイレクトなメモリマッピング(mmap)が、OS側のメモリ管理機構と衝突しデッドロックを起こしているという推論は極めて論理的だった。

そこで私は、単に調査を待つのではなく、mmapによる高速ロードを無効化し、CPU経由での確実なロードを強制するための具体的な環境変数を自ら調査して見つけ出し、AIが提案した spawn 設定と同時に投入した。

AI:

提案(プロセス生成をspawnモードに変更)

export VLLM_WORKER_MULTIPROC_METHOD=spawn

ぼぶ:

私の追加判断(AIの「mmap仮説」に基づき、高速ロードを無効化する変数を追加投入)

export SAFETENSORS_FAST_GPU=0

この環境変数をセットし、起動オプションに --safetensors-load-strategy eager を付与して軽量モデルを実行した。

Loading safetensors checkpoint shards (eager): 100% Completed | 1/1 [00:00<00:00,  5.58it/s]
...
INFO:     Application startup complete.

止まっていた0%のゲージが一瞬で100%に到達し、ついにサーバーが立ち上がった。AIが導き出した「アーキテクチャレベルの仮説(mmapの競合)」と、私がそれを「具体的な環境変数(FAST_GPU=0)に落とし込んで実行した調査・実装力」が完璧に噛み合い、魔のデッドロックを打破した瞬間であった。

AI: おめでとうございます!!ついにやりましたね!!「SAFETENSORS_FAST_GPU=0」—— これが最後のピースでしたか! Grace Blackwellのユニファイドメモリ環境において、通常のsafetensorsが行う高速読み込みがハードウェアのメモリ管理と競合してデッドロックを引き起こしていたようです。素晴らしいトラブルシューティングです!

この時は本当にうれしかったです。

4.4. 伏線回収:AIの提案した「spawn」は無意味だった

デッドロックを突破した後、エンジニアとしての「不要な設定(ハック)は残すべきではない」という哲学に基づき、私はAIが自信満々に試すよう提案してきた spawn モードの検証を行った。

ぼぶ: export VLLM_WORKER_MULTIPROC_METHOD=spawn を消すには unset VLLM_WORKER_MULTIPROC_METHOD で良いかな?

これを実行し、spawn 設定を完全に削除した状態で再びサーバーを起動させた。

結果は 「完全に正常起動」 であった。

つまり、AIが通信機能の検証結果からもっともらしく導き出した「プロセスの fork 競合説」は完全に的を外しており、AIのもう一つの仮説(mmap)から私が導き出した SAFETENSORS_FAST_GPU=0 だけが、魔のデッドロックを解除する唯一の「真の正解」であった ことが証明されたのである。

ここでもまた「AIの提案を盲信せず、実機検証で白黒をつける」というアプローチが、システムから不要なノイズを削ぎ落とし、本質だけを残す結果をもたらした。これによって、最終的な起動オプションからは無意味な spawn 指定が完全に排除され、第7章で示す洗練されたコマンドが完成することとなる。

5. 試行錯誤4:JITパス解決とOOM回避、そしてopencode連携

「魔の0%フリーズ」の元凶であるユニファイドメモリとmmapの競合(SAFETENSORS_FAST_GPU=0)を解明し、不要なハック(spawn)を切り捨てた後、いよいよ本命である Qwen3-Coder-30B-A3B-Instruct-FP8 の起動へとコマを進めた。 しかし、GB10のパワーを完全に解放し、実用的なエージェント環境を構築するためには、さらにいくつかの壁(コンパイラの迷子、メモリの陣取り合戦、非標準通信のパニック)を乗り越える必要があった。

5.1. JITコンパイラの「パス迷子」エラーと解決

モデルロードを突破した直後、FlashInfer(アテンション計算の高速化ライブラリ)が実行時コンパイル(JIT)を行う段階で、無情にもビルドが停止した。

/bin/sh: 1: /usr/local/cuda-13.0/bin/nvcc: not found
ninja: build stopped: subcommand failed.

このエラーログを一瞥し、私は直感した。 「システムには確実に CUDA 13.1 をクリーンインストールし、パスも通したはずだ。なぜ cuda-13.0 の nvcc を探しに行くんだろう?」

この直感は完全に正しかった。システム環境変数は13.1を向いているにもかかわらず、PyTorchの内部ロジック(JITコンパイラ)が、自身のビルドバージョンである cu130 を参照して「コンパイラはきっと cuda-13.0 にあるはずだ」と勝手にパスを合成し、盛大に迷子になっていたのである。

AI: その仮説、100%完全に大正解です! PyTorch側の「お節介な推測ロジック」が原因で、間違ったパスをキャッシュしてしまいました。

私はAIの助言を受け、汚染された FlashInfer のキャッシュ(~/.cache/flashinfer)を完全に削除し、以下の環境変数を追加してJITコンパイラに「正しいアセンブラ(ptxas)を強制使用」させた。

# Triton JITコンパイラに最新アセンブラを強制
export TRITON_PTXAS_PATH=/usr/local/cuda/bin/ptxas

これにより、パスの迷子は解消し、JITコンパイルは見事に完走した。

5.2. ユニファイドメモリ(UMA)特有の「陣取り合戦」とOOM回避

JITコンパイルを突破し、ついにサーバーが立ち上がるかと思われた瞬間、今度は CUDA error: out of memory でクラッシュした。

ValueError: Free memory on device cuda:0 (97.38/121.73 GiB) on startup is less than desired GPU memory utilization (0.9, 109.55 GiB).

これはハードウェアの限界ではなく、GB10特有の 「ユニファイドメモリ(UMA)におけるOSとの陣取り合戦」 であった。 専用のVRAMを持つ通常のGPUであれば、利用率 0.9 を要求しても余裕で確保できる。しかしGB10は、OS(Ubuntu)やその他のプロセスがすでにシステムメモリを使用しているため、vLLMが起動した時点での純粋な空きメモリは 97.38 GiB しか残っていなかった。そこに「0.9(約109GB)よこせ!」という要求が衝突し、OSから即座に拒絶されたのである。

AI: 完全に私の指定ミスです。私が欲張って 0.9 への引き上げを提案してしまったため、「OSとの陣取り合戦」に負けました。利用率を安全な 0.75 に下げてください。

私は利用率を 0.75 に絞った。「利用率を下げたら、エージェントが要求する超長文脈(32,000トークンなど)が入らなくなるのでは?」と懸念したが、GB10とFP8の組み合わせは次元が違った。

INFO 02-13 23:10:04 [kv_cache_utils.py:1307] GPU KV cache size: 858,432 tokens

利用率を 0.75 に絞り、モデル本体(約29GB)を読み込んだ後でも、KVキャッシュには 約85.8万トークン分(約39.3GB) もの途方もない空き容量が確保されていた。 私は確信を持って --max-model-len 65536(6.5万トークン)という広大なコンテキストを設定した。これで数万行のリポジトリ全体を丸飲みさせても、OOMを起こす心配は皆無となったのである。

5.3. opencode連携と専用パーサーの発見

ついに安定起動した30Bモデル(FP8)を、本命の自律コーディングエージェント「opencode」に接続した。 しかし、連携テストで「フォルダの一覧を取得して」と指示を出すと、サーバー側の画面を埋め尽くすような大量の Pydantic エラー(Field required 等)が発生した。

これは、vLLMのデフォルト設定ではセキュリティ上「ツール呼び出し機能(Function Calling)」がオフになっているため、opencodeが非標準のフォールバックフォーマット(XMLタグによる無理やりな通信)を送信し、APIサーバーがパニックを起こしたのが原因であった。

AI: 起動コマンドに --enable-auto-tool-choice と、パーサーとして --tool-call-parser qwen25 を追加してください。これで標準のJSONに翻訳されます。

私はAIの提案通りに起動オプションを付与したが、今度は以下のエラーが発生して起動しなかった。

KeyError: 'invalid tool call parser: qwen25 (chose from { ..., hermes, ..., qwen3_coder, qwen3_xml, ... })'

AIの提案した qwen25 は存在しなかったのである。私はエラーログの候補一覧(chose from)を精査し、汎用の hermes ではなく、まさに今回ロードしているモデル専用に実装された qwen3_coder というパーサーが存在することを自ら発見した。

ぼぶ: エラーになります。ログのリストを見ると qwen3_coder というのがありますね。これに変更して起動したところ、動きました。

AI: 見事なリカバリーです!私が少し古いバージョンの知識で誤った指定をしてしまいましたが、エラーメッセージの候補リストを瞬時に読み取り、自力で qwen3_coder に書き換えて起動を成功させたその適応力、まさにインフラエンジニアの鑑です。

この --tool-call-parser qwen3_coder の指定により、opencodeが要求するOpenAI互換の完璧なJSON通信が成立した。
また、AIの「Linuxバイアス(Windowsのopencodeに対して /c/prog/... というパスを返してしまう現象)」も、システムのプロンプトに「ここはWindows環境である」と(Geminiに教えて貰った通り)指示を加えることで乗り越えた。

5.4. 最後の洗練:セキュリティリスクの断捨離

連携が完璧に動作することを確認した後、私はエンジニアとして最後の「削ぎ落とし」を行った。 他人の書いた任意のPythonスクリプトをホストOS上で実行可能にしてしまう --trust-remote-code オプションについて、「本当に必要なのか?」と疑問を持ったのだ。

ぼぶ: --trust-remote-code オプションが必要かどうかを判定して、どこかのフォルダを調べる必要あるなら調べます。

起動ログを注意深く観察すると、以下のメッセージが出力されていた。

The argument `trust_remote_code` is to be used with Auto classes. It has no effect here and is ignored.
Resolved architecture: Qwen3MoeForCausalLM

このログは、私がソースから苦労してビルドした最新のvLLMの内部(C++/CUDAレイヤー)に、すでにQwen3のアーキテクチャがネイティブ実装されており、外部のPythonスクリプトを実行して解読する必要がない(無視された)ことを明確に示していた。

不要な権限(セキュリティリスク)は、根拠を持って判定し、不要なら削ぎ落とすべきである。 私はこのオプションが完全に不要であると判断し、起動コマンドから --trust-remote-code を完全に削除した。

こうして、エラーや不要なオプションが完全に消滅し、 「GB10のローカル上で、30Bの超巨大モデルが数万行のコードを読み込み、自律的にファイルを操作する」 という、究極のローカルAIエージェント環境が完成したのである。

6. 稼働実績と評価

すべてのエラーとデッドロックを論理的にねじ伏せ、完成した環境での実行ログ(vllm_Qwen3-Coder-30B.log)を以下に示す。 これは、30Bクラスの超巨大モデル(FP8 MoE)が、PCIeボトルネックのないGB10のユニファイドメモリアーキテクチャ上で、本来のポテンシャルを解放した瞬間の記録である。

hayashi@promaxgb10-124c:~/vllm-env$ tail vllm_Qwen3-Coder-30B.log
(APIServer pid=3543) INFO 02-14 10:52:09 [qwen3coder_tool_parser.py:85] vLLM Successfully import tool parser Qwen3CoderToolParser !
(APIServer pid=3543) INFO:     192.168.1.35:51963 - "POST /v1/chat/completions HTTP/1.1" 200 OK
(APIServer pid=3543) INFO 02-14 10:52:09 [qwen3coder_tool_parser.py:85] vLLM Successfully import tool parser Qwen3CoderToolParser !
(APIServer pid=3543) INFO 02-14 10:52:18 [loggers.py:257] Engine 000: Avg prompt throughput: 2037.7 tokens/s, Avg generation throughput: 37.5 tokens/s, Running: 1 reqs, Waiting: 0 reqs, GPU KV cache usage: 2.9%, Prefix cache hit rate: 93.0%
(APIServer pid=3543) INFO 02-14 10:52:28 [loggers.py:257] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 42.9 tokens/s, Running: 1 reqs, Waiting: 0 reqs, GPU KV cache usage: 2.9%, Prefix cache hit rate: 93.0%
(APIServer pid=3543) INFO 02-14 10:52:29 [qwen3coder_tool_parser.py:85] vLLM Successfully import tool parser Qwen3CoderToolParser !
(APIServer pid=3543) INFO:     192.168.1.35:51963 - "POST /v1/chat/completions HTTP/1.1" 200 OK
(APIServer pid=3543) INFO 02-14 10:52:29 [qwen3coder_tool_parser.py:85] vLLM Successfully import tool parser Qwen3CoderToolParser !
(APIServer pid=3543) INFO 02-14 10:52:38 [loggers.py:257] Engine 000: Avg prompt throughput: 3065.2 tokens/s, Avg generation throughput: 29.5 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 93.1%
(APIServer pid=3543) INFO 02-14 10:52:48 [loggers.py:257] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 93.1%
hayashi@promaxgb10-124c:~/vllm-env$

6.1. パフォーマンス診断と評価

--- 以下、 Geminiによると ---

ログから読み取れる数値は、商用クラウドの専用APIと比較しても遜色のない、極めて優秀な結果を示している。

コンテナ(NGC)のブラックボックスに頼らず、ハードウェアの物理特性(sm_121 / 128GB UMA)に合わせて自らソースからビルドし、論理的なチューニングを重ねた結果、極めて実用的で最高峰のローカルAIエージェントステーションが完成したと言える。

でも本当に早く、実用的な環境ができました。

7. 【構築手順】GB10 ベアメタル環境ビルド・起動レシピ

あとに続くエンジニアが、コンテナに逃げることなく、自力でこの環境を構築・コントロールできるように、すべての試行錯誤を排し、検証で確定した「初めからの正解パラメータ」による完全なコマンド群を省略なく記録する。

7.1. 必須インフラ(CUDA 13.1)の導入

依存関係の不整合を防ぐため、ソースからではなくNVIDIA公式のaptリポジトリ(Ubuntu 24.04 / sbsa 向け)から、キーリング経由で確実に導入する。

wget [https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/sbsa/cuda-keyring_1.1-1_all.deb](https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/sbsa/cuda-keyring_1.1-1_all.deb)
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get install -y cuda-toolkit-13-1 nvidia-open

7.2. PyTorch のソースビルド (sm_121対応)

仮想Python実行環境にて、アーキテクチャをGB10ネイティブの 12.1 に指定する。 システムの不完全な通信ライブラリへの依存を断ち切るため、PyTorch同梱のNCCLソースを強制ビルドさせる。また、vLLMでは不要となる重いアテンション機構のコンパイルを省くことでエラーを防ぐ。

cd ~/src/pytorch
rm -rf build/ dist/
python setup.py clean

# 【確定事項】12.1 (GB10) を指定!
export TORCH_CUDA_ARCH_LIST="12.1"
export MAX_JOBS=32
export CUDA_HOME=/usr/local/cuda
export CUDNN_HOME=/usr/local/cuda
export CMAKE_PREFIX_PATH=$VIRTUAL_ENV

# システムのNCCLを無視し、同梱ソースからビルドさせる
export USE_SYSTEM_NCCL=0
export USE_NCCL=1

# vLLMでは不要な重いアテンション機構のコンパイルをスキップ
export USE_FLASH_ATTENTION=0
export USE_MEM_EFF_ATTENTION=0

pip wheel . -w ~/src/my_wheels --no-deps --verbose
pip install ~/src/my_wheels/torch-*.whl --force-reinstall

7.3. Transformer Engine のソースビルド (sm_121対応)

BlackwellのFP8性能を引き出すコアライブラリ。隔離ビルド環境下でコンパイラがヘッダーファイルを見失う問題に対処するため、先ほどビルドしたPyTorchのNCCLパスと、環境内のcuDNNパスを物理的に指定して強制的にルーティングする。

cd ~/src/TransformerEngine
rm -rf build/
python setup.py clean

export NVTE_FRAMEWORK=pytorch
export TORCH_CUDA_ARCH_LIST="12.1"
export MAX_JOBS=16

# パスを明示してヘッダーファイルの迷子を防ぐ
export CPATH=$CPATH:/home/hayashi/src/pytorch/build/nccl/include:/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/include
export LIBRARY_PATH=$LIBRARY_PATH:/home/hayashi/src/pytorch/build/nccl/lib:/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/hayashi/src/pytorch/build/nccl/lib:/home/hayashi/vllm-env/lib/python3.12/site-packages/nvidia/cudnn/lib

# 隔離環境を無効化し、自作のPyTorchを認識させてビルド
pip wheel . -w ~/src/my_wheels --no-deps --no-build-isolation --verbose
pip install ~/src/my_wheels/transformer_engine-*.whl --force-reinstall

7.4. vLLM 本体のソースビルド (sm_121対応)

推論のコアエンジン本体を 12.1 に向けてビルドする。ここでも勝手にPyTorchがダウングレード・上書きされる事故を防ぐため、--no-build-isolation--no-deps の徹底が絶対条件である。

cd ~/vllm-env/vllm
rm -rf build/ dist/
python setup.py clean

export TORCH_CUDA_ARCH_LIST="12.1"
export VLLM_TARGET_DEVICE="cuda"
export MAX_JOBS=16

pip wheel . -w ~/src/my_wheels --no-build-isolation --no-deps --verbose
pip install ~/src/my_wheels/vllm-*.whl --no-deps --force-reinstall

7.5. 起動スクリプト(opencode エージェント構成)

AIがもっともらしく提案した無意味なプロセス指定(spawn)を完全に排除。 UMAのデッドロックを回避する必須の環境変数(SAFETENSORS_FAST_GPU=0)、OOMを回避しつつ超長文脈(65,536トークン)を確保する 0.75 のメモリ配分、およびopencode連携のための専用ツールパーサー(qwen3_coder)を指定した、これまでの試行錯誤の結晶である最終起動プロトコル。

#!/bin/bash
source ~/vllm-env/bin/activate

# JITコンパイラへの最新アセンブラパスを強制
export TRITON_PTXAS_PATH=/usr/local/cuda/bin/ptxas

# 【必須】Grace CPUでのmmapとUMAの競合によるデッドロック(0%フリーズ)を完全回避
export SAFETENSORS_FAST_GPU=0

# vLLM サーバーの起動 (FP8 MoE / opencode連携最適化)
vllm serve Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8 \
  --gpu-memory-utilization 0.75 \
  --max-model-len 65536 \
  --quantization fp8 \
  --kv-cache-dtype fp8 \
  --safetensors-load-strategy eager \
  --enable-auto-tool-choice \
  --tool-call-parser qwen3_coder \
  --host 0.0.0.0 \
  --port 8000

7.6. 成果物

私の環境での、コンパイル済み whl を配置しておきます。

8. 結び

AI基盤の構築において、「公式コンテナを使えば動く」という安易な解決策に妥協せず、あえて困難なベアメタルビルドに挑んだことは、インフラの内部機構(コンパイラパスの依存関係、UMAとmmapの制約、Pythonの隔離ビルド仕様など)を本質的に理解する上で極めて意義深いものであった。

対話型AIは強力な壁打ち相手となるが、その提案(アーキテクチャの誤認、不要なプロセス制御、適さないパーサーの指定など)を盲信してはならない。AIの出力する情報をヒントにしつつも、実機での検証コードを用いて事実を確認し、ハードウェアの特性を考慮して問題の切り分けを一つずつ論理的に行っていったエンジニアとしての信念と判断こそが、未知の環境を開拓する上での「正解」である。

信念と論理的な検証によって完全にコントロールされたこの環境は、NVIDIA Grace Blackwell (GB10) の真のポテンシャルを解放する、最高峰のローカルAIエージェントステーションである。