Foundation Model入門 – Swiftで始めるAIアプリ開発

Swift

Foundation Modelとは

Foundation Models | Apple Developer Documentation
Perform tasks with the on-device model that specializes in language understanding, structured output, and tool calling.

Foundation Modelとは、WWDC25で発表されたフレームワークです。

Apple Intelligence を支えるオンデバイス大規模言語モデル(LLM)にアクセスできます。

この登場によりiOSアプリに、簡単にAI機能を導入できるようになりました。

今回はWWDC25の動画を元に、Foundation Modelの特徴や使い方についてまとめました。

主な特徴

Foundation Modelは、すべての処理がデバイス上で完結します。

そのため軽量で速度が速く、オフラインでも動作します。

またOSに組み込まれているので、アプリサイズを増やすことなく使えます。

さらに Guided Generation という革新的な機能のおかげで、開発者にとってもシンプルで使いやすいツールになっています。

動作環境

  • macOS Tahoe 26.0
  • Xcode 26.0 beta

基本的な使い方

ではさっそくFoundation Modelの使い方について解説していきます。

基本的には LanguageModelSessionrespond(to:) にプロンプトを指定するだけです。

(動作確認にはPlayground macroを使用しています)

Swift
import FoundationModels
import Playgrounds

#Playground {
    do {
        let session = LanguageModelSession()
        let response = try await session.respond(to: "何か面白い話をして")
        print(response)
    } catch {
        print(error)
    }
}

LanguageModelSession

LanguageModelSession | Apple Developer Documentation
An object that represents a session that interacts with a language model.

LanguageModelSessionはモデルと対話するセッションを表すオブジェクトです。

このオブジェクトを通じて、プロンプトを指定することでAIとやりとりできます。プロンプトやAIからのレスポンスの履歴はトランスクリプトに記録されています。

また、instructionsを指定することで、モデルがどのように応答すべきかを定めることができます。

Swift
let session = LanguageModelSession(
    instructions: """
    あなたは親切で丁寧なカスタマーサポートです。
    常に敬語を使い、簡潔に回答してください。
    """
)

Guided Generation

FoundationModelでは、モデルが構造的に正しい出力のみを生成するよう、生成プロセスを制約することができます。

従来のAIは、レスポンスとしてStringが返ってきて、受け取り側で適切な型にパースする必要がありました。しかしAIが必ずしも正しい値を出力してくれる保証はなく、パースエラーになってしまうことも考えられます。

Foundation Modelでは、AIから構造化された型が返ってきて、受け取り側はそれを直接使用することができます。

使い方は簡単で、AIに返して欲しい型に @Generable を付与して、sessionに渡すだけです。

Swift
import FoundationModels
import Playgrounds

@Generable
struct SearchSuggestions {
    @Guide(description: "検索提案のリスト", .count(4))
    var searchTerms: [String]
}

#Playgrounds {
  let session = LanguageModelSession()
  
	let prompt = """
	有名なランドマークを訪問するアプリの
	検索提案リストを生成してください
	"""
	
	let response = try await session.respond(
	    to: prompt,
	    generating: SearchSuggestions.self
	)
	
	print(response.content.searchTerms)
	// 出力例: ["東京タワー", "富士山", "金閣寺", "厳島神社"]
}

@Generable

Generable | Apple Developer Documentation
A type that the model uses when responding to prompts.

@Generable を付与することで、AIに対して「この型で回答して」と指定することができます。

Swift
@Generable
struct Profile {
    var name: String
    var age: Int
}

// AIが必ずProfile型で回答してくれる
let response = try await session.respond(generating: Profile.self)

またプロパティの生成順序は、ソースコードで定義されている順です。なので、あるプロパティが別のプロパティに影響されることを期待する場合は順序はよく考える必要があります。

@Guide

Guide(description:) | Apple Developer Documentation
Allows for influencing the allowed values of properties of a generable type.

@Guide@Generable を付与した構造体のプロパティの説明と生成される値の制御を行うことができます。

適切な説明を与えることで、AIの出力の質を上げることができます。

Swift
@Guide(description: "検索提案のリスト", .count(4))
var searchTerms: [String]

また生成される値の制御を行うことができ、配列なら最大数、Stringなら正規表現などを指定することができます。

以下は制御できる値の一例です。

数値型(Int, Double, Float等)

  • .minimum(value) – 最小値
  • .maximum(value) – 最大値
  • .range(min...max) – 範囲
Swift
  @Guide(description: "商品の価格", .minimum(100))
  let price: Int

  @Guide(description: "税率", .maximum(1))
  let taxRate: Double

  @Guide(description: "在庫数", .range(1...10))
  let stock: Int

配列型

  • .count(n) – 正確にn個
  • .maximumCount(n) – 最大n個
  • .minimumCount(n) – 最小n個
Swift
@Guide(description: "商品", .count(5))
let items: [String]

@Guide(description: "予約済み商品", .maximumCount(5))
let preOrderedItems: Double

文字列型

  • .anyOf([...]) – 選択肢から

  • Regex {...} – 正規表現パターン
Swift
@Generable 
struct Person { 
    @Guide(/(Mr|Mrs)\. \w+/) // 「Mr.」または「Mrs.」に続き、半角スペースと英単語の名前 
    let name: String         // 生成例: "Mrs. Tanaka"
}

ストリーミング機能

ストリーミング機能とは、「AIが文章を完成形で送ってくるのではなく、ひと単語ずつリアルタイムで送ってくる機能」のことです。

AIの完成を待たずにできた部分から表示していくので、ユーザの待ち時間を楽しい体験に変えてくれます。

【従来のAI】デルタストリーミング

デルタストリーミングは、生成された文字だけを送る方式です。

例えばAIが「こんにちは」と生成するとき、「こ」「ん」「に」「ち」「わ」という感じで、生成された順に送ってきます。

JSONや構造化されたデータにしたい場合、受け取り側でパースする必要があります。

しかし、AIが期待する値を返さない可能性や、出力される度にパースする必要があるので、手間がかかります。

【Foundation Model】スナップショットストリーミング

Foundation Modelは、スナップショットストリーミングという方式を採用しています。

これは「AIが生成途中の完全な状態を段階的に送ってくれる方式」です。

受け取り側はパースする必要がなく、受け取った値をそのまま使うことができます。

Swift
@Generable
struct Profile {
    var name: String
    var age: Int
}

送信1: Profile.PartiallyGenerated(name: nil, age: nil)
送信2: Profile.PartiallyGenerated(name: "田中", age: nil)  
送信3: Profile.PartiallyGenerated(name: "田中", age: 25)

 各段階で完全で有効な構造体

スナップショットストリーミング機能を実現するには、streamResponse(to:)を使用します。

streamResponseから返ってくるResponseStreamという型は、AsyncSequenceなので try await で値を受け取ることができます。

Swift
import SwiftUI
import FoundationModels

struct ContentView: View {
    @State private var text = ""
    var body: some View {
        ScrollView {
            Button("生成する") {
                let session = LanguageModelSession()
                let stream = session.streamResponse(to: "何か面白くて、教訓に富んだ話をして")

                Task {
                    for try await partial in stream {
                        text = partial
                    }
                }
            }

            Text(text)
        }
        .padding()
    }
}

PartiallyGenerated

PartiallyGenerated | Apple Developer Documentation
A representation of partially generated content

PartiallyGeneratedは、まだ生成途中のデータを安全に扱うための型で、@Generable マクロによって自動で生成されます。

PartiallyGeneratedで定義されるプロパティはすべてオプショナルになっており、このおかげでスナップショットの機能が実現できます。

Swift
@Generable
struct Profile {
    var name: String      // ←1番目に生成(0.5秒)
    var age: Int          // ←2番目に生成(1.0秒) 
    var hobbies: [String] // ←3番目に生成(1.5秒)
}

// @Generableマクロが自動で作成
// 各プロパティがOptionalで定義される
struct Profile.PartiallyGenerated {
    var name: String?      
    var age: Int?          
    var hobbies: [String]?
}

// ストリーミングの流れ
// 0.0秒: 生成開始
PartiallyGenerated(name: nil, age: nil, hobbies: nil)

// 0.5秒: 名前だけ完成
PartiallyGenerated(name: "田中太郎", age: nil, hobbies: nil)

// 1.0秒: 名前と年齢が完成  
PartiallyGenerated(name: "田中太郎", age: 25, hobbies: nil)

// 1.5秒: 全部完成!
PartiallyGenerated(name: "田中太郎", age: 25, hobbies: ["読書", "映画"])

Tool Calling

Tool Callingとは、AIが自分で判断して、指定した関数を呼び出してくれる機能です。

使うにはToolプロトコルに準拠した構造体が必要です。AIが必要に応じて、Toolのcall関数を呼び出してくれます。

Swift
struct GetNumberTool: Tool {
    let name = "getRandomNumber"
    let description = "1から10の数字を返す"

    @Generable
    struct Arguments {
        // 引数なし(空でもOK)
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        let number = Int.random(in: 1...10)
        return ToolOutput("\(number)")
    }
}

#Playground {
    do {
        let session = LanguageModelSession(
            tools: [GetNumberTool()]
        )
        let response = try await session.respond(to: "数字を1つ教えて")
        print(response.content) // 1から10で返してくれる

    } catch {
        print(error)
    }
}

Tool CallingはAIの知識不足を補えるなどのメリットがあります。

Foundation Modelは全ての処理をデバイスで完結できる反面、リアルタイムな情報の取得ができません。しかし、Tool callingでAPIを使ってリアルタイムの情報を返すことで、本来できなかったレスポンスができるようになります。

Swift
struct WeatherTool: Tool {
    let name = "getWeather"
    let description = "天気を取得"

    @Generable
    struct Arguments {
        let cityName: String
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        // ここでAPI呼び出し
        let weather = await WeatherService.getCurrentWeather()
        return ToolOutput("\(arguments.cityName)\(weather.condition)\(weather.temperature)度")
    }
}

// AIだけだと...
ユーザー: "東京の、今の天気は?"
AI: "申し訳ありませんが、リアルタイムの天気情報は分かりません"

// Tool Callingがあると...
ユーザー: "東京の、今の天気は?" 
AI: 天気ツールを呼び出し  "東京は晴れ、気温22度です"

できること、できないこと

FoundationModelは全ての処理がデバイスで完結する「デバイススケールモデル」として設計されています。

軽量で高速で動くメリットがある反面、知識が限定的であったり、できることが制限されています。

得意なこと

  • テキスト処理・分析
  • コンテンツ生成
  • 構造化データ処理
  • アプリ統合機能

苦手なこと

  • 知識ベースタスク
  • 高度な推論
  • 大規模・長文処理
  • リアルタイム情報

まとめ

今回はWWDC25で発表された、Foundation Modelについて解説しました。

AIをアプリに組み込めるようになれば、アプリの表現の幅がぐっと広がると思います。

iOS26の正式リリースが待ち遠しいですね。

ぜひご自身の手で色々と試してみてください。

ここまでのご閲覧ありがとうございました!

参考にした記事

Foundation Modelフレームワークの紹介 - WWDC25 - ビデオ - Apple Developer
Apple...
Foundation Modelフレームワークの詳細 - WWDC25 - ビデオ - Apple Developer
Foundation...

コメント

タイトルとURLをコピーしました