WWDC25:Code-along: Bring on-device AI to your app using the Foundation Models framework

前回の「Deep dive into the Foundation Models framework」に引き続き、Foundation Models framework のセッションメモ(今回もAI要約+筆者加筆修正)。前半はだいたい前出の内容と被っていた。UIに組み込む際の体験向上、パフォーマンスの検証や改善のtipsについて。

Foundation Models のデモアプリが結果を逐次表示する際、やたらぬるぬると表示更新される様子が気になっていて、実装難易度高そうだと思っていたが、ストリームで吐き出されるデータ表現が自動的に identifiable であるため、実装者はただアニメーションを指定すれば良いという、にわかに信じがたい魔法のような話だった。


Introduction

  • Foundation Models frameworkを使い、SwiftUIアプリにオンデバイスAI機能を追加する方法を実演
  • 旅行プラン作成アプリを例に、ランドマーク選択→旅程自動生成→外部情報取得→ストリーミング表示→パフォーマンス最適化までを一通り解説

Prompt engineering

  • XcodeのPlayground機能を活用し、プロンプトの試行錯誤を効率化
  • @Generable annotation, @Guide macro
  • Instructions (プロンプトの上位形式 – the higher level form of prompting) により、モデルの役割や期待する出力例を明示し、精度を高める
  • 生成結果は Observable オブジェクトとしてUIにバインドし、リアルタイムに反映
    • 初期化タイミングによっては、不要なタ再生成が行われパフォーマンスに影響するため、Task modfier 内で初期化し、表示時1度だけの生成を保証するべき

Tool calling

  • Tool プロトコルを実装することで、モデルがアプリ内の任意の関数やAPI(例:MapKit)を呼び出せる
  • ツールには名前・説明・call メソッド(引数はGenerable 型)を定義
  • モデルは必要に応じてツールを自律的に呼び出し、外部データ(例:ランドマーク周辺の観光地情報)を取得
    • ツールの有無、ある目的に対して使って欲しい tool の明示、呼び出し頻度はプロンプトや instruction で調整可能
  • Apple Intelligenceの利用可否 = Foundation models の利用可否や、モデルの準備状況も考慮し、UIで適切に案内・制御
    • SystemLanguageModelmodel.availability で判別
    • Xcode の build scheme から、モデルの無効化が可能 (Simulated Foundation Models Availability)

Streaming output

  • 旅程生成の出力をストリーミングで受け取り、部分的にUIへ即時反映
    • session.streamResponse(...) API
    • PartiallyGenerated 型(全プロパティが optional な構造体)を活用し、生成途中のデータも段階的に表示
  • SwiftUIのForEachやアニメーション、トランジションを組み合わせて、スムーズな体験を実現
    • PartiallyGeneratable 構造体は自動的に identifiable、IDの自前管理は不要
  • ストリーミングにより、ユーザーは生成完了を待たずに内容を確認できる

Profiling

  • Foundation Models Instrument を使い、アプリのパフォーマンスを可視化・最適化
  • モデルのロードや推論、ツール呼び出しの各工程の所要時間を計測
  • 初回リクエスト時の遅延対策として「プリウォーム(session.prewarm())」を推奨
    • モデルがリクエストをもらう前に、モデルをロードしておく
    • 例: ユーザーがプロンプトのタイピング開始時
    • 今回はランドマークタップ時(Generate ボタンタップ前)
  • 生成スキーマをプロンプトに含めるかどうかを状況に応じて最適化し、トークン数やレイテンシを削減
    • モデルがリクエスト生成前にレスポンスフォーマットを完全に理解していればincludeSchemaInPromptfalse に指定する
      • 有効ないくつかのケースを紹介
  • 実機での計測を推奨し、シミュレータとの違いに注意
    • Simulator on M4 Mac > iPhone の場合あり

WWDC25:Deep dive into the Foundation Models framework

前回の「Meet the Foundation Models framework」に続いて、Foundation Models framework を深ぼるセッションビデオのメモ。今回もAIに要約してもらったものをベースに理解したことを書き足していった。

Tool は Inputに対してOutput が一定決まっている(連絡先やカレンダー)ユースケースに対応しており、一方でたとえばカスタムデータからインサイトを得るような、ファインチューニング的な方法は現時点での Foundation Models framework ではまだ実現できなさそうだった。あくまで、オンデバイスLLMに外部リソースへの一問一答的な参照手段を与えるという理解。desciriptionを記述することでモデルが勝手に選択して使うという意味では、MCPに近いかも?将来的に、自身が保有するデータをこのツール定義としてアプリ外に公開し、アプリ間でAI同士やりとりできるようになると面白いかも、と妄想が広がった。


Sessions (Prompting / Transcript / Sampling)

  • session.respond(to: userInput)
    • instruction promptをトークン (small substrings) に分解
    • LLMがトークンシーケンスを受け取り、response を生成
    • Foundation Models framework が一連の処理を担うので使い手は気にしなくて良いが、トークンは free ではない:計算コストとレイテンシが生じる
  • ステートフルなセッションとその状態管理
    • セッション(LanguageModelSession)は状態を持ち (statefull)、やりとりの履歴(transcript)を保持する
    • session.transcript: デバッグやUIへの表示に有用
    • ただし、context limit あり:入力・出力のトークン数が多いと遅延やエラー(.exceededContextWindowSize)が発生する
      • 履歴のない新しいセッションを開始
      • 既存のセッションから transcript を要約し引き継げる
        • 例1. 最初(instruction)と最後のやりとりのみ引き継ぐ
        • 例2. transcipt 全体を要約して引き継ぐ (外部ライブラリ or Foundation Models 自体を用いて)
  • サンプリングと出力の多様性
    • 同じプロンプトに対して異なるアウトプットが生じる
    • モデルの出力 = トークンは、確からしさの分布に基づき確率的に選択される(sampling)
      • デフォルトは randam sampling
      • ゲームなどの用途に対して、再現性を求めたい場合:GenerationOptions でサンプリング方法や多様性 temperatureを調整可能 (数値大きい方がアウトプットが多様)
      • 決定論的な出力(.greedy)も選択できるが、モデルのバージョンによって結果が変わる場合がある
  • 言語サポート
    • 入力言語が未対応の場合は .unsupportedLanguageOrLocale エラーが発生
    • モデルが対応している言語かどうかを事前にAPIで確認可能

Generable

  • @Generable マクロを使うことで、Swiftの型に沿った構造化データを安全に生成できる
    • constrained decoding により、特定のスキーマに沿った正しい出力のみが生成される
      • ハルシネーションが発生しても、最終的にスキーマ定義されたトークンのみを採用することで誤りを防ぐ
    • enumやassociated value、配列、数値型など多様な型に対応
    • @Guide マクロでプロパティごとに値の範囲や説明を指定可能
      • @Guide(.range(1...10)) for Int
      • @Guide(.count(3)) for Array
      • @Guide(desciption: "A full name")
    • プロパティの生成順序はソースコードの宣言順に従うため、依存関係やUI表示順に注意
    • 文字列に@Guide(.pattern(...))を指定して 、正規表現(regex)による文字列制約も可能
      • Regex builder syntax

Dynamic Schemas

  • 実行時に構造が決まるデータにも対応可能(DynamicGenerationSchema
    • Dynamic schemas はPropertyのリストを持ち、Propertyごとがnameとpropertyの型を定義するschemaを持つ
    • Dynamic schemas は配列を持つことが可能
    • 他の dynamic schemas をスキーマ名を通じて参照することが可能
  • ユーザー入力などで動的にスキーマを構築し、モデルに渡すことができる
  • 検証済みスキーマに変換してから推論を行うため、動的でありながら同時に型安全性が保たれる

Tool Calling

  • Tool プロトコルを実装することで、モデルがアプリ内の任意の関数やAPIを呼び出せる
    • Tool.name は短く、しかし省略は用いず英語としてreadableで分かりやすくするのが推奨。動詞を使うべき e.g. "findContact"
    • Tool.description も同様に長すぎず (1文推奨)、実装の説明を含めるべきでない
      • この文字列がそのままプロンプトに用いられるため、トークンが長くなりレイテンシが増大する
  • インプットArgument を定義
    • モデルがツールを呼び出す際にArgumentを生成する
    • 入力引数もGenerable で型安全に生成されるため、想定外の値が渡される心配がない
  • ツールはインスタンスで、そのライフサイクルをコントロール可能
    • セッションの初期化時に渡し、セッション中は同じインスタンスが使われる
    •  ツールは状態を持つこともでき、複数回・並列で呼び出される場合もある
  • 例:連絡先やカレンダーの情報を使って、よりパーソナルな体験を実現

まとめ

  • Foundation Models frameworkは、オンデバイスで安全かつ柔軟にLLMを活用できる強力なツール
  • セッション管理、構造化出力、動的スキーマ、ツール呼び出しなど、実践的な機能が豊富
  • プライバシーを守りつつ、アプリに高度なAI体験を組み込むことが可能

WWDC25:Meet the Foundation Models framework

Foundation Models フレームワークが気になっていたので、一度Liquid Glass を離れて3本目に見たのでメモ。オンデバイスモデルならではの制約を実際に使いながら把握していきたい。

前回まで、Liquid Glass の抽象的な思想をしっかり理解する意気で、几帳面にもビデオを頭から見てメモを構築したが、無駄に時間がかかるので今回は先にAIにまとめてもらって、そこに自分の理解を加筆していった。


1. フレームワークの概要

  • Foundation Modelsフレームワークは、Apple Intelligenceを支えるオンデバイス大規模言語モデル(LLM)へのアクセスを提供
  • macOS、iOS、iPadOS、visionOSで利用可能
  • スライドに示された用途例:コンテンツ生成/生成的対話/アプリ内ユーザーガイド/生成的クイズ/パーソナライズ/分類/要約/セマンティック検索/洗練・精緻化/質問応答/カスタマイズ学習/タグ生成/エンティティ抽出/トピック検出
  • オンデバイスで動作するため、プライバシーが保護され、オフラインでも使用可能

2. モデルの特徴

  • Xcode Playgrounds 上の数行のコードで実演
  • 30億パラメータを持つ大規模言語モデル
  • 2ビット量子化
  • 要約、抽出、分類などのタスクに最適化
  • デバイススケールのモデルであり、サーバースケールのLLMとは異なる用途に設計
    • 世界クラスの知識や高度な推論には向いていない
    • タスクを小さなピースに分解することが求められる

3. Guided Generation

  • LLMは自然言語による非構造的なアウトプットをするが、アプリのビューへのマッピングには不向き
    • JSONやCSVへの吐き出しをプロンプトで指示できるが、確率論的なモデルにおいて正確性を保証できない
  • そこで構造化された出力を保証する機能
  • @Generable@Guideマクロを使用
  • Swiftの型システムを活用して自然言語プロンプトを補強
    • @Generable: モデルに生成して欲しい型を定義
    • @Guide: プロパティに対して自然言語による説明を付与し、生成する値を制御する
    • プリミティブ型、配列、Generable型、再帰的な構造もサポート

4. Snapshot Streaming: ストリーミング機能

  • デルタではなくスナップショットを使用
    • 典型的なストリーミングアウトプットはデルタが用いられる
    • 生成した結果を組み立てる責務はデベロッパー側にある:構造的になると難しい
  • スナップショット:モデルの生成したデルタを部分的な生成結果として表現
    • @Generated マクロを展開するとPartiallyGenerated
      • すべてのプロパティが Optional
  • SwiftUIとの統合が容易
    • streamResponse(to:options:)
    • stream responses aync sequences
      • ↑ snapshot を逐次的に受ける
  • Best practices
    • SwiftUI によるアニメーション/トランジションを考慮する:レイテンシを隠すために
  • view identity を考慮する:特に配列において
  • プロパティの順序が重要
    • アニメーション/モデルのアウトプット どちらに対しても大切
    • summary を表すプロパティは最後に定義するのが良い
    • 参照:Code-along: Bring on-device AI to your app using the Foundation Models framework

5. ツール呼び出し機能

  • 外部情報源との統合
  • モデルがアプリ内のコード(Tool)を実行可能
    • e.g. struct GetWhatherTool: Tool
    • name description
    • call(arguments:) async -> ToolOutput
      • 外部情報源とのやり取りを実装(e.g. ジオコードから住所、位置情報から天気)
    • ツールの説明をもとに、モデルがツールを自律的に呼び出し、最終レスポンスに組み込む
  • よりダイナミックな定義が可能
    • 動的生成スキーマ
    • 実行時の引数/動作の定義

6. ステートフルセッション

  • セッションベースの設計
    • instruction: モデルがどう応答するべきかを定義:e.g. 口調や言葉数
    • カスタム指示の提供が可能
  • インストラクションとプロンプトと指示の違いについての説明
    • instructions should come from you
    • propmts may come from you / users
    • 前者が優先され、prompt injection 攻撃を予防する
  • multi-turn interactions
    • モデルとのインタラクションはコンテキストに保持され、1セッション内での 過去のやりとりを参照、理解できる
    • session.transcriptで過去のやり取りを出力可能
  • 組み込みのユースケース (built-in use cases)
    • e.g. SystemLanguageModel(useCase: .contentTagging)
    • Content taggin adapter の説明
  • エラーハンドリング
    • ガードレール違反
    • 未対応の言語
    • コンテクストウィンドウの超過