mcpField
A
axiom-foundation-models-ref

axiom-foundation-models-ref

github.com/charleswiltgen開発1.2k185 回インストール今日更新
リポジトリ

axiom-foundation-models-ref について

Apple の Foundation Models フレームワークを使う Swift 開発者向けの API リファレンスです。セッション、構造化生成、ストリーミング、ツール連携と、モデルのデバイス上での特性を説明します。

主な機能

  1. 01LanguageModelSession による複数ターン対話
  2. 02@Generable による構造化出力
  3. 03ストリーミング生成と部分結果
  4. 04ツールプロトコルとセッション連携
  5. 05Foundation Models の機能概要

活用シーン

  1. 01デバイス上のテキスト生成の実装
  2. 02モデル出力の Swift 型への変換
  3. 03モデルからカスタムツールを呼び出す機能の実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-foundation-models-ref

インストール後、Claude Code で/axiom-foundation-models-refを入力して読み込まれたか確認します。

詳細

Foundation Models Framework — 完全 API リファレンス

概要

Foundation Models フレームワークは、Swift API を使用して Apple のデバイス上で動作する大規模言語モデル(30 億パラメーター、2 ビット量子化)にアクセスできます。このリファレンスでは、すべての API、WWDC 2025 のコード例すべて、および包括的な実装パターンを解説します。

モデル仕様

30 億パラメーターのモデル、2 ビット量子化、コンテキスト長は 4096 トークン(入力と出力の合計)です。デバイス上での要約、抽出、分類、生成に最適化されています。世界知識、複雑な推論、数学、翻訳には適していません。すべてデバイス上で動作するため、ネットワーク通信も費用もなく、データがデバイスの外に出ることもありません。


このリファレンスを使う場面

以下の場合にこのリファレンスを使用してください。

  • Foundation Models の機能を実装する場合
  • API の機能を理解する場合
  • 特定のコード例を探す場合
  • Foundation Models を使ったアーキテクチャを計画する場合
  • プロトタイプから本番環境へ移行する場合
  • 実装の問題をデバッグする場合

関連するスキル:

  • axiom-foundation-models — アンチパターン、プレッシャーシナリオ、判断ツリーを含む規律スキル
  • axiom-foundation-models-diag — 問題のトラブルシューティング用診断スキル

LanguageModelSession

概要

LanguageModelSession は、モデルと対話するための中核クラスです。会話履歴(トランスクリプト)を保持し、複数ターンのやり取りを処理して、モデルの状態を管理します。

セッションの作成

基本的な作成方法:

import FoundationModels

let session = LanguageModelSession()

カスタム指示を指定する場合:

let session = LanguageModelSession(instructions: """
    You are a friendly barista in a pixel art coffee shop.
    Respond to the player's question concisely.
    """
)
WWDC 301:1:05 より

ツールを使用する場合:

let session = LanguageModelSession(
    tools: [GetWeatherTool()],
    instructions: "Help user with weather forecasts."
)
WWDC 286:15:03 より

特定のモデル/ユースケースを指定する場合:

let session = LanguageModelSession(
    model: SystemLanguageModel(useCase: .contentTagging)
)
WWDC 286:18:39 より
指示とプロンプト

指示:

  • 開発者が指定します
  • モデルの役割、スタイル、制約を定義します
  • ほとんどの場合、静的です
  • トランスクリプトの最初のエントリーになります
  • モデルは、プロンプトよりも指示に従うようにトレーニングされています(セキュリティ機能)

プロンプト:

  • ユーザー(または動的なアプリの状態)が指定します
  • 生成に対する具体的なリクエストです
  • 動的な入力です
  • respond(to:) を呼び出すたびに、プロンプトがトランスクリプトに追加されます

セキュリティ上の考慮事項:

  • 信頼できないユーザー入力を指示に絶対に埋め込まないでください
  • ユーザー入力はプロンプトのみに含めてください
  • これにより、プロンプトインジェクション攻撃を防止できます
respond(to:) メソッド

基本的なテキスト生成:

func respond(userInput: String) async throws -> String {
    let session = LanguageModelSession(instructions: """
        You are a friendly barista in a world full of pixels.
        Respond to the player's question.
        """
    )
    let response = try await session.respond(to: userInput)
    return response.content
}
WWDC 301:1:05 より

戻り値の型:.content プロパティを持つ Response<String>

respond(to:generating:) メソッド

@Generable による構造化出力:

@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.self
)

print(response.content) // SearchSuggestions instance
WWDC 286:5:51 より

戻り値の型:.content プロパティを持つ Response<SearchSuggestions>

生成オプション

sampling:、temperature:、includeSchemaInPrompt: を含む GenerationOptions については、サンプリングと生成オプションを参照してください。


複数ターンのやり取り

コンテキストの保持
let session = LanguageModelSession()

// First turn
let firstHaiku = try await session.respond(to: "Write a haiku about fishing")
print(firstHaiku.content)
// Silent waters gleam,
// Casting lines in morning mist—
// Hope in every cast.

// Second turn - model remembers context
let secondHaiku = try await session.respond(to: "Do another one about golf")
print(secondHaiku.content)
// Silent morning dew,
// Caddies guide with gentle words—
// Paths of patience tread.

print(session.transcript) // Shows full history
WWDC 286:17:46 より

仕組み:

  • respond() を呼び出すたびに、エントリーがトランスクリプトに追加されます
  • モデルはコンテキストとしてトランスクリプト全体を使用します
  • これにより、会話形式のやり取りが可能になります
Transcript プロパティ
let transcript = session.transcript

for entry in transcript.entries {
    print("Entry: \(entry.content)")
}

用途:

  • 生成の問題をデバッグする
  • UI に会話履歴を表示する
  • チャットログをエクスポートする
  • コンテキスト管理のために内容を要約する

isResponding プロパティ

同時リクエストを防ぐため、session.isResponding に応じて UI の動作を制御します。

Button("Go!") {
    Task { haiku = try await session.respond(to: prompt).content }
}
.disabled(session.isResponding)
WWDC 286:18:22 より

@Generable マクロ

概要

@Generable を使用すると、Swift の型を使ってモデルから構造化出力を得られます。このマクロはコンパイル時にスキーマを生成し、制約付きデコードによって構造の正しさを保証します。

基本的な使い方

構造体での使用:

@Generable
struct Person {
    let name: String
    let age: Int
}

let response = try await session.respond(
    to: "Generate a person",
    generating: Person.self
)

let person = response.content // Type-safe Person instance
WWDC 301:8:14 より

列挙型での使用:

@Generable
struct NPC {
    let name: String
    let encounter: Encounter

    @Generable
    enum Encounter {
        case orderCoffee(String)
        case wantToTalkToManager(complaint: String)
    }
}
WWDC 301:10:49 より
対応する型

プリミティブ型:

  • String
  • Int、Float、Double、Decimal
  • Bool

コレクション:

  • [ElementType](配列)

合成型:

@Generable
struct Itinerary {
    var destination: String
    var days: Int
    var budget: Float
    var rating: Double
    var requiresVisa: Bool
    var activities: [String]
    var emergencyContact: Person
    var relatedItineraries: [Itinerary] // Recursive!
}
WWDC 286:6:18 より
@Guide の制約

@Guide は生成されるプロパティを制約します。description:(自然言語)、.range()(数値の範囲)、.count() / .maximumCount()(配列の長さ)、および Regex(パターンマッチング)をサポートします。

@Generable
struct NPC {
    @Guide(description: "A full name")
    let name: String

    @Guide(.range(1...10))
    let level: Int

    @Guide(.count(3))
    let attributes: [String]
}
WWDC 301:11:20 より
制約付きデコード

仕組み:

  1. @Generable マクロがコンパイル時にスキーマを生成します
  2. スキーマが有効なトークンシーケンスを定義します
  3. 生成中、モデルは次のトークンの確率分布を作成します
  4. フレームワークがスキーマに基づいて無効なトークンをマスクします
  5. モデルはスキーマに従って有効なトークンのみを選択できます
  6. 構造的な正しさが保証されます。つまり、幻覚によるキーや無効な JSON は生成されません

WWDC 286 より:「制約付きデコードにより、構造上の誤りを防止します。モデルが無効なフィールド名や誤った型を生成できないようにします。」

メリット:

  • パースコードが不要です
  • 実行時のパースエラーが発生しません
  • 型安全な Swift オブジェクトを使用できます
  • コンパイル時の安全性が確保されます(構造体への変更はコンパイラーが検出します)
プロパティの宣言順序

プロパティは宣言された順序で生成されます:

@Generable
struct Itinerary {
    var name: String        // Generated FIRST
    var days: [DayPlan]     // Generated SECOND
    var summary: String     // Generated LAST
}

重要な理由:

  • 後のプロパティから前のプロパティを参照できます
  • モデルの品質が向上します。コンテンツの後に要約を配置できます
  • ストリーミングの UX が向上します。重要なプロパティを先に配置できます
WWDC 286:11:00 より

ストリーミング

概要

Foundation Models は差分ストリーミングではなく、スナップショットストリーミングを使用します。生の差分ではなく、フレームワークはオプショナルなプロパティが段階的に埋まっていく PartiallyGenerated 型をストリーミングします。

PartiallyGenerated 型

@Generable マクロは、ネストされた PartiallyGenerated 型を自動的に作成します:

@Generable
struct Itinerary {
    var name: String
    var days: [DayPlan]
}

// Compiler generates:
extension Itinerary {
    struct PartiallyGenerated {
        var name: String?        // All properties optional!
        var days: [DayPlan]?
    }
}
WWDC 286:9:20 より
streamResponse メソッド
@Generable
struct Itinerary {
    var name: String
    var days: [Day]
}

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

for try await partial in stream {
    print(partial) // Incrementally updated Itinerary.PartiallyGenerated
}
WWDC 286:9:40 より

戻り値の型:AsyncSequence<Itinerary.PartiallyGenerated>

SwiftUI との統合
struct ItineraryView: View {
    let session: LanguageModelSession
    let dayCount: Int
    let landmarkName: String

    @State
    private var itinerary: Itinerary.PartiallyGenerated?

    var body: some View {
        VStack {
            if let name = itinerary?.name {
                Text(name).font(.title)
            }

            if let days = itinerary?.days {
                ForEach(days, id: \.self) { day in
                    DayView(day: day)
                }
            }

            Button("Start") {
                Task {
                    do {
                        let prompt = """
                            Generate a \(dayCount) itinerary \
                            to \(landmarkName).
                            """

                        let stream = session.streamResponse(
                            to: prompt,
                            generating: Itinerary.self
                        )

                        for try await partial in stream {
                            self.itinerary = partial
                        }
                    } catch {
                        print(error)
                    }
                }
            }
        }
    }
}
WWDC 286:10:05 より
ベストプラクティス

1. SwiftUI アニメーションを使用する:

if let name = itinerary?.name {
    Text(name)
        .transition(.opacity)
}

2. 配列のビュー ID:

// ✅ GOOD - Stable identity
ForEach(days, id: \.id) { day in
    DayView(day: day)
}

// ❌ BAD - Identity changes
ForEach(days.indices, id: \.self) { index in
    DayView(day: days[index])
}

3. プロパティ順序の最適化:

// ✅ GOOD - Title first for streaming
@Generable
struct Article {
    var title: String      // Shows immediately
    var summary: String    // Shows second
    var fullText: String   // Shows last
}
WWDC 286:11:00 より

ツールプロトコル

概要

ツールを使うと、モデルはカスタムコードを自律的に実行して、外部データの取得やアクションの実行ができます。ツールは MapKit、WeatherKit、Contacts、EventKit、または任意のカスタム API と統合できます。

プロトコルの定義
protocol Tool {
    var name: String { get }
    var description: String { get }

    associatedtype Arguments: Generable

    func call(arguments: Arguments) async throws -> ToolOutput
}
例:GetWeatherTool
import FoundationModels
import WeatherKit
import CoreLocation

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: String
    }

    func 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)

        // Or if your tool's output is natural language:
        // let output = ToolOutput("\(arguments.city)'s temperature is \(temperature) degrees.")

        return output
    }
}
WWDC 286:13:42 より
セッションへのツールの追加
let session = LanguageModelSession(
    tools: [GetWeatherTool()],
    instructions: "Help the user with weather forecasts."
)

let response = try await session.respond(
    to: "What is the temperature in Cupertino?"
)

print(response.content)
// It's 71˚F in Cupertino!
WWDC 286:15:03 より

仕組み:

  1. ツールを指定してセッションを初期化します
  2. ユーザーのプロンプト:「東京の天気は?」
  3. モデルがプロンプトを分析し、天気データが必要だと判断します
  4. モデルがツール呼び出しを生成します:getWeather(city: "Tokyo")
  5. フレームワークが call() メソッドを呼び出します
  6. コードが API から実際のデータを取得します
  7. ツールの出力がトランスクリプトに挿入されます
  8. モデルがツールの出力を使って最終的な応答を生成します

WWDC 301 より:「モデルはツールを呼び出すタイミングと回数を自律的に判断します。1 つのリクエストで複数のツールを、並列で呼び出すこともできます。」

ステートフルなツール

ツール呼び出し間で状態を維持するには、struct ではなく class を使用します。ツールのインスタンスはセッションの存続期間中保持されるため、以前に返した結果を記録するようなパターンが可能になります:

class FindContactTool: Tool {
    let name = "findContact"
    let description = "Finds a contact from a specified age generation."
    var pickedContacts = Set<String>()

    @Generable
    struct Arguments {
        let generation: Generation
        @Generable
        enum Generation { case babyBoomers, genX, millennial, genZ }
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        // Fetch, filter out already-picked, return new contact
        pickedContacts.insert(pickedContact.givenName)
        return ToolOutput(pickedContact.givenName)
    }
}
WWDC 301:18:47、301:21:55 より
ToolOutput

2 つの形式があります:

  1. 自然言語(String):
return ToolOutput("Temperature is 71°F")
  1. 構造化形式(GeneratedContent):
let content = GeneratedContent(properties: ["temperature": 71])
return ToolOutput(content)
ツールの命名に関するベストプラクティス

推奨事項:

  • 短く読みやすい名前:getWeather、findContact
  • 動詞を使う:get、find、fetch、create
  • 説明は 1 文にします
  • 説明は簡潔にします(プロンプトに含まれるため)

避けること:

  • 略語:gtWthr
  • 説明に実装の詳細を含めること
  • 長い説明(トークン数が増加します)

WWDC 301 より:「ツール名と説明はそのままプロンプトに含まれます。文字列が長いほどトークン数が増え、レイテンシーが高くなります。」

複数のツール
let session = LanguageModelSession(
    tools: [
        GetWeatherTool(),
        FindRestaurantTool(),
        FindHotelTool()
    ],
    instructions: "Plan travel itineraries."
)

// Model autonomously decides which tools to call and when
ツール呼び出しの動作

重要な事実:

  • 1 回のリクエストで、ツールは複数回呼び出される場合があります
  • 複数のツールを並列で呼び出すことができます
  • 呼び出すタイミングはモデルが決定します(呼び出しが保証されるわけではありません)
  • @Generable により、引数の有効性が保証されます

WWDC 301 より:「ツールが並列で呼び出される場合、呼び出しメソッドが同時に実行されることがあります。データにアクセスする際は、この点に注意してください。」


動的スキーマ

概要

DynamicGenerationSchema を使うと、コンパイル時ではなく実行時にスキーマを作成できます。ユーザー定義の構造、レベル作成ツール、動的フォームに便利です。

動的スキーマの作成と使用

DynamicGenerationSchema.Property でプロパティを作成し、それらを組み合わせてスキーマを構成した後、GenerationSchema で検証します。

// Build schema at runtime
let questionProp = DynamicGenerationSchema.Property(
    name: "question", schema: DynamicGenerationSchema(type: String.self)
)
let answersProp = DynamicGenerationSchema.Property(
    name: "answers", schema: DynamicGenerationSchema(
        arrayOf: DynamicGenerationSchema(referenceTo: "Answer")
    )
)

let riddleSchema = DynamicGenerationSchema(name: "Riddle", properties: [questionProp, answersProp])
let answerSchema = DynamicGenerationSchema(name: "Answer", properties: [/* text, isCorrect */])

// Validate and use
let schema = try GenerationSchema(root: riddleSchema, dependencies: [answerSchema])
let response = try await session.respond(to: "Generate a riddle", schema: schema)

let question = try response.content.value(String.self, forProperty: "question")
WWDC 301 より:14:50、301:15:10
動的な @Generable と静的な @Generable

@Generable を使う場合:

  • 構造がコンパイル時にわかっている
  • 型安全性を求める
  • 自動解析を求める

動的スキーマを使う場合:

  • 構造が実行時になって初めてわかる
  • ユーザー定義のスキーマを使う
  • 最大限の柔軟性を求める

WWDC 301 より:「コンパイル時の @Generable は型安全性を提供し、動的スキーマは実行時の柔軟性を提供します。どちらも同じ制約付きデコードの保証を利用します。」


サンプリングと生成オプション

貪欲法(決定論的) — テストやデモで使用します。同じモデルバージョン内でのみ決定論的です。

let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(sampling: .greedy)
)

Temperature — ばらつきを制御します。0.1-0.5 は焦点を絞り、1.0 はデフォルト、1.5-2.0 は創造的な出力になります。

let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 0.5)
)
WWDC 301 より:6:14

組み込みのユースケース

コンテンツタグ付けアダプター

次の用途に特化したアダプター:

  • タグの生成
  • エンティティの抽出
  • トピックの検出
@Generable
struct Result {
    let topics: [String]
}

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

let response = try await session.respond(
    to: articleText,
    generating: Result.self
)
WWDC 286 より:19:19
カスタムユースケース

カスタム指示を使う場合:

@Generable
struct Top3ActionEmotionResult {
    @Guide(.maximumCount(3))
    let actions: [String]
    @Guide(.maximumCount(3))
    let emotions: [String]
}

let session = LanguageModelSession(
    model: SystemLanguageModel(useCase: .contentTagging),
    instructions: "Tag the 3 most important actions and emotions in the given input text."
)

let response = try await session.respond(
    to: text,
    generating: Top3ActionEmotionResult.self
)
WWDC 286 より:19:35

エラー処理

GenerationError の種類

LanguageModelSession.GenerationError のケースをキャッチします。

  • .exceededContextWindowSize — コンテキスト制限(4096 トークン)を超過しました。トランスクリプトを要約するか、新しいセッションを作成してください。
  • .guardrailViolation — コンテンツポリシーに抵触しました。適切なメッセージを表示してください。
  • .unsupportedLanguageOrLocale — 対応していない言語です。supportedLanguages を確認してください。
WWDC 301 より:3:37、301:7:06
コンテキストウィンドウの管理
戦略 1:新しいセッション
var session = LanguageModelSession()

do {
    let response = try await session.respond(to: prompt)
    print(response.content)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // New session, no history
    session = LanguageModelSession()
}
WWDC 301 より:3:37
戦略 2:要約したセッション
do {
    let response = try await session.respond(to: prompt)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // New session with some history
    session = newSession(previousSession: session)
}

private func newSession(previousSession: LanguageModelSession) -> LanguageModelSession {
    let allEntries = previousSession.transcript.entries
    var condensedEntries = [Transcript.Entry]()

    if let firstEntry = allEntries.first {
        condensedEntries.append(firstEntry) // Instructions

        if allEntries.count > 1, let lastEntry = allEntries.last {
            condensedEntries.append(lastEntry) // Recent context
        }
    }

    let condensedTranscript = Transcript(entries: condensedEntries)
    // Note: transcript includes instructions
    return LanguageModelSession(transcript: condensedTranscript)
}
WWDC 301 より:3:55
フォールバックアーキテクチャ

Foundation Models が利用できない場合(古いデバイス、ユーザーによるオプトアウト、非対応の地域)でも、適切に機能を縮退させます。

func summarize(_ text: String) async throws -> String {
    let model = SystemLanguageModel.default
    switch model.availability {
    case .available:
        let session = LanguageModelSession()
        let response = try await session.respond(to: "Summarize: \(text)")
        return response.content
    case .unavailable:
        // Fallback: truncate with ellipsis, or call server API
        return String(text.prefix(200)) + "..."
    }
}

アーキテクチャパターン:Foundation Models をプロトコルの背後に配置すると、実装を切り替えられます。

protocol TextSummarizer {
    func summarize(_ text: String) async throws -> String
}

struct OnDeviceSummarizer: TextSummarizer { /* Foundation Models */ }
struct ServerSummarizer: TextSummarizer { /* Server API fallback */ }
struct TruncationSummarizer: TextSummarizer { /* Simple truncation */ }
ネストした @Generable のトラブルシューティング

ネストした @Generable 型は、それぞれ独立して @Generable に準拠する必要があります。

// ✅ Both types marked @Generable
@Generable struct Itinerary {
    var days: [DayPlan]
}

@Generable struct DayPlan {
    var activities: [String]
}

// ❌ Will fail — nested type not @Generable
@Generable struct Itinerary {
    var days: [DayPlan]  // DayPlan must also be @Generable
}
struct DayPlan { var activities: [String] }

よくある問題:非 Generable 型の配列はコンパイルできますが、実行時に失敗します。型グラフ内のすべての型を確認してください。


利用条件

利用可能かどうかの確認
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)")
        }
    }
}
WWDC 286 より:19:56
対応言語
let supportedLanguages = SystemLanguageModel.default.supportedLanguages
guard supportedLanguages.contains(Locale.current.language) else {
    // Show message
    return
}
WWDC 301 より:7:06
要件

デバイス要件:

  • Apple Intelligence 対応デバイス
  • iPhone 15 Pro 以降
  • M1 以降のチップを搭載した iPad
  • Apple シリコン搭載の Mac

地域要件:

  • 対応地域(Apple Intelligence の提供状況を確認してください)

ユーザー要件:

  • ユーザーが「設定」で Apple Intelligence を有効にしていること

パフォーマンスとプロファイリング

Foundation Models Instrument

アクセス方法:Instruments アプリ → Foundation Models テンプレート

メトリクス:

  • モデルの初回読み込み時間
  • トークン数(入力/出力)
  • リクエストごとの生成時間
  • レイテンシの内訳
  • 最適化の機会

WWDC 286 より:「新しい Instruments のプロファイリングテンプレートを使うと、最適化できる領域を確認し、改善効果を定量化できます。」

最適化:事前ウォームアップ

問題:最初のリクエストでは、モデルの読み込みに 1~2 秒かかります

解決策:ユーザーが操作する前にセッションを作成します

class ViewModel: ObservableObject {
    private var session: LanguageModelSession?

    init() {
        // Prewarm on init
        Task {
            self.session = LanguageModelSession(instructions: "...")
        }
    }

    func generate(prompt: String) async throws -> String {
        let response = try await session!.respond(to: prompt)
        return response.content
    }
}

WWDC 259 より:「ユーザーが操作する前にセッションを事前ウォームアップすると、初回のレイテンシを低減できます。」

短縮される時間:初回の生成で 1~2 秒

最適化: includeSchemaInPrompt

問題: 大きな @Generable スキーマはトークン数を増加させます

解決策: 後続のリクエストではスキーマの挿入をスキップします

// First request - schema inserted
let first = try await session.respond(
    to: "Generate first person",
    generating: Person.self
)

// Subsequent requests - skip schema
let second = try await session.respond(
    to: "Generate another person",
    generating: Person.self,
    options: GenerationOptions(includeSchemaInPrompt: false)
)

WWDC 259 より: 「includeSchemaInPrompt を false に設定すると、後続のリクエストのトークン数とレイテンシが減少します。」

節約できる時間: リクエストあたり 10~20%

最適化: プロパティの順序

@Generable 構造体では、重要なプロパティを先に宣言します。ストリーミングでは、タイトルが全文より先に表示されると、体感レイテンシが 2.5 秒から 0.2 秒に短縮されます。例についてはストリーミングのベストプラクティスを参照してください。


フィードバックと分析

LanguageModelFeedbackAttachment を使用すると、Feedback Assistant を通じてモデルの品質に関する問題を Apple に報告できます。input、output、sentiment(.positive/.negative)、issues(カテゴリ + 説明)、および desiredOutputExamples を指定して作成します。JSON としてエンコードし、Feedback Assistant のレポートに添付します。

WWDC 286:22:13 より

Xcode Playgrounds

概要

Xcode Playgrounds を使用すると、アプリ全体を再ビルドすることなく、プロンプトを迅速に反復できます。

基本的な使用方法
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? Respond only with a title"
    )
}
WWDC 286:2:28 より

Playgrounds は、アプリで定義された型(@Generable 構造体など)にもアクセスできます。


API クイックリファレンス

  • LanguageModelSession — メインインターフェース: respond(to:) → Response<String>、respond(to:generating:) → Response<T>、streamResponse(to:generating:) → AsyncSequence<T.PartiallyGenerated>。プロパティ: transcript、isResponding。
  • SystemLanguageModel — default.availability(.available/.unavailable(reason))、default.supportedLanguages、init(useCase:)
  • GenerationOptions — sampling(.greedy/.random)、temperature、includeSchemaInPrompt
  • @Generable — 制約付きデコーディングによる構造化出力を可能にするマクロ
  • @Guide — プロパティの制約: description:、.range()、.count()、.maximumCount()、Regex
  • Tool プロトコル — name、description、Arguments: Generable、call(arguments:) → ToolOutput
  • DynamicGenerationSchema — GeneratedContent 出力を伴う実行時スキーマ定義
  • GenerationError — .exceededContextWindowSize、.guardrailViolation、.unsupportedLanguageOrLocale

移行戦略

サーバー LLM からの移行
  • 移行すべき場合: プライバシーが必要、オフラインが必要、リクエストごとのコストが懸念される、およびユースケースが適合する場合(要約/抽出/分類)
  • サーバーを使い続ける場合: 世界知識、複雑な推論、または 4096 トークンを超えるコンテキストが必要な場合
手動の JSON パースからの移行

JSON を要求して手動でパースする代わりに、respond(to:generating:) とともに @Generable を使用します。完全な移行パターンについては、axiom-foundation-models のシナリオ 2 を参照してください。


リソース

WWDC: 286, 259, 301

スキル: axiom-foundation-models, axiom-foundation-models-diag


最終更新: 2025-12-03 バージョン: 1.0.0 スキルタイプ: リファレンス 内容: WWDC 2025 のすべてのコード例を含む

コメント