はじめに
ローカル LLM (Local LLM) をエージェント用途で使う場合、モデルの賢さだけを見ても判断しにくい。ブラウザ操作や CLI 操作では、応答が遅いと待ち時間が積み上がる。一方で、速いだけのモデルを選ぶと、ツール呼び出しの引数を間違えたり、存在しない関数を呼び出したりして、結局リトライが増える。
今回は、Apple M3 Ultra の Mac Studio で、vllm-mlx を使って Qwen 系モデルをローカル実行したときの 速度(token/sec) と Function Calling 品質を測った。速度は vllm-mlx-bench、品質は BFCL の simple_python で確認した。Playwright や CLI エージェント用途で、どの量子化モデルを選ぶか判断するための作業メモとして整理した。
測定環境
| 項目 | 内容 |
|---|---|
| 実施日 | 2026-05-19 |
| ハードウェア | Apple M3 Ultra 256 GB unified memory 800 GB/s memory bandwidth 80 GPU cores |
| 推論ランタイム | vllm-mlx |
| 速度測定 | vllm-mlx-bench |
| 品質測定 | BFCL simple_python |
| Python | 3.12 |
BFCL の依存関係に合わせるため、このリポジトリでは Python 3.12 を使っている。
uv sync
速度ベンチマークは次の条件で実行した。
PROMPTS=1 MAX_TOKENS=512 TEMPERATURE=0 WARMUP=1 ./benchmarks.sh
各モデルのサーバー起動は、評価ランナー内では次の形になっている。
vllm-mlx serve <model-repo> \
--port 8000 \
--continuous-batching \
--host 0.0.0.0 \
--served-model-name <model-name> \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder
BFCL は simple_python を対象に実行した。
BFCL_TEST_CATEGORY=simple_python ./bfcl_benchmarks.sh
この BFCL 結果は simple_python だけであり、BFCL 全体のスコアではない。single_turn、multi_turn、REST API 呼び出し、複数関数選択、並列呼び出しはこの表には含めていない。
速度ベンチマークの結果
vllm-mlx-bench から見ているのは、生成速度、TTFT、TPOT、総レイテンシ、生成トークン数、実行成否である。回答品質や Playwright タスク成功率は、この速度測定だけでは判断していない。
| モデル | 量子化 | 生成速度 tok/s | TTFT ms | TPOT ms | 総トークン数 | 総時間 s | 結果 |
|---|---|---|---|---|---|---|---|
| Qwen3.5-9B-MLX | 4bit | 114.77 | 128.0 | 8.71 | 36 | 0.43 | 成功 |
| Qwen3.6-35B-A3B | nvfp4 | 103.47 | 129.9 | 9.66 | 369 | 3.69 | 成功 |
| Qwen3.6-35B-A3B | 8bit | 87.73 | 142.5 | 11.40 | 344 | 4.05 | 成功 |
| Qwen3.6-35B-A3B | bf16 | 73.85 | 152.5 | 13.54 | 341 | 4.76 | 成功 |
| Qwen3.5-122B-A10B | mxfp4 | 61.18 | 163.1 | 16.35 | 298 | 5.02 | 成功 |
| Qwen3.5-122B-A10B | 8bit | 46.12 | 201.7 | 21.68 | 512 | 11.28 | 成功 |
| Qwen3.5-9B | bf16 | 42.56 | 179.1 | 23.50 | 29 | 0.84 | 成功 |
| Qwen3.6-27B | mxfp4 | 41.79 | 188.6 | 23.93 | 332 | 8.11 | 成功 |
| Qwen3.5-397B-A17B | 4bit | 41.14 | 197.0 | 24.31 | 512 | 12.62 | 成功 |
| Qwen3.6-27B | OptiQ-4bit | 37.08 | 207.8 | 26.97 | 334 | 9.19 | 成功 |
| Qwen3.6-27B | 8bit | 23.67 | 251.1 | 42.25 | 331 | 14.19 | 成功 |
| Qwen3.6-27B | bf16 | 13.58 | 376.0 | 73.61 | 322 | 24.01 | 成功 |
| Qwen3.5-122B-A10B | bf16 | — | — | — | — | — | OOM |
生成速度を並べると、35B-A3B 系と 27B 系の差が見えやすい。
初回トークンまでの待ち時間は、生成速度ほど大きな差ではないが、Qwen3.6-27B bf16 だけは明確に重い。
速度だけを見ると、Qwen3.5-9B-MLX 4bit が 114.77 tok/s で最速だった。次に Qwen3.6-35B-A3B nvfp4 が 103.47 tok/s。どちらも TTFT は 130 ms 前後で、対話的に使う前提では待ち始めの遅さが目立ちにくい。
Qwen3.6-35B-A3B 系が Qwen3.6-27B 系より速い。35B という名前だけを見ると重そうだが、A3B は 1 トークン生成時に有効化されるパラメータが約 3B であることを示す命名で、Dense な 27B とは速度の出方が違う。実測でも Qwen3.6-35B-A3B nvfp4 は 103.47 tok/s、Qwen3.6-27B mxfp4 は 41.79 tok/s だった。
Function Calling 品質の結果
品質側は BFCL の simple_python を使った。これは、1つの Python 関数定義に対して正しい1回の関数呼び出しを生成できるかを見るカテゴリである。Playwright MCP や CLI エージェントのすべてを代表するものではないが、ツール呼び出しの基本精度を見るには使いやすい。
| モデル | 量子化 | 精度 % | 生成時間 sec | 評価時間 sec | 結果 |
|---|---|---|---|---|---|
| Qwen3.5-122B-A10B | mxfp4 | 97.0 | 595 | 20 | 成功 |
| Qwen3.6-27B | mxfp4 | 96.2 | 916 | 6 | 成功 |
| Qwen3.5-122B-A10B | 8bit | 96.0 | 1099 | 30 | 成功 |
| Qwen3.6-27B | 8bit | 95.8 | 1680 | 28 | 成功 |
| Qwen3.6-27B | bf16 | 95.5 | 2867 | 26 | 成功 |
| Qwen3.6-27B | OptiQ-4bit | 94.5 | 1581 | 4 | 成功 |
| Qwen3.6-35B-A3B | bf16 | 94.2 | 625 | 6 | 成功 |
| Qwen3.6-35B-A3B | 8bit | 94.0 | 763 | 6 | 成功 |
| Qwen3.6-35B-A3B | nvfp4 | 93.8 | 628 | 26 | 成功 |
| Qwen3.5-9B-MLX | 4bit | 93.2 | 709 | 6 | 成功 |
| Qwen3.5-9B | bf16 | 69.5 | 884 | 6 | 成功 |
| Qwen3.5-122B-A10B | bf16 | — | — | — | OOM |
| Qwen3.5-397B-A17B | 4bit | — | 375 | — | サーバー終了 |
精度は上位が 93% から 97% 台に固まった。Qwen3.5-9B bf16 だけが大きく離れている。
Qwen3.5-122B-A10B mxfp4 が 97.0% で最も高かった。Qwen3.6-27B mxfp4 も 96.2% で、速度は控えめだが Function Calling の基本精度は高い。
一方で、Qwen3.5-9B bf16 は 69.5% まで落ちた。同じ 9B 系でも Qwen3.5-9B-MLX 4bit は 93.2% だったため、9B というサイズだけで判断すると危ない。モデル名と量子化の組み合わせで結果が大きく変わった。
BFCL の run_summary.json には tok/s は含まれない。上の生成時間は BFCL 全ケースを処理するのにかかった実時間であり、vllm-mlx-bench の生成速度とは別物として扱っている。
速度と品質を並べて見る
エージェント用途では、速度と Function Calling 精度を別々に見ても決めにくい。そこで、vllm-mlx-bench の tok/s と BFCL simple_python の精度を並べた。
| モデル | 量子化 | BFCL 精度 % | 生成速度 tok/s | 見方 |
|---|---|---|---|---|
| Qwen3.5-122B-A10B | mxfp4 | 97.0 | 61.2 | 精度が最も高く、速度も許容しやすい |
| Qwen3.6-27B | mxfp4 | 96.2 | 41.8 | 精度重視なら候補に残る |
| Qwen3.5-122B-A10B | 8bit | 96.0 | 46.1 | 高精度だが mxfp4 の方が速かった |
| Qwen3.6-27B | 8bit | 95.8 | 23.7 | 精度は高いが対話用途では遅い |
| Qwen3.6-27B | bf16 | 95.5 | 13.6 | 精度は高いが待ち時間が大きい |
| Qwen3.6-27B | OptiQ-4bit | 94.5 | 37.1 | 27B 系で速度を少し取りたい場合の候補 |
| Qwen3.6-35B-A3B | bf16 | 94.2 | 73.9 | 速度と精度のバランスがよい |
| Qwen3.6-35B-A3B | 8bit | 94.0 | 87.7 | 速度寄りで使いやすい |
| Qwen3.6-35B-A3B | nvfp4 | 93.8 | 103.5 | 速度重視なら有力 |
| Qwen3.5-9B-MLX | 4bit | 93.2 | 114.8 | 最速。精度は少し下がる |
| Qwen3.5-9B | bf16 | 69.5 | 42.6 | Function Calling 用途では避けたい |
速度と精度を同じ図に置くと、右上に近いほどエージェント用途では扱いやすい。Qwen3.6-35B-A3B nvfp4 は速度側に寄り、Qwen3.5-122B-A10B mxfp4 は精度側に寄る。
自分が Playwright や CLI エージェントでまず試すなら、速度重視では Qwen3.6-35B-A3B nvfp4、精度も含めた総合では Qwen3.5-122B-A10B mxfp4 を見る。Qwen3.5-9B-MLX 4bit は最速だが、BFCL simple_python では 122B mxfp4 や 27B mxfp4 より少し下がるため、失敗時のリトライも含めて判断する。
Qwen3.6-27B bf16 は 95.5% と精度は高いが、13.58 tok/s だった。ローカルで対話しながら使うには待ちが長い。検証用にはよいが、普段使いの第一候補にはしにくい。
詰まった点
Qwen3.5-122B-A10B bf16 は OOM で落ちた。速度ベンチマーク側のログではピーク使用量が約 240 GB に達しており、256 GB unified memory の環境でも余裕はなかった。
Qwen3.5-397B-A17B 4bit は vllm-mlx-bench では 41.14 tok/s の結果が取れたが、BFCL simple_python では生成中にサーバープロセスが終了した。速度だけを見ると使えそうに見えるが、少なくともこの BFCL 実行では最後まで通っていない。
もう1つ注意点として、BFCL simple_python は Function Calling の入口だけを見るテストである。ブラウザ操作ではページ状態の把握、複数手順の分解、ツール実行結果を読んだ後の修正が必要になる。ここで高いモデルが、そのまま Playwright などの複雑な操作に対応できるとは限らない。
今回の結論
速度だけなら Qwen3.5-9B-MLX 4bit が最速だった。ただし、Function Calling 精度も合わせると、Playwright や CLI エージェント用途では Qwen3.6-35B-A3B nvfp4 と Qwen3.5-122B-A10B mxfp4 が現実的な候補になった。
Qwen3.6-35B-A3B nvfp4 は 103.47 tok/s で、BFCL simple_python は 93.8%。速度を優先して操作待ちを減らしたい場合に使いやすい。Qwen3.5-122B-A10B mxfp4 は 61.18 tok/s、BFCL simple_python は 97.0%。ツール呼び出しの安定性を重視する場面ではこちらを選びたい。
一方で、Qwen3.6-27B bf16 のように精度は高くても速度が厳しいモデルや、Qwen3.5-9B bf16 のように速度は出ても Function Calling 精度が落ちるモデルもあった。ローカルエージェント用途では、モデルサイズや量子化名だけでなく、速度とツール呼び出し精度を並べて見る必要がある。
Appendix
モデルのサイズ
| モデル | サイズ |
|---|---|
| mlx-community/Qwen3.5-122B-A10B-bf16 | 228 GB |
| mlx-community/Qwen3.5-397B-A17B-4bit | 209 GB |
| mlx-community/Qwen3.5-122B-A10B-8bit | 122 GB |
| mlx-community/Qwen3-Coder-Next-bf16 | 119 GB |
| mlx-community/Qwen3.6-35B-A3B-bf16 | 65 GB |
| mlx-community/Qwen3.5-122B-A10B-mxfp4 | 61 GB |
| mlx-community/Qwen3.6-27B-bf16 | 51 GB |
| mlx-community/Qwen3-Coder-Next-mxfp4 | 39 GB |
| mlx-community/Qwen3.6-35B-A3B-8bit | 35 GB |
| mlx-community/Qwen3.6-27B-8bit | 28 GB |
| mlx-community/Qwen3.6-35B-A3B-nvfp4 | 19 GB |
| mlx-community/Qwen3.5-9B-bf16 | 18 GB |
| mlx-community/Qwen3.6-27B-OptiQ-4bit | 15 GB |
| mlx-community/Qwen3.6-27B-mxfp4 | 14 GB |
| mlx-community/Qwen3.5-9B-8bit | 9.7 GB |
| mlx-community/Qwen3.5-9B-MLX-4bit | 5.6 GB |
| mlx-community/Qwen3-VL-8B-Instruct-4bit | 5.4 GB |



