Apple's Foundation Models framework moved beyond a single on-device session with iOS 27: you can now switch the model and instruction set at runtime within a session, plug in your own model provider through a protocol, and evaluate your prompts systematically. This post focuses on just three major capabilities added to the framework in 2026 after WWDC26: Dynamic Profiles, multimodal prompting, and the Performance and evaluation tools. We covered the basic session setup, @Generable, and the streaming API in Apple Foundation Models: On-Device LLM Framework; we don't repeat them here — we go straight to production scenarios, real API signatures, and the post-iOS-27-GA test checklist.
💡 Pro Tip:DynamicProfileBuilderenforces the single-active-profile constraint at compile time — useif/elseexpressions instead of parallelifblocks so the compiler verifies that constraint for you; design the switching logic from the start as an expression that returns a single profile.
Table of Contents
- Where the framework landed with iOS 27
- Why these three take priority
- Language Model protocol: plugging in your own provider
- When you should plug in your own provider
- Switching models/tools within a session via Dynamic Profiles
- Multimodal prompting: image analysis with Attachment
- What changes in practice
- Catching regressions with prompt evaluation (Performance and evaluation)
- On-device vs. Private Cloud Compute
- Selection criteria
- Post-iOS-27-GA adoption and test checklist
- Rollout order
- FAQ
- What do Dynamic Profiles do in the Apple Foundation Models framework?
- How does a third-party LLM provider get connected on iOS via the Language Model protocol?
- How is on-device model output evaluated, and how are regressions caught?
- What changed with Foundation Models in iOS 27?
- How big is the context window difference between SystemLanguageModel and PrivateCloudComputeLanguageModel?
- Conclusion
- Sources
Where the framework landed with iOS 27
The "What's new" section on Foundation Models framework's official reference page lists three new articles (and three WWDC26 sessions). The articles: adding server-side intelligence with Private Cloud Compute, composing dynamic sessions with instructions and profiles, and analyzing images with multimodal prompting. These three headings make up the actual delta on the Foundation Models side of iOS 27 — we cover all three in turn in this post.
iOS 27 reached general availability on September 14, 2026, following the announcements made at WWDC26 (June 8-12, 2026). Since the GA release shipped on that date, the APIs below are available in the stable release and don't require a beta flag.
Why these three take priority
Apple's own ordering isn't arbitrary: Private Cloud Compute expands the context window, Dynamic Profiles allow multiple task modes within the same session, and multimodal prompting removes the text-only limit. Together, the three make one LanguageModelSession reusable across different screens without rebuilding it each time.
Here's how the three articles' titles in the official docs map to the sections of this post:
"What's new" article | Section in this post |
|---|---|
Adding server-side intelligence with Private Cloud Compute | On-device vs. Private Cloud Compute |
Composing dynamic sessions with instructions and profiles | Switching models/tools within a session via Dynamic Profiles |
Analyzing images with multimodal prompting | Multimodal prompting: image analysis with Attachment |
Beyond these three, the Custom language model provider and Performance and evaluation sections don't stand as separate items in the "What's new" list, but both are part of the same documentation tree and directly affect production decisions — which is why I cover them as separate headings too.
Language Model protocol: plugging in your own provider
Foundation Models is no longer limited to Apple's own models. The framework offers a lightweight protocol, protocol LanguageModel: Sendable; the docs describe it verbatim as: "Implement this protocol to create a bridge between a model and the framework." On the provider side, an Executor does the heavy lifting — translating framework types into platform-specific requests and streaming results through LanguageModelExecutorGenerationChannel.
1import FoundationModels2 3// Framework declaration: protocol LanguageModel: Sendable4// (requirements per the docs: capabilities + Executor configuration)5// Once you plug in your provider, only one line changes at the call site:6let session = LanguageModelSession(model: MyCustomServerLanguageModel())The most practical part of this API surface: session.respond(to:) stays the same no matter the provider. Apple's own conforming types, SystemLanguageModel (on-device) and PrivateCloudComputeLanguageModel (server-side), conform to the same protocol — so switching between your provider and Apple's models needs no calling-code change, only the model: parameter.
When you should plug in your own provider
If you have an in-house fine-tuned model, a third-party API, or a service that must be hosted in a specific region for regulatory reasons, the LanguageModel protocol connects you to it without giving up Apple's session/tool-calling/streaming infrastructure. The provider is typically packaged as a Swift Package and added to the app.
Switching models/tools within a session via Dynamic Profiles
The Composing dynamic sessions with instructions and profiles article defines a three-layer architecture. Here are the layers, in the doc's own words: "Dynamic instructions: Re-evaluate before every model request and supply the instructions and tools needed at that time." "Profiles: Associate dynamic instructions with session-level properties, like which model to use and the reasoning level." "Dynamic profiles: Orchestrates transitions between multiple profiles and maintains one active profile at a time."
So at the bottom layer, the instructions themselves are re-evaluated on every request:
1import FoundationModels2 3struct PresentationInstructions: DynamicInstructions {4 var body: some DynamicInstructions {5 // Generate the instruction text based on the user's current screen context.6 Instructions("Help me improve my presentation.")7 }8}9 10let session = LanguageModelSession(11 dynamicInstructions: PresentationInstructions()12)One layer up, Profile pairs instructions with session-level settings like model choice, temperature, and reasoning level:
1Profile {2 // Instructions and tools needed for a creative task.3}4// Use the PCC model instance created in the outer profile.5.model(pccModel)6// Use higher creativity temperature for poetry fans.7.temperature(likesPoetry ? 0.8 : 0.1)8// Apply deeper reasoning for astronomy fans.9.reasoningLevel(likesAstronomy ? .deep : .light)reasoningLevel accepts values from the ContextOptions.ReasoningLevel enum, and there are four of them: deep, light, moderate, and custom(_:).
At the top, LanguageModelSession.DynamicProfile is a protocol; you write a type conforming to it to manage transitions between multiple profiles, and inside its body you pick profiles with if/else expressions — this is how the compiler verifies the single-active-profile constraint:
1import FoundationModels2 3struct PresentationProfile: LanguageModelSession.DynamicProfile {4 // Create an instance of the server model.5 var pccModel = PrivateCloudComputeLanguageModel()6 7 // The profile's data source.8 var isEditingImage = true9 var isEditingAnimation = false10 11 // Determine which profile to load based on the current state.12 var body: some LanguageModelSession.DynamicProfile {13 if isEditingImage {14 Profile {15 Instructions("Help with image-editing steps.")16 }17 } else if isEditingAnimation {18 Profile {19 Instructions("Improve the animation timing.")20 }21 .model(pccModel)22 .temperature(0.2)23 .reasoningLevel(.light)24 } else {25 Profile {26 Instructions("Help me improve my presentation.")27 }28 .temperature(0.8)29 }30 }31}32 33let session = LanguageModelSession(profile: PresentationProfile())To keep the conversation history at a reasonable length even as the profile changes, you apply the historyTransform modifier on top of the profile:
1Profile {2 Instructions("Help me generate book ideas.")3}4.historyTransform { history in5 // Apply a local transform before sending the request to the model; this6 // transform doesn't mutate the transcript's global state.7 Array(history.suffix(20))8}If you want to abstract away repeated behavior across profile transitions, protocol DynamicProfileModifier comes in — its only requirement is defining a type with a func body(content: Self.Content) -> Self.Body signature. The docs describe this as a way to bundle traits like model selection and temperature into a single self-contained modifier. In practice, you can use it to define shared low-temperature + onResponse logging behavior in one place between, say, a "research mode" and a "summarize mode"; the doc's DebugProfileModifier example does exactly this, combining the .temperature(0.0) and .onResponse { ... } traits into a single modifier.
Multimodal prompting: image analysis with Attachment
The Analyzing images with multimodal prompting article defines the Attachment struct for including images alongside text in a prompt. The example in the docs combines a text prompt and two images in the same request, and lets you supply orientation information when needed.
1import CoreGraphics2import FoundationModels3 4func compareImages(imageOne: CGImage, imageTwo: CGImage) async throws -> String {5 let session = LanguageModelSession()6 let response = try await session.respond {7 "Compare these two images by using three bullet points:"8 9 Attachment(imageOne)10 11 // If the image doesn't already have a rotation applied, transform it12 // with orientation before sending it to the model.13 Attachment(imageTwo, orientation: .right)14 }15 return response.content16}The example scenarios given in the docs cover four main use cases: image classification, summarizing a photo of a document, generating an image description for accessibility, and extracting a recipe idea from a photo of a refrigerator. All four work through the same Attachment API. The doc's "Use built-in image analysis tools" section adds: "The Vision framework provides optical character recognition (OCR) and barcode tools that you can add to a session in the Foundation Models framework." So if you need to extract text, you can add OCRTool to the same session, and if you need to read a barcode, you can add BarcodeReaderTool; it's recommended to supply Attachment/label(_:) when using a tool.
What changes in practice
Our earlier foundational post only covered text-only prompts with @Generable output. With multimodal prompting, you can now attach a photo the user just took directly to a prompt over the same LanguageModelSession and get a structured response back (a recipe object, say, or accessibility-description text); for flows needing text extraction or barcode reading, you add the Vision tool to the same session.
Catching regressions with prompt evaluation (Performance and evaluation)
The official name for this topic group in the Foundation Models reference is "Performance and evaluation," and it consists of three articles: Evaluating prompts to measure performance and improve model responses, Evaluating language model responses, and Analyzing the runtime performance of your Foundation Models app. The middle item points you to a separate framework introduced with iOS 27, Evaluations; Apple's Private Cloud Compute guide points to the same tool: "Start with the on-device model and evaluate it with the Evaluations framework." So the Foundation Models side of the guidance tells you what to test, while Evaluations tells you how to measure it with data sets and metrics. A direct quote from the evaluation article: "Prompt evaluation is the practice of thoroughly testing your prompts against real-world scenarios to measure quality, catch failures early, and confidently improve your feature over time."
The practical consequence of this definition: when you switch a profile with Dynamic Profiles (say, a research mode using reasoningLevel(.deep)), you need to re-test the prompts tied to that profile against real-world scenarios — otherwise you won't notice if one profile transition silently breaks another. Apple also supports this workflow on the Python side: the docs reference a Python Foundation Models SDK at github.com/apple/python-apple-fm-sdk, meaning you can set up these test sets outside of Swift too; I prefer wiring it into CI.
On the runtime side, you can inspect token consumption and response times of the prompt/response loop through Instruments — this matters especially once you move to Private Cloud Compute and the context window grows.
On-device vs. Private Cloud Compute
The Adding server-side intelligence with Private Cloud Compute article summarizes the difference between the two models in a table. The table below carries these differences over verbatim:
Feature | SystemLanguageModel | PrivateCloudComputeLanguageModel |
|---|---|---|
Preserves privacy | Yes | Yes |
Works offline | Yes | No |
Usage limit | Unlimited | Has a daily limit |
Reasoning support | Not supported | Supports multiple levels |
Context window | 4K | 32K |
The platform requirement is explicit in the docs: "PrivateCloudComputeLanguageModel is available on iOS 27, macOS 27, watchOS 27, and visionOS 27 or later." So this model won't compile without an availability guard:
1func makeSession() -> LanguageModelSession {2 if #available(iOS 27.0, macOS 27.0, watchOS 27.0, visionOS 27.0, *) {3 return LanguageModelSession(model: PrivateCloudComputeLanguageModel())4 }5 return LanguageModelSession(model: SystemLanguageModel())6}Selection criteria
For long document summarization beyond the 4K context window, or multi-step reasoning tasks, switching to Private Cloud Compute makes sense; but since you're subject to a daily usage limit, staying on the on-device SystemLanguageModel for short, high-volume requests (instant suggestions, say) keeps both latency and cost low. Dynamic Profiles lets you switch between the two exactly where needed, within the same session, without the user noticing.
Post-iOS-27-GA adoption and test checklist
Now that iOS 27 is GA (September 14, 2026), here are the items to check before rolling out Dynamic Profiles and Private Cloud Compute in your production app:
- Don't forget the availability guard:
PrivateCloudComputeLanguageModelonly exists on iOS 27/macOS 27/watchOS 27/visionOS 27 and later; aSystemLanguageModelfallback is a must for users on older OS versions. - Build a separate evaluation set for each profile: each
Profileinside aDynamicProfilecan carry a differenttemperature/reasoningLevelcombination, so a single evaluation set can't cover all profiles. - Bound history growth with
historyTransform: if profile transitions are frequent, the context window (especially at the 4K on-device limit) can fill up quickly without a cutoff likeArray(history.suffix(20)). - Test Attachment-based flows separately: multimodal prompts have a different latency profile than text-only prompts, so they should be measured separately with Instruments.
- Isolate-test the Executor layer before shipping your own
LanguageModelprovider: verify that results streamed throughLanguageModelExecutorGenerationChannelare correctly streamed independent of the code that callssession.respond(to:). - Wire the evaluation set into CI (recommended): the Python Foundation Models SDK referenced in the docs (
github.com/apple/python-apple-fm-sdk) lets you set up this suite outside of Swift; I usually add it to the build pipeline and run it automatically on every profile change, so regressions are caught without waiting for manual testing. - Don't skip runtime performance measurement: the Analyzing the runtime performance of your Foundation Models app article recommends tracking token consumption and response times through Instruments; keeping this measurement separate for profiles that move to Private Cloud Compute lets you see early how close you are to the daily usage limit.
Rollout order
It's safer to apply the items above in sequence rather than all at once: first the availability guards and fallback, then the evaluation set for each profile, then isolate-testing the Attachment flows and Executor layer, and finally wiring the evaluation set into CI and making runtime measurement continuous. This ordering surfaces early the errors that show up when you skip a step and jump ahead (testing Private Cloud Compute without an availability guard, for example).
GOLDEN TIP
The most valuable insight in this article
This tip holds the article's most important takeaway.
Easter Egg
You found a hidden gem!
There's a hidden detail in this section. Want to uncover it?
Reader Reward
To help you gather your checklist in one place while shipping the 2026 additions to Foundation Models, here's a short summary of the APIs and checklist items covered in this post. Review this list before adding a new Dynamic Profile or Attachment flow.
FAQ
What do Dynamic Profiles do in the Apple Foundation Models framework?
Dynamic Profiles is a three-layer API that lets you change the model, instructions, and session settings at runtime, based on your app's state, within a LanguageModelSession: at the bottom, Dynamic Instructions is re-evaluated on every request; in the middle, Profile associates instructions with settings like model choice and reasoning level; and at the top, DynamicProfile manages transitions between multiple profiles and keeps only one profile active at a time.
How does a third-party LLM provider get connected on iOS via the Language Model protocol?
The provider defines a type conforming to protocol LanguageModel: Sendable; the actual translation work is handled by an Executor that converts framework types into platform-specific requests and streams the results through LanguageModelExecutorGenerationChannel. Integration on the caller's side is a single line: LanguageModelSession(model: MyCustomServerLanguageModel()), after which the same session.respond(to:) API surface continues to be used.
How is on-device model output evaluated, and how are regressions caught?
Apple provides three official guides under "Performance and evaluation": Evaluating prompts to measure performance and improve model responses covers systematically testing prompts against real-world scenarios; Evaluating language model responses shows response scoring over a sample set via the Evaluations framework from iOS 27; and Analyzing the runtime performance of your Foundation Models app covers measuring token consumption and response times with Instruments. You can also set these suites up outside Swift with the Python Foundation Models SDK (github.com/apple/python-apple-fm-sdk); I prefer wiring it into CI.
What changed with Foundation Models in iOS 27?
According to the "What's new" section, three things were added: server-side intelligence via Private Cloud Compute (a larger context window and multi-level reasoning), runtime instruction/model switching via Dynamic Profiles, and analyzing images alongside text via multimodal prompting. iOS 27 reached general availability on September 14, 2026, after being announced at WWDC26 (June 8-12, 2026).
How big is the context window difference between SystemLanguageModel and PrivateCloudComputeLanguageModel?
SystemLanguageModel works offline with unlimited usage at a 4K context window, while PrivateCloudComputeLanguageModel offers a 32K context window and multi-level reasoning, but is subject to a daily usage limit and doesn't work offline; it's also only available on iOS 27/macOS 27/watchOS 27/visionOS 27 and later.
Conclusion
iOS 27 took Foundation Models beyond its single-model, single-instruction limits into a platform that switches at runtime, accepts your own provider, and can be evaluated systematically. With Dynamic Profiles you switch model/instructions by task mode within the same session, bring images into a prompt with Attachment, and verify with the Performance and evaluation guides that these changes don't cause regressions.
If you're not yet comfortable with the basic session/@Generable/streaming API, check out Apple Foundation Models: On-Device LLM Framework first. For the on-device pipeline with Core ML, Apple Intelligence and On-Device AI Pipeline with Core ML completes the picture. For a cross-platform comparison, Gemini Nano: iOS/Android Cross-Platform On-Device AI is a good reference. For general on-device ML infrastructure, see On-Device Machine Learning on iOS and On-Device Machine Learning with Core ML.
Sources
- Foundation Models — Apple Developer Documentation — the framework's main reference page; the "What's new" section lists the iOS 27 additions.
- LanguageModel protocol — the protocol and Executor pattern used to plug in custom model providers.
- Composing dynamic sessions with instructions and profiles — the official definition and code examples for Dynamic Instructions, Profile, and DynamicProfile.
- Analyzing images with multimodal prompting — the
AttachmentAPI and its usage scenarios. - Adding server-side intelligence with Private Cloud Compute — the on-device/PCC comparison table and platform requirements.
- Evaluating prompts to measure performance and improve model responses — the Performance and evaluation guide.
- iOS 27 — Wikipedia — cross-verification of the GA date (September 14, 2026) and the WWDC26 announcement date.
Tags
iOS Development News
Weekly Swift tips, SwiftUI tricks and iOS best practices. No spam, only valuable content.
Your subscription starts when you open the link in the confirmation email and press “Confirm my subscription”. The newsletter keeps open/click statistics; you can unsubscribe anytime with one click. Privacy
