こんにちは、パレイド技術部です。
前回記事では、Macbook Air M5 で gpt-oss:20b が実用可能かを検証しました。
結論、gpt-oss:20b は期待通り動作した一方で、動くはずの qwen3.5:27b では不安的な結果になりました。
今回はいつもの Ollama ではなく MLX を使って qwen3.5b の実用可能性を追求してみます。
Apple Silicon なら MLX が本命の導入
前回 Ollama でうまく動かなかったため調べたところ、MLX なら qwen3.5:27B が約 22GB のメモリ使用量で約25 token/sec 出た、という事例が見つかりました。
MLXとは、Apple が提供する Apple Silicon 向けの機械学習フレームワークで、Metal フレームワークを活用した高速な推論処理が特徴です。Python からネイティブにモデルを操作でき、軽量かつ高効率なローカル LLM 実行環境を構築できます。
Ollama の手軽さやクロスプラットフォームでのAPI利用は魅力的ですが、今回は出先での作業という条件を鑑みて Apple Silicon 特化の MLX 環境を Python 上で直接構築してみます。
なお MLX で利用可能な qwen3.5 は、パラメータ数や量子化でバリエーションがあります。主な選択肢は以下のとおりです。
| モデル | パラメータ | 量子化 | サイズ | 32GB Mac で | 備考 |
|---|---|---|---|---|---|
| Qwen3.5-4B-MLX-4bit | 4B | 4bit | ~3.0GB | ◎ 余裕 | 軽量・高速、品質は限定的 |
| Qwen3.5-9B-MLX-4bit | 9B | 4bit | ~5.9GB | ◎ 余裕 | バランス型 |
| Qwen3.5-27B-4bit | 27B | 4bit | ~16.1GB | ○ 動作可 | 本連載で採用。日本語品質が高い |
| Qwen3.5-27B-mxfp8 | 27B | 8bit | ~28.7GB | △ ギリギリ | 品質向上するがメモリ厳しい |
| Qwen3.5-35B-A3B-4bit | 35B (MoE, 実効6B) | 4bit | ~20.4GB | △ 動作可 | MoE 構成、活性パラメータは6B |
| Qwen3.5-397B-A17B-4bit | 397B (MoE, 実効17B) | 4bit | ~62GB | × 不可 | デスクトップ向け |
今回、Macbook Air M5 は オプションで 32GB メモリ搭載のため、理屈ではmxfp8も動きそうです。 実際は他にもアプリやサービスを動かす必要があるため、4bit のものを選択しました。
MLX Server は OpenAI互換で便利、でも本番利用は”非推奨”
MLX には OpenAI と互換性のあるAPIが提供できる MLX Server があるとのことで、すでに自動生成パイプラインに OpenAI の API キーで動作する実装も済んでいたため、まずこれを試しました。
pip install mlx-lm の一コマンドで環境を整え、Claude Code に実装を調整してもらいます。
テストには前回同様、自動生成パイプラインを使っています。時間にあまり意味はありません。
| モデル | 実装方式 | Pass A時間 | Pass B時間 | Pass C時間 | Pass D時間 | 合計 | 文字数 | 備考 |
|---|---|---|---|---|---|---|---|---|
| qwen3.5:27b (MLX) | mlx_lm.server | 120s | 516s | 452s | 540s | 1628s | 4379字 | 実験中 3 回クラッシュ・resume で完走 |
Ollamaで試した際は900秒でタイムアウトしていた処理が、一応は完了することができました。 ただし、特定の処理でクラッシュが多発し、やり直せばうまくいく場合もあるものの実用は厳しい印象。 調べたところ既知の問題で、そもそも MLX Server は公式ドキュメントでも「本番利用は非推奨(not recommended for production)」と明記されています。
MLX Server は諦めて、Python コード内で load と generate メソッドを直接呼び出す実装をClaude Codeに進めてもらいます。
もともと OpenAI との互換は必要はなく、パフォーマンス追求なら最終系はこちらと考えていたため結果的にはちょうど良いかも。
ただし、直接のモデル呼び出しにはパラメータの設定などが必要で、AIに全てお任せとはならず、作業がそれなりに発生しました。
Thinkingのタグ除去が必要
MLX Serverが返す応答は <thinking> というタグが含まれ、大量のトークンが返ってきます。どうも LLM が生成した思考プロセスがすべて入っているようです。これは推論モードを持つモデル共通の挙動ですが、Ollama では自動でカットされた最終の回答内容のみが返るため、処理の追加が必要でした。
今回はシンプルに、Python側の実装で除去しました。具体的には、生成されたテキスト全体から最後の </thinking> タグを抽出し、それ以降を最終回答とみなして利用します。タグでなく会話文として文字列に現れることもあるので、処理には注意が必要です。実験中、これで何回かハマりました。
また qwen3.5 は qwen3 同様、推論モードのオンオフが制御できるようです。
せっかくなので、推論モードありとなし、両パターン試してみましょう。
コンテキスト長、最大トークン数の明示が必要
MLX での直接実行では、Ollama のように num_ctx をリクエスト単位で指定する仕組みがありません。mlx_lm.generate に渡す max_tokens は出力トークン数の上限であり、入力側のコンテキスト長はモデルの上限(Qwen3.5 は 131,072 トークン)がそのまま適用されます。
ここで注意が必要なのは、思考モード(<think>...</think>)を有効にした場合、思考部分と最終回答の両方が max_tokens に含まれる点です。たとえば max_tokens=2048 で思考に 1500 トークン使うと、最終回答には 548 トークンしか残りません。思考モードを使う場合は、余裕をもって max_tokens を大きく設定する必要があります。
参考まで、現在のパイプライン処理では、各パスのコンテキスト長を以下のように設定しています。 処理の内容に幅が出る GUI ではコンテキスト長は大きめの設定が楽ですが、用途に合わせて絞った方が処理速度やメモリ容量には有効です。
| Pass | 用途 | num_ctx | max_tokens | 備考 |
|---|---|---|---|---|
| A | 記事骨子生成 | 8192 | 2048 | JSON 出力、think OFF |
| B | セクション執筆 | 8192 | 2048 | 1セクション単位、think OFF |
| C | アセンブル | 8192 | 8192 | 全セクション結合、think OFF |
| D | 文字数調整 | 8192 | 8192 | 完成記事全体 |
qwen3.5: 9b vs 27b、思考モード有無での 4 パターン計測
実測結果は下記のとおりです。MacBook Air M5 上で、qwen3.5 の 9b と 27b モデルそれぞれについて、「思考モードあり/なし」の計 4 パターンを比較しました。結果は予想以上でした。
| モデル | think-c | Pass A | Pass B | Pass C | Pass D | 合計 | Pass C字数 | 最終字数 |
|---|---|---|---|---|---|---|---|---|
| qwen3.5:9b (MLX) | OFF | 51s | 166s | 171s | 170s | 727s | 5601字 | 5339字 |
| qwen3.5:9b (MLX) | ON | 35s | 150s | 432s | 178s | 797s | 5650字 | 5425字 |
| qwen3.5:27b (MLX) | OFF | 187s | 574s | 496s | 511s | 1771s | 3949字 | 3720字 |
| qwen3.5:27b (MLX) | ON | 156s | 504s | 1455s | 499s | 2616s | 3966字 | 3730字 |
速度面では、9b モデルは「thinkingあり」でも生成が速く、「なし」の場合と1分程度の差です。思考モードありのほうが全体に文章の品質が安定しました。一方、27b モデルは「thinkingあり」の状態で生成時間が大きく変わりますが、品質はその分向上しています。過去の Ollama 検証で感じた不安定な挙動も、MLX 環境では安定しており、長時間のプロセスも途中でクラッシュせず、一貫性のある動作結果が得られました。
なお品質の分析は、詳細は割愛しますが客観性確保のため Claude Code に評価してもらっています。自分で見た感じも基本的には納得の評価でした。
品質面では、27bと「思考モードあり」の組み合わせが優れていました。特に日本語のニュアンスや、指示された制約条件の遵守率は、他の3パターンを明確に上回ります。ただし、組み合わせによってはthinkingが暴走するパターンもあり用途を絞った運用が必要です。
9b モデルは速いが浅い、27b モデルは遅いが深くて正確、とパラメータ数のトレードオフが素直に現れた形です。この結果から、Mac 環境で実用的な高品質な出力を求めるなら、少し生成時間を犠牲にしても 27b+thinking を採用するのが正解と言えそうです。
速度のみに捉われず、タスクの性質に合わせてモデルサイズと思考プロセスを選択肢として用意しておくことが、ローカル LLM 活用の鍵となるはずです。
MLXでの他のモデルの使用
同条件で、gpt-oss:20b や gemma3:12b も試したのですが、速度は MLX の恩恵で速くなったものの、文字数を調整する処理で逆に文字数が増大したり、thinking が暴走して処理が終わらなくなったため、それ以上の検証はやめました。 コンテキスト長、最大トークン数の指定などチューニングの余地はあるかもしれませんが、今回は qwen3.5:27b で品質も十分なのでそれ以上の検証は行なっていません。
Ollama の良さもを再認識
今回の一連の実験を通じて、Ollama も良くできているなと改めて思います。Ollama はモデルのダウンロードから実行までがワンクリックで済み、日常のタスクや開発の切り替え、また複数モデルの切り替えが頻繁な場面では圧倒的に便利です。また、Open WebUI などの GUI と親和性が高く、クロスプラットフォーム対応も整っているため、Windows や Linux 環境との連携が必要な場合も安心です。
一方で、Apple Silicon の真価を引き出すには MLX の出番です。特に、27b 級の大型モデルを長時間稼働させたり、思考プロセスの解析など高度な制御が必要な実験では、MLX の高速性が際立ちます。私の環境では、Ollama では動かなかった qwe3.5:27bがMLXなら安定して動きます。
MLX は高速ですが、導入でかなりトライ&エラーの部分がありました。Claude Codeがあれば改修しながら進められますが、一定の知識がないと相応の時間がかかると思われます。手軽さと利便性を優先して Ollama で試し、モデルが定まって必要に応じて MLX で性能を追求するステップが最適解と言えます。
まとめ
今回は、Apple Silicon 環境における MLX と Ollama の比較を通じて、速度と安定性の観点で MLX の優位性を検証しました。特に思考プロセスを伴う高品質な生成タスクでは、MLX のネイティブ実装が Ollama を明らかに上回ります。


