Raspberry Pi 5 でローカル LLM を動かす — Ollama を3ヶ月使った実用ライン
Raspberry Pi 5(8GB)に Ollama を入れて、ローカル LLM を3ヶ月ほど回している。最初に触ったときの正直な感想は「思ったより動く、でも期待しすぎると裏切られる」だった。
クラウド API のコスト削減が目的で始めたのだが、実用ラインがどこにあるかを掴むまでに、それなりに試行錯誤が必要だった。動くモデル、諦めるべきモデル、tokens/s の実測値、向いている用途と向いていない用途。手元で計測した数字を中心に書き残しておく。
なぜ Pi で LLM を動かそうと思ったか
きっかけは Anthropic の請求書だった。月3,000円ほど。金額自体は大きくないが、用途を見ると7割が「ログを要約する」「テキストをラベル分類する」みたいな単純作業だったのだ。これに毎月3,000円払うのは、ちょっと違うなと思った。
ちょうど自宅で Raspberry Pi 5 を24時間サーバーとして運用していたので、空きリソースで LLM が動かせないか試してみたくなった。アイドル時のメモリは5GBくらい余っていた。8B クラスの量子化モデルなら載りそうな見込み。
結論から言うと、用途を絞れば普通に使える。ただし「ChatGPT の代わり」を期待してはいけない。
セットアップは拍子抜けするほど簡単
Ollama のインストールは、公式のワンライナーでほぼ終わる。
curl -fsSL https://ollama.com/install.sh | sh
ARM64 対応のバイナリが配布されているので、Pi でも何もせず動く。systemd ユニットも自動で登録される。サービス自体は ollama serve がローカルの 11434 ポートで待ち受ける。
モデルの取得もコマンド一発。
ollama pull llama3.2:3b
ollama pull qwen2.5:3b
ollama pull phi3.5:3.8b
ここで重要なのが、サイズ選択だ。Pi 5 の 8GB モデルでも、7B や 8B のモデルはギリギリ動くが、コンテキストを長く取ると OOM で落ちる。実用的に安心して使えるのは 3B〜4B クラスまで。これは何度かハマって学んだ。
microSD じゃなくて NVMe に置く
モデルファイルは数 GB あるので、microSD に置くと初回ロードがしんどい。自分は M.2 HAT で NVMe SSD を増設してそこに ~/.ollama を移している。Llama 3.2 3B のロードが microSD で約20秒、NVMe で約4秒。体感がまったく違う。
# /etc/systemd/system/ollama.service.d/override.conf
[Service]
Environment="OLLAMA_MODELS=/mnt/nvme/ollama_models"
実測 tokens/s と「使えるモデル」の線引き
3ヶ月触って手元で計測した値が以下。プロンプト長を統一して、生成側のスループットだけを見ている。
| モデル | サイズ | tokens/s | 実用感 |
|---|---|---|---|
| llama3.2:1b | 1.3GB | 約14 | 軽い分類なら即応答 |
| qwen2.5:3b | 1.9GB | 約7 | 日本語も意外に粘る |
| llama3.2:3b | 2.0GB | 約7 | 英語は安定、日本語は微妙 |
| phi3.5:3.8b | 2.2GB | 約5 | 推論は強いが遅い |
| llama3.1:8b | 4.7GB | 約2 | 正直、待てない |
体感の話をすると、tokens/s が 5 を切ると「待ってる」感じが強くなる。バックグラウンドのバッチ処理なら気にならないが、対話的な用途だと 7 以上は欲しい。
日本語の品質では Qwen2.5 が頭一つ抜けていた。3B クラスでこの自然さは正直驚きだった。Llama 3.2 の 3B は英語だと文句なしだが、日本語では時々おかしな助詞が混じる。
向いている用途・向いていない用途
3ヶ月の運用で見えてきた「これは Pi でやらせるべき」「これはクラウドに任せるべき」の線引きがある。
向いているもの
- ログの異常検知・要約: 夜間に systemd ジャーナルを食わせて、エラーパターンを分類させる。多少遅くても朝までに終われば問題ない
- 定型テキストのラベル分類: 受信メールを「要対応」「自動処理」「無視」に振り分ける用途
- ファイル名・コミットメッセージの提案: 短い入出力なら 1B モデルでも十分実用
- プライバシー要件のあるテキスト: 外に出したくない個人メモを要約させるとか
向いていないもの
- 長い文章の生成: ブログ記事を一気に書かせるような用途は素直にクラウドの方がいい
- コーディング支援: 8B クラスでも GPT や Claude には全然及ばない。Claude Code を cron で回す方が圧倒的に速くて精度が出る
- 同時複数リクエスト: 1リクエストで CPU を100%食うので、並列度はほぼ1だと思った方がいい
夜間バッチで使い倒す
自分が一番ハマっている使い方は、夜間バッチでログ要約を回すパターンだ。日中は他の用途で Pi を使うので、Ollama は止めている。深夜2時から4時の間だけ起動して、その日のログを処理する。
# systemd timer の例
# /etc/systemd/system/log-summarize.timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
以前は cron から systemd timer に移行したばかりだったので、Ollama のジョブもそのまま timer に統一した。手前のバッチが終わってから Ollama を起動するように、After= でつなげている。
# Python から叩く例
import requests
def summarize(text: str) -> str:
res = requests.post(
"http://localhost:11434/api/generate",
json={"model": "qwen2.5:3b", "prompt": text, "stream": False},
timeout=300,
)
return res.json()["response"]
API は OpenAI 互換のエンドポイントもあるので、既存のクライアントコードを切り替えるだけで済むケースも多い。OPENAI_BASE_URL=http://localhost:11434/v1 を環境変数で渡せば、ライブラリ側の修正はゼロでいけることもあった。
熱・電力との折り合い
正直に言うと、ここが一番気を使う。
3B モデルでも推論中は CPU 100% が数秒〜数十秒続く。アクティブクーラーを付けていても、室温25℃で SoC 温度が65℃前後まで上がる。夏場の閉め切った部屋で長時間回すのは怖いので、自分は推論時間に上限を設けている。OLLAMA_KEEP_ALIVE=2m でアイドル後はモデルをメモリから降ろすようにすると、無駄な発熱が減った。
消費電力はアイドル時 3W、推論中 9W くらい。月間で見ても電気代は数十円の差なので、コストはほぼ無視できる。
ちなみに、もし Pi では物足りなくなったら、やはり VPS を契約してそこで動かす方が現実的だと思う。Pi で動かすことに固執しすぎると、生産性を落とす。
3ヶ月使ってみての総評
API 課金が月3,000円から月800円に減った。期待していたほどではないが、クラウドへの依存が減ったのは精神衛生上いい。回線が落ちても、Anthropic 側がメンテに入っても、ローカルのバッチは動き続ける。
一方で、ChatGPT を完全に置き換えるのは無理だった。複雑な依頼や長文生成では、やはり大規模モデルの方が圧倒的に賢い。Pi で動かす意味は「シンプルなタスクをローカルで完結させる」ところにある。役割を切り分けて使うのが現実解だと思う。
これから Pi 5 で LLM を試そうと思っている人には、まず Qwen2.5 3B から触ってみることをすすめたい。日本語のレスポンスが期待値を超えてくる確率が高い。そこから少しずつ用途を広げていくのがいい。ここはまだ試行錯誤中の領域なので、半年後にはまた違う結論になっているかもしれない。