UGREEN DXP6800 Pro + Ollama 続編:64GB化したNASで qwen3-coder:30b は Sonnet の代わりになるのか?
- takeshiohno
- 1 日前
- 読了時間: 11分
はじめに
前回の記事では、UGREEN DXP6800 Pro に eGPU 経由で RTX 2000 Ada を載せ、Ollama を Docker 上で動かし、さらに Zed からローカルLLMへ接続するところまでをまとめました。
前回時点での到達点はこうでした。
Ollama は ollama/ollama:0.24.0 に固定
NVIDIA Driver は 535.261.03
GPU は RTX 2000 Ada 16GB
qwen3:14b は 100% GPU で快適に動作
qwen3-coder:30b は本体RAM不足で本格検証できず
UGREEN DXP6800 Pro の本体RAMを 64GB に増設予定
今回はその続きです。
NAS本体のメモリを 8GB から 64GB に増設し、qwen3-coder:30b がどこまで実用になるのかを試しました。
さらに今回は単なるベンチマークだけではなく、実際に Zed 経由でローカルLLMを使い、Sonnet と qwen3-coder:30b に同じようなコーディング課題を投げて、成果物の質も比較してみました。
結論から言うと、
qwen3-coder:30b はローカルLLMとしてはかなり健闘する。ただし、Sonnet の代替というより「用途を絞れば実用的なローカル補助役」という位置づけ。
という感触です。
今回の構成
最終的な構成は以下です。
UGREEN DXP6800 Pro
├ RAM: 64GB DDR5 SODIMM
├ eGPU: RTX 2000 Ada Generation 16GB
├ NVIDIA Driver: 535.261.03
├ Docker
│ ├ ollama: ollama/ollama:0.24.0
│ └ open-webui: ghcr.io/open-webui/open-webui:main
└ Zed から http://<NASのIP>:11434 で接続Ollamaを 0.24.0 に固定している理由は前回と同じです。
Ollama v0.30系以降の新エンジンでは、この環境だと CUDA error: device kernel image is invalid が出て、モデルが起動できませんでした。ドライバーを上げる選択肢もありますが、今回は安定性を優先し、旧GGMLエンジンの 0.24.0 に固定しています。
まずハマった:コンテナ内だけ nvidia-smi が落ちる
RAM増設後、30Bの検証に進もうとしたところ、まず次の問題が出ました。
ホスト側では nvidia-smi が正常に通ります。
NVIDIA-SMI 535.261.03
Driver Version: 535.261.03
CUDA Version: 12.2
GPU: NVIDIA RTX 2000 Ada Generation
Memory: 0MiB / 16380MiBところが、Ollamaコンテナ内で実行するとこうなりました。
docker exec -it ollama nvidia-smiFailed to initialize NVML: Unknown ErrorホストではGPUが見えているのに、Ollamaコンテナ内ではNVML初期化に失敗する状態です。
切り分けとして、CUDAテストコンテナを実行しました。
docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smiこれは正常に通りました。
つまり、NVIDIAドライバーも NVIDIA Container Runtime も正常。問題は既存の ollama コンテナの作り方だけでした。
そこで、Ollamaコンテナを --gpus all 付きで作り直しました。
docker stop ollama
docker rm ollama
docker run -d \
--name ollama \
--gpus all \
--network ai \
-v ollama:/root/.ollama \
-p 11434:11434 \
--restart unless-stopped \
ollama/ollama:0.24.0作り直し後は、コンテナ内でも nvidia-smi が通るようになりました。
docker exec -it ollama nvidia-smiNVIDIA-SMI 535.261.03
Driver Version: 535.261.03
CUDA Version: 12.2ここでようやく、本当の意味で30BのGPUオフロード検証に進めます。
ベンチマーク結果
テストには自作の test.sh を使いました。
条件は以下です。
temperature: 0
seed: 42
T1: 短文生成 64 token
T2: 長文生成 768 token
生成 tok/s と prompt処理 tok/s を計測
qwen3:14b
=== qwen3:14b (ctx=8192) ===
[T1] 生成 64tok @ 22 tok/s | prompt処理 544 tok/s | load 5308ms
[T2] 生成 768tok @ 22 tok/s | prompt処理 599 tok/s | load 123ms14Bは前回同様、非常に安定しています。
ollama ps では 100% GPU。VRAM内に収まり、システムRAMをほぼ使わずに動きます。
qwen3-coder:30b
=== qwen3-coder:30b (ctx=16384) ===
[T1] 生成 21tok @ 24 tok/s | prompt処理 41 tok/s | load 8244ms
[T2] 生成 768tok @ 21 tok/s | prompt処理 51 tok/s | load 124ms
=== qwen3-coder:30b (ctx=32768) ===
[T1] 生成 21tok @ 22 tok/s | prompt処理 32 tok/s | load 8194ms
[T2] 生成 768tok @ 19 tok/s | prompt処理 41 tok/s | load 122ms
=== qwen3-coder:30b (ctx=65536) ===
[T1] 生成 21tok @ 20 tok/s | prompt処理 24 tok/s | load 7800ms
[T2] 生成 768tok @ 17 tok/s | prompt処理 31 tok/s | load 132ms意外だったのは、生成速度だけを見ると30Bがかなり速いことです。
ctx 16k では 21〜24 tok/s、ctx 64k でも 17〜20 tok/s 出ています。
以前、GPU接続が壊れていた状態では 9〜11 tok/s 程度だったので、Ollamaコンテナを正しくGPU接続できるようにしたことで、30Bの生成速度はおよそ2倍になりました。
30BはどのくらいGPUに載っているのか
ctx 65536 で qwen3-coder:30b を起動した状態の ollama ps はこうでした。
NAME SIZE PROCESSOR CONTEXT
qwen3-coder:30b 25 GB 36%/64% CPU/GPU 65536nvidia-smi はこうです。
Memory-Usage: 15653MiB / 16380MiB
Process: /usr/bin/ollama 15648MiBつまり、VRAM 16GBをほぼ使い切り、64%をGPU、36%をCPU側に逃がして動いています。
メモリ状況は以下でした。
Mem: 62Gi total / 15Gi used / 47Gi available
Swap: 37Gi total / 6.5Mi usedSwapは実質未使用です。
これはかなり良い状態です。
30Bを完全にGPUへ載せるにはVRAM 16GBでは足りませんが、64GB RAM化によってCPU/GPUオフロードが安定し、実用速度で動くようになりました。
ただし、Zed経由ではかなり遅く感じる
ここでベンチマークと実利用の差が出ました。
ベンチ上では qwen3-coder:30b は 17〜24 tok/s 出ています。数字だけ見ると、14Bと大差ないようにも見えます。
しかし、Zedから使うとかなり遅く感じます。
理由は prompt処理速度です。
qwen3:14b
prompt処理: 500〜600 tok/s
qwen3-coder:30b
prompt処理: 24〜51 tok/sZedは、選択範囲だけでなく、周辺コード、ファイル情報、ワークスペース文脈などをまとめてモデルに渡します。
そのため、体感速度を支配するのは「生成速度」よりも「入力を読む速さ」です。
30Bは回答を書き始めればそこそこ速いのですが、書き始めるまでが重い。Zed上では、ここがかなり目立ちます。
特に ctx 65536 のような大きいコンテキストでは、prompt処理が 24〜31 tok/s まで落ちます。
そのため、Zedの常用モデルとしては、30Bをそのまま使うより、16kや32kに絞った派生モデルを作る方が現実的です。
cat > Modelfile.qwen3-coder-zed <<'EOF'
FROM qwen3-coder:30b
PARAMETER num_ctx 16384
PARAMETER num_predict 2048
PARAMETER temperature 0.1
PARAMETER top_p 0.9
SYSTEM """
You are a concise coding assistant for Zed.
Answer in Japanese unless code-only is requested.
Prefer short, direct answers.
When asked to write code, output the code first.
Do not write long explanations unless explicitly requested.
"""
EOF
docker exec -i ollama ollama create qwen3-coder:zed -f - < Modelfile.qwen3-coder-zedSonnet と qwen3-coder:30b に同じ課題を投げてみる
次に、実際のコーディング課題で比較しました。
課題はこれです。
PowerShellでCSVでユーザ情報を取得し、AD上にユーザを作成するスクリプトを書いてください。Sonnetにはこの短いプロンプトをそのまま投げました。
一方、qwen3-coder:30b には、出力が長くなりすぎないように、少し制約を付けたプロンプトを使いました。
PowerShellスクリプトだけを書いてください。説明は不要です。
要件:
- CSVをImport-Csvで読み込む
- CSV列: SamAccountName, GivenName, Surname, DisplayName, UserPrincipalName, Path, Password
- Active Directory上にユーザを作成する
- 既存ユーザがいる場合はスキップする
- 初回ログオン時にパスワード変更を要求する
- エラーはtry/catchでログ出力する
- 実行前確認用にWhatIf対応する
出力は以下だけ:
1. CSVサンプル
2. PowerShellスクリプト
長い解説、前提説明、注意事項は書かないでください。この時点で、すでに少し条件が違います。
Sonnetは曖昧な依頼をどこまで補ってくれるか。qwenは明確な制約を与えたとき、どこまで実用コードを出せるか。
そういう比較です。
成果物比較:Sonnet版
Sonnet版は、かなり「業務スクリプト」寄りの成果物でした。
入っていた要素は以下です。
CSVファイル存在確認
必須カラムチェック
Active Directory モジュール確認
OU存在確認
既存ユーザー確認
作成・更新・スキップ・失敗件数の集計
ログファイル出力
Manager設定
終了コード
実行結果サマリ
これはかなり実務寄りです。
ADユーザー作成のような操作は、失敗したときに「どの行で、なぜ失敗したか」が残らないと困ります。その意味で、Sonnet版は運用スクリプトとして必要な要素をかなり先回りして入れていました。
ただし、問題もありました。
一番大きいのは WhatIf の扱いです。
Sonnet版では、[CmdletBinding(SupportsShouldProcess)] を使いつつ、独自に [switch]$WhatIf も定義していました。
PowerShellでは SupportsShouldProcess を有効にすると、-WhatIf は共通パラメータとして提供されます。そのため、明示的に $WhatIf を定義するのは避けた方がよいです。
ここは修正必須です。
また、Sonnet版はCSVカラムが多めでした。
FirstName
LastName
DisplayName
SamAccountName
UserPrincipalName
Email
Department
Title
OU
Password
PasswordNeverExpires
AccountEnabled
Description
OfficePhone
Manager
実務的ではありますが、最初のサンプルとしては少し重い印象です。
成果物比較:qwen3-coder:30b版
qwen版は、かなり短く、プロンプトに素直なコードでした。
入っていた要素は以下です。
Import-Csv
Import-Module ActiveDirectory
New-ADUser
既存ユーザーはスキップ
ChangePasswordAtLogon $true
手動の WhatIf 対応
try/catch
最低限の要件にはきちんと沿っています。
特に、今回のプロンプトで指定した「説明不要」「コード中心」「既存ユーザーはスキップ」「初回ログオン時にパスワード変更」は守れていました。
一方で、本番投入には不足があります。
CSVファイル存在確認がない
必須カラム検証がない
空欄チェックがない
OU/Pathの存在確認がない
ログファイル出力が弱い
成功/失敗件数のサマリがない
パスワードポリシー違反時の扱いが弱い
ADコマンドのフィルタ指定に改善余地がある
つまり、qwen版は「サンプルとしては良いが、そのまま業務利用するには薄い」という評価です。
採点してみる
今回の成果物を、実用性・安全性・保守性でざっくり採点するとこうです。
モデル | 点数 | コメント |
Sonnet | 78点 | 業務向けの構成は良い。ただし WhatIf 実装とカラム過多が減点。 |
qwen3-coder:30b | 62点 | プロンプトには素直。短くて読みやすいが、AD運用スクリプトとしては検証・ログ・安全性が不足。 |
Sonnetは「曖昧な依頼から実務に必要なものを補う」のが得意です。qwenは「明確に指定された要件を短くコード化する」のはできますが、実務上の事故防止策を自発的に盛る力はSonnetより弱い印象でした。
速度面の比較
品質以前に、Zed経由での体感差は大きいです。
Sonnetはクラウドモデルなので、手元のNASのprompt処理速度やVRAM制約を受けません。一方、qwen3-coder:30b はローカルで動いているので、入力が大きくなると素直に遅くなります。
今回のようなPowerShellスクリプト生成でも、qwen3-coder:30b は「終わる感じがしない」ように見えました。
これは生成速度そのものよりも、
Zedが送るシステムプロンプト
ワークスペース文脈
大きめのコンテキスト設定
30Bのprompt処理の遅さ
qwen系の長文化傾向
が組み合わさった結果だと思います。
ローカルLLMをZedで使う場合、モデルの性能だけでなく、「どのくらい入力を送るか」が体感速度を大きく左右します。
Zedでの使い分け
今回の検証後、Zedでは以下の運用がよさそうだと感じました。
普段使い
qwen3:14b14Bは 100% GPU で動き、prompt処理が非常に速いです。
ちょっとしたコード説明、短い修正、コマンド生成、設定ファイルの確認なら、14Bの方が快適です。
品質優先のローカルコード生成
qwen3-coder:zed30Bをそのまま使うのではなく、num_ctx 16384、num_predict 2048 程度に制限したZed用モデルを作るのがよさそうです。
64kコンテキストは夢がありますが、Zed常用には重いです。
複雑な設計・本番投入前レビュー
Sonnet実務で事故ると困るスクリプトや、要件が曖昧な相談は、まだSonnetの方が安心です。
特にAD、Microsoft 365、Azure、セキュリティ、権限まわりのようなテーマでは、クラウドモデルの方が先回り力が高いと感じました。
qwen3-coder:30b をうまく使うプロンプト
qwen3-coder:30b は、曖昧な依頼を丸投げするより、出力条件を強く指定した方が良いです。
悪い例:
PowerShellでCSVでユーザ情報を取得し、AD上にユーザを作成するスクリプトを書いてください。この依頼だと、モデルがどこまで説明するか、どのカラムを想定するか、ログやWhatIfを入れるかが曖昧です。
良い例:
PowerShellスクリプトだけを書いてください。説明は不要です。
要件:
- CSVをImport-Csvで読み込む
- CSV列: SamAccountName, GivenName, Surname, DisplayName, UserPrincipalName, Path, Password
- Active Directory上にユーザを作成する
- 既存ユーザがいる場合はスキップする
- 初回ログオン時にパスワード変更を要求する
- エラーはtry/catchでログ出力する
- 実行前確認用にWhatIf対応する
出力は以下だけ:
1. CSVサンプル
2. PowerShellスクリプト
長い解説、前提説明、注意事項は書かないでください。さらに短くしたい場合はこうです。
PowerShellコードだけ出してください。
説明不要。
CSV列は SamAccountName,GivenName,Surname,DisplayName,UserPrincipalName,Path,Password。
Import-Csvで読み込み、New-ADUserでユーザ作成。
既存ユーザはスキップ。
ChangePasswordAtLogonはtrue。
try/catchでエラー処理。
WhatIf対応。
コードブロック1つだけ。ローカルLLMは、プロンプトで「どこまで書くか」を明示するとかなり扱いやすくなります。
今回の結論
64GB RAM化により、UGREEN DXP6800 Pro + RTX 2000 Ada 16GB の構成で qwen3-coder:30b は実用速度で動くようになりました。
特に、ctx 65536でも 17〜20 tok/s 出ているのはかなり良い結果です。
qwen3-coder:30b
- ctx 16384: 21〜24 tok/s
- ctx 32768: 19〜22 tok/s
- ctx 65536: 17〜20 tok/s
- 36% CPU / 64% GPU
- VRAM 約15.6GB使用
- Swapほぼ未使用ただし、Zed経由での体感はベンチほど軽くありません。
理由は、30Bのprompt処理が遅く、Zedが大量の文脈を送ると初動がかなり重くなるからです。
Sonnetとの比較では、qwen3-coder:30b は短いコード生成には十分使えます。しかし、曖昧な依頼を実務レベルの成果物に仕上げる力は、まだSonnetの方が上です。
今回の私なりの結論はこうです。
qwen3:14b
→ Zed常用の軽快モデル
qwen3-coder:30b
→ ローカルで品質を少し上げたいときのコード生成モデル
Sonnet
→ 実務投入前提・曖昧な要件・設計相談・レビュー向けローカルLLMは、クラウドLLMを完全に置き換えるものではありません。ただし、NAS上で常時動かせて、Zedから直接呼べて、コード生成や軽い相談に使えるというだけでも十分に価値があります。
何より、手元のUGREEN DXP6800 Proが、ストレージだけでなくローカルAI開発環境としても使えるようになったのはかなり面白いです。
前回は「30Bはメモリ増設後の宿題」で終わりました。今回、その宿題にはひとまず答えが出ました。
30Bは動きます。ただし、快適に使うにはモデル選びとプロンプト設計が必要です。
次は、Zed用に qwen3-coder:zed のような軽量設定モデルを作り、実際のプロジェクトでどこまで使えるかを継続して試してみます。


コメント