2025 AI & Machine Learning
WWDC25 · 23 min · AI & Machine Learning
Meet the Foundation Models framework
Learn how to tap into the on-device large language model behind Apple Intelligence! This high-level overview covers everything from guided generation for generating Swift data structures and streaming for responsive experiences, to tool calling for integrating data sources and sessions for context management. This session has no prerequisites.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 19 snippets
Playground - Trip to Japan
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")
} Playground - Loop over landmarks
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")
}
} Creating a Generable struct
// Creating a Generable struct
struct SearchSuggestions {
(description: "A list of suggested search terms", .count(4))
var searchTerms: [String]
} Responding with a Generable type
// Responding with a Generable type
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) Composing Generable types
// Composing Generable types
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]
} PartiallyGenerated types
// PartiallyGenerated types
struct Itinerary {
var name: String
var days: [Day]
} Streaming partial generations
// Streaming partial generations
let stream = session.streamResponse(
to: "Craft a 3-day itinerary to Mt. Fuji.",
generating: Itinerary.self
)
for try await partial in stream {
print(partial)
} Streaming itinerary view
struct ItineraryView: View {
let session: LanguageModelSession
let dayCount: Int
let landmarkName: String
private var itinerary: Itinerary.PartiallyGenerated?
var body: some View {
//...
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)
}
}
}
}
} Property order matters
struct Itinerary {
(description: "Plans for each day")
var days: [DayPlan]
(description: "A brief summary of plans")
var summary: String
} Defining a tool
// Defining a tool
import WeatherKit
import CoreLocation
import FoundationModels
struct GetWeatherTool: Tool {
let name = "getWeather"
let description = "Retrieve the latest weather information for a city"
struct Arguments {
(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
}
} Attaching tools to a session
// Attaching tools to a session
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! Supplying custom instructions
// Supplying custom instructions
let session = LanguageModelSession(
instructions: """
You are a helpful assistant who always \
responds in rhyme.
"""
) Multi-turn interactions
// Multi-turn interactions
let session = LanguageModelSession()
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.
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)
// (Prompt) Write a haiku about fishing
// (Response) Silent waters gleam...
// (Prompt) Do another one about golf
// (Response) Silent morning dew... Gate on isResponding
import SwiftUI
import FoundationModels
struct HaikuView: View {
private var session = LanguageModelSession()
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)
}
} Using a built-in use case
// Using a built-in use case
let session = LanguageModelSession(
model: SystemLanguageModel(useCase: .contentTagging)
) Content tagging use case - 1
// Content tagging use case
struct Result {
let topics: [String]
}
let session = LanguageModelSession(model: SystemLanguageModel(useCase: .contentTagging))
let response = try await session.respond(to: ..., generating: Result.self) Content tagging use case - 2
// Content tagging use case
struct Top3ActionEmotionResult {
(.maximumCount(3))
let actions: [String]
(.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: ..., generating: Top3ActionEmotionResult.self) Availability checking
// Availability checking
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)")
}
}
} Encodable feedback attachment data structure
let feedback = LanguageModelFeedbackAttachment(
input: [
// ...
],
output: [
// ...
],
sentiment: .negative,
issues: [
LanguageModelFeedbackAttachment.Issue(
category: .incorrect,
explanation: "..."
)
],
desiredOutputExamples: [
[
// ...
]
]
)
let data = try JSONEncoder().encode(feedback) Resources
Related sessions
-
19 min -
22 min -
31 min -
26 min