WWDC Quick Look 💓 By SwiftGGTeam
Foundation Models フレームワークの新機能

Foundation Models フレームワークの新機能

元の動画を見る

ハイライト

Apple は Foundation Models フレームワークをオープンソース化し、マルチモーダル理解、Private Cloud Compute の大規模モデル接続、Agent 体験を構築する Dynamic Profile、さらに fm CLI と Python SDK を追加しました。これにより開発者はデバイス上でもクラウド上でも大規模モデル機能を呼び出せます。

主要内容

閉じたものから開いたものへ:フレームワークが全面的にオープンソース化

昨年 Apple が Foundation Models フレームワークを発表したとき、開発者は iOS/macOS App 内でシステム内蔵の on-device モデルを呼び出すことしかできませんでした。機能は限られ、拡張性にも制約がありました。

今年 Apple はフレームワークの中核コードを完全にオープンソース化し、Foundation Models Framework Utilities パッケージも公開しました。このパッケージは OS バージョンの間でも実験的機能を継続的に更新できます。つまり Swift 開発者は Linux サーバー上でもこのコードを実行でき、Apple プラットフォームだけに縛られなくなります。

モデル選択が「単一」から「任意」へ

これまでは 1 つの LanguageModelSession がシステム内蔵の on-device モデルにしか結び付けられませんでした。推論能力は限られ、コンテキストウィンドウは数千 token 程度で、複雑なタスクではすぐに足りなくなりました。

今年 Apple は LanguageModel プロトコルを導入し、ローカルでもリモートでも任意のモデルをフレームワークに接続できるようにしました。システムには 3 種類の実装が用意されています。

  • SystemLanguageModel:デバイス上モデル。8192 token のコンテキストを持ち、Vision 機能が追加された
  • PrivateCloudComputeLanguageModel:クラウドモデル。32000 token のコンテキストと推論機能をサポートする
  • CoreAILanguageModel / MLXLanguageModel:Apple Neural Engine または Mac GPU 上でオープンソースモデルを実行する

サードパーティモデルもサポートされます。Anthropic と Google はどちらも Swift Package を公開しています。パッケージを import してモデルを初期化し、session に渡せば、下流のコードはそのまま動きます。

マルチモーダル:画像を直接 Prompt に入れる

デバイス上モデルは画像を理解できるようになりました。前処理も固定サイズへの切り抜きも不要です。UIImageNSImageCGImage、Core Image 型、CVPixelBuffer、ファイル URL をそのまま prompt に入れられます。

let response = try await session.respond {
    "これは何の動物ですか?"
    Attachment(UIImage(...))
}

モデルは任意のサイズとアスペクト比の画像に対応します。画像が大きいほど消費 token が増え、遅延も高くなります。開発者は用途に応じて解像度を選ぶ必要があります。

クラウドモデルをゼロ設定で接続する

Private Cloud Compute(PCC)モデルは Apple Intelligence の背後にあるものと同じ種類の大規模モデルです。32K コンテキスト、組み込み推論機能、API Key 不要、アカウント認証不要です。

開発者が変更するのは 1 行だけです。

let model = PrivateCloudComputeLanguageModel()
let session = LanguageModelSession(model: model)

let response = try await session.respond(
    to: "はさみを使わない工作をおすすめしてください。",
    contextOptions: ContextOptions(reasoningLevel: .light)
)

reasoningLevel はモデルの思考の深さを制御します。.light は応答が速く、.deep は品質が高い一方でより多くの計算資源を使います。

PCC は初年度ダウンロード数が 200 万未満の開発者には無料です。ユーザーには 1 日あたりの固定利用枠があり、iCloud+ 登録者はより多くの枠を得られます。watchOS 27 も PCC に対応し、手首の上から大規模モデルを使えます。

Agent 体験:Dynamic Profile がコンテキストを管理する

Agent App は通常、さまざまなタスクを切り替える必要があります。画像解析ではある指示とツールセットを使い、ブレインストーミングでは別のものを使います。これまでは複数の session を手動で作り、会話履歴を手動で移行する必要があり、コードは長く、間違いも起きやすくなっていました。

Dynamic Profile は宣言的 API でこの問題を解きます。struct が DynamicProfile プロトコルに準拠し、App の状態に応じて異なる Profile を返します。

struct CraftProfile: LanguageModelSession.DynamicProfile {
    let states: CraftProjectStates

    var body: some DynamicProfile {
        switch states.mode {
        case .craftAnalysis:
            Profile {
                Instructions { /* 解析用の指示 */ }
                RecordImageAnalysisTool()
                SwitchModeTool(states: states)
            }
        case .brainstorm:
            Profile {
                Instructions { /* ブレインストーミング用の指示 */ }
                BrainstormRecordTool()
            }
            .model(states.privateCloudCompute)
            .reasoningLevel(.deep)
        }
    }
}

let session = LanguageModelSession(profile: CraftProfile())

Profile が切り替わるとき、フレームワークは会話履歴を自動的に保持します。開発者は業務ロジックに集中すればよいだけです。解析段階ではデバイス上モデルで高速に応答し、ブレインストーミング段階では PCC の深い推論に自動で切り替える、といった流れが途切れずに動きます。

システムツール:Vision と Spotlight の組み込み統合

フレームワークには 2 つの Vision ツールと 1 つの検索ツールが追加されました。

  • BarcodeReaderTool:バーコード情報を読み取る
  • OCRTool:画像から構造化テキストを抽出する
  • Spotlight 検索ツール:Core Spotlight インデックスに基づくローカル RAG(検索拡張生成)を実現する

これらのツールは追加設定なしで使えます。session の tools 配列に直接追加するだけです。

Token 使用量が透明になる

サードパーティモデルを token 課金で使う場合、開発者は消費量を正確に把握する必要があります。Session と response には新しく usage 属性が追加されました。

print(response.usage.input.totalTokenCount)
print(response.usage.input.cachedTokenCount)
print(response.usage.output.totalTokenCount)
print(response.usage.output.reasoningTokenCount)

入力 token、キャッシュヒットした token、出力 token、推論 token の数を正確に追跡できます。

Mac 開発者ツール:fm CLI と Python SDK

macOS 27 では fm コマンドラインツールが導入され、Terminal から直接 on-device モデルと PCC を呼び出せます。

fm chat "折り紙の谷折りとは何ですか?"
fm generate --image IMG_1234.jpg "説明的なファイル名を提案してください"

shell スクリプトに組み込めば、文書要約、情報抽出、コンテンツ生成に使えます。

Python 開発者向けには公式 SDK もあります。

import apple_fm_sdk as fm

model = fm.SystemLanguageModel()
is_available, reason = model.is_available()

if is_available:
    session = fm.LanguageModelSession(model=model)
    response = await session.respond(prompt="こんにちは!")
    print(response)

Python SDK は Swift フレームワークの中核機能をカバーし、prompt から構造化応答まで数行で扱えます。

詳細

デバイス上モデルのコンテキストを問い合わせる

02:46

iOS 26.4 から、開発者はモデルのコンテキストサイズと token 数を問い合わせ、ハードウェア能力に応じて動的に調整できます。

let model = SystemLanguageModel()
print(model.contextSize)
// 8192

let count = try await model.tokenCount(for: "origami を表す日本語の文字は何ですか?")
print(count)

要点:

  • contextSize は現在のモデルの最大コンテキスト長を token 単位で返す
  • tokenCount(for:) は指定テキストの token 数を計算し、リクエストがコンテキスト制限を超えるか事前に見積もれる
  • デバイスごとの on-device モデルは異なる context size を持つ可能性があるため、ハードコードではなく実行時に問い合わせるのが望ましい

画像添付の型

03:52

let response = try await session.respond {
    "これは何の動物ですか?"
    Attachment(UIImage(...))
}

要点:

  • Attachment()UIImageNSImageCGImage、Core Image 型、CVPixelBuffer、ファイル URL をサポートする
  • 画像サイズとアスペクト比に制限はなく、フレームワークが自動処理する
  • 大きな画像はより多くの token を消費するため、用途に合った解像度を選ぶ

Token 使用量を確認する

08:45

let response = try await session.respond(
    to: "はさみを使わない工作をおすすめしてください。",
    contextOptions: ContextOptions(reasoningLevel: .light)
)

print(response.usage.input.totalTokenCount)
print(response.usage.input.cachedTokenCount)
print(response.usage.output.totalTokenCount)
print(response.usage.output.reasoningTokenCount)

要点:

  • usage.input.totalTokenCount:今回のリクエストで消費した入力 token の総数
  • usage.input.cachedTokenCount:キャッシュから読まれた入力 token 数。キャッシュヒットはコスト低減につながる
  • usage.output.totalTokenCount:モデルが生成した出力 token の総数
  • usage.output.reasoningTokenCount:推論過程に使われた出力 token 数。reasoning モデルでのみ利用される

Dynamic Profile:モード切り替えと会話履歴の保持

11:55

@Observable
final class AppStates {
    var mode: Mode
}

let appStates: AppStates
var session: LanguageModelSession?

func updateSession() {
    let originalTranscript = session?.transcript.dropFirstInstructions() ?? Transcript()

    switch appStates.mode {
    case .craftAnalysis:
        session = LanguageModelSession(
            tools: [
                RecordImageAnalysisTool(),
                SwitchModeTool(states: appStates)
            ],
            instructions: "ユーザーの手芸プロジェクトを分析してください...",
            transcript: originalTranscript
        )
    case .brainstorm:
        session = LanguageModelSession(
            tools: [
                RecordBrainstormRecordTool(),
            ],
            instructions: "いくつかアイデアをブレインストーミングしてください...",
            transcript: originalTranscript
        )
    }
}

struct SwitchModeTool: Tool {
    let description = "別のモードに切り替えます。"
    let states: AppStates

    @Generable
    struct Arguments {
        let mode: Mode
    }

    func call(arguments: Arguments) async throws -> some PromptRepresentable {
        appStates.mode = arguments.mode
        return "\(arguments.mode) に正常に切り替えました。"
    }
}

withObservationTracking {
    appStates.mode
} onChange: {
    updateSession()
}

要点:

  • transcript.dropFirstInstructions() は会話履歴を保持しつつ古い指示を捨て、指示の蓄積を避ける
  • SwitchModeTool により、モデルは自発的にツールを呼び出して App モードを切り替えられる
  • @Generable を付けた引数構造体により、フレームワークはパラメータ解析ロジックを自動生成する
  • withObservationTracking はモード変化を監視し、session を自動再構築する

宣言的な Dynamic Profile

12:42

struct CraftProfile: LanguageModelSession.DynamicProfile {
    var body: some DynamicProfile {
        Profile {
            Instructions {
                """
                あなたは手芸に詳しい専門アシスタントです。 \
                recordImageAnalysis ツールを使って、         \
                手芸プロジェクト画像の解析を記録してください。
                """
            }
            RecordImageAnalysisTool()
        }
    }
}

let session = LanguageModelSession(profile: CraftProfile())

要点:

  • DynamicProfile プロトコルは some DynamicProfile を返す body 属性の実装を要求する
  • Profile ビルダー内には Instructions と任意の Tool を配置できる
  • Session 初期化時に profile インスタンスを渡すと、フレームワークがコンテキストを自動管理する

モデル切り替えを含む Dynamic Profile

14:36

struct CraftProfile: LanguageModelSession.DynamicProfile {
    let states: CraftProjectStates

    var body: some DynamicProfile {
        switch states.mode {
        case .craftAnalysis:
            Profile {
                Instructions { /* ... */ }
                RecordImageAnalysisTool()
                SwitchModeTool(states: states)
            }
        case .brainstorm:
            Profile {
                Instructions { /* ... */ }
                BrainstormRecordTool()
            }
            .model(states.privateCloudCompute)
            .reasoningLevel(.deep)
        }
    }
}

要点:

  • .model() modifier は基盤となるモデルを切り替える。たとえばデバイス上モデルから PCC へ切り替える
  • .reasoningLevel(.deep) はモデルに深い推論を求め、創造的生成など複雑なタスクに向く
  • 条件分岐が現在有効な Profile を決定し、切り替えロジックはフレームワークが処理する
  • 会話履歴は切り替え時に自動保持される

Python SDK の基本的な使い方

18:29

import apple_fm_sdk as fm

model = fm.SystemLanguageModel()

is_available, reason = model.is_available()

if is_available:
    session = fm.LanguageModelSession(model=model)
    response = await session.respond(prompt="こんにちは!")
    print(response)

要点:

  • apple_fm_sdk は Python 側のパッケージ名
  • is_available() は現在のデバイスでモデルを実行できるか確認する
  • LanguageModelSession の API は Swift 側と一貫している
  • 非同期呼び出しをサポートし、Python の asyncio エコシステムと自然に連携する

核心的な示唆

1. 画像を「理解する」日記 App を作る

  • 作るもの:ユーザーが写真を撮ったあと、App が画像内の物体、場面、文字を自動認識し、構造化タグとして日記に保存する。
  • 作る価値SystemLanguageModel に Vision 機能が追加され、AttachmentUIImage を直接受け取れる。OCRToolBarcodeReaderTool は文字とバーコード情報を抽出する。すべてデバイス上で動作し、クラウドにアップロードしない。
  • 始め方LanguageModelSession を作り、respond クロージャでテキスト prompt と Attachment(UIImage) を同時に渡す。OCRToolBarcodeReaderTool を組み合わせて抽出結果を処理する。

2. 「検索できる」個人知識アシスタントを作る

  • 作るもの:ユーザーが自然言語で質問すると、アシスタントがローカル文書、メール、ノートを検索してから回答を生成する。
  • 作る価値:フレームワークには Spotlight 検索ツールが組み込まれており、Core Spotlight インデックスを直接使ってローカル RAG を実装できる。ベクトルデータベースも埋め込みモデルも不要で、数行のコードでモデルにユーザーのローカルファイルを「覚えさせる」ことができる。
  • 始め方:session の tools 配列に Spotlight 検索ツールを追加する。ユーザーが質問すると、モデルは自動的にそれを呼び出して関連内容を検索し、結果をコンテキストとして回答を生成する。

3. 「自動でアップグレードする」創作支援ライティングアシスタントを作る

  • 作るもの:アウトライン段階ではデバイス上モデルで素早く応答し、本文を展開する段階では PCC の深い推論へ自動切り替えする。
  • 作る価値:Dynamic Profile により、モデル切り替えは宣言的な設定になる。アウトライン段階は SystemLanguageModel で低遅延を確保し、展開段階は .model(PrivateCloudComputeLanguageModel()).reasoningLevel(.deep) で品質を高める。会話履歴は自動保持される。
  • 始め方DynamicProfile に準拠する struct を定義し、ライティング段階に応じて switch で異なる Profile を返す。展開ブランチには .model().reasoningLevel() modifier を追加する。

4. fm CLI でファイルを一括処理する

  • 作るもの:shell スクリプトで画像の一括リネーム、PDF 要約、文書の重要情報抽出を行う。
  • 作る価値:macOS 27 には fm コマンドが標準搭載され、Terminal から on-device モデルと PCC を直接呼び出せる。Swift コードも API Key 設定も不要。
  • 始め方:macOS 27 をインストールしたあと、Terminal で fm chat "あなたの質問" または fm generate --image 画像.jpg "指示" を実行し、それを shell スクリプトに組み込んで一括処理する。

5. クロスプラットフォームな Swift サーバー AI App を作る

  • 作るもの:Swift でバックエンド AI サービスを書き、iOS App と Web フロントエンドの両方に提供する。
  • 作る価値:Foundation Models フレームワークはオープンソース化後、Linux をサポートする。CoreAILanguageModelMLXLanguageModel はサーバー上でオープンソースモデルを動かせる。統一された LanguageModel プロトコルにより、クライアントとサーバーで同じインターフェースを共有できる。
  • 始め方:Linux サーバーにオープンソースの Foundation Models フレームワークを導入し、CoreAILanguageModel でモデルをロードして HTTP API を公開する。iOS 側ではサードパーティモデル package を同じプロトコルに接続し、インターフェースを揃える。

関連セッション

コメント

GitHub Issues · utterances