西川和久の不定期コラム

人間なら半日の作業が2時間に。ローカルLLM「Qwen3 Coder Next」で爆速開発

 正確な時期は不明だが、Claude Codeで外部のLLMが使えるようになった。そこで今回はコーディング向けLLMである「Qwen3 Coder Next」を使ってお題のアプリを作ってみたい。

DGX Spark互換機GIGABYTE「AI TOP ATOM」その後

 去年(2025年)の12月、年末のまとめ記事内でDGX Spark互換機ともいえる、GIGABYTEの「AI TOP ATOM」を購入した話に触れたが、その後何に使ってた?から書いてみたい。

DGX Spark互換機、GIGABYTE「AI TOP ATOM」。Blackwell搭載でユニファイドメモリ128GB。SSD 4TB

 まずCUDAの作動確認も兼ねインストールしたのが画像/動画生成向け環境「ComfyUI」とLLMを動作させるためのソフト「LM Studio」。この2つは特に説明の必要はないだろう。ただ、筆者はGeForce RTX 5090やGeForce RTX 4090(48GB改)+GeForce RTX 4080 Super(32GB改)を搭載したPCと、M4 Max 128GB搭載MacBook Proを持っている関係で、速度面的にAI TOP ATOMで積極的に使う理由がない。

 次にai-toolkitを使ったLoRA学習環境。速度的にはGeForce RTX 5090など強力なGPUが使える環境には及ばないものの、何しろ音が静かで熱もあまり出ず、消費電力も小さい……。遅くてもLoRAができるまで待てば済む話なので、こちらはAI TOP ATOMを使うメリットの方が大きい。

 タイミングよく、Z-Image-Turbo、FLUX.2 [klein]、Z-Image-Baseがリリースされたこともあり、しばらくの間はLoRA学習専用機になっていた(笑)。

 LoRA学習が一通り終わったところで、AIコーディングアシスタントのClaude Codeにおいて、標準のモデルであるSonnetやOpusでなく、LLMのエンドポイントを指定できる方法があると知った。これをOllamaやLM Studioで試してみたものの、M4 Maxの環境でも速度的にイマイチ。当然AI TOP ATOMだとさらにtok/sなどが遅くなる。

 ……と、帯に短し襷に長しで、正直これといった使い道はなかった。そんなある日、LM Studioが4.0になり並行リクエストに対応した。試しにとClaude Codeから接続してみると、リクエストが2~4程度は常にある状態となった。つまり4.0以前のバージョンだと、1つずつしかリクエストをこなせないため遅くなっていたのだ。

LM Studioの並列リクエスト処理

 そんな中、Xの投稿で「vLLMを使うとDGX Spark + Qwen3 Coder Next(80B/3Bアクティブ)で100tok/s超える!」と見かけた。通常だと50tok/s前後しか出ないのに本当か?とネットでいろいろ検索して見つけたのがNVIDIAデベロッパーフォーラムの以下の記事だ。

HOW-TO: Run Qwen3-Coder-Next on Spark

 確かに、ベンチマーク結果は100tok/sを超えている部分もある。使ってる環境はeugr / spark-vllm-dockerだ。

 正確には、シングルリクエストだと50tok/s前後と変わらないものの、並列リクエストで100tok/s以上を叩き出している。先に書いたようにClaude Codeはほとんど並列リクエストを出しているため、これは効果ありそう!と試してみた次第だ。

 vLLMは本連載初登場なので少し説明すると、ざっくりOllamaやllama.cppと同じ、LLMをロードし、OpenAI API互換のエンドポイントなどを装備しているLLM推論フレームワーク。LM Studioはllama.cppを使いやすくするUI的な位置付けとなる。

 vLLMも基本同じなのだが、PagedAttentionによる効率的なKVキャッシュ管理、同時リクエスト最適化など、ほかにはない特徴があり、用途がハマるとより高速に作動する。Claude Codeを少しでも速く動かすため今回はこれを使おう、というわけだ。

spark-vllm-dockerをインストールする

 インストールは紆余曲折したのだが(笑)、結果だけ。

$ git clone https://github.com/eugr/spark-vllm-docker/
$ cd spark-vllm-docker
$ git checkout dfb300e
$ ./build-and-copy.sh --vllm-ref v0.15.1 --use-wheels release

となる。なおDockerイメージのリビルドは、

$ docker builder prune

である。git pullしてコードが変わった時などにまずこれを動かし、そして上記の./build-and-copy.shを実行する。

 checkout dfb300eは2026年2月8日の最終コミットとなっている。2月9日からはコード的にかなり手が入り--use-wheels releaseのオプションが廃止されている。

 「これだと古くてまずいのでは!?」という話もあるだろうが、このリポジトリ、元々はQwen3 Coder NextをDGX Sparkで動かすが目的だったのに、問題に対応するため、ほかのモデルや環境に対応し出し、git pullするタイミングによっては肝心のQwen3 Coder Nextが動かなかったり、動いても遅かったり……と、散々なことになった。加えてvLLMも頻繁にコミットされているので、リリース版に固定しないと作動しなかったりする。

 といった具合で、いろいろ試して行き着いた結果が上記のコマンドとなる。クラスタ(複数台接続)にも対応しているが、手元には1台しかAI TOP ATOMがないため、シングルでの起動方法は、

$ ./launch-cluster.sh --solo \
exec vllm serve Qwen/Qwen3-Coder-Next-FP8 \
        --enable-auto-tool-choice \
        --tool-call-parser qwen3_coder \
        --gpu-memory-utilization 0.8 \
        --host 0.0.0.0 --port 8888 \
        --load-format fastsafetensors \
        --attention-backend flashinfer \
        --enable-prefix-caching
※1 portは好みで変える
※2 コンテキスト長は指定しない限り最大に設定

これでOK。初回Qwen3 Coder Nextをダウンロードするので時間がかかる。「Application startup complete.」というメッセージが出れば準備完了だ。

spark-vllm-docker起動中。vLLMはbuildで指定したversion 0.15.1になっている

 早速並列リクエストのテストプログラムを動かした結果が以下の通り。コードはここ にあるが、最後のfor n in [1, 5, 10, 20]:をfor n in [1, 2, 3, 4]:に変えてある。

============================================================
ベンチマーク: 1並列リクエスト
============================================================
総実行時間: 4.39秒
平均応答時間: 4.39秒
最速応答: 4.39秒
最遅応答: 4.39秒
合計生成トークン: 200
平均トークン/秒: 45.53 t/s
スループット: 0.23 req/s
実効スループット: 45.51 tokens/s

============================================================
ベンチマーク: 2並列リクエスト
============================================================
総実行時間: 5.51秒
平均応答時間: 5.51秒 (±0.00)
最速応答: 5.51秒
最遅応答: 5.51秒
合計生成トークン: 400
平均トークン/秒: 36.31 t/s
スループット: 0.36 req/s
実効スループット: 72.59 tokens/s
並列効率: 50.0% (理想値100%)

============================================================
ベンチマーク: 3並列リクエスト
============================================================
総実行時間: 7.74秒
平均応答時間: 7.73秒 (±0.00)
最速応答: 7.73秒
最遅応答: 7.74秒
合計生成トークン: 600
平均トークン/秒: 25.86 t/s
スループット: 0.39 req/s
実効スループット: 77.54 tokens/s
並列効率: 33.3% (理想値100%)

============================================================
ベンチマーク: 4並列リクエスト
============================================================
総実行時間: 7.62秒
平均応答時間: 7.62秒 (±0.00)
最速応答: 7.62秒
最遅応答: 7.62秒
合計生成トークン: 800
平均トークン/秒: 26.25 t/s
スループット: 0.52 req/s
実効スループット: 104.96 tokens/s
並列効率: 25.0% (理想値100%)

 このように、4並列リクエストで104.96tok/s出ている上、2と3もなかなかの値だ。この時、AI TOP ATOMのメモリ(メインメモリ+VRAM)は111.4GB使用。つまりギリギリで動いている。

spark-vllm-dockerでQwen3 Coder Next(FP8)をロードするとメモリ(メインメモリ+VRAM)は111.4GB使用

 参考までにM4 Max 128GBだと(ただしMLXの4bit)、

============================================================
ベンチマーク: 1並列リクエスト
============================================================
総実行時間: 3.96秒
平均応答時間: 3.96秒
最速応答: 3.96秒
最遅応答: 3.96秒
合計生成トークン: 199
平均トークン/秒: 50.20 t/s
スループット: 0.25 req/s
実効スループット: 50.19 tokens/s

============================================================
ベンチマーク: 2並列リクエスト
============================================================
総実行時間: 3.86秒
平均応答時間: 3.84秒 (±0.03)
最速応答: 3.82秒
最遅応答: 3.86秒
合計生成トークン: 398
平均トークン/秒: 51.84 t/s
スループット: 0.52 req/s
実効スループット: 103.10 tokens/s
並列効率: 50.3% (理想値100%)

============================================================
ベンチマーク: 3並列リクエスト
============================================================
総実行時間: 4.35秒
平均応答時間: 4.16秒 (±0.32)
最速応答: 3.80秒
最遅応答: 4.35秒
合計生成トークン: 597
平均トークン/秒: 47.99 t/s
スループット: 0.69 req/s
実効スループット: 137.34 tokens/s
並列効率: 34.8% (理想値100%)

============================================================
ベンチマーク: 4並列リクエスト(ダウンするケースが多い)
============================================================
総実行時間: 5.04秒
平均応答時間: 4.87秒 (±0.33)
最速応答: 4.38秒
最遅応答: 5.03秒
合計生成トークン: 796
平均トークン/秒: 41.02 t/s
スループット: 0.79 req/s
実効スループット: 158.08 tokens/s
並列効率: 25.9% (理想値100%)

となる。DGX Spark互換機よりスコアはいいのだが、8bitでコンテキスト長最大だとOSがメモリ不足で固まる可能性があり、4bitを利用している。並列リクエストが4の場合、LM Studioの処理がダウンするケースが頻繁に発生する。

 つまり、FP8の精度でコンテキスト長最大だとAI TOP ATOMのみ作動可能。まさに「用途はこれだ!」という環境となる。

Claude Codeでエンドポイントを切り替えて使うには?

 Claude Codeでエンドポイントを切り替えて使う方法は簡単だ。

 macOS/Ubuntuだと、

ANTHROPIC_AUTH_TOKEN=lmstudio ANTHROPIC_BASE_URL=http://192.168.11.100:8888 claude --model Qwen/Qwen3-Coder-Next-FP8

 これでOK。つまり環境変数にANTHROPIC_AUTH_TOKEN=lmstudio ANTHROPIC_BASE_URL=を入れれば良い(前者はダミー)。起動すると、画面上にQwen/Qwen3-Coder-Next-FP8の文字が見える。また本来のモデルに切り替えたい場合は/modelで一覧から選択すれば良い。

Qwen/Qwen3-Coder-Next-FP8で起動したClaude Code。/modelでSonnet 4.5やOpus 4.6も見える

 まずお手並み拝見ということで、MCPを使いMySQLへ接続。昔書いていたWordpressのDBを使って最新の記事一覧は以下の通り。ちょうど8年前の記事一覧が出てきた。記事が多い順にカテゴリ一覧も同様。

最新の記事一覧(約8年前のBLOG)
記事が多い順にカテゴリ一覧

 カテゴリ工作に属する記事の要約とするとこの通り。

⏺ カテゴリ「工作」に属する記事の要約:
  ---
  1. nutube ポタアン 回路図 (2017-01-26)
  ID: 262
  Nutubeを使用したポータブルアンプ制作記事。Google検索で自分の投稿内容が上位4つを独占したことに驚いたというエピソード。
  - 主な内容: Nutubeを使ったプリアンプ制作
  - 特徴: FETバッファを使用した出力回路、WIMA MKPなどの高品質コンデンサを採用
  - ゲイン: 6dB(プリとしてはやや高め)
  ---
  2. about Nutube (2017-01-01)
  ID: 71
  Nutubeの紹介とポタアン製作記事。
  - 背景: 元旦にMojo(ポタアン)からNutubeへ入れ替え、アンプ+SPで鳴らしている
  - 製作: スイッチサイエンスで販売されているNutube用基板を使用
  - 参考: MJ無線と実験2016年11月号でNutubeヘッドフォンアンプの製作記事が掲載予定
  ---
両記事とも Nutube(Vacuum Tubeブランドの電子管)を活用したオーディオ制作について書かれています。

 実施にかかった時間はどれも数秒。これだけ出れば、MCPを使ったMySQLの問い合わせにコストのかかるSonnetやOpusを使わず、Qwen3 Coder Nextで十分対応できる。Planだけ使うのもありだろう。

 筆者のようにProだとまぁまぁリミットに引っかかるが、Maxを契約するほどは使わないケースでは、/modelで切り替えながらトークン抑えるのが吉かもしれない。

同じお題でQwen3 Coder Next vs Opus 4.6

 最後は、Qwen3 Coder Nextと出たばかり最新鋭のOpus 4.6と同じ指示でどこまで差が出るか?を試してみたい。

 先月、音楽生成のHearMuLAをご紹介したが、その後ACE Step 1.5がリリースされた。詳細はまた別の機会にするとして、このリポジトリ、APIが使えるサーバー、Gradioを使ったUI及び、簡単なhtmlでのUIなどが含まれている。

 今回はAPIサーバーの仕様を理解、Next.jsを使ったUIをそれぞれ同じプロンプトで作ってもらった。検索などを速くするためgit cloneでリポジトリはローカルにコピーして実行している。プロンプトはこんな感じだ。

ACE-Step-1.5/ のAPI仕様に基づき、以下の仕様のアプリを作ってください
1. sample_queryを使い、キーワードから、歌詞、Prompt、曲を自動生成
2. 使用可能なモデル選択。デフォルトはTurbo
3. 使用可能な言語選択。デフォルトは日本語
4. 音楽再生Player、元のキーワード、生成した歌詞、Prompt、その他Metaデータの表示
5. Node.jsを使い、フロント/サーバーを一本化してシンプルに
6. Darkモード
7. ACE Step serverは192.168.11.200:8001。変更可能に
8. acestep-ui/ へ作成
9. Planの説明は日本語
10. 実装する前にcurlで実際ACE Step APIを使い作動確認
※ Opus 4.6は8. acestep-oops/ へ作成に変更

 以下、作業中の動画を掲載する。いかがだろうか?十分実用的な速度で動いていると思う。

左上がClaude Code、左下はちょっとした作業用、右上がUI(npm start)用コンソール。右下がspark-vllm-dockerのコンソール。最近はVSCodeすら起動しなくなった(笑)。API仕様把握、curlによるAPIの作動確認、Plan作成、実装少し……まで(2:30)

 完成した(もちろん完動)UIは以下の通り。レイアウトなど少し違うが、入力/出力は同じになっている。ただ「お!どちらもできる♪Qwen3 Coder Nextでいいじゃん」というのは早合点。

Qwen3 Coder Next版UI
Opus 4.6版UI

 かかった時間だが、Opus 4.6では8分ほど。うち1カ所、生成したmp3をハンドリングする部分にバグがあり、指示して終わり。ところがQwen3 Coder Nextはやりとりを繰り返し約2時間……と大きな差が生じた。

 mp3のハンドリングに関してはどちらも鬼門で引っかかったが、Opus 4.6はChrome > 検証 > Networkに出たurlをコピペすれば解決した。

 ところがQwen3 Coder Nextは何度やってもダメ(ここだけで1時間ほど格闘)。あげく、Chat形式のAPI /v1/chat/completionsを使えばmp3はBASE64になっているから簡単にアクセスできると勝手にコードを変更する始末(笑)。

 さらにcompletionsのレスポンスに含まれるメタデータをどうしても正規表現では切り出せず四苦八苦(30分以上)。やっと完成という感じだ。

 Opus 4.6にQwen3 Coder Nextで作ったUIのコードを見てもらったところ、

⏺ acestep-uiは「まず動かしてみよう」から試行錯誤して育てた感じですね。CLAUDE.mdに「このAPI使うな」「正規表現のエスケープ注意」など苦労の跡が残っていて、console.logも大量に残っている。/v1/chat/completions経由でMarkdownをパースしてメタデータを取り出すのは結構力技で、そこだけでserver.jsの1/3を使っています。
.
.中略
.
/v1/audioのパスが/v1/audio?path=D%3A%5Cworks%5C...という既にエンコード済みのURLで返ってくるので、素直に encodeURIComponent すると二重エンコードになって「Access denied: path outside allowed directory」になる。

前回のClaude(acestep-ui作成時)はこれにハマって、「/release_task ダメ」「/v1/audioで403」とCLAUDE.mdに書き残して、丸ごと /v1/chat/completionsに逃げたわけですね。completionsならBase64でaudioが返るのでパス問題を回避できる、と。

今回のOpusでも初回は同じ罠を踏みましたが、remoteパラメータでACE-Stepの返すパスをそのまま転送する方式で解決できました。

教訓として残しておきます。

⏺ Wrote 1 memory (ctrl+o to expand)

と、この最後の“教訓として残しておきます。”……で、実際メモリへ追加しているところがなかなか笑える。視点を変えて、筆者が従える部下のエンジニアと考えた場合、

  • Opus 4.6は経験/実践とも豊富で指示に忠実。信用できるエンジニア
  • Qwen3 Coder Nextは、知識はあるけど実践不足、目的を達成するなら指示/禁止事項を無視。一緒に働きたくないタイプのエンジニア(笑)

という感じだろうか?参考までにopencodeとMiniMax M2.5 Freeを使い同じことを試したところ、やはりmp3の取得で引っかかり、結果BASE64が戻るcompletionsへ変えてしまった(笑)。Opus 4.6の方がやはり数枚上手といったところか。

 ただし、Qwen3 Coder Nextと比較して、筆者とのやり取りは圧倒的に少なく、curlでAPIをテストし続け、うまく動いたら実装……この点は手間要らずなので評価できる。


 とはいえ、たった80BのLLMがClaude Codeを使って、紆余曲折しつつ何とかここまでできたのも事実。また8分 vs 2時間はかなりの差があるものの、人間だと半日?はかかるだろう。今年(2026年)2月でこの状況なので、年末辺りだと普通に使えるレベルになるのでは?と期待したいところ。

 メモリ128GBフルに近い状態が必要なので、今回の内容を試せる人は少ないとは思うが、何かの参考になれば幸いだ。