8GBノートPCでローカルAIを起動してフリーズしたときの修復方法
YouTubeを見てターミナルにモデルのインストールコマンドを入力した途端、画面がフリーズしてしまった経験があるでしょう。8GBや16GBのRAMを搭載した旧型のMacBookや普及型ノートPCでローカルLLMがダウンする理由は、演算コアが不足しているからではありません。メモリ帯域幅が極端に狭い状態で、ランタイムが限界を超えたデータを読み込もうとすることが本当の原因です。デバイスの帯域幅を計測し、コンテキストサイズだけを調整すれば、古い端末でもコード補助モデルを動かして活用することができます。
システムPythonを汚さずに環境診断ツールを導入する
最新のmacOSやUbuntuでは、システムPythonへ勝手にパッケージをインストールできないよう制限されています。pip installを実行した瞬間、PEP 668エラー(error: externally-managed-environment)を出して停止します。面倒だからとシステム保護を強制的に解除するフラグ(--break-system-packages)を付与すると、後でOSの基本ツールが破損してOSの再インストールが必要になります。独立した仮想環境の切り分けをサポートする pipx を使用して診断ツールを導入します。
Alex Jonesが開発したオープンソースの診断ツール llmfit を分離環境でデプロイし、ハードウェアのスペックを抽出します。
`bash
macOS基準のpipxインストール (Linuxは sudo apt install -y pipx)
brew install pipx
pipx ensurepath
llmfitのインストールおよびハードウェアスキャン結果の保存
pipx install llmfit
mkdir -p ~/local-ai-workspace/{configs,logs,scripts}
llmfit --json system > ~/local-ai-workspace/logs/system_specs.json
`
ターミナルでこのプロセスを完了させると、システムライブラリに影響を与えることなく、1分でデバイスのRAM容量とメモリバスの情報が system_specs.json ファイルにまとめられます。
帯域幅を計算して3Bと7Bモデルを選定する
ローカル言語モデルが出力を生成するプロセスは、以前に出力されたトークンを確認しながら次の文字を予測していく逐次処理です。各ステップでモデルの数十億に及ぶ重みデータをメモリバスから丸ごと読み込む必要があります。つまり、体感速度はGPUクロックではなくメモリ帯域幅の数値によって決まります。
1秒あたりのトークン出力速度(TPS)は以下の公式で計算します。
TPS approx rac{ ext{Memory Bandwidth (GB/s)}}{ ext{Model Weights Size (GB)} + ext{KV Cache per Step (GB)}} imes eta数式の eta はランタイムの実効帯域幅効率(MBU)の値であり、通常0.65前後です。
帯域幅が45GB/s水準の一般的なDDR4デスクトップRAMに、4ビット量子化した7Bモデル(約4.5GB)をそのまま配置した場合、演算速度は 45div4.5imes0.65approx6.5extTPS に留まります。文字が1文字ずつ途切れながら表示されるため、実務のサポート用としてはストレスが溜まります。一方、288GB/sの帯域幅を持つRTX 4060 8GBモデルや、帯域幅が100GB/sを超えるMシリーズの統合メモリに配置すれば、秒間35〜40トークンを達成し、リアルタイムのタイピング速度を軽々と上回ります。
お使いのデバイスのスペックを確認した上で、使用するモデルは大きく分けて2つに絞ります。
- コード記述およびテスト作成: 4.7GBサイズの
Qwen2.5-Coder-7B-Instruct (Q4_K_M) を配置します。16GB統合メモリのMacBookや8GB VRAMの外付けグラフィックス環境で35 TPS以上を記録します。
- ドキュメント要約およびコミットログ作成: 2.0GBサイズの
Llama-3.2-3B-Instruct (Q4_K_M) を使用します。低電力ノートPCのDDR4環境でもRAMの消費を抑え、15 TPS前後を安定して出力します。
コンテキストウィンドウを4096に制限してOOMエラーを防ぐ
せっかくモデルを起動しても、何度かやり取りを重ねるうちにプロセスが突然終了します。ターミナルに出力される Exit Code 137 は、OSのメモリ管理カーネル(LinuxのOOM-KillerやmacOSのJetSam)がRAM不足によりプロセスを強制終了(SIGKILL)したことを意味します。
外付けGPUを使用している場合は、さらに厄介なサイレントCPUフォールバック(Silent CPU Fallback)が発生します。VRAMの限界を超えた際にプロセスを終了させるのではなく、演算レイヤーの一部を低速なシステムRAMへ追いやるため、この時にGPUの使用率が急落し、秒間1トークンレベルまで低下します。
原因は、会話が長くなるほどRAMを圧迫するKV(Key-Value)キャッシュです。Llama-3アーキテクチャ基準でコンテキストを32,768(32K)トークンまで開放しておくと、重みの4.5GBに加えてキャッシュメモリだけでさらに4.0GBが追加されます。8GBのデバイスでは確実にクラッシュする構造です。この長さを4,096(4K)トークンに制限しておけば、キャッシュ容量が512MBに減少し、8GB環境でもクラッシュを防げます。
現在の状態を確認し、上限を固定する手順は以下の通りです。
まずターミナルで ollama ps を入力します。PROCESSOR 項目に 100% GPU ではなく 30%/70% CPU/GPU のように分割して表示される場合は、すでにVRAMを超過して低速なRAMへ追いやられている状態です。
設定ファイルを作成し、コンテキストサイズを固定します。~/local-ai-workspace/configs/Modelfile.coder を開き、以下の内容を記述します。
`dockerfile
FROM qwen2.5-coder:7b
キャッシュの肥大化を防ぐための4096トークン上限
PARAMETER num_ctx 4096
PARAMETER temperature 0.2
`
ターミナルからカスタムモデルとしてビルドします。
`bash
ollama create custom-coder:7b -f ~/local-ai-workspace/configs/Modelfile.coder
`
ビルド完了後、macOSではターミナルに sudo purge を入力してディスクキャッシュを解放し、Windowsでは使用していないWSLインスタンスを wsl --shutdown で整理して、利用可能な基本RAMを最低2GB以上確保しておきます。
外部への流出を防ぐローカルパイプラインの構築
社内のソースコードや個人プロジェクトが外部へ流出しないよう、モデルのサービングエンドポイントをローカルループバック(127.0.0.1)のみにバインドします。
~/local-ai-workspace/scripts/serve_secure.sh ファイルを作成し、以下のコードを追加します。
`bash
#!/bin/bash
export OLLAMA_HOST="127.0.0.1:11434"
export OLLAMA_ORIGINS="http://127.0.0.1:*,http://localhost:*"
ollama serve > ~/local-ai-workspace/logs/ollama_runtime.log 2>&1 &
`
スクリプトを実行した後、ターミナルで lsof -i :11434 | grep LISTEN を入力し、リッスンアドレスが 127.0.0.1:11434 になっているか確認します。もし外部からのアクセスが可能な 0.0.0.0:11434 が表示された場合は、直ちにプロセスを終了させる必要があります。
連携にはVS Codeのプラグインである Continue.dev を使用します。設定ファイル(~/.continue/config.json)を開き、チャット用モデルと自動補完用モデルを分割します。
`json
{
"models": [
{
"title": "Local Qwen2.5-Coder (Chat)",
"provider": "ollama",
"model": "custom-coder:7b",
"apiBase": "http://127.0.0.1:11434"
},
{
"title": "Local Llama3.2 (Summary)",
"provider": "ollama",
"model": "llama3.2:3b",
"apiBase": "http://127.0.0.1:11434"
}
],
"tabAutocompleteModel": {
"title": "Local Autocomplete",
"provider": "ollama",
"model": "qwen2.5-coder:1.5b",
"apiBase": "http://127.0.0.1:11434"
},
"allowAnonymousTelemetry": false
}
`
質問応答には先ほどコンテキストを制限した7Bモデルを割り当て、タブ補完には1GBの超軽量モデルである qwen2.5-coder:1.5b を指定します。これで補完の遅延が解消されます。
検証はインターネットを切断した状態で行います。Wi-Fiをオフにしたオフライン環境でターミナルを開き、直接リクエストを送信してみます。
`bash
curl -s -X POST http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.2:3b",
"prompt": "ローカル分離ネットワークテスト",
"stream": false
}' | grep "response"
`
ネットワークが遮断された状態で正常なJSONレスポンスが返ってきたら、外部クラウドに依存せず自分のノートPCのリソース内だけで安全に動作する開発環境のセットアップが完了です。