Unlock Local AI on iOS: A Hands‑On Guide to Apple’s Foundation Models Framework

This article introduces Apple’s Foundation Models framework, explaining its core features, system requirements, and step‑by‑step Swift code for importing the framework, checking model availability, creating sessions, handling generation options, guided output, tool calling, streaming responses, and maintaining conversational context for privacy‑preserving on‑device AI.

WeiLi Technology Team
WeiLi Technology Team
WeiLi Technology Team
Unlock Local AI on iOS: A Hands‑On Guide to Apple’s Foundation Models Framework

Overview

Apple Intelligence Foundation Models is a new API announced at WWDC 2025 that lets developers run local AI models directly on iOS, iPadOS, macOS, and visionOS devices, ensuring privacy by keeping all data processing on the device.

Core Features

Local Execution : All data stays on the device, protecting user privacy.

Offline Availability : No network connection required.

Swift Native Support : Seamlessly integrates with Swift language features.

Multi‑Platform Support : Works on iOS, iPadOS, macOS, and visionOS.

System Requirements

iOS 26 or later

Devices that support Apple Intelligence

Apple Intelligence must be enabled in Settings

Importing the Framework

import FoundationModels

Checking Model Availability

import FoundationModels

// Check model availability
if SystemLanguageModel.default.availability == .available {
    print("Foundation Models available")
} else {
    print("Foundation Models unavailable")
}

let supportedLanguages = SystemLanguageModel.default.supportedLanguages
guard supportedLanguages.contains(Locale.current.language) else { return }

Basic Usage

Initialize a LanguageModelSession with optional instructions and call respond(to:) to get a response. Only one request can be processed at a time; check isResponding before sending a new request.

import FoundationModels
import Playgrounds

func respond(userInput: String) async throws -> String {
    let session = LanguageModelSession(instructions: """
    You are a professional tour guide.
    Respond to the tourist’s question.
    """)
    do {
        let response = try await session.respond(to: userInput)
        return response.content
    } catch LanguageModelSession.GenerationError.exceededContextWindowSize {
        // Handle context overflow
    }
}

The model’s context window is limited to 4096 tokens; exceeding it throws GenerationError.exceededContextWindowSize. When this happens, start a new session or split the input into smaller chunks.

Generation Options

// Configure generation parameters
let options = GenerationOptions(temperature: 2.0)
let session = LanguageModelSession()
let prompt = "Write me a story about coffee."
let response = try await session.respond(to: prompt, options: options)

Guided Generation (Structured Output)

Define output structures with @Generable and @Guide macros so the model returns data in a specific format.

import FoundationModels

@Generable
struct SearchSuggestions {
    @Guide("Name of the suggested landmark")
    let name: String
    @Guide(description: "Related keywords (max 4)", .count(4))
    let keywords: [String]
    @Guide("Category such as culture, nature, entertainment")
    let category: String
    @Guide("Priority from 1 to 10")
    let priority: Int
}

Use the struct when calling the model:

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)
let suggestions = response.content
print("Name: \(suggestions.name)")
print("Keywords: \(suggestions.keywords.joined(separator: ", "))")
print("Category: \(suggestions.category)")
print("Priority: \(suggestions.priority)")

Streaming Output

For structured formats like JSON, stream tokens as complete units to avoid parsing errors.

let stream = session.streamResponse(to: "prompt", generating: SearchSuggestions.self)
for try await suggestions in stream {
    print(suggestions)
}

Tool Calling

Define custom tools that the model can invoke, providing name and description. Use @Generable and @Guide to describe tool arguments.

import CoreLocation
import WeatherKit

struct GetWeatherTool: Tool {
    let name = "GetWeather"
    let description = "Get current weather for a city"
    @Generable
    struct Arguments {
        @Guide("City name to query")
        let city: String
    }
    func call(with arguments: Arguments) async throws -> ToolOutput {
        let geocoder = CLGeocoder()
        let placemarks = try await geocoder.geocodeAddressString(arguments.city)
        guard let location = placemarks.first?.location else {
            return "Unable to find city: \(arguments.city)"
        }
        let weather = try await WeatherService.shared.weather(for: location)
        let temperature = weather.currentWeather.temperature.value
        let condition = weather.currentWeather.condition.description
        return ToolOutput("\(arguments.city) weather: \(condition), \(Int(temperature))°C")
    }
}

struct CreateCalendarEventTool: Tool {
    let name = "CreateCalendarEvent"
    let description = "Create a new calendar event"
    @Generable
    struct Arguments {
        @Guide("Event title")
        let title: String
        @Guide("Date (YYYY‑MM‑DD)")
        let date: String
        @Guide("Time (HH:MM)")
        let time: String
        @Guide("Optional description")
        let description: String?
    }
    func call(with arguments: Arguments) async throws -> ToolOutput {
        return ToolOutput("Created event: \(arguments.title) at \(arguments.date) \(arguments.time)")
    }
}

Initialize a session with these tools and let the model decide when to call them.

class ToolEnabledService {
    private var session: LanguageModelSession?
    func initializeSession() async throws {
        session = try await LanguageModelSession(
            tools: [GetWeatherTool(), CreateCalendarEventTool()],
            instructions: """
            You are an assistant that can fetch weather and create calendar events.
            Use GetWeather for weather queries and CreateCalendarEvent for scheduling.
            """
        )
    }
    func handleUserRequest(_ request: String) async throws -> String {
        guard let session = session else { throw AIError.sessionNotInitialized }
        let response = try await session.response(to: request)
        return response.content
    }
}

Session Context Memory

The LanguageModelSession automatically retains conversation history, allowing follow‑up queries to be understood in context.

class ContextAwareService {
    private var session: LanguageModelSession?
    func initializeSession() async throws { session = try await LanguageModelSession() }
    func continuousChat() async throws {
        guard let session = session else { throw AIError.sessionNotInitialized }
        let r1 = try await session.response(to: "Write a haiku about fish")
        print("AI: \(r1.content)")
        let r2 = try await session.response(to: "Now write one about golf")
        print("AI: \(r2.content)")
        print("
=== Transcript ===")
        for msg in session.transcript { print("\(msg.role): \(msg.content)") }
    }
}

Use‑Case Adapters

Foundation Models provides specialized adapters for tasks such as content tagging.

class ContentTaggingService {
    private var session: LanguageModelSession?
    func initializeSession() async throws {
        let model = SystemLanguageModel(useCase: .contentTagging)
        session = try await LanguageModelSession(model: model)
    }
    func tagContent(_ content: String) async throws -> [String] {
        guard let session = session else { throw AIError.sessionNotInitialized }
        let prompt = "Generate tags for: \(content)"
        let response = try await session.response(to: prompt)
        return response.content.components(separatedBy: ",").map { $0.trimmingCharacters(in: .whitespaces) }
    }
    func extractEntities(from text: String) async throws -> [String] {
        guard let session = session else { throw AIError.sessionNotInitialized }
        let prompt = "Extract entities from: \(text)"
        let response = try await session.response(to: prompt)
        return response.content.components(separatedBy: "
").filter { !$0.isEmpty }
    }
}

Real‑World Examples

Intelligent notes app and customer‑service bot demonstrate how to combine tools, structured output, and context‑aware conversations.

// Intelligent Notes App (excerpt)
class IntelligentNotesApp {
    private var session: LanguageModelSession?
    init() { Task { try await initializeAI() } }
    private func initializeAI() async throws {
        session = try await LanguageModelSession(
            tools: [SummarizeNotesTool(), ExtractKeywordsTool()],
            instructions: "You are a smart note assistant."
        )
    }
    func summarizeNote(_ content: String) async throws -> String { /* ... */ }
    func extractKeywords(from content: String) async throws -> [String] { /* ... */ }
    @Generable
    struct NoteCategory { /* ... */ }
    func categorizeNote(_ content: String) async throws -> NoteCategory { /* ... */ }
}

// Customer Service Bot (excerpt)
class CustomerServiceBot {
    private var session: LanguageModelSession?
    init() { Task { try await setupBot() } }
    private func setupBot() async throws {
        session = try await LanguageModelSession(
            tools: [OrderLookupTool(), RefundProcessTool(), FAQSearchTool()],
            instructions: "You are a polite, patient service assistant."
        )
    }
    @Generable
    struct CustomerIntent { /* ... */ }
    func analyzeCustomerMessage(_ message: String) async throws -> CustomerIntent { /* ... */ }
    func respondToCustomer(_ message: String) async throws -> String { /* ... */ }
}

Foundation Models empowers iOS developers to embed powerful, privacy‑preserving AI directly into apps, enabling personalized and intelligent experiences across a wide range of use cases.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

iOS developmentSwiftApple IntelligenceLocal AIfoundation-models
WeiLi Technology Team
Written by

WeiLi Technology Team

Practicing data-driven principles and believing technology can change the world.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.