On iOS 27 and macOS 27, you conform a type to DynamicInstructions and another to LanguageModelSession.DynamicProfile. The profile body must resolve to one Profile. The framework re-evaluates that body on every prompt.
import FoundationModels
struct SupportCopy: DynamicInstructions {
var record: PromptRecord
var body: some DynamicInstructions {
Instructions { record.instructions }
}
}
struct SupportProfile: LanguageModelSession.DynamicProfile {
var registry: PromptRegistry
var body: some LanguageModelSession.DynamicProfile {
if let live = registry.live {
Profile { SupportCopy(record: live) }
} else {
Profile {
Instructions { "You are a brief support guide. Ask one clarifying question." }
}
}
}
}
let session = LanguageModelSession(profile: SupportProfile(registry: registry))
That sketch follows the WWDC26 Dynamic Profile shape. Confirm protocol names in the Xcode 27 SDK. Use switch or if / else so exactly one profile is active. Parallel if blocks are the wrong shape.
Put tools next to the instructions they need. A refund tool should not join a browse-only profile. A fat tool list costs context and can raise TTFT. Measure that in Stream tokens and measure speed. Grade the new text in Test AI behavior before you ship before you mark it live.
Next, A/B and rollback.
Key concepts
- Conform a type to
DynamicInstructionsand another toLanguageModelSession.DynamicProfile. - The Profile body must resolve to exactly one
Profileand re-evaluates every prompt. - Confirm protocol names in the Xcode 27 SDK.
- Put tools next to the instructions that need them.
Takeaways
- The registry picks the text. The Dynamic Profile applies it on the next prompt.
- Grade new text in evals and measure TTFT before marking it live.
- Exactly one profile is active per request.