🐨

Phi-4-miniを使って完全オフラインなAIチャットアプリを作成

2025/03/10に公開

※iPad Proで画面録画→Macに転送して横長になるようにスクショを撮ってます。

ソースコード

以下にアップしてます。
https://github.com/IkeuchiRyuto/LocalGenAIApp

UI

ChatUI用のライブラリなどありますが、カスタマイズ性を考えて自分で作ってます。
まだテキストしか対応してないので今後マルチモーダル化していきます。
https://github.com/IkeuchiRyuto/LocalGenAIApp/blob/main/LocalGenAIApp/Screens/LocalAIChatScreenView.swift

推論ロジック

SLMEvaluatorクラスが処理を握っています。
Phi-4-miniに限らずSLMは無駄に出力しがちなので、システムプロンプトでしっかり制御が必要です。

https://github.com/IkeuchiRyuto/LocalGenAIApp/blob/main/LocalGenAIApp/Features/MLX/SLMEvaluator.swift

今はストリーミング出力してますが、もし一括で返したい場合は以下の箇所をコメントアウトすればOKです。

SLMEvaluator.swift
                return try mlxGenerate(
                    input: input, parameters: generateParameters, context: context
                ) { tokens in
//                    // update the output -- this will make the view show the text as it generates
//                    if tokens.count % displayEveryNTokens == 0 {
//                        let text = context.tokenizer.decode(tokens: tokens)
//                        print(text)
//                        Task { @MainActor in
//                            self.output = text
//                        }
//                    }
                    if tokens.count >= maxTokens {
                        return .stop
                    } else {
                        return .more
                    }
                }

技術スタック

開発言語...Swift / SwiftUI
使用パッケージ...mlx-swift / swift-transformers / swift-markdownui
モデル形式...MLX
採用モデル...Phi-4-mini

形式はMLXを採用

以下の記事でも紹介していますが、Appleデバイスに限ってはMLXをお勧めします。
Appleが研究しててMetalを使った処理の最適化をしてくれます。
※Metal...AppleシリコンのGPUとCPUを効率よく使い分けて最適化するAPI

https://zenn.dev/headwaters/articles/c1190b6fd2b5ab

今メジャーなのは圧倒的にLlama.cppですが、僕はMLXを推します。
コミュニティーも活発でPhi-4-miniが登場した日にissueを出してサポート依頼を出したところ、その日のうちに対応してくれました。

ちなみにそのissueが以下なのですが、海外のエンジニアに煽られましたww
https://github.com/ml-explore/mlx-swift-examples/issues/213

量子化は必須

今回アプリで使っているモデルはこちら。
8bit量子化でサイズが約4GBほど。
Wi-Fiを使えば5分くらいで端末にダウンロードできます。
https://huggingface.co/mlx-community/Phi-4-mini-instruct-8bit

サイズに関しては端末のストレージが許す限り何GBでもいいのですが、推論に使うメモリが大きく関わってきます。
M4のiPad Proだと余裕で動きますが、iPad 7 miniだとかなりギリギリです。
また、iOSアプリは1つのアプリが使用できるメモリ量などが決まってますし、別アプリも同時に立ち上げてるケースがほとんどだと思うので、端末のGPU・CPUをフルで使えることはありません。

iPhoneやiPad miniで運用していく場合は4bitの量子化モデルにして、ファインチューニングをして特定のタスクだけこなせるようにするのが現状は一番良いかなと思います。

オフラインチャットを作るならネイティブ言語

今回はSwiftを使って実装しました。
個人的にも得意なのはReactNativeとかFlutterですが、これといったパッケージがない状況です。
一応Llama.cppのFlutter版などもありますが、一般の方がLlama.cppのコードを参考にFlutterに書き換えてるのでバグが発生した時に困ります。

今回ガッツリSwiftを書いたのですが、以前(3年前くらい)に書いた時より体感書きやすくなってました。
StoryboardからSwiftUIのコードベースでのUI実装に切り替わったのがでかいんですかね。

Swiftで作るなら

作ったアプリでも使っているMLX-Swift。
以下のmlx-swift-examplesリポジトリをCloneしたらすぐにでもローカルで動かせます。
https://github.com/ml-explore/mlx-swift-examples

こちらは現状一番メジャーな方法のLlama.cpp
iOS以外のOSにも対応してるの強いですが、C++で開発されてるので自分で修正とかは難しいかもしれません。
https://github.com/ggml-org/llama.cpp

ReactNativeで作るなら..

これになりますかね。
最後の更新が5ヶ月前なので新しいモデルは全くサポートされてません。
https://github.com/cdiddy77/react-native-llm-mediapipe

あとはこれもアリかもしれません。
こちらはONNX形式のモデルを動かすそうです。
https://github.com/daviddaytw/react-native-transformers

Flutterで作るなら...

FlutterのAI Toolkitを使ったら実現できそうですね。
ただこれを使って作ったという記事が見つからないのでちょっとよくわからない..
https://docs.flutter.dev/ai-toolkit/custom-llm-providers

もしくはLlama.cppのFlutter(Dart)版を使う
https://github.com/netdur/llama_cpp_dart

Apple Intelligenceにも注目

すでにアメリカでは使えるようになっているのですが、今年の5,6月くらいから日本でもサポートされていくようです。
ユースケースによってはApple Intelligenceを使うのも全然アリだと思ってます。
一応Swiftでアプリに組み込むことができるものの、APIとしてサポートされてるわけではないので、アプリに合わせた細かいカスタマイズできるようになると非常に嬉しいなー。

https://www.apple.com/jp/apple-intelligence/
https://zenn.dev/headwaters/articles/d90998469039fe

ヘッドウォータース

Discussion