🔯

WWDC25: 「Foundation Modelフレームワークの紹介」の要約

に公開

WWDC25のセッション、「Foundation Modelフレームワークの紹介」(Meet the Foundation Models framework) の要約です。

https://developer.apple.com/jp/videos/play/wwdc2025/286

Foundation Modelフレームワークで使用できるモデル

特徴

  • オンデバイスで動作するためプライバシーが確保される
  • オフラインで使用できる
  • OSに組み込まれているためアプリが肥大化しない

モデルの特徴と用途

30億個 (3B) のパラメータを持ち、2bit量子化されています。要約や抽出、分類などに対して最適化されており、広い知識の収集や高度な推論を目的としていません。

ガイド付き生成

モデルの生成結果に型を指定できます。プロンプトを使って生成結果のフォーマットを指定する必要はありません。

ガイド付き生成を行うには、以下の2つのマクロを使用します。

  • @Generable マクロ: レスポンスの定義を行うstructに付与します
  • @Guide マクロ: レスポンスのプロパティに付与し、プロパティの説明を書きます。それによってLLMの生成結果を指定します
@Generable
struct SearchSuggestions {
  @Guide(description: "A list of suggested search terms", .count (4))
  var searchTerms: [String]
}

以下のようにして使います。

let prompt = """
Generate a list of suggested search terms for an app about visiting famous landmarks.
"""

let response = try await session.respond(
  to: prompt,
  generating: SearchSuggestions.selfprint(response.content)
// SearchSuggestions (searchTerms: ["Hot springs", "Watery wonders", ...])

Generable型で使える型

  • String
  • Double
  • Float
  • Decimal
  • Boolean

上記の他に配列や、Generable型を再帰的に使用することもできます。

ストリーミング

streamResponse メソッドを使うと、レスポンスをストリーム形式で受け取ることができます。
ストリームで受け取るときは、PartiallyGenerated 型でラップされた形になります。

let stream = session.streamResponse(
  to: "Craft a 3-day itinerary to Mt. Fuji."
  generating: Itinerary.self
)

for try await partial in stream {
  print(partial)
  // Itinerary.PartiallyGenerated (name: nil, days: nil)
  // Itinerary.PartiallyGenerated(name: "Mt.", days: nil)
  // Itinerary.PartiallyGenerated(name: "Mt. Fuji", days: nil)
}

SwiftUIに適用する場合

SwiftUIのViewで、ストリーミングの形で生成結果を受け取る場合、PartiallyGenerated 型のStateを作成し、そこにレスポンスのスナップショットを保存します。

@State
private var itinerary: Itinerary.PartiallyGenerated?

注意点

  • モデルのレスポンスは遅いので、SwiftUIのアニメーションなどを利用してユーザーに遅延を感じさせない (退屈させない) ように工夫しましょう
  • SwiftUIのViewの識別子は慎重に検討しましょう
     - レスポンスに配列を指定する場合は特に注意する (Viewの再利用の話?)
  • プロパティが生成される順序はstructで宣言された順番になります
    • 例えば、モデルが生成する要約の品質を最適化したい場合、要約のプロパティ (@Guide var summary: String) をstructの最後のプロパティにする必要があります

Tool calling

モデルがレスポンスを作成する際にメソッド (Tool) を実行して、その結果をレスポンスに組み込むことができます。

Tool Callngを使用する場合、Toolプロトコルに準拠したstructを定義します。

import FoundationModels

struct GetWeatherTool: Tool {
  let name = "getWeather"
  let description = "Retrieve the latest weather information for a city"

  @Generable
  struct Arguments {
    @Guide(description: "The city to fetch the weather for")
    var city: Stringfunc call(arguments: Arguments) async throws -> ToolOutput {
    let places = try await CLGeocoder().geocodeAddressString(arguments.city)
    let weather = try await WeatherService.shared.weather(for: places.first!.location!)
    let temperature = weather.currentWeather.temperature.value
    let content = GeneratedContent(properties: ["temperature": temperature])
    let output = ToolOutput(content)

    return output
  }
}

Toolを利用してモデルから結果を生成する場合、セッションの引数にToolを指定します。

let session = LanguageModelSession (
  tools: [GetWeatherTool()],
  instructions: "Help the user with weather forecasts."
)

カスタム指示

モデルに役割や応答について指示できます。カスタム指示の指定は任意です。指定しない場合は妥当なデフォルトの指示が使用されます。

let session = LanguageModelSession(
instructions: """
  You are a helpful assistant who always \
  responds in rhyme.
"""

カスタム指示の注意

指示とプロンプトの違いを理解する必要があります。指示はデベロッパーが提供するものである一方で、プロンプトはユーザーからも提供できます。プロンプトよりも指示が優先されるため、プロンプトインジェクションには指示を使うなど、用途に合った使い方をしましょう。

マルチターンインタラクション

セッションの respond または steamResponse メソッドを使う場合、会話が記憶されます。また、sessionオブジェクトの transcript プロパティを見ると、過去のやり取りを見ることができます。

複数回実行しないようにする

モデルがレスポンスを作成している間は、sessionオブジェクトの isResponding プロパティが true になります。Button.disabled(session.isResponding) の設定するなど、何度もモデルにレスポンスを要求しないようにする必要があります。

組み込みのユースケースを使用する

モデルを指定する際に、ユースケースを指定することができます。指定するには SystemLanguageModel のイニシャライザで指定します。

let session = LanguageModelSession(
  model: SystemLanguageModel(useCase: .contentTagging)
)

モデルが利用できるかを確認する

モデルが利用できるかを確認するには、SystemLanguageModelの availability プロパティを使用します。

availability プロパティは、availableunavailable のenumです。unavailable の場合はその理由も確認できます。

struct AvailabilityExample: View {
  private let model = SystemLanguageModel.default

  var body: some View {
    switch model.availability {
      case available:
        Text("Model is available").foregroundStyle(.green)
      case unavailable(let reason):
        Text("Model is unavailable").foregroundStyle(.red)
        Text("Reason: \(reason)")
    }
  }
}

開発者体験

Foundation Modelを簡単に試す

Swift Playgroundですぐに試せます。

import FoundationModels
import Playgrounds

#Playground {
  let session = LanguageModelSession()
  let response = try await session.respond(to: "What's a good name for a trip to Japan? Reply only with a title")
}

パフォーマンスのチェック

新しいInstrumentsのアプリのプロファイルテンプレートを使うと、モデルの遅延をプロファイルし、改善に繋げることができる。

Discussion