はじめに

日常的な開発パイプラインやエージェント用途において、LLMの推論環境をどう構築するかは常に悩ましい問題です。今回は、コーディング特化のモデルとして注目している「IQuest-Coder-V1-40B」を対象に、CPU(EPYC 9175F)のみを利用した推論と、GPU(vLLM環境・nvfp4)を利用した推論のパフォーマンスを実測し、さらにAider(AIコーディングエージェント)のwhole-edit形式での実用性まで検証しました。

結論から言えば、40BクラスのDenseモデルをCPUで動作させることはパイプライン用途には構造的に無理があります。GPU(特にnvfp4を活かした構成)へ移行することで圧倒的な効率と制御性を得られる一方、Aiderのwhole-editも40B Denseとは相性が悪いことが分かりました。本記事では、その具体的な挙動と評価のプロセスを、実測データとともに解説します。

実験環境

項目仕様
CPUAMD EPYC 9175F(Zen 5, 16C, L3 512MB)
GPUNVIDIA RTX PRO 6000 Blackwell Max-Q(96GB VRAM)
メモリDDR5-6400 768GB(12ch)
OSUbuntu 24.04 LTS

検証構成

構成Runtime量子化配置
A: CPU推論llama.cpp server(Podman)Q5_K_M(GGUF)CPU RAM
B: GPU推論vLLMnvfp4GPU VRAM
C: Aider利用vLLM(Loop-Instruct variant)nvfp4GPU VRAM

背景と課題:CPU推論の限界

IQuest-Coder-V1-40B-Instructは40B級のDense(非MoE)コーディング特化モデルです。MoEモデルと違い推論時に全パラメータを使うため、計算量がそのままモデルサイズに比例します。

最初に試したのは、IQuest-Coder-V1-40B-Instruct.q5_k_m.gguf を Podman 上の llama.cpp server を用いて、GPUを使わずにCPU(AMD EPYC 9175F, 16コア)のみで起動する構成です。コンテキスト長は 8192 に設定し、AiderやエージェントシステムなどTTFT(Time To First Token)と低レイテンシが求められる「待たない」パイプライン処理を想定していました。

しかし、実際に運用してみると以下のような致命的な問題が発生しました。

  • 常にコアが張り付く: 40BのDenseモデルは全層を毎トークン計算するため、MoE(Mixture of Experts)モデルのように計算を省略できず、CPUに過大な負荷がかかります。
  • TTFTの破綻: プロンプトが4k〜5kトークンを超えると(例: task.n_tokens=4640)、Prompt evaluationの処理時間が支配的となり、生成(tok/s)が始まる前の時点で体感が破綻してしまいました。
  • ストレージの恩恵がない: モデルをSSDに配置することでロード時間は短縮されましたが、生成速度やPrompt evalの速度にはほぼ無関係でした。
  • スループット寄りの設定: llama-server の設定上、batch-size 2048ubatch-size 512 といったスループット重視(バッチ大)の構成になっており、これが低レイテンシを求めるパイプライン用途と致命的に噛み合いませんでした。

NUMA bindやスレッド指定、mlockなど、基本的なチューニングは施しており、CPU性能自体は素直に使い切れていましたが、本質的には「40BのDenseモデルをCPUで回している」こと自体が最大のボトルネックでした。CPU環境では、体感の悪さは単なる設定不足ではなく「正常な挙動」です。

構成A 計測結果

項目実測値
TTFT(4k-5kプロンプト時)数十秒(体感破綻)
CPU使用率全コア100%張り付き
問題の本質40B全層を毎トークン計算、省略不可

GPU(nvfp4)環境への移行と実測

CPUでの限界を踏まえ、GPUを利用した構成(vLLM + nvfp4)へと移行しました。比較対象として、111Bクラスの推論モデルである command-a-reasoning も並行して評価しています。

実測スループット

vLLMのログから得られた実測値は以下の通りです。

指標実測値
PP速度(Prompt throughput)1,100-2,300 tok/s
TG速度(Generation throughput)25-28 tok/s(安定)
KVキャッシュ使用率2-12%
Prefixキャッシュヒット率20-45%

vLLMログからの連続計測(抜粋):

  Engine 000: Avg generation throughput: 28.3 tokens/s, KV cache usage: 2.0%, Prefix cache hit rate: 22.8%
Engine 000: Avg generation throughput: 28.0 tokens/s, KV cache usage: 2.3%, Prefix cache hit rate: 22.8%
Engine 000: Avg generation throughput: 27.8 tokens/s, KV cache usage: 2.8%, Prefix cache hit rate: 22.8%
Engine 000: Avg generation throughput: 27.4 tokens/s, KV cache usage: 3.5%, Prefix cache hit rate: 22.8%
  
  • Prompt throughputは約1100〜2300 tok/sで、入力処理は完全に問題なく、CPU、トークナイザ、IPCにも十分な余裕があります。
  • Generation throughputは安定して25〜28 tok/sで、40Bクラスとしては非常に良好な数値です。111B(command-a-reasoning)と比較すると約2.3〜2.5倍の速度が出ています。
  • KV cache usageは2〜12%程度で、長文の履歴や巨大なコンテキストに引きずられることなく、素直にデコードできています。
  • Prefix cache hit rateは20〜45%で、システムプロンプトやツールスキーマを完全に固定化することで、さらなる改善の余地があります。

実行状態も非常に安定しており、Running: 1 reqs の間はスループットが落ちることなく出続けています。「0 tok/s」が記録される瞬間は単なる集計窓のタイミングであり、ハングやデッドロックといった兆候は一切ありませんでした。

TG速度25-28 tok/sの出力長別体感レイテンシ:

  • 200トークン: 約7-8秒
  • 400トークン: 約14-16秒
  • 800トークン: 約30秒

これは111Bモデルの半分以下の待ち時間であり、Aiderなどのエージェントやテスト生成の場面で明確な差となって表れます。

Aider whole-edit形式での検証

GPU nvfp4環境でAider(whole-edit形式)を試したところ、また別の問題が浮上しました。

指標実測値
TG速度0.6-8 tok/s(不安定)
KVキャッシュ使用率7-13%(急激に増加)
Prefixキャッシュヒット率6%(ほぼ無効)

whole-edit形式はファイル全体を再生成するため出力トークン数が爆発します。repo-map + 複数ファイル添付でコンテキストが肥大し、KVキャッシュが急速に膨張します。Prefixキャッシュヒット率が6%しか出ないのは、コンテキストが毎回変動するためです。

比較サマリ

構成TG速度(tok/s)実用判定用途
A: CPU Q5_K_M測定不能(TTFT破綻)不可-
B: GPU nvfp425-28実用agent/テスト生成/CI
C: Aider whole-edit0.6-8非実用-

Performance Factor:パラメータあたりの生成効率

実務での体感に直結する指標として、モデル規模(パラメータ数)あたりの生成トークン数を「PF(Performance Factor)」として定義しました。

PF ≒ generation tok/s ÷ モデル規模(B)

モデルパラメータTG速度tok/s per B相対PF
command-a-reasoning111B~11 tok/s0.101.0
IQuest-Coder-40B nvfp440B26-28 tok/s0.65-0.70≈6.5-7.0
小型7B fp167B60-80 tok/s9-11別枠

「パラメータあたりの生成性能」において、IQuest-Coder-40Bは111B系の6〜7倍という圧倒的な効率を叩き出しています。これはnvfp4が正しく効いている証拠であり、「大モデルの知性 vs 実行速度」のトレードオフにおいて非常に優れた位置にあります。

考察

なぜDenseはCPUで厳しいのか

MoEモデル(例: Kimi-K2.5の活性32B)はトークンごとに一部のエキスパートだけ計算します。Denseは40B全層を毎回計算するため、計算量の削減が効きません。同じ「40B級」でもCPU推論の負荷は根本的に異なります。

EPYC 9175Fの12チャネルメモリ帯域でも、Denseの全層アクセスパターンではメモリ帯域が飽和します。MoEのようにL3キャッシュにエキスパートを載せる戦略も使えません。

項目Dense 40BMoE 229B(活性10B)
毎トークンの計算量40B全層10B相当
L3キャッシュ活用効かない(全層アクセス)効く(エキスパート局所性)
CPU推論のTG測定困難10-37 tok/s
CPU推論の実用性非実用バッチ用途で実用

Aider whole-editの構造的問題

whole-edit形式が遅い原因:

  1. ファイル全体を出力するためトークン数が膨大
  2. repo-map + 添付ファイルでpromptも肥大
  3. Prefixキャッシュヒット率が6%(変動するコンテキストのため)
  4. KVキャッシュが急速に膨張(7→13%)

対策はwhole-editを避けてdiff/patch形式に変更することです。出力トークン数を大幅に削減でき、生成速度の問題を構造的に回避できます。

モデル品質と制御性

長文で構造化されたGo言語のテストコード生成において破綻がなく、論理の崩れやハルシネーションは、場合によっては111BのReasoning系モデルよりも少ないケースがありました。「考えすぎないInstruct型」特有の素直なEOS(End of Sequence)や、stopmax_tokens の確実な効き具合が、自動化されたコード生成と極めて相性が良いのです。

深い推論や証明、長文思考においては確かに command-a-reasoning が上回りますが、実務では「速度」「止まりやすさ」「制御しやすさ」の方が価値を持つケースが多々あります。

安定運用できている理由

このモデルが安定している理由として四つ挙げられる。モデル単体ではなく、モデルとサービングと実装の相性まで含めて評価したうえでの結論だ。

  1. nvfp4 × vLLM main/nightly の組み合わせが成立している
  2. stop / max_tokens が適切に効いている
  3. Instruct 型らしく EOS が素直で、出力の終端制御がしやすい
  4. agent-gateway の設計と噛み合っている。特に non-stream 時だけ retrieval を差し込むような実装方針とも整合している

つまり、たまたまベンチマークが良かったのではなく、日常運用で問題になりやすい箇所が比較的きれいに揃っている。

改善策の優先順位

もし同様の構成で悩んでいる方がいれば、以下の順序で対策を検討してください。

  1. GPUを使う(最優先) --device nvidia.com/gpu=all および --n-gpu-layers 999 を指定し、GPUのVRAMをフル活用してください。RTX PRO 6000 MAX-Q 96GBのような大容量VRAMがあるなら、使わない理由はありません。
  2. CPUのまま運用する場合の応急処置
    • batch-size を 512〜1024 に下げる。
    • ubatch-size を 128〜256 に下げる。
    • 履歴やリポジトリマップ(repo-map)などのプロンプトを削る。
  3. モデルをスケールダウンする パイプラインの制約でどうしてもCPUを使わざるを得ないなら、7B〜14Bクラスのモデルに落とすのが現実解です。

再現方法

GPU nvfp4(推奨構成)

  vllm serve IQuestLab/IQuest-Coder-V1-40B-Instruct-nvfp4 \
  --max-num-seqs 1 \
  --max-model-len 32768
  

CPU Q5_K_M(参考: 非推奨)

  podman run --rm -it \
  -p 8081:8080 --shm-size 16g --cap-add=SYS_NICE \
  -v "$MO":/models:ro,Z $IMG \
  --host 0.0.0.0 --port 8080 -m "$MODEL" \
  --jinja -c 8192 \
  --threads 14 --threads-batch 14 \
  -b 2048 -ub 512 \
  --parallel 1 --flash-attn on
  

Aider設定の最適化

  • --edit-format diff: whole-editを避けて出力を削減
  • temperature=0: greedy固定で生成を高速化
  • repo-mapと/add対象を最小限に
  • max_model_lenを必要最小に設定

結論と今後の展望

「IQuest-Coder-V1-40B」をnvfp4とvLLMで稼働させる構成は、速度・安定性・制御性のすべてにおいて実務の本命(デフォルト)として十二分に機能することが確認できました。40BクラスのDense モデルの位置づけが明確になった結果、使い分けは次のようになります。

  • 日常(agent/aider/CI): IQuest-Coder-40B nvfp4(本命)
  • 深い推論・設計レビュー: command-a-reasoning(サブ)
  • バッチ処理(CPU常駐): MoEモデル(Kimi-K2.5等)

40Bクラスで安定して25–28 tok/sが出るのであれば、日常的なエージェント処理やCI、テスト生成で111Bモデルを常用する理由はほぼ消滅します。今後は、IQuest-Coder-40Bをメインのルーティング先に据え、難解な推論や設計レビューが求められる特異なケースのみ command-a-reasoning へ流すアーキテクチャが最も美しいと考えています。

次のステップとしては、Prefix cacheのヒット率を現在の40%から60%以上に引き上げるためのプロンプト固定化と、p95を基準としたSLOベースの最終チューニングを進めていく予定です。