Foundation Modelsカスタムアダプター:Appleが推奨しないライフサイクル
SystemLanguageModel.Adapter型は、Appleのオンデバイス言語モデルにカスタムトレーニング済みの重みをロードできる仕組みです。1 フレームワークがこれをサポートしており、Appleはトレーニングツールキットを提供しています。エンタイトルメント、.fmadapterパッケージ形式、適切なデバイス向けの適切なアダプターをダウンロードするためのBackground Assets統合、すべてが文書化されています。
ところが、同じ型に関するAppleのドキュメントには、こう明記されています。原文をそのまま引用すると、”Adapters consume a large amount of storage space and isn’t recommended for most apps.”1 このクラスターの前回の記事Foundation Models Use Casesでは、ほとんどのアプリが進むべき本筋について取り上げました。本記事はその第三のレールにあたります。カスタムアダプターのトレーニング、パッケージング、出荷といった運用上のライフサイクル、そしてそれを採用すべきでない場面についてのAppleの明確な指針を扱います。
TL;DR
- カスタムアダプターは、オンデバイスのシステム言語モデルに重ねるLoRAでトレーニングされた重み行列です。2 Appleのツールキットがその技術名を明示的に裏付けています。
- 各アダプターは単一のシステムモデルバージョンに紐付きます。Appleがベースモデルを更新するたびに、アダプターを再トレーニングすることになります。3
- Appleの推奨は、原文のままだとこうなります。”Use the base system model for most prompt engineering, guided generation, and tools. If you need to specialize the model, train a custom Adapter… Use custom adapters only if you’re comfortable training foundation models in Python.”1
- アダプター資産はサイズが大きく(約160 MB)、Background Assetsを介してバンドルされ、エンタイトルメント(
com.apple.developer.foundation-model-adapter)でゲートされています。デプロイにあたっては、Apple Developer Program加入のAccount Holderがこれを申請する必要があります。3 - このパスが意味を持つのは、限定的な用途のアプリです。ファインチューニング済みのサーバーサイドLLMをオンデバイスで再現したいアプリ、スタイル・フォーマット・ポリシーに対する厳格な遵守要件があるアプリ、対象タスクにおいてプロンプトエンジニアリングの上限が明確になっているアプリ、といったところでしょう。2
アダプターとは実際に何なのか
SystemLanguageModel.Adapterはstructで、iOS、iPadOS、Mac Catalyst、macOS、visionOSで利用可能です(いずれも26.0以降)。4 型に関するAppleの説明はこうです。
“Use the base system model for most prompt engineering, guided generation, and tools. If you need to specialize the model, train a custom Adapter to alter the system model weights and optimize it for your custom task. Use custom adapters only if you’re comfortable training foundation models in Python.”4
仕組みもドキュメントに明記されています。Appleのアダプタートレーニングガイドはこう述べています。2
“The system model uses a parameter-efficient fine-tuning (PEFT) approach known as LoRA (Low-Rank Adaptation). In LoRA, the original model weights are frozen, and small trainable weight matrices called ‘adapters’ are embedded through the model’s network. During training, only adapter weights are updated, significantly reducing the number of parameters to train.”
LoRAは公開された手法であり、論文の歴史も公表されています。5 Appleが提供しているのは、ツールキット、.fmadapterパッケージ形式、アダプターをロードするオンデバイスランタイム、そしてBackground Assetsを介した出荷を支えるライフサイクル基盤です。
型のAPI表面
Adapter構造体は小さな表面を公開しています。4
init(fileURL: URL) throws:「ファイルURLからアダプターを生成します」。Xcodeでのローカルテストに用います。init(name: String) throws:「Background Assetsフレームワーク経由でダウンロードされたアダプターを生成します」。本番環境で利用します。func compile() async throws:「LanguageModelSessionでアダプターを使用する前に準備します。アダプターにドラフトモデルが含まれる場合は呼び出してください」。var creatorDefinedMetadata: [String : Any]:メタデータの作成者定義フィールドからの値。static func removeObsoleteAdapters() throws:現在のシステムモデルと一致しなくなったアダプターをクリアします。static func compatibleAdapterIdentifiers(name: String) -> [String]:互換性のあるアダプターアセットパックのIDを取得します。enum AssetError:アセット関連の失敗を表すエラー型です。
SystemLanguageModelにはアダプター用の対応イニシャライザがあります。convenience init(adapter: SystemLanguageModel.Adapter, guardrails: SystemLanguageModel.Guardrails)で、説明には「アダプター付きでベースバージョンのモデルを生成します」とあります。6
デプロイ専用のエンタイトルメントキーはcom.apple.developer.foundation-model-adapterです。「Foundation Modelsフレームワークのカスタムアダプターを有効化できるかどうかを示すブール値」と記述されています。6 トレーニングやXcodeでのローカルテストには不要ですが、App Storeに出荷する前には必須となります。3
Appleの「アダプター採用を検討するタイミング」基準
ツールキットのページには具体的な採用シグナルが示されています。2
- 「LLMに適したデータセットを保有している」、もしくはファインチューニング済みのサーバーベースLLMをすでに利用していてオンデバイスでの同等性を実現したい。
- 「モデルを主題の専門家にしたい」。
- 「特定のスタイル、フォーマット、ポリシーへの遵守をモデルに守らせたい」。
- 「プロンプトエンジニアリングだけではタスクに必要な精度や一貫性に到達できない」。
- 「推論時のレイテンシーを下げたい。プロンプトエンジニアリングによる解決策が呼び出しごとに長いプロンプトと事例を必要とするのなら、そのタスク向けに特化されたアダプターは最小限のプロンプトで済みます」。
同ガイドは、引き受けることになるコストも列挙しています。2
- 対象スキルを示すプロンプトと応答ペアからなるデータセット。
- アダプターの品質を評価するプロセス。
- アプリにサーバーからアダプターをロードするプロセス。
そしてストレージ税です。「各アダプターはアプリ内で約160 MBのストレージスペースを消費します。他の大型アセットと同様に、アダプターはアプリのメインバンドルに含めるべきではありません。複数のアダプターバージョンがあると、アプリは大きくなりすぎてインストールが困難になるからです」。2
フレームワークの推奨は、Appleが2か所で繰り返し述べているとおり、デフォルトはプロンプトエンジニアリングとツール呼び出しで、アダプターに手を伸ばすのは上記の基準が満たされたときに限るというものです。
Appleが規定する形でのトレーニング
トレーニングパイプラインはPythonで動きます。Appleのツールキットは、サンプルコード、特定のシステムモデルバージョンに対応したモデルアセット、データセットユーティリティ、そして.fmadapterパッケージを生成するエクスポートステップを同梱しています。2
ハードウェア要件は次のとおりです。「Appleシリコンと32 GB以上のメモリを搭載したMac、またはLinuxのGPUマシン」。Pythonは3.11以降が必要です。2
データセットの形式は次のとおりです。2
- 形式はjsonl。
role("user"または"assistant")とcontentフィールドを持ちます。 - 基本的なタスクには100〜1,000サンプル。
- 複雑なタスクには5,000サンプル以上。
- ツールキット内の
Schema.mdにフルスキーマが記載されており、ガイド付き生成やAIセーフティフック向けのフィールドも含まれています。
データ品質に関するAppleの注意書きは引用に値します。「量より質を重視してください。明瞭で一貫性があり、よく構造化されたサンプルからなる小さなデータセットの方が、ノイズの多い低品質サンプルからなる大きなデータセットよりも有効な場合があります」。2
トレーニングはツールキットのtrain_adapterエントリーポイントから起動します。
python -m examples.train_adapter \
--train-data /path/to/train.jsonl \
--eval-data /path/to/valid.jsonl \
--epochs 5 \
--learning-rate 1e-3 \
--batch-size 4 \
--checkpoint-dir /path/to/my_checkpoints/
任意で、アダプターのトレーニング後に対応するドラフトモデルをトレーニングできます。2 ドラフトモデルとはシステムベースモデルのより小型のバージョンで、推論加速の公開技法である投機的デコーディングを可能にします。7 Appleはこう位置付けています。「ドラフトモデルをトレーニングしないことを選んだ場合、アダプターのユースケースで投機的デコーディングは利用できません」。2
単一バージョン制約
アダプターについて運用上もっとも重大な事実は、特定のシステムモデルバージョンへのバインドです。3
“Each adapter is compatible with a single specific system model version. You must train a new adapter for every new base model version. A runtime error occurs if your app runs on a person’s device without a compatible adapter.”
ツールキットはモデルと連動してバージョン管理されています。執筆時点で、Appleは2つのベータ版ツールキット(Beta 0.1.0とBeta 0.2.0、いずれも削除済み)と1つの正式版(26.0.0)を公開しています。2 リリースサイクルに関するAppleの方針はこうです。「システムモデルが更新されるたびに新しいツールキットがリリースされます。システムモデルはiOS、macOS、visionOSで共有されており、システムモデルの更新はそれらプラットフォームのOSアップデートの一部として行われます(ただし、すべてのOSアップデートでモデル更新が伴うわけではありません)」。2
運用上の含意としては、アダプターを出荷するアプリチームはAppleのサイクルで動くモデル更新ライフサイクルを購読することになる、ということです。各ベースモデルの更新は、再トレーニング、再評価、再公開の強制要因となります。
アセットパックとしてのパッケージング
アダプターファイルはアプリ内バンドルが明示的に推奨されないほど大きいものです。Appleはアダプターの配信をBackground Assets経由でルーティングしています。3
ツールキットは.fmadapterパッケージを生成し、ツールキットがそれをBackground Assetsのアセットパックとしてもバンドルします。Xcode 16以降のba-packageコマンドラインツールがこのバンドル作業を担い、ツールキットがそれを内部で呼び出します。3
ホスティングの選択肢は次のとおりです。3
- Apple-Hosted, Managed. Appleがアセットをホストし、OSがダウンロードライフサイクルを管理します。
- Self-Hosted, Managed. 自前のサーバーでホストし、OSがダウンロードライフサイクルを管理します。
- Self-Hosted, Unmanaged. 自前でホストとライフサイクル管理の双方を行います。
必要なInfo.plistキーはホスティング選択肢ごとに異なります。3 Apple-Hosted ManagedにはBAHasManagedAssetPacks、BAAppGroupID、BAUsesAppleHostingが必要、Self-Hosted Managedには最初の2つが必要、Self-Hosted Unmanagedには不要です。各パスにはXcodeが生成するアセットダウンローダー拡張ターゲットも含まれます。
実行時に正しいアダプターを選ぶ
アセットダウンローダー拡張のBackgroundDownloadHandler.swiftが生成されると、XcodeがshouldDownload(_:)コールバックを配線します。アダプターアセット向けのAppleの例はこうです。3
func shouldDownload(_ assetPack: AssetPack) -> Bool {
if assetPack.id.hasPrefix("mygameshader") {
return true
}
return SystemLanguageModel.Adapter.isCompatible(assetPack)
}
SystemLanguageModel.Adapter.isCompatible(_:)は、現在のシステムモデルにアダプターが一致するアセットパックに対してtrueを返します。同じコールバックで、アプリが必要とするアダプター以外のアセットを通過させることもできます。
ロードとダウンロードのトラッキング
アセットがデバイスに到着すると、ロードパスは次のようになります。3
SystemLanguageModel.Adapter.removeObsoleteAdapters()
let adapter = try SystemLanguageModel.Adapter(name: "myAdapter")
互換性のあるアダプターがデバイスにキャッシュされていない場合、コンストラクションがダウンロードを開始します。UXに関するAppleの注意書きはこうです。「アダプターはデータサイズが大きいため、ダウンロードに時間がかかる場合があります。特にWi-Fiやセルラーネットワーク上では顕著です。ネットワーク接続がないユーザーは、アダプターをすぐに使うことはできません」。3
ステータス遷移はAssetPackManagerから取得できます。3
let assetpackIDList = SystemLanguageModel.Adapter.compatibleAdapterIdentifiers(name: name)
if let assetPackID = assetpackIDList.first {
let statusUpdates = AssetPackManager.shared.statusUpdates(forAssetPackWithID: assetPackID)
for await status in statusUpdates {
switch status {
case .began(let assetPack): ...
case .paused(let assetPack): ...
case .downloading(let assetPack, let progress): ...
case .finished(let assetPack): ...
case .failed(let assetPack, let error): ...
@unknown default: ...
}
}
}
ドキュメント化されたDownloadStatusUpdateの5ケースは次のとおりです。.began、.paused、.downloading、.finished、.failed。3 フレームワーク側の@unknown default分岐は必須です。Appleが将来のSDKバージョンでケースを追加する可能性があるためです。
ステータスが.finishedに達したら、アダプターをセッションに組み込む準備が整います。
let adaptedModel = SystemLanguageModel(adapter: adapter)
let session = LanguageModelSession(model: adaptedModel)
ドラフトモデルとそのレート制限
アダプターがドラフトモデルとともに出荷されている場合、adapter.compile()を呼び出すと使用準備が整います。Appleのドキュメントは、これを別個で計算コストの高いステップとして明記しています。3
“The first time a device downloads a new version of your adapter, a call to
compile()fully compiles your draft model and saves it to the device. During subsequent launches of your app, a call tocompile()checks for a saved compiled draft model and returns it immediately if it exists.”
公開されているレート制限もあります。3
“Rate limiting protects device resources that are shared between all apps and processes. If the framework determines that a new compilation is necessary, it rate-limits the compilation process on all platforms, excluding macOS, to three draft model compilations per-app, per-day.”
macOSが除外されているのは興味深い点です。制限が適用されるのはiOS、iPadOS、visionOSです。Appleはコンパイルをアプリ起動をブロックしないようにBackground Tasksでスケジュールされたタスク内で実行することを推奨しています。3
開発時の落とし穴もあります。「Xcode経由でアプリを起動するたびに、Xcodeはアプリに新しいUUIDを割り当てるため、フルコンパイルプロセスが毎回走ります。テスト中にレート制限エラーを受け取った場合は、Xcodeでアプリを停止し、再起動してレートカウンターをリセットしてください」。3
テストとシミュレータ制約
アダプターのテストには物理デバイスが必要です。Appleは明示しています。「アダプターのテストには物理デバイスが必要であり、Simulatorではサポートされません」。3
Xcodeでのローカルテストでは、名前ではなくファイルURLから初期化します。3
let localURL = URL(filePath: "absolute/path/to/my_adapter.fmadapter")
let adapter = try SystemLanguageModel.Adapter(fileURL: localURL)
Appleが提示するパターンは、テスト用にローカルファイルをインポートし、アプリを公開する前にプロジェクトから削除する、というものです。アダプターファイルはバンドルするには大きすぎるためです。3
このパスが運用面で支払うコスト
ライフサイクルをまとめると、カスタムアダプターを出荷するアプリは次のものに署名することになります。
- Pythonトレーニングインフラ。 最低でもAppleシリコンと32 GBメモリを備えたMac、もしくはLinuxのGPUマシン。2
- Appleのサイクルに従った再トレーニングのリズム。 システムモデルが更新されるたびに、新しいアダプターと新しいツールキットバージョンが必要です。3
- 配信スタック。 App Store Connect経由のApple-hostedアセットパック、またはアセットダウンローダー統合を実行する自前サーバー。3
- ストレージ上のバージョン別アダプター。 複数のベースモデルバージョンが世の中に存在する場合、複数のアダプターをホストし、デバイスがマッチするものを取得することになります。3
- エンタイトルメントゲート。 Apple Developer Program加入のAccount Holderが申請するもので、承認なしには出荷できません。2
- アダプターバージョンごとの160 MB税。 アプリバンドル内ではなく、ダウンロード後のユーザーデバイス上に置かれます。2
- 物理デバイスでのテスト。 Simulatorはアダプターを実行しません。3
これが運用コストの素直な姿です。採用シグナルが揃ったときの利点は、オンデバイスモデルが最小限のプロンプトでタスクに特化し、レイテンシーが下がり、呼び出しごとのAPIコストがゼロになり、データの完全な局所性が得られることです。すでにファインチューニング済みのサーバーサイド推論にコストを払っており、オンデバイスでの同等性を求めるアプリにとっては、それが端的なトレードオフです。
まとめ
- アダプターはAppleが文書化した手法によるLoRAです。 ベースの重みは凍結され、小さなトレーニング可能な行列がモデルのネットワーク全体に組み込まれ、トレーニング中はアダプターの重みのみが更新されます。2
- システムモデルバージョンごとに1アダプター、例外なし。 OSリリースに連動した再トレーニングを計画してください。3
.fmadapterフローはエンドツーエンドです。 Pythonでトレーニングし、ツールキットでパッケージ化し、Background Assetsアセットパックとしてホストし、アプリで名前によりロードし、ドラフトモデルをBackground Taskでコンパイルする、という流れになります。- Apple自身が、ほとんどのアプリはこのパスを取らないよう推奨しています。 別々の2つのAppleドキュメントページが、ほとんどのユースケースでは思いとどまるよう促しています。1 ツールキットページの基準を読んでください。デフォルトの答えは「No」です。
- ハードウェアでテストしてください。 Simulatorはアダプターを実行しません。物理デバイスセッションと
Background Tasksフレームワークのコンパイルスロットを軸にテスト計画を組んでください。
Apple Ecosystemクラスター全体としては、組み込みの特化に関する判断基準、フレームワークの中核を成すToolプロトコル、エージェント的ワークフローの分割(アプリ内とツーリングLLMの使い分け)、より広いルーティング論点としてのApp Intents vs MCPを参照してください。ハブはApple Ecosystem Seriesにあります。AIエージェントを伴うiOSの広範な文脈については、iOS Agent Development guideをご覧ください。
FAQ
自分のアプリが本当にカスタムアダプターを必要としているかどうか、どう見分ければいいですか?
ツールキットガイドのAppleの「アダプター採用を検討するタイミング」セクションを読んでください。2 シグナルは次のとおりです。オンデバイスでミラーしたい既存のファインチューニング済みサーバーサイドLLMがある、精度におけるプロンプトエンジニアリングの上限が文書化されている、特定のスタイル・フォーマット・ポリシーの遵守が確固たる要件である、プロンプトエンジニアリング単体では満たせないレイテンシー目標がある。ほとんどのアプリはこれらのいずれにも該当せず、Apple自身がそう述べています。
エンタイトルメントは実際に何をゲートしているのですか?
トレーニングではなく、デプロイです。Appleのドキュメントは明示しています。「アダプターのトレーニングやローカルテストにはこのエンタイトルメントは不要です」。3 Apple Developer Program加入のAccount HolderがFoundation Models Framework Adapter Entitlementページからcom.apple.developer.foundation-model-adapterを申請し、エンタイトルメントが取得できればApp Storeに出荷する道筋が開かれます。2
アダプターのサイズはどのくらいで、どこに置かれますか?
Appleが文書化した数値はこうです。「各アダプターはアプリ内で約160 MBのストレージスペースを占有します」。2 アダプターはアプリバンドル内には置かれません。Appleはこれらを、Appleのサーバー(managed)または自前のサーバー(managedまたはunmanaged)にホストされたBackground Assets経由でルーティングし、デバイスは現在のシステムモデルに一致するバージョンをダウンロードします。3
Appleがベースモデルを更新したら、何が起きますか?
再トレーニングします。ドキュメントから引用すると、「各アダプターは特定の単一のシステムモデルバージョンと互換性があります。新しいベースモデルバージョンごとに新しいアダプターをトレーニングしなければなりません。互換性のあるアダプターがない状態でユーザーのデバイス上でアプリが動作するとランタイムエラーが発生します」。3 実務上は、配信スタックが複数のアダプターバージョンを同時にホストし、デバイスがisCompatible(_:)に基づいて適切なものを取得します。
アダプターと.contentTaggingの関係はどうなっていますか?
.contentTaggingは、Appleが提供するSystemLanguageModel.UseCaseの2つの静的プロパティのうちの1つで、姉妹記事で取り上げました。これはAppleが管理する特化機能であり、エンタイトルメントによるゲートはなく、フレームワークに含まれています。一方、カスタムAdapterは、Appleのユースケースがカバーしないタスクに対する開発者管理の同等物です。Appleのドキュメントは、.contentTaggingの内部動作を説明する際に「adapted」という語を使っていますが、それは形式的なAdapter型と同じものではありません。本記事が扱うのは、その形式的な型の方です。
ドラフトモデルを必ずトレーニングしなければなりませんか?
いいえ。Appleのドキュメントはこう述べています。「ドラフトモデルをトレーニングしないことを選んだ場合、アダプターのユースケースで投機的デコーディングは利用できません」。2 アダプター自体はそれでもロードして動作します。投機的デコーディングによる推論速度の向上が得られないだけです。ドラフトモデルは任意の二段目のトレーニングパスにあたります。
References
-
Apple Developer, “SystemLanguageModel.Adapter”. 型の説明、ほとんどのアプリに対する利用非推奨、”Use custom adapters only if you’re comfortable training foundation models in Python.” 2026-05-04取得。 ↩↩↩↩
-
Apple Developer, “Get started with Foundation Models adapter training”. ツールキット概要、LoRAメカニズム、ハードウェア要件、データセット形式、トレーニングCLI、ドラフトモデルオプション、ツールキットバージョン表、エンタイトルメント申請フロー。2026-05-04取得。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩
-
Apple Developer, “Loading and using a custom adapter with Foundation Models”. アセットパックホスティング、Info.plistキー、
shouldDownload(_:)の例、ステータス遷移、レート制限、Simulator除外、単一バージョン互換性制約。2026-05-04取得。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple Developer, “SystemLanguageModel.Adapter”. 構造体のAPI表面:
init(fileURL:)、init(name:)、compile()、creatorDefinedMetadata、removeObsoleteAdapters()、compatibleAdapterIdentifiers(name:)、AssetError。2026-05-04取得。 ↩↩↩ -
Hu et al., “LoRA: Low-Rank Adaptation of Large Language Models”, arXiv:2106.09685. Appleが利用する手法が参照する元論文。 ↩
-
Apple Developer, “SystemLanguageModel”.
init(adapter:guardrails:)コンビニエンスイニシャライザとcom.apple.developer.foundation-model-adapterエンタイトルメントの説明。2026-05-04取得。 ↩↩ -
Leviathan et al., “Fast Inference from Transformers via Speculative Decoding”, arXiv:2211.17192、およびChen et al., “Accelerating Large Language Model Decoding with Speculative Sampling”, arXiv:2302.01318. Appleのドラフトモデルが採用する投機的デコーディング手法。アダプタートレーニングガイドが直接引用しています。 ↩