所要時間: 約30分 | 難易度: ★★☆☆☆
この記事で作るもの
この記事を読めば、Apple Silicon搭載MacでLlama 3などの最新LLMをMLXで高速に動かし、Pythonから制御するチャットスクリプトを自作できるようになります。
- MLXフレームワークを使ったローカルLLM実行環境
- Llama 3 (8B) を4-bit量子化で動かすPythonスクリプト
- 1秒間に約50〜100トークンを生成する高速な推論体験
前提知識として、ターミナルでコマンドが打てることと、Pythonの基礎(変数や関数の概念)が必要です。 複雑な機械学習の数式は一切使いません。
先に確認するスペック・料金
ローカルLLMを動かす上で、Macのスペック選びが成功の9割を決めます。 結論から言うと、Apple Silicon(M1/M2/M3/M4チップ)を搭載したMacが必須で、Intel MacではMLXは動きません。
最も重要なのは「ユニファイドメモリ(RAM)」の容量です。 LLMの重みデータはすべてメモリ上に展開されるため、最低でも16GB、できれば24GB以上のメモリを積んだモデルを推奨します。 8GBモデルでも動かないことはないですが、OSやブラウザが使う分を差し引くと、モデルを読み込んだ瞬間にスワップが発生して実用的な速度(レスポンス0.5秒以内)を維持できません。
GPUコア数は多いに越したことはありませんが、MLXの恩恵はメモリ帯域の広さに依存するため、無印チップよりも「Pro」や「Max」の方が圧倒的に有利です。 私は私物のMac Studio(M2 Ultra / メモリ128GB)と、検証用のMacBook Air(M3 / メモリ16GB)でテストしていますが、メモリさえ足りていればAirでも驚くほど快適に動作します。 API料金は完全に0円、月額$20のChatGPT Plusを契約し続けるより、メモリを盛ったMacを買うほうが長期的なコスパは高いと確信しています。
なぜこの方法を選ぶのか
MacでローカルLLMを動かす手段は、他にも「Llama.cpp」や「Ollama」があります。 しかし、Pythonエンジニアが開発に組み込むなら、Appleが公式に開発している「MLX」を選ぶべきです。
MLXの最大の特徴は、Apple SiliconのGPUパワーを最大限に引き出すために設計された「統合メモリ(Unified Memory)」への最適化です。 PyTorchでMPS(Metal Performance Shaders)を使う方法もありますが、私が検証した結果、同じモデルでもMLXの方が生成速度が1.5倍〜2倍速くなるケースが多くありました。
また、MLXは配列操作がNumPyに非常に似ているため、エンジニアにとって学習コストが低いです。 「とにかくチャットができればいい」ならOllamaで十分ですが、「自分のプログラムの一部としてLLMを高度に制御したい」なら、MLXを使いこなすのが最短ルートになります。
Step 1: 環境を整える
まずは、MLXを動かすためのクリーンなPython環境を作成します。 macOS標準のPythonを汚さないよう、必ず仮想環境(venv)を使いましょう。
# プロジェクト用のディレクトリを作成して移動
mkdir mlx-test && cd mlx-test
# Python 3.10以上が必要です
# 仮想環境を作成
python3 -m venv .venv
# 仮想環境を有効化
source .venv/bin/activate
# MLXと周辺ライブラリをインストール
# mlx-lmはHugging Faceからモデルをダウンロードして動かすための便利なラッパーです
pip install mlx-lm mlx
ここでmlx-lmをインストールするのは、生のMLXでモデルをロードするよりもコードが格段に短くなるからです。
実務では「車輪の再発明」を避け、公式が推奨する高レベルAPIを使うのが正解です。
⚠️ 落とし穴:
Pythonのバージョンが3.9以下だとMLXの最新機能が動かないことがあります。
python3 --versionで確認し、古い場合はHomebrewなどで3.10以上を入れ直してください。
また、Xcode Command Line Toolsが入っていないとコンパイルエラーが出るため、xcode-select --installを実行しておく必要があります。
Step 2: モデルの選定と準備
ローカルLLMを動かす際、モデルの「重さ」と「賢さ」のバランスが重要です。 今回は、Metaが公開している「Llama-3-8B-Instruct」を、MLX用に最適化(4-bit量子化)されたバージョンで使用します。
本来、LLMのパラメータは膨大なメモリを消費しますが、4-bit量子化という技術を使うと、精度をほぼ維持したままメモリ消費量を1/4程度に抑えられます。 8B(80億パラメータ)モデルの場合、通常なら32GB以上のメモリが必要ですが、4-bit版なら5GB程度の空きメモリがあれば余裕で動きます。
自分で変換するのは時間がかかるため、Hugging Face上の「mlx-community」という公式アカウントが公開している配布済みモデルを利用します。
# config.py という名前で保存
# モデルのIDを指定。最初は軽量で高性能なLlama 3 8Bがおすすめ。
MODEL_ID = "mlx-community/Meta-Llama-3-8B-Instruct-4bit"
# 生成時のパラメータ設定
# temperatureは「回答のランダム性」を制御します
# 0.7は「少し創造的」、0.0にすると「常に同じ回答」になります
GEN_CONFIG = {
"temp": 0.7,
"max_tokens": 512,
}
「なぜこのモデルか」というと、Llama 3は日本語能力が飛躍的に向上しており、日本語で指示を出しても破綻しにくいからです。 かつてのLlama 2時代に感じた「英語しかまともに話せない」という不満は、このモデルで解消されました。
Step 3: 動かしてみる
いよいよ最小限のコードでLLMを動かしてみます。 MLXの凄さは、これだけのコードでGPU(Metal)がフル稼働する点にあります。
# main.py
from mlx_lm import load, generate
# モデルとトークナイザーをロード
# load関数は、ローカルにモデルがなければ自動でHugging Faceからダウンロードします
model, tokenizer = load("mlx-community/Meta-Llama-3-8B-Instruct-4bit")
# 実行
prompt = "美味しいカレーを作るコツを3つ教えてください。"
response = generate(model, tokenizer, prompt=prompt, verbose=True)
print(response)
期待される出力
美味しいカレーを作るコツは以下の3つです。
1. 玉ねぎを飴色になるまでじっくり炒める:これがコクの深さを決めます。
2. スパイスを加熱して香りを引き出す:油でスパイスを熱することで風味が立ちます。
3. 最後に隠し味(醤油やチョコレートなど)を加える:味が引き締まります。
ターミナルに文字が流れ始めた瞬間の「自分のMacでAIが思考している感」は、API経由では味わえない興奮があります。 実行時、アクティビティモニタを確認してみてください。 「GPU使用率」が跳ね上がり、CPUは意外と余裕があるはずです。これがMLXの最適化の成果です。
Step 4: 実用レベルにする
上記のコードでは、全ての回答が生成されるまで「待ち」が発生します。 実務で使うチャットアプリなら、ChatGPTのように1文字ずつ出力される「ストリーミング」は必須機能です。
また、以前の会話内容を覚えさせる「履歴保持」も実装してみましょう。 LLM自体には記憶力がないため、過去の会話をリストとして管理し、毎回プロンプトに含める必要があります。
# chat.py
import sys
from mlx_lm import load, stream_generate
# モデルのロード(一度ロードすればメモリに常駐します)
model, tokenizer = load("mlx-community/Meta-Llama-3-8B-Instruct-4bit")
def chat():
# 会話履歴を保持するリスト
messages = [
{"role": "system", "content": "あなたは親切なAIアシスタントです。"}
]
print("AI: 何かお手伝いできますか? (exitで終了)")
while True:
user_input = input("あなた: ")
if user_input.lower() == "exit":
break
messages.append({"role": "user", "content": user_input})
# Llama 3のフォーマットに合わせたプロンプト構築
# apply_chat_templateを使うと、モデル固有のタグ付けを自動で行ってくれます
prompt = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
print("AI: ", end="", flush=True)
# ストリーミング生成
collected_content = ""
for response in stream_generate(model, tokenizer, prompt):
print(response, end="", flush=True)
collected_content += response
print("\n")
messages.append({"role": "assistant", "content": collected_content})
if __name__ == "__main__":
chat()
このコードではapply_chat_templateを使っているのがミソです。
LLMにはモデルごとに「<|user|>」や「[INST]」といった特定のタグが必要ですが、これを手動で書くとミスが起きて精度が落ちます。
ライブラリの機能に任せることで、モデルを入れ替えた際(例:Mistralなど)も最小限の修正で済みます。
実際に試した私の感想ですが、M2 Max環境でこのスクリプトを動かすと、返答の速さは有料版ChatGPTと遜色ありません。 むしろ通信遅延がない分、初動のレスポンスはローカルの方が速く感じます。
よくあるトラブルと解決法
| エラー内容 | 原因 | 解決策 |
|---|---|---|
ImportError: No module named 'mlx' | 仮想環境が有効化されていない | source .venv/bin/activate を実行してください。 |
Killed: 9 | メモリ不足(OOM) | モデルをさらに小さいもの(Llama-3-1Bなど)に変えるか、他のアプリを閉じてください。 |
| 生成が非常に遅い | GPUが使われていない、またはスワップ発生 | メモリ不足を確認。量子化されていないモデル(fp16)を使っていないか確認してください。 |
| 文字化けする | トークナイザーの不一致 | load関数で指定したモデル名が正しいか再確認してください。 |
次のステップ
ここまでで、Apple Siliconの性能を引き出してローカルLLMを動かす基礎はマスターできました。 しかし、ローカルLLMの真価は単なるチャットではありません。
次に取り組むべきは「RAG(検索拡張生成)」の構築です。 自分のPC内にあるPDFやMarkdownファイルをベクトル化し、それをLLMに読み込ませることで、社外秘の情報や個人の知識ベースに基づいた回答が可能になります。 OpenAIのAPIにプライベートなファイルを送るのは抵抗がありますが、MLXによる完全ローカル環境ならデータが外部に漏れる心配は0です。
また、さらに高速化を目指すなら「MLX Swift」を使ってiOSアプリに組み込む道もあります。 今回Pythonで学んだロジックはそのままSwiftでも応用できるため、エッジAI開発の土台として非常に強力です。 まずは自分専用の「オフラインで動く究極のメモ要約ツール」あたりから作ってみることをおすすめします。
よくある質問
Q1: MacBook Airの8GBメモリでも動きますか?
動きますが、かなり厳しいです。Llama-3-8Bの4-bit版はモデルだけで約5GB消費するため、OS分を含めるとメモリはパンパンになります。動作を確認するだけなら可能ですが、日常的に使うなら1B(10億パラメータ)クラスの超軽量モデルを探す方が快適です。
Q2: モデルのダウンロードに時間がかかります。中断しても大丈夫ですか?
はい、中断しても次回実行時に続きから再開(レジューム)されます。MLX-LMはHugging Faceのキャッシュ機能を利用しているため、一度ダウンロードに成功すれば、次回からは一瞬で起動します。
Q3: GPUの負荷が100%になりっぱなしでMacが壊れませんか?
Apple Siliconは電力効率が非常に高く、熱制御も優秀なので、長時間回しても基本的には大丈夫です。ただし、ファンレスのMacBook Airで数時間生成し続けるとサーマルスロットリングで速度が落ちることはあります。Mac miniやPro/Maxモデルならその心配もありません。
📦 この記事に関連する商品(楽天メインで価格確認)
Mac Studio128GB以上のメモリを積めば、70Bクラスの巨大LLMもローカルで実用的に動かせます
※アフィリエイトリンクを含みます



