2014年から個人開発で iOS/Android アプリを公開し続けて12年、累計5,000万ダウンロードを超えた壁紙アプリの保守をしながら、最近モバイル端末で動く小型モデルの使い道を整理しています。Qiita でエレクス株式会社さんの「最軽量のローカル LLM はどのくらい使い物になるのか?」という Qwen2.5 0.5B 実機検証記事を読んで、ちょうど私が Android で Gemini Nano の活用を検討している文脈と重なるテーマでした。並べて整理してみます。
0.5B モデルは「汎用 AI として弱い」のか
エレクス株式会社さんの検証では、Qwen2.5 0.5B で LP 制作やバグ調査をさせると、要件の省略、HTML/CSS の不整合、日本語の混乱(「私」が「我」のまま出力される)などが多発したと報告されていました。結論として「精密なコーディング補助や論理推論を期待するなら最低7B以上、まともに使うなら14B」と書かれています。
これは挙動として正確だと思います。ただ、検証の最後で著者が ChatGPT に問い合わせて引き出している通り、Qwen2.5 0.5B の設計思想はそもそも「自然な会話をする高性能 AI」ではなく、「スマホや組み込み機器でも動く超軽量な言語処理エンジン」です。命令の分類、JSON 生成、大型 LLM への処理振り分けの前段ルーターとして、単純処理を高速・低コストで常時実行するためのモデル、という位置づけになっています。
これは Gemini Nano の設計思想と、見事に重なります。
Gemini Nano の前段ルーター用途
Gemini Nano は Android デバイスの AICore 上で動く、Google のオンデバイス小型モデルです。Pixel 8 Pro 以降を中心に配信され、開発者向けには Android AICore Developer Preview 経由で利用できる API が用意されています。
Gemini Nano が向いている使い方として、Google が公式に挙げている例には次のようなものがあります。
- スマートリプライの候補生成
- メッセージの要約
- 文章の続きを補完
- 文章の校正
- ボイスメッセージの内容を1行で要約
これらに共通しているのは、入力と出力の長さが短く、判断が確定的で、ユーザーの待ち時間を1秒以内に抑えたい、という条件です。Qwen2.5 0.5B の「前段ルーター」用途と、本質的に同じ層を狙っています。
モバイルアプリ開発者から見た判断軸
私の壁紙アプリ群で、もし小型モデルを使うとしたらどこか、を整理すると、次のような切り分けになります。
- ユーザー入力の意図分類 — 「壁紙を保存して」「次の画像を見せて」「広告を消して」のような短い発話を、確定的なアクションに振り分ける
- 画像メタデータの要約 — 浮世絵作品のタイトル・作者・年代から1行説明文を生成する
- 検索クエリの正規化 — ユーザーの自由入力をタグセットに変換する
- 新規クラッシュレポートの分類 — Crashlytics の新規クラッシュをカテゴリ別に振り分ける
これらは全部、大型モデルに投げると応答が遅く、トークンコストもかかります。Qwen2.5 0.5B か Gemini Nano のような0.5B〜1B クラスで十分に処理できる粒度です。
逆に向かないのは、次のような用途です。
- 文章の創作(レビュー返信文の生成、紹介文の執筆)
- 長文ドキュメントの要約
- 複雑な論理推論を含むコード生成
- 多言語間の自然な翻訳
エレクス株式会社さんが Qwen2.5 0.5B に LP 制作をさせて躓いていたのは、明確に「向かない用途」を選んでいたためで、これはモデルの責任ではなく適用範囲の選び方の問題です。
ルーター設計の実装イメージ
Gemini Nano か Qwen2.5 0.5B を前段ルーターとして組み込むときの典型的な構成は、次のようになります。
// Android アプリ側、Gemini Nano の利用イメージ(概念コード)
class IntentRouter(private val nanoSession: GenerativeAiClient) {
suspend fun route(userUtterance: String): RoutedIntent {
val prompt = """
ユーザーの発話を、以下のいずれかに分類してください。
JSONで {"intent": "..."} の形式のみ返してください。
候補:
- SAVE_WALLPAPER
- NEXT_WALLPAPER
- PREV_WALLPAPER
- REMOVE_ADS
- UNKNOWN
発話: $userUtterance
""".trimIndent()
val response = nanoSession.generateContent(prompt)
return parseJson(response).toRoutedIntent()
}
}
// 呼び出し側
val router = IntentRouter(nanoSession)
val intent = router.route(userText)
when (intent) {
is SAVE_WALLPAPER -> handleSave()
is NEXT_WALLPAPER -> handleNext()
is UNKNOWN -> {
// 確定できなかった場合のみ Gemini Pro に問い合わせる
val proResult = geminiProClient.fallback(userText)
handleByFallback(proResult)
}
}この構成のポイントは、Gemini Nano か Qwen2.5 0.5B が「確実に処理できる範囲」を JSON スキーマで縛り、UNKNOWN を返したケースだけ大型モデルにフォールバックすることです。前段ルーターがちゃんと UNKNOWN を返してくれることが大事で、無理に分類させて誤判断するより、判断できないと言ってもらう方が運用上は安全です。
実装上のハマりどころ
実際に Gemini Nano を Android アプリに組み込もうとして躓いたポイントを、いくつか書いておきます。
ひとつめは、配信されているデバイスの範囲が想定より狭いことです。Pixel 8 Pro 以降と限定的で、私の壁紙アプリのユーザー層(累計5,000万 DL のうち多くが Android の中下位機種)では、ほぼ届きません。前段ルーターを Gemini Nano に依存させると、対応デバイスでだけ動く分岐が増えて、保守コストが上がる落とし穴があります。
ふたつめは、コールドスタートのレイテンシです。Gemini Nano は AICore がモデルを初回ロードする際に1〜2秒のオーバーヘッドがあり、ユーザーが初めて発話したときの体感が悪くなります。アプリ起動時にウォームアップする実装を入れるか、初回だけ Gemini Pro にフォールバックする実装を入れるか、で対応します。
みっつめは、レスポンスの揺れです。同じプロンプトでも出力が微妙に変わるため、JSON パースが時々失敗します。これは Qwen2.5 0.5B でも同じ性質で、temperature=0 相当の指定とリトライ機構を併用するのが現実解でした。
Qwen2.5 0.5B が選ばれる場面
Gemini Nano が AICore 経由で配信される一方、Qwen2.5 0.5B は Ollama 経由で配布されており、サーバー側・組み込み機器側で動かす自由度があります。私の場合は次のような場面で Qwen を選びそうです。
- アプリ内で完結させずサーバー側で前段ルーターを動かしたい場合
- Android だけでなく iOS や Web からも同じルーターを呼びたい場合
- 出力の揺れを完全に手元でコントロールしたい場合(モデル重みを固定したい)
逆に Gemini Nano を選ぶのは、次のような場面です。
- 端末で完結させてプライバシー上の利点を取りたい場合
- ネットワーク接続なしでも動かしたい場合
- AICore が配信されている対応デバイスに絞ったプレミアム機能を作りたい場合
私の壁紙アプリでは、ユーザーの大半が AICore 非対応デバイスのため、当面は Qwen2.5 0.5B の方が現実的だと判断しています。
「使い物にならない」と「適用範囲が違う」の区別
エレクス株式会社さんの検証記事は、結論として「最軽量ローカル LLM は日常タスクで使うのはほぼ不可能」と評価していました。これは「日常タスク」を汎用チャット用途として読むなら正しいです。
ただ、モバイルアプリ開発の文脈で「前段ルーター」を日常タスクとして再定義するなら、評価は反転します。短い意図分類、JSON 生成、振り分け処理に限れば、0.5B クラスは応答速度が圧倒的で、コストもゼロに近く、十分に「使い物になる」レンジに入ります。
モデルの評価は「何の用途に対して使い物になるか」を切り分けないと、設計判断としては機能しません。Gemini Nano と Qwen2.5 0.5B はどちらも前段ルーターとして優秀で、汎用 AI として使うと弱い、というのが結局のところ正確な評価だと思います。
明日からの作業では、壁紙アプリの検索クエリ正規化に Qwen2.5 0.5B を組み込む実験を始める予定です。動作したら、その実装をまた書き残します。