axiom-foundation-models-ref

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Foundation Models Framework — Complete API Reference

Foundation Models Framework — 完整API参考文档

Overview

概述

The Foundation Models framework provides access to Apple's on-device Large Language Model (3 billion parameters, 2-bit quantized) with a Swift API. This reference covers every API, all WWDC 2025 code examples, and comprehensive implementation patterns.
Foundation Models框架通过Swift API提供对Apple端侧大语言模型(30亿参数,2位量化)的访问。本参考文档涵盖所有API、全部WWDC 2025代码示例以及全面的实现模式。

Model Specifications

模型规格

Technical Details:
  • Parameters: 3 billion (3B)
  • Quantization: 2-bit
  • Context Window: 4096 tokens (combined input + output)
  • Supported Languages: English + additional languages via
    SystemLanguageModel.default.supportedLanguages
  • Platforms: iOS 26+, macOS 26+, iPadOS 26+, axiom-visionOS 26+
Optimized For:
  • Text summarization
  • Information extraction
  • Content classification
  • Content generation
  • Tag generation
  • Entity detection
NOT Optimized For:
  • World knowledge queries
  • Complex multi-step reasoning
  • Mathematical computation
  • Translation (use dedicated translation models)
Privacy & Performance:
  • Runs entirely on-device
  • No network required (works offline)
  • Data never leaves device
  • No per-request costs
  • Integrated into OS (doesn't increase app size)

技术细节:
  • 参数: 30亿(3B)
  • 量化: 2位
  • 上下文窗口: 4096个token(输入+输出总和)
  • 支持语言: 英语 + 可通过
    SystemLanguageModel.default.supportedLanguages
    查看的其他语言
  • 支持平台: iOS 26+、macOS 26+、iPadOS 26+、visionOS 26+
优化方向:
  • 文本摘要
  • 信息提取
  • 内容分类
  • 内容生成
  • 标签生成
  • 实体检测
非优化方向:
  • 世界知识查询
  • 复杂多步骤推理
  • 数学计算
  • 翻译(请使用专用翻译模型)
隐私与性能:
  • 完全在设备端运行
  • 无需网络支持(可离线使用)
  • 数据永远不会离开设备
  • 无按请求计费成本
  • 集成到系统中(不会增加应用大小)

When to Use This Reference

何时使用本参考文档

Use this reference when:
  • Implementing Foundation Models features
  • Understanding API capabilities
  • Looking up specific code examples
  • Planning architecture with Foundation Models
  • Migrating from prototype to production
  • Debugging implementation issues
Related Skills:
  • axiom-foundation-models
    — Discipline skill with anti-patterns, pressure scenarios, decision trees
  • axiom-foundation-models-diag
    — Diagnostic skill for troubleshooting issues

在以下场景使用本参考文档:
  • 实现Foundation Models功能时
  • 了解API能力时
  • 查找特定代码示例时
  • 基于Foundation Models规划架构时
  • 从原型迁移到生产环境时
  • 调试实现问题时
相关技能:
  • axiom-foundation-models
    — 包含反模式、压力场景、决策树的专业技能
  • axiom-foundation-models-diag
    — 用于排查问题的诊断技能

LanguageModelSession

LanguageModelSession

Overview

概述

LanguageModelSession
is the core class for interacting with the model. It maintains conversation history (transcript), handles multi-turn interactions, and manages model state.
LanguageModelSession
是与模型交互的核心类。它维护对话历史(transcript)、处理多轮交互并管理模型状态。

Creating a Session

创建会话

Basic Creation:
swift
import FoundationModels

let session = LanguageModelSession()
With Custom Instructions:
swift
let session = LanguageModelSession(instructions: """
    You are a friendly barista in a pixel art coffee shop.
    Respond to the player's question concisely.
    """
)
基础创建方式:
swift
import FoundationModels

let session = LanguageModelSession()
带自定义指令:
swift
let session = LanguageModelSession(instructions: """
    你是像素艺术咖啡店中的友好咖啡师。
    简洁地回复玩家的问题。
    """
)

From WWDC 301:1:05

来自WWDC 301:1:05

With Tools:
swift
let session = LanguageModelSession(
    tools: [GetWeatherTool()],
    instructions: "Help user with weather forecasts."
)
带工具:
swift
let session = LanguageModelSession(
    tools: [GetWeatherTool()],
    instructions: "帮助用户获取天气预报。"
)

From WWDC 286:15:03

来自WWDC 286:15:03

With Specific Model/Use Case:
swift
let session = LanguageModelSession(
    model: SystemLanguageModel(useCase: .contentTagging)
)
带特定模型/用例:
swift
let session = LanguageModelSession(
    model: SystemLanguageModel(useCase: .contentTagging)
)

From WWDC 286:18:39

来自WWDC 286:18:39

Instructions vs Prompts

指令与提示词的区别

Instructions:
  • Come from developer
  • Define model's role, style, constraints
  • Mostly static
  • First entry in transcript
  • Model trained to obey instructions over prompts (security feature)
Prompts:
  • Come from user (or dynamic app state)
  • Specific requests for generation
  • Dynamic input
  • Each call to
    respond(to:)
    adds prompt to transcript
Security Consideration:
  • NEVER interpolate untrusted user input into instructions
  • User input should go in prompts only
  • Prevents prompt injection attacks
指令:
  • 开发者提供
  • 定义模型的角色、风格、约束
  • 大多为静态内容
  • 是对话历史中的第一条内容
  • 模型被训练为优先遵循指令而非提示词(安全特性)
提示词:
  • 用户提供(或来自动态应用状态)
  • 是生成内容的具体请求
  • 动态输入
  • 每次调用
    respond(to:)
    都会将提示词添加到对话历史中
安全注意事项:
  • 绝对不要将不可信的用户输入插入到指令中
  • 用户输入应仅作为提示词使用
  • 防止提示词注入攻击

respond(to:) Method

respond(to:) 方法

Basic Text Generation:
swift
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
}
基础文本生成:
swift
func respond(userInput: String) async throws -> String {
    let session = LanguageModelSession(instructions: """
        你是充满像素风格世界中的友好咖啡师。
        回复玩家的问题。
        """
    )
    let response = try await session.respond(to: userInput)
    return response.content
}

From WWDC 301:1:05

来自WWDC 301:1:05

Return Type:
Response<String>
with
.content
property
返回类型: 带
.content
属性的
Response<String>

respond(to:generating:) Method

respond(to:generating:) 方法

Structured Output with @Generable:
swift
@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
使用@Generable的结构化输出:
swift
@Generable
struct SearchSuggestions {
    @Guide(description: "建议搜索词列表", .count(4))
    var searchTerms: [String]
}

let prompt = """
    为一个关于参观著名地标景点的应用生成建议搜索词列表。
    """

let response = try await session.respond(
    to: prompt,
    generating: SearchSuggestions.self
)

print(response.content) // SearchSuggestions实例

From WWDC 286:5:51

来自WWDC 286:5:51

Return Type:
Response<SearchSuggestions>
with
.content
property
返回类型: 带
.content
属性的
Response<SearchSuggestions>

Generation Options

生成选项

Deterministic Output (Greedy Sampling):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(sampling: .greedy)
)
确定性输出(贪心采样):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(sampling: .greedy)
)

From WWDC 301:6:14

来自WWDC 301:6:14

Low Variance (Conservative):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 0.5)
)
High Variance (Creative):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 2.0)
)
低方差(保守型):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 0.5)
)
高方差(创意型):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 2.0)
)

From WWDC 301:6:14

来自WWDC 301:6:14

Skip Schema in Prompt (Optimization):
swift
let response = try await session.respond(
    to: prompt,
    generating: Person.self,
    options: GenerationOptions(includeSchemaInPrompt: false)
)
Use when: Subsequent requests with same @Generable type. Reduces token count and latency.

在提示词中跳过模式(优化):
swift
let response = try await session.respond(
    to: prompt,
    generating: Person.self,
    options: GenerationOptions(includeSchemaInPrompt: false)
)
适用场景: 后续请求使用相同@Generable类型时。减少token数量和延迟。

Multi-Turn Interactions

多轮交互

Retaining Context

保留上下文

swift
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
swift
let session = LanguageModelSession()

// 第一轮
let firstHaiku = try await session.respond(to: "写一首关于钓鱼的俳句")
print(firstHaiku.content)
// 静水面微光,
// 晨雾中投出钓线——
// 希望在每一竿。

// 第二轮 - 模型会记住上下文
let secondHaiku = try await session.respond(to: "再写一首关于高尔夫的")
print(secondHaiku.content)
// 晨露悄无声,
// 球童轻声来指引——
// 步步皆耐心。

print(session.transcript) // 显示完整对话历史

From WWDC 286:17:46

来自WWDC 286:17:46

How it works:
  • Each
    respond()
    call adds entry to transcript
  • Model uses entire transcript for context
  • Enables conversational interactions
工作原理:
  • 每次
    respond()
    调用都会向对话历史中添加条目
  • 模型使用完整对话历史作为上下文
  • 支持对话式交互

Transcript Property

Transcript属性

swift
let transcript = session.transcript

for entry in transcript.entries {
    print("Entry: \(entry.content)")
}
Use cases:
  • Debugging generation issues
  • Displaying conversation history in UI
  • Exporting chat logs
  • Condensing for context management

swift
let transcript = session.transcript

for entry in transcript.entries {
    print("条目: \(entry.content)")
}
使用场景:
  • 调试生成问题
  • 在UI中显示对话历史
  • 导出聊天日志
  • 压缩内容以管理上下文

isResponding Property

isResponding属性

swift
struct HaikuView: View {
    @State private var session = LanguageModelSession()
    @State private var haiku: String?

    var body: some View {
        if let haiku {
            Text(haiku)
        }

        Button("Go!") {
            Task {
                haiku = try await session.respond(
                    to: "Write a haiku about something you haven't yet"
                ).content
            }
        }
        // Gate on `isResponding`
        .disabled(session.isResponding)
    }
}
swift
struct HaikuView: View {
    @State private var session = LanguageModelSession()
    @State private var haiku: String?

    var body: some View {
        if let haiku {
            Text(haiku)
        }

        Button("开始!") {
            Task {
                haiku = try await session.respond(
                    to: "写一首关于你还没写过的事物的俳句"
                ).content
            }
        }
        // 根据`isResponding`状态禁用按钮
        .disabled(session.isResponding)
    }
}

From WWDC 286:18:22

来自WWDC 286:18:22

Why important: Prevents multiple concurrent requests, which could cause errors or unexpected behavior.

重要性: 防止并发请求,避免引发错误或意外行为。

@Generable Macro

@Generable宏

Overview

概述

@Generable
enables structured output from the model using Swift types. The macro generates a schema at compile-time and uses constrained decoding to guarantee structural correctness.
@Generable
允许通过Swift类型从模型获取结构化输出。该宏在编译时生成模式,并使用约束解码保证结构正确性。

Basic Usage

基础用法

On Structs:
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
用于结构体:
swift
@Generable
struct Person {
    let name: String
    let age: Int
}

let response = try await session.respond(
    to: "生成一个人物",
    generating: Person.self
)

let person = response.content // 类型安全的Person实例

From WWDC 301:8:14

来自WWDC 301:8:14

On Enums:
swift
@Generable
struct NPC {
    let name: String
    let encounter: Encounter

    @Generable
    enum Encounter {
        case orderCoffee(String)
        case wantToTalkToManager(complaint: String)
    }
}
用于枚举:
swift
@Generable
struct NPC {
    let name: String
    let encounter: Encounter

    @Generable
    enum Encounter {
        case orderCoffee(String)
        case wantToTalkToManager(complaint: String)
    }
}

From WWDC 301:10:49

来自WWDC 301:10:49

Supported Types

支持的类型

Primitives:
  • String
  • Int
    ,
    Float
    ,
    Double
    ,
    Decimal
  • Bool
Collections:
  • [ElementType]
    (arrays)
Composed Types:
swift
@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!
}
基本类型:
  • String
  • Int
    ,
    Float
    ,
    Double
    ,
    Decimal
  • Bool
集合类型:
  • [ElementType]
    (数组)
组合类型:
swift
@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] // 递归支持!
}

From WWDC 286:6:18

来自WWDC 286:6:18

@Guide Constraints

@Guide约束

Natural Language Description:
swift
@Generable
struct NPC {
    @Guide(description: "A full name")
    let name: String
}
自然语言描述:
swift
@Generable
struct NPC {
    @Guide(description: "全名")
    let name: String
}

From WWDC 301:11:20

来自WWDC 301:11:20

Numeric Range:
swift
@Generable
struct Character {
    @Guide(.range(1...10))
    let level: Int
}
数值范围:
swift
@Generable
struct Character {
    @Guide(.range(1...10))
    let level: Int
}

From WWDC 301:11:20

来自WWDC 301:11:20

Array Count:
swift
@Generable
struct Suggestions {
    @Guide(.count(3))
    let attributes: [Attribute]
}
数组数量:
swift
@Generable
struct Suggestions {
    @Guide(.count(3))
    let attributes: [Attribute]
}

From WWDC 301:11:20

来自WWDC 301:11:20

Array Maximum Count:
swift
@Generable
struct Result {
    @Guide(.maximumCount(3))
    let topics: [String]
}
Regex Patterns:
swift
@Generable
struct NPC {
    @Guide(Regex {
        Capture {
            ChoiceOf {
                "Mr"
                "Mrs"
            }
        }
        ". "
        OneOrMore(.word)
    })
    let name: String
}

session.respond(to: "Generate a fun NPC", generating: NPC.self)
// > {name: "Mrs. Brewster"}
数组最大数量:
swift
@Generable
struct Result {
    @Guide(.maximumCount(3))
    let topics: [String]
}
正则表达式模式:
swift
@Generable
struct NPC {
    @Guide(Regex {
        Capture {
            ChoiceOf {
                "Mr"
                "Mrs"
            }
        }
        ". "
        OneOrMore(.word)
    })
    let name: String
}

session.respond(to: "生成一个有趣的NPC", generating: NPC.self)
// > {name: "Mrs. Brewster"}

From WWDC 301:13:40

来自WWDC 301:13:40

Constrained Decoding

约束解码

How it works:
  1. @Generable
    macro generates schema at compile-time
  2. Schema defines valid token sequences
  3. During generation, model creates probability distribution for next token
  4. Framework masks out invalid tokens based on schema
  5. Model can only pick tokens valid according to schema
  6. Guarantees structural correctness - no hallucinated keys, no invalid JSON
From WWDC 286: "Constrained decoding prevents structural mistakes. Model is prevented from generating invalid field names or wrong types."
Benefits:
  • Zero parsing code needed
  • No runtime parsing errors
  • Type-safe Swift objects
  • Compile-time safety (changes to struct caught by compiler)
工作原理:
  1. @Generable
    宏在编译时生成模式
  2. 模式定义有效的token序列
  3. 生成过程中,模型为下一个token创建概率分布
  4. 框架根据模式屏蔽无效token
  5. 模型只能选择符合模式的有效token
  6. 保证结构正确性 - 不会出现幻觉字段,不会生成无效JSON
来自WWDC 286: "约束解码可防止结构错误。模型无法生成无效字段名或错误类型。"
优势:
  • 无需解析代码
  • 无运行时解析错误
  • 类型安全的Swift对象
  • 编译时安全(结构体变更会被编译器捕获)

Property Declaration Order

属性声明顺序

Properties generated in order declared:
swift
@Generable
struct Itinerary {
    var name: String        // Generated FIRST
    var days: [DayPlan]     // Generated SECOND
    var summary: String     // Generated LAST
}
Why it matters:
  • Later properties can reference earlier ones
  • Better model quality: Summaries after content
  • Better streaming UX: Important properties first
属性按声明顺序生成:
swift
@Generable
struct Itinerary {
    var name: String        // 第一个生成
    var days: [DayPlan]     // 第二个生成
    var summary: String     // 最后一个生成
}
重要性:
  • 后续属性可以引用前面的属性
  • 更好的模型生成质量:摘要在内容之后生成
  • 更好的流式体验:重要属性优先生成

From WWDC 286:11:00

来自WWDC 286:11:00



Streaming

流式传输

Overview

概述

Foundation Models uses snapshot streaming (not delta streaming). Instead of raw deltas, the framework streams
PartiallyGenerated
types with optional properties that fill in progressively.
Foundation Models使用快照流式传输(而非增量流式传输)。框架不传输原始增量,而是传输
PartiallyGenerated
类型,该类型包含会逐步填充的可选属性。

PartiallyGenerated Type

PartiallyGenerated类型

The
@Generable
macro automatically creates a
PartiallyGenerated
nested type:
swift
@Generable
struct Itinerary {
    var name: String
    var days: [DayPlan]
}

// Compiler generates:
extension Itinerary {
    struct PartiallyGenerated {
        var name: String?        // All properties optional!
        var days: [DayPlan]?
    }
}
@Generable
宏会自动创建嵌套的
PartiallyGenerated
类型:
swift
@Generable
struct Itinerary {
    var name: String
    var days: [DayPlan]
}

// 编译器自动生成:
extension Itinerary {
    struct PartiallyGenerated {
        var name: String?        // 所有属性均为可选!
        var days: [DayPlan]?
    }
}

From WWDC 286:9:20

来自WWDC 286:9:20

streamResponse Method

streamResponse方法

swift
@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
}
swift
@Generable
struct Itinerary {
    var name: String
    var days: [Day]
}

let stream = session.streamResponse(
    to: "制定一份富士山3日行程。",
    generating: Itinerary.self
)

for try await partial in stream {
    print(partial) // 逐步更新的Itinerary.PartiallyGenerated
}

From WWDC 286:9:40

来自WWDC 286:9:40

Return Type:
AsyncSequence<Itinerary.PartiallyGenerated>
返回类型:
AsyncSequence<Itinerary.PartiallyGenerated>

SwiftUI Integration

SwiftUI集成

swift
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)
                    }
                }
            }
        }
    }
}
swift
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("开始") {
                Task {
                    do {
                        let prompt = """
                            生成一份\(dayCount)天的\(landmarkName)行程。
                            """

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

                        for try await partial in stream {
                            self.itinerary = partial
                        }
                    } catch {
                        print(error)
                    }
                }
            }
        }
    }
}

From WWDC 286:10:05

来自WWDC 286:10:05

Best Practices

最佳实践

1. Use SwiftUI animations:
swift
if let name = itinerary?.name {
    Text(name)
        .transition(.opacity)
}
2. View identity for arrays:
swift
// ✅ 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. Property order optimization:
swift
// ✅ GOOD - Title first for streaming
@Generable
struct Article {
    var title: String      // Shows immediately
    var summary: String    // Shows second
    var fullText: String   // Shows last
}
1. 使用SwiftUI动画:
swift
if let name = itinerary?.name {
    Text(name)
        .transition(.opacity)
}
2. 数组的视图标识:
swift
// ✅ 推荐 - 稳定的标识
ForEach(days, id: \.id) { day in
    DayView(day: day)
}

// ❌ 不推荐 - 标识会变化
ForEach(days.indices, id: \.self) { index in
    DayView(day: days[index])
}
3. 属性顺序优化:
swift
// ✅ 推荐 - 重要属性优先,适配流式传输
@Generable
struct Article {
    var title: String      // 立即显示
    var summary: String    // 第二个显示
    var fullText: String   // 最后显示
}

From WWDC 286:11:00

来自WWDC 286:11:00



Tool Protocol

Tool协议

Overview

概述

Tools let the model autonomously execute your custom code to fetch external data or perform actions. Tools integrate with MapKit, WeatherKit, Contacts, EventKit, or any custom API.
工具允许模型自主执行你的自定义代码,以获取外部数据或执行操作。工具可与MapKit、WeatherKit、Contacts、EventKit或任何自定义API集成。

Protocol Definition

协议定义

swift
protocol Tool {
    var name: String { get }
    var description: String { get }

    associatedtype Arguments: Generable

    func call(arguments: Arguments) async throws -> ToolOutput
}
swift
protocol Tool {
    var name: String { get }
    var description: String { get }

    associatedtype Arguments: Generable

    func call(arguments: Arguments) async throws -> ToolOutput
}

Example: GetWeatherTool

示例:GetWeatherTool

swift
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
    }
}
swift
import FoundationModels
import WeatherKit
import CoreLocation

struct GetWeatherTool: Tool {
    let name = "getWeather"
    let description = "获取城市的最新天气信息"

    @Generable
    struct Arguments {
        @Guide(description: "要获取天气的城市")
        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)

        // 或者如果工具输出为自然语言:
        // let output = ToolOutput("\(arguments.city)的气温是\(temperature)度。")

        return output
    }
}

From WWDC 286:13:42

来自WWDC 286:13:42

Attaching Tools to Session

为会话附加工具

swift
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!
swift
let session = LanguageModelSession(
    tools: [GetWeatherTool()],
    instructions: "帮助用户获取天气预报。"
)

let response = try await session.respond(
    to: "库比蒂诺的气温是多少?"
)

print(response.content)
// 库比蒂诺的气温是71˚F!

From WWDC 286:15:03

来自WWDC 286:15:03

How it works:
  1. Session initialized with tools
  2. User prompt: "What's Tokyo's weather?"
  3. Model analyzes prompt, decides weather data needed
  4. Model generates tool call:
    getWeather(city: "Tokyo")
  5. Framework calls
    call()
    method
  6. Your code fetches real data from API
  7. Tool output inserted into transcript
  8. Model generates final response using tool output
From WWDC 301: "Model autonomously decides when and how often to call tools. Can call multiple tools per request, even in parallel."
工作原理:
  1. 初始化会话并传入工具
  2. 用户提示: "东京的天气如何?"
  3. 模型分析提示,判断需要天气数据
  4. 模型生成工具调用:
    getWeather(city: "Tokyo")
  5. 框架调用
    call()
    方法
  6. 你的代码从API获取真实数据
  7. 工具输出被插入到对话历史中
  8. 模型使用工具输出生成最终回复
来自WWDC 301: "模型会自主决定何时以及调用工具的频率。每个请求可调用多个工具,甚至并行调用。"

Example: FindContactTool

示例:FindContactTool

swift
import FoundationModels
import Contacts

struct FindContactTool: Tool {
    let name = "findContact"
    let description = "Finds a contact from a specified age generation."

    @Generable
    struct Arguments {
        let generation: Generation

        @Generable
        enum Generation {
            case babyBoomers
            case genX
            case millennial
            case genZ
        }
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        let store = CNContactStore()

        let keysToFetch = [CNContactGivenNameKey, CNContactBirthdayKey] as [CNKeyDescriptor]
        let request = CNContactFetchRequest(keysToFetch: keysToFetch)

        var contacts: [CNContact] = []
        try store.enumerateContacts(with: request) { contact, stop in
            if let year = contact.birthday?.year {
                if arguments.generation.yearRange.contains(year) {
                    contacts.append(contact)
                }
            }
        }

        guard let pickedContact = contacts.randomElement() else {
            return ToolOutput("Could not find a contact.")
        }

        return ToolOutput(pickedContact.givenName)
    }
}
swift
import FoundationModels
import Contacts

struct FindContactTool: Tool {
    let name = "findContact"
    let description = "查找特定年代的联系人。"

    @Generable
    struct Arguments {
        let generation: Generation

        @Generable
        enum Generation {
            case babyBoomers
            case genX
            case millennial
            case genZ
        }
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        let store = CNContactStore()

        let keysToFetch = [CNContactGivenNameKey, CNContactBirthdayKey] as [CNKeyDescriptor]
        let request = CNContactFetchRequest(keysToFetch: keysToFetch)

        var contacts: [CNContact] = []
        try store.enumerateContacts(with: request) { contact, stop in
            if let year = contact.birthday?.year {
                if arguments.generation.yearRange.contains(year) {
                    contacts.append(contact)
                }
            }
        }

        guard let pickedContact = contacts.randomElement() else {
            return ToolOutput("未找到联系人。")
        }

        return ToolOutput(pickedContact.givenName)
    }
}

From WWDC 301:18:47

来自WWDC 301:18:47

Stateful Tools

有状态工具

Tools can maintain state across calls using
class
instead of
struct
:
swift
class FindContactTool: Tool {
    let name = "findContact"
    let description = "Finds a contact from a specified age generation."

    var pickedContacts = Set<String>() // State!

    @Generable
    struct Arguments {
        let generation: Generation

        @Generable
        enum Generation {
            case babyBoomers
            case genX
            case millennial
            case genZ
        }
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        // Fetch contacts...
        contacts.removeAll(where: { pickedContacts.contains($0.givenName) })

        guard let pickedContact = contacts.randomElement() else {
            return ToolOutput("Could not find a contact.")
        }

        pickedContacts.insert(pickedContact.givenName) // Update state
        return ToolOutput(pickedContact.givenName)
    }
}
工具可使用
class
而非
struct
来维护跨调用的状态:
swift
class FindContactTool: Tool {
    let name = "findContact"
    let description = "查找特定年代的联系人。"

    var pickedContacts = Set<String>() // 状态!

    @Generable
    struct Arguments {
        let generation: Generation

        @Generable
        enum Generation {
            case babyBoomers
            case genX
            case millennial
            case genZ
        }
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        // 获取联系人...
        contacts.removeAll(where: { pickedContacts.contains($0.givenName) })

        guard let pickedContact = contacts.randomElement() else {
            return ToolOutput("未找到联系人。")
        }

        pickedContacts.insert(pickedContact.givenName) // 更新状态
        return ToolOutput(pickedContact.givenName)
    }
}

From WWDC 301:21:55

来自WWDC 301:21:55

Why: Tool instance persists for session lifetime. Can track what's been called.
优势: 工具实例在会话生命周期内持续存在。可跟踪已调用的内容。

Example: GetContactEventTool

示例:GetContactEventTool

swift
import FoundationModels
import EventKit

struct GetContactEventTool: Tool {
    let name = "getContactEvent"
    let description = "Get an event with a contact."

    let contactName: String

    @Generable
    struct Arguments {
        let day: Int
        let month: Int
        let year: Int
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        // Fetch events from Calendar...
        let eventStore = EKEventStore()
        // ... implementation ...
        return ToolOutput(/* event details */)
    }
}
swift
import FoundationModels
import EventKit

struct GetContactEventTool: Tool {
    let name = "getContactEvent"
    let description = "获取与联系人相关的事件。"

    let contactName: String

    @Generable
    struct Arguments {
        let day: Int
        let month: Int
        let year: Int
    }

    func call(arguments: Arguments) async throws -> ToolOutput {
        // 从日历获取事件...
        let eventStore = EKEventStore()
        // ... 实现代码 ...
        return ToolOutput(/* 事件详情 */)
    }
}

From WWDC 301:22:27

来自WWDC 301:22:27

ToolOutput

ToolOutput

Two forms:
  1. Natural language (String):
swift
return ToolOutput("Temperature is 71°F")
  1. Structured (GeneratedContent):
swift
let content = GeneratedContent(properties: ["temperature": 71])
return ToolOutput(content)
两种形式:
  1. 自然语言(字符串):
swift
return ToolOutput("气温为71°F")
  1. 结构化(GeneratedContent):
swift
let content = GeneratedContent(properties: ["temperature": 71])
return ToolOutput(content)

Tool Naming Best Practices

工具命名最佳实践

DO:
  • Short, readable names:
    getWeather
    ,
    findContact
  • Use verbs:
    get
    ,
    find
    ,
    fetch
    ,
    create
  • One sentence descriptions
  • Keep descriptions concise (they're in prompt)
DON'T:
  • Abbreviations:
    gtWthr
  • Implementation details in description
  • Long descriptions (increases token count)
From WWDC 301: "Tool name and description put verbatim in prompt. Longer strings mean more tokens, which increases latency."
推荐:
  • 简短、易读的名称:
    getWeather
    ,
    findContact
  • 使用动词:
    get
    ,
    find
    ,
    fetch
    ,
    create
  • 描述为一句话
  • 描述保持简洁(会被包含在提示词中)
不推荐:
  • 使用缩写:
    gtWthr
  • 在描述中包含实现细节
  • 过长的描述(会增加token数量)
来自WWDC 301: "工具名称和描述会直接包含在提示词中。字符串越长,token数量越多,延迟越高。"

Multiple Tools

多工具使用

swift
let session = LanguageModelSession(
    tools: [
        GetWeatherTool(),
        FindRestaurantTool(),
        FindHotelTool()
    ],
    instructions: "Plan travel itineraries."
)

// Model autonomously decides which tools to call and when
swift
let session = LanguageModelSession(
    tools: [
        GetWeatherTool(),
        FindRestaurantTool(),
        FindHotelTool()
    ],
    instructions: "规划旅行行程。"
)

// 模型会自主决定调用哪些工具以及何时调用

Tool Calling Behavior

工具调用行为

Key facts:
  • Tool can be called multiple times per request
  • Multiple tools can be called in parallel
  • Model decides when to call (not guaranteed to call)
  • Arguments guaranteed valid via @Generable
From WWDC 301: "When tools called in parallel, your call method may execute concurrently. Keep this in mind when accessing data."

关键要点:
  • 每个请求中工具可被多次调用
  • 多个工具可被并行调用
  • 模型决定何时调用(不保证一定会调用)
  • 通过@Generable保证参数有效
来自WWDC 301: "当工具被并行调用时,你的call方法可能会并发执行。访问数据时请考虑这一点。"

Dynamic Schemas

动态模式

Overview

概述

DynamicGenerationSchema
enables creating schemas at runtime instead of compile-time. Useful for user-defined structures, level creators, or dynamic forms.
DynamicGenerationSchema
支持在运行时而非编译时创建模式。适用于用户定义的结构、关卡创建器或动态表单。

Creating Dynamic Schemas

创建动态模式

swift
@Generable
struct Riddle {
    let question: String
    let answers: [Answer]

    @Generable
    struct Answer {
        let text: String
        let isCorrect: Bool
    }
}
swift
@Generable
struct Riddle {
    let question: String
    let answers: [Answer]

    @Generable
    struct Answer {
        let text: String
        let isCorrect: Bool
    }
}

From WWDC 301:14:50

来自WWDC 301:14:50

If this structure is only known at runtime:
swift
struct LevelObjectCreator {
    var properties: [DynamicGenerationSchema.Property] = []

    mutating func addStringProperty(name: String) {
        let property = DynamicGenerationSchema.Property(
            name: name,
            schema: DynamicGenerationSchema(type: String.self)
        )
        properties.append(property)
    }

    mutating func addBoolProperty(name: String) {
        let property = DynamicGenerationSchema.Property(
            name: name,
            schema: DynamicGenerationSchema(type: Bool.self)
        )
        properties.append(property)
    }

    mutating func addArrayProperty(name: String, customType: String) {
        let property = DynamicGenerationSchema.Property(
            name: name,
            schema: DynamicGenerationSchema(
                arrayOf: DynamicGenerationSchema(referenceTo: customType)
            )
        )
        properties.append(property)
    }

    var root: DynamicGenerationSchema {
        DynamicGenerationSchema(
            name: name,
            properties: properties
        )
    }
}

// Create riddle schema
var riddleBuilder = LevelObjectCreator(name: "Riddle")
riddleBuilder.addStringProperty(name: "question")
riddleBuilder.addArrayProperty(name: "answers", customType: "Answer")

// Create answer schema
var answerBuilder = LevelObjectCreator(name: "Answer")
answerBuilder.addStringProperty(name: "text")
answerBuilder.addBoolProperty(name: "isCorrect")

let riddleDynamicSchema = riddleBuilder.root
let answerDynamicSchema = answerBuilder.root
如果该结构仅在运行时才可知:
swift
struct LevelObjectCreator {
    var properties: [DynamicGenerationSchema.Property] = []

    mutating func addStringProperty(name: String) {
        let property = DynamicGenerationSchema.Property(
            name: name,
            schema: DynamicGenerationSchema(type: String.self)
        )
        properties.append(property)
    }

    mutating func addBoolProperty(name: String) {
        let property = DynamicGenerationSchema.Property(
            name: name,
            schema: DynamicGenerationSchema(type: Bool.self)
        )
        properties.append(property)
    }

    mutating func addArrayProperty(name: String, customType: String) {
        let property = DynamicGenerationSchema.Property(
            name: name,
            schema: DynamicGenerationSchema(
                arrayOf: DynamicGenerationSchema(referenceTo: customType)
            )
        )
        properties.append(property)
    }

    var root: DynamicGenerationSchema {
        DynamicGenerationSchema(
            name: name,
            properties: properties
        )
    }
}

// 创建谜语模式
var riddleBuilder = LevelObjectCreator(name: "Riddle")
riddleBuilder.addStringProperty(name: "question")
riddleBuilder.addArrayProperty(name: "answers", customType: "Answer")

// 创建答案模式
var answerBuilder = LevelObjectCreator(name: "Answer")
answerBuilder.addStringProperty(name: "text")
answerBuilder.addBoolProperty(name: "isCorrect")

let riddleDynamicSchema = riddleBuilder.root
let answerDynamicSchema = answerBuilder.root

From WWDC 301:15:10

来自WWDC 301:15:10

Validating and Using Dynamic Schemas

验证与使用动态模式

swift
let schema = try GenerationSchema(
    root: riddleDynamicSchema,
    dependencies: [answerDynamicSchema]
)

let session = LanguageModelSession()
let response = try await session.respond(
    to: "Generate a fun riddle about coffee",
    schema: schema
)

let generatedContent = response.content // GeneratedContent
let question = try generatedContent.value(String.self, forProperty: "question")
let answers = try generatedContent.value([GeneratedContent].self, forProperty: "answers")
swift
let schema = try GenerationSchema(
    root: riddleDynamicSchema,
    dependencies: [answerDynamicSchema]
)

let session = LanguageModelSession()
let response = try await session.respond(
    to: "生成一个关于咖啡的有趣谜语",
    schema: schema
)

let generatedContent = response.content // GeneratedContent
let question = try generatedContent.value(String.self, forProperty: "question")
let answers = try generatedContent.value([GeneratedContent].self, forProperty: "answers")

From WWDC 301:15:10

来自WWDC 301:15:10

Dynamic vs Static @Generable

动态模式与静态@Generable对比

Use @Generable when:
  • Structure known at compile-time
  • Want type safety
  • Want automatic parsing
Use Dynamic Schemas when:
  • Structure only known at runtime
  • User-defined schemas
  • Maximum flexibility
From WWDC 301: "Compile-time @Generable gives type safety. Dynamic schemas give runtime flexibility. Both use same constrained decoding guarantees."

使用@Generable的场景:
  • 结构在编译时已知
  • 需要类型安全
  • 需要自动解析
使用动态模式的场景:
  • 结构仅在运行时可知
  • 用户定义的模式
  • 需要最大灵活性
来自WWDC 301: "编译时@Generable提供类型安全。动态模式提供运行时灵活性。两者均使用相同的约束解码保证。"

Sampling & Generation Options

采样与生成选项

Sampling Methods

采样方法

Random Sampling (Default):
swift
let response = try await session.respond(to: prompt)
// Different output each time
Greedy Sampling (Deterministic):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(sampling: .greedy)
)
// Same output for same prompt (given same model version)
随机采样(默认):
swift
let response = try await session.respond(to: prompt)
// 每次输出不同
贪心采样(确定性):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(sampling: .greedy)
)
// 相同提示词输出相同内容(模型版本相同时)

From WWDC 301:6:14

来自WWDC 301:6:14

Use greedy for:
  • Unit tests
  • Demos that need repeatability
  • When consistency critical
Caveat: Only deterministic for same model version. OS updates may change model, changing output.
贪心采样适用场景:
  • 单元测试
  • 需要可重复性的演示
  • 一致性要求高的场景
注意事项: 仅在模型版本相同时具有确定性。系统更新可能会更改模型,从而改变输出。

Temperature Control

温度控制

Low variance (focused, conservative):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 0.5)
)
// Predictable, focused output
High variance (creative, diverse):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 2.0)
)
// Varied, creative output
低方差(聚焦、保守):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 0.5)
)
// 可预测、聚焦的输出
高方差(创意、多样):
swift
let response = try await session.respond(
    to: prompt,
    options: GenerationOptions(temperature: 2.0)
)
// 多样、有创意的输出

From WWDC 301:6:14

来自WWDC 301:6:14

Temperature scale:
  • 0.1-0.5
    : Very focused
  • 1.0
    (default): Balanced
  • 1.5-2.0
    : Very creative

温度范围:
  • 0.1-0.5
    : 高度聚焦
  • 1.0
    (默认): 平衡
  • 1.5-2.0
    : 极具创意

Built-in Use Cases

内置用例

Content Tagging Adapter

内容标签适配器

Specialized adapter for:
  • Tag generation
  • Entity extraction
  • Topic detection
swift
@Generable
struct Result {
    let topics: [String]
}

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

let response = try await session.respond(
    to: articleText,
    generating: Result.self
)
专用适配器适用于:
  • 标签生成
  • 实体提取
  • 主题检测
swift
@Generable
struct Result {
    let topics: [String]
}

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

let response = try await session.respond(
    to: articleText,
    generating: Result.self
)

From WWDC 286:19:19

来自WWDC 286:19:19

Custom Use Cases

自定义用例

With custom instructions:
swift
@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
)
带自定义指令:
swift
@Generable
struct Top3ActionEmotionResult {
    @Guide(.maximumCount(3))
    let actions: [String]
    @Guide(.maximumCount(3))
    let emotions: [String]
}

let session = LanguageModelSession(
    model: SystemLanguageModel(useCase: .contentTagging),
    instructions: "标记给定输入文本中最重要的3个动作和3种情绪。"
)

let response = try await session.respond(
    to: text,
    generating: Top3ActionEmotionResult.self
)

From WWDC 286:19:35

来自WWDC 286:19:35



Error Handling

错误处理

GenerationError Types

GenerationError类型

exceededContextWindowSize:
swift
do {
    let response = try await session.respond(to: prompt)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // Context limit (4096 tokens) exceeded
    // Solution: Condense transcript, create new session
}
exceededContextWindowSize:
swift
do {
    let response = try await session.respond(to: prompt)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // 超出上下文窗口限制(4096个token)
    // 解决方案: 压缩对话历史,创建新会话
}

From WWDC 301:3:37

来自WWDC 301:3:37

guardrailViolation:
swift
do {
    let response = try await session.respond(to: userInput)
} catch LanguageModelSession.GenerationError.guardrailViolation {
    // Content policy triggered
    // Solution: Show graceful message, don't generate
}
unsupportedLanguageOrLocale:
swift
do {
    let response = try await session.respond(to: userInput)
} catch LanguageModelSession.GenerationError.unsupportedLanguageOrLocale {
    // Language not supported
    // Solution: Check supported languages, show message
}
guardrailViolation:
swift
do {
    let response = try await session.respond(to: userInput)
} catch LanguageModelSession.GenerationError.guardrailViolation {
    // 触发内容策略
    // 解决方案: 显示友好提示,不生成内容
}
unsupportedLanguageOrLocale:
swift
do {
    let response = try await session.respond(to: userInput)
} catch LanguageModelSession.GenerationError.unsupportedLanguageOrLocale {
    // 语言不被支持
    // 解决方案: 检查支持的语言,显示提示
}

From WWDC 301:7:06

来自WWDC 301:7:06

Context Window Management

上下文窗口管理

Strategy 1: Fresh Session

策略1: 新会话

swift
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()
}
swift
var session = LanguageModelSession()

do {
    let response = try await session.respond(to: prompt)
    print(response.content)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // 创建无历史的新会话
    session = LanguageModelSession()
}

From WWDC 301:3:37

来自WWDC 301:3:37

Strategy 2: Condensed Session

策略2: 压缩会话

swift
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)
}
swift
do {
    let response = try await session.respond(to: prompt)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // 创建带部分历史的新会话
    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) // 保留指令

        if allEntries.count > 1, let lastEntry = allEntries.last {
            condensedEntries.append(lastEntry) // 保留最近上下文
        }
    }

    let condensedTranscript = Transcript(entries: condensedEntries)
    // 注意: 对话历史包含指令
    return LanguageModelSession(transcript: condensedTranscript)
}

From WWDC 301:3:55

来自WWDC 301:3:55



Availability

可用性

Checking Availability

检查可用性

swift
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)")
        }
    }
}
swift
struct AvailabilityExample: View {
    private let model = SystemLanguageModel.default

    var body: some View {
        switch model.availability {
        case .available:
            Text("模型可用").foregroundStyle(.green)
        case .unavailable(let reason):
            Text("模型不可用").foregroundStyle(.red)
            Text("原因: \(reason)")
        }
    }
}

From WWDC 286:19:56

来自WWDC 286:19:56

Supported Languages

支持的语言

swift
let supportedLanguages = SystemLanguageModel.default.supportedLanguages
guard supportedLanguages.contains(Locale.current.language) else {
    // Show message
    return
}
swift
let supportedLanguages = SystemLanguageModel.default.supportedLanguages
guard supportedLanguages.contains(Locale.current.language) else {
    // 显示提示
    return
}

From WWDC 301:7:06

来自WWDC 301:7:06

Requirements

要求

Device Requirements:
  • Apple Intelligence-enabled device
  • iPhone 15 Pro or later
  • iPad with M1+ chip
  • Mac with Apple silicon
Region Requirements:
  • Supported region (check Apple Intelligence availability)
User Requirements:
  • User opted in to Apple Intelligence in Settings

设备要求:
  • 支持Apple Intelligence的设备
  • iPhone 15 Pro或更新机型
  • 配备M1及以上芯片的iPad
  • 配备Apple芯片的Mac
地区要求:
  • 支持地区(请查看Apple Intelligence可用性)
用户要求:
  • 用户在设置中已选择启用Apple Intelligence

Performance & Profiling

性能与分析

Foundation Models Instrument

Foundation Models工具

Access: Instruments app → Foundation Models template
Metrics:
  • Initial model load time
  • Token counts (input/output)
  • Generation time per request
  • Latency breakdown
  • Optimization opportunities
From WWDC 286: "New Instruments profiling template lets you observe areas of optimization and quantify improvements."
访问方式: 打开Instruments应用 → 选择Foundation Models模板
指标:
  • 模型初始加载时间
  • Token数量(输入/输出)
  • 每个请求的生成时间
  • 延迟细分
  • 优化机会
来自WWDC 286: "新的Instruments分析模板可让你观察优化空间并量化改进效果。"

Optimization: Prewarming

优化: 预加载

Problem: First request takes 1-2s to load model
Solution: Create session before user interaction
swift
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
    }
}
From WWDC 259: "Prewarming session before user interaction reduces initial latency."
Time saved: 1-2 seconds off first generation
问题: 第一个请求加载模型需要1-2秒
解决方案: 在用户交互前创建会话
swift
class ViewModel: ObservableObject {
    private var session: LanguageModelSession?

    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秒延迟

Optimization: includeSchemaInPrompt

优化: includeSchemaInPrompt

Problem: Large @Generable schemas increase token count
Solution: Skip schema insertion for subsequent requests
swift
// 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)
)
From WWDC 259: "Setting includeSchemaInPrompt to false decreases token count and latency for subsequent requests."
Time saved: 10-20% per request
问题: 大型@Generable模式会增加token数量
解决方案: 后续请求跳过模式插入
swift
// 第一个请求 - 插入模式
let first = try await session.respond(
    to: "生成第一个人物",
    generating: Person.self
)

// 后续请求 - 跳过模式
let second = try await session.respond(
    to: "再生成一个人物",
    generating: Person.self,
    options: GenerationOptions(includeSchemaInPrompt: false)
)
来自WWDC 259: "将includeSchemaInPrompt设置为false可减少后续请求的token数量和延迟。"
节省时间: 每个请求可节省10-20%时间

Optimization: Property Order

优化: 属性顺序

swift
// ✅ GOOD - Important properties first
@Generable
struct Article {
    var title: String      // Shows in 0.2s (streaming)
    var summary: String    // Shows in 0.8s
    var fullText: String   // Shows in 2.5s
}

// ❌ BAD - Important properties last
@Generable
struct Article {
    var fullText: String   // User waits 2.5s
    var summary: String
    var title: String
}
UX impact: Perceived latency drops from 2.5s to 0.2s with streaming

swift
// ✅ 推荐 - 重要属性优先
@Generable
struct Article {
    var title: String      // 流式传输时0.2秒即可显示
    var summary: String    // 0.8秒显示
    var fullText: String   // 2.5秒显示
}

// ❌ 不推荐 - 重要属性在后
@Generable
struct Article {
    var fullText: String   // 用户需要等待2.5秒
    var summary: String
    var title: String
}
用户体验影响: 配合流式传输,感知延迟从2.5秒降至0.2秒

Feedback & Analytics

反馈与分析

LanguageModelFeedbackAttachment

LanguageModelFeedbackAttachment

swift
let feedback = LanguageModelFeedbackAttachment(
    input: [
        // Input tokens/prompts
    ],
    output: [
        // Output tokens/content
    ],
    sentiment: .negative,
    issues: [
        LanguageModelFeedbackAttachment.Issue(
            category: .incorrect,
            explanation: "Model hallucinated facts"
        )
    ],
    desiredOutputExamples: [
        [
            // Example of desired output
        ]
    ]
)

let data = try JSONEncoder().encode(feedback)
// Attach to Feedback Assistant report
swift
let feedback = LanguageModelFeedbackAttachment(
    input: [
        // 输入token/提示词
    ],
    output: [
        // 输出token/内容
    ],
    sentiment: .negative,
    issues: [
        LanguageModelFeedbackAttachment.Issue(
            category: .incorrect,
            explanation: "模型生成了虚假信息"
        )
    ],
    desiredOutputExamples: [
        [
            // 期望输出示例
        ]
    ]
)

let data = try JSONEncoder().encode(feedback)
// 附加到Feedback Assistant报告中

From WWDC 286:22:13

来自WWDC 286:22:13

Use for:
  • Reporting quality issues
  • Providing examples of desired behavior
  • Helping Apple improve models
  • Tracking sentiment

用途:
  • 报告质量问题
  • 提供期望行为的示例
  • 帮助Apple改进模型
  • 跟踪情感倾向

Xcode Playgrounds

Xcode Playgrounds

Overview

概述

Xcode Playgrounds enable rapid iteration on prompts without rebuilding entire app.
Xcode Playgrounds支持在不重建整个应用的情况下快速迭代提示词。

Basic Usage

基础用法

swift
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"
    )
}
swift
import FoundationModels
import Playgrounds

#Playground {
    let session = LanguageModelSession()
    let response = try await session.respond(
        to: "日本之旅的好名字是什么?仅回复标题"
    )
}

From WWDC 286:2:28

来自WWDC 286:2:28

Accessing App Types

访问应用类型

swift
import FoundationModels
import Playgrounds

#Playground {
    let session = LanguageModelSession()
    for landmark in ModelData.shared.landmarks {
        let response = try await session.respond(
            to: "What's a good name for a trip to \(landmark.name)? Respond only with a title"
        )
    }
}
swift
import FoundationModels
import Playgrounds

#Playground {
    let session = LanguageModelSession()
    for landmark in ModelData.shared.landmarks {
        let response = try await session.respond(
            to: "去\(landmark.name)旅行的好名字是什么?仅回复标题"
        )
    }
}

From WWDC 286:2:43

来自WWDC 286:2:43

Benefit: Can access types defined in your app (like @Generable structs)

优势: 可访问应用中定义的类型(如@Generable结构体)

API Quick Reference

API快速参考

Classes

ClassPurpose
LanguageModelSession
Main interface for model interaction
SystemLanguageModel
Access to model availability and use cases
GenerationOptions
Configure sampling, temperature, schema inclusion
ToolOutput
Return value from Tool.call()
GeneratedContent
Dynamic structured output
DynamicGenerationSchema
Runtime schema definition
Transcript
Conversation history
用途
LanguageModelSession
与模型交互的主接口
SystemLanguageModel
访问模型可用性和用例
GenerationOptions
配置采样、温度、模式包含选项
ToolOutput
Tool.call()的返回值
GeneratedContent
动态结构化输出
DynamicGenerationSchema
运行时模式定义
Transcript
对话历史

Protocols

协议

ProtocolPurpose
Tool
Define custom tools for model to call
Generable
(Not direct protocol) Macro-generated conformance
协议用途
Tool
定义模型可调用的自定义工具
Generable
(非直接协议)宏生成的一致性

Macros

MacroPurpose
@Generable
Enable structured output for types
@Guide
Add constraints to @Generable properties
用途
@Generable
为类型启用结构化输出
@Guide
为@Generable属性添加约束

Enums

枚举

EnumPurpose
SystemLanguageModel.Availability
.available
or
.unavailable(reason)
GenerationError
Error types (context exceeded, guardrail, language)
SamplingMethod
.greedy
or
.random
枚举用途
SystemLanguageModel.Availability
.available
.unavailable(reason)
GenerationError
错误类型(上下文超出、安全策略、语言不支持)
SamplingMethod
.greedy
.random

Key Methods

关键方法

MethodReturnPurpose
session.respond(to:)
Response<String>
Generate text
session.respond(to:generating:)
Response<T>
Generate structured output
session.streamResponse(to:generating:)
AsyncSequence<T.PartiallyGenerated>
Stream structured output
方法返回值用途
session.respond(to:)
Response<String>
生成文本
session.respond(to:generating:)
Response<T>
生成结构化输出
session.streamResponse(to:generating:)
AsyncSequence<T.PartiallyGenerated>
流式传输结构化输出

Properties

属性

PropertyTypePurpose
session.transcript
Transcript
Conversation history
session.isResponding
Bool
Whether currently generating
SystemLanguageModel.default.availability
Availability
Model availability status
SystemLanguageModel.default.supportedLanguages
[Language]
Supported languages

属性类型用途
session.transcript
Transcript
对话历史
session.isResponding
Bool
是否正在生成内容
SystemLanguageModel.default.availability
Availability
模型可用性状态
SystemLanguageModel.default.supportedLanguages
[Language]
支持的语言

Migration Strategies

迁移策略

From Server LLMs

从云端LLM迁移

When to migrate:
  • Privacy concerns (data leaving device)
  • Offline requirements
  • Cost concerns (per-request fees)
  • Use case is summarization/extraction/classification
When NOT to migrate:
  • Need world knowledge
  • Need complex reasoning
  • Need very long context (>4096 tokens)
适合迁移的场景:
  • 隐私顾虑(数据离开设备)
  • 离线需求
  • 成本顾虑(按请求计费)
  • 用例为摘要/提取/分类
不适合迁移的场景:
  • 需要世界知识
  • 需要复杂推理
  • 需要超长上下文(>4096个token)

From Manual JSON Parsing

从手动JSON解析迁移

Before:
swift
let prompt = "Generate person as JSON"
let response = try await session.respond(to: prompt)
let data = response.content.data(using: .utf8)!
let person = try JSONDecoder().decode(Person.self, from: data)
After:
swift
@Generable
struct Person {
    let name: String
    let age: Int
}

let response = try await session.respond(
    to: "Generate a person",
    generating: Person.self
)
Benefits:
  • No parsing code
  • Guaranteed structure
  • Type safety
  • No crashes from invalid JSON

迁移前:
swift
let prompt = "以JSON格式生成人物"
let response = try await session.respond(to: prompt)
let data = response.content.data(using: .utf8)!
let person = try JSONDecoder().decode(Person.self, from: data)
迁移后:
swift
@Generable
struct Person {
    let name: String
    let age: Int
}

let response = try await session.respond(
    to: "生成一个人物",
    generating: Person.self
)
优势:
  • 无需解析代码
  • 保证结构正确
  • 类型安全
  • 不会因无效JSON崩溃

Resources

资源

WWDC: 286, 259, 301
Skills: axiom-foundation-models, axiom-foundation-models-diag

Last Updated: 2025-12-03 Version: 1.0.0 Skill Type: Reference Content: All WWDC 2025 code examples included
WWDC: 286, 259, 301
技能: axiom-foundation-models, axiom-foundation-models-diag

最后更新: 2025-12-03 版本: 1.0.0 技能类型: 参考文档 内容: 包含所有WWDC 2025代码示例