axiom-foundation-models-ref
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFoundation 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:
- — Discipline skill with anti-patterns, pressure scenarios, decision trees
axiom-foundation-models - — Diagnostic skill for troubleshooting issues
axiom-foundation-models-diag
在以下场景使用本参考文档:
- 实现Foundation Models功能时
- 了解API能力时
- 查找特定代码示例时
- 基于Foundation Models规划架构时
- 从原型迁移到生产环境时
- 调试实现问题时
相关技能:
- — 包含反模式、压力场景、决策树的专业技能
axiom-foundation-models - — 用于排查问题的诊断技能
axiom-foundation-models-diag
LanguageModelSession
LanguageModelSession
Overview
概述
LanguageModelSessionLanguageModelSessionCreating 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 adds prompt to transcript
respond(to:)
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: with property
Response<String>.content返回类型: 带属性的
.contentResponse<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: with property
Response<SearchSuggestions>.content返回类型: 带属性的
.contentResponse<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 historyswift
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 call adds entry to transcript
respond() - 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@GenerableBasic 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,DoubleDecimal Bool
Collections:
- (arrays)
[ElementType]
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,DoubleDecimal 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:
- macro generates schema at compile-time
@Generable - Schema defines valid token sequences
- During generation, model creates probability distribution for next token
- Framework masks out invalid tokens based on schema
- Model can only pick tokens valid according to schema
- 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)
工作原理:
- 宏在编译时生成模式
@Generable - 模式定义有效的token序列
- 生成过程中,模型为下一个token创建概率分布
- 框架根据模式屏蔽无效token
- 模型只能选择符合模式的有效token
- 保证结构正确性 - 不会出现幻觉字段,不会生成无效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 types with optional properties that fill in progressively.
PartiallyGeneratedFoundation Models使用快照流式传输(而非增量流式传输)。框架不传输原始增量,而是传输类型,该类型包含会逐步填充的可选属性。
PartiallyGeneratedPartiallyGenerated Type
PartiallyGenerated类型
The macro automatically creates a nested type:
@GenerablePartiallyGeneratedswift
@Generable
struct Itinerary {
var name: String
var days: [DayPlan]
}
// Compiler generates:
extension Itinerary {
struct PartiallyGenerated {
var name: String? // All properties optional!
var days: [DayPlan]?
}
}@GenerablePartiallyGeneratedswift
@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:
- Session initialized with tools
- User prompt: "What's Tokyo's weather?"
- Model analyzes prompt, decides weather data needed
- Model generates tool call:
getWeather(city: "Tokyo") - Framework calls method
call() - Your code fetches real data from API
- Tool output inserted into transcript
- 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."
工作原理:
- 初始化会话并传入工具
- 用户提示: "东京的天气如何?"
- 模型分析提示,判断需要天气数据
- 模型生成工具调用:
getWeather(city: "Tokyo") - 框架调用方法
call() - 你的代码从API获取真实数据
- 工具输出被插入到对话历史中
- 模型使用工具输出生成最终回复
来自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 instead of :
classstructswift
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)
}
}工具可使用而非来维护跨调用的状态:
classstructswift
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:
- Natural language (String):
swift
return ToolOutput("Temperature is 71°F")- Structured (GeneratedContent):
swift
let content = GeneratedContent(properties: ["temperature": 71])
return ToolOutput(content)两种形式:
- 自然语言(字符串):
swift
return ToolOutput("气温为71°F")- 结构化(GeneratedContent):
swift
let content = GeneratedContent(properties: ["temperature": 71])
return ToolOutput(content)Tool Naming Best Practices
工具命名最佳实践
DO:
- Short, readable names: ,
getWeatherfindContact - Use verbs: ,
get,find,fetchcreate - 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."
推荐:
- 简短、易读的名称: ,
getWeatherfindContact - 使用动词: ,
get,find,fetchcreate - 描述为一句话
- 描述保持简洁(会被包含在提示词中)
不推荐:
- 使用缩写:
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 whenswift
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
概述
DynamicGenerationSchemaDynamicGenerationSchemaCreating 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.rootFrom 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 timeGreedy 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 outputHigh 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:
- : Very focused
0.1-0.5 - (default): Balanced
1.0 - : Very creative
1.5-2.0
温度范围:
- : 高度聚焦
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 reportswift
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
类
| Class | Purpose |
|---|---|
| Main interface for model interaction |
| Access to model availability and use cases |
| Configure sampling, temperature, schema inclusion |
| Return value from Tool.call() |
| Dynamic structured output |
| Runtime schema definition |
| Conversation history |
| 类 | 用途 |
|---|---|
| 与模型交互的主接口 |
| 访问模型可用性和用例 |
| 配置采样、温度、模式包含选项 |
| Tool.call()的返回值 |
| 动态结构化输出 |
| 运行时模式定义 |
| 对话历史 |
Protocols
协议
| Protocol | Purpose |
|---|---|
| Define custom tools for model to call |
| (Not direct protocol) Macro-generated conformance |
| 协议 | 用途 |
|---|---|
| 定义模型可调用的自定义工具 |
| (非直接协议)宏生成的一致性 |
Macros
宏
| Macro | Purpose |
|---|---|
| Enable structured output for types |
| Add constraints to @Generable properties |
| 宏 | 用途 |
|---|---|
| 为类型启用结构化输出 |
| 为@Generable属性添加约束 |
Enums
枚举
| Enum | Purpose |
|---|---|
| |
| Error types (context exceeded, guardrail, language) |
| |
| 枚举 | 用途 |
|---|---|
| |
| 错误类型(上下文超出、安全策略、语言不支持) |
| |
Key Methods
关键方法
| Method | Return | Purpose |
|---|---|---|
| | Generate text |
| | Generate structured output |
| | Stream structured output |
| 方法 | 返回值 | 用途 |
|---|---|---|
| | 生成文本 |
| | 生成结构化输出 |
| | 流式传输结构化输出 |
Properties
属性
| Property | Type | Purpose |
|---|---|---|
| | Conversation history |
| | Whether currently generating |
| | Model availability status |
| | Supported languages |
| 属性 | 类型 | 用途 |
|---|---|---|
| | 对话历史 |
| | 是否正在生成内容 |
| | 模型可用性状态 |
| | 支持的语言 |
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代码示例