Foundation Models framework in a business app: what works
What Apple's on-device Foundation Models framework can do in a business app: summaries, field extraction, sorting, device limits and the 5.1.2(i) consent rule.
In short:
- Apple’s Foundation Models framework gives an iOS 26 app direct access to the model behind Apple Intelligence. It runs on the device, works offline, and Apple lists no usage limit for it.
- It needs an Apple Intelligence iPhone: iPhone 15 Pro or later. The base model, AFM Core, has 3 billion parameters and a context window of 4K to 8K tokens per session. On iOS 27, iPhone Air, iPhone 17 Pro, iPhone 18 Pro and iPhone Duo get AFM Core Advanced, with 20 billion parameters and 8K tokens. Read
contextSizeat runtime for the exact figure. - Apple says the on-device model is suited to summarizing, extracting details, classifying and tagging text. It says to avoid basic math, writing code and logical reasoning.
- Guided generation fills in a Swift type you define, so a field extraction always comes back as a typed struct with no JSON to parse.
- For longer documents, iOS 27 adds Apple’s Private Cloud Compute model (32K tokens, a daily limit per person). If you send personal data to someone else’s AI instead, App Review Guideline 5.1.2(i) requires a clear disclosure and explicit permission first.
Which devices and OS versions can run it?
Apple publishes the matrix on its page about detecting available models. For iPhones:
| iPhone | AFM Core (on device, 3B) | AFM Core Advanced (on device, 20B) | AFM Cloud (Private Cloud Compute) |
|---|---|---|---|
| iPhone 15 Pro and 15 Pro Max, all iPhone 16 models, iPhone 17 | Yes | No | Yes, iOS 27 |
| iPhone Air, iPhone 17 Pro and 17 Pro Max | iOS 26 | iOS 27 | Yes, iOS 27 |
| iPhone 18 Pro models, iPhone Duo | No | Yes | Yes, iOS 27 |
Every device has exactly one on-device model, and your app can’t choose which. iPads need an M1 chip or later (or the iPad mini with A17 Pro), and Macs need M1 or later. Apple’s Apple Intelligence support page adds three conditions that catch business users out:
- Storage. Apple Intelligence needs up to 8 GB free, or up to 14 GB on newer models such as iPhone Air and iPhone 17 Pro and later.
- Language. The device language and Siri language must match a supported language. The current list has 16, including English, French, German, Spanish, Japanese, Korean and both forms of Chinese. Arabic and Hindi aren’t on it.
- China. Apple Intelligence doesn’t currently work on devices bought in mainland China.
Plan for staff or customers whose phones can’t run it. Your app needs a fallback path, even if that path is “this feature isn’t available on this device”.
What is the Foundation Models framework good at?
Apple’s guide to generating content lists what the on-device model handles: summarizing, extracting entities, understanding text, refining or editing text, classifying, writing creative text and generating tags. It lists three things to avoid: basic math, creating code and logical reasoning.
Some common business tasks, sorted into Apple’s categories:
| Task in a business app | Apple’s category | Fit |
|---|---|---|
| Summarize notes from a customer visit | Summarize | Good, if the notes fit the context window |
| Pull supplier, invoice number and total from an email | Extract entities | Good, with guided generation |
| Route an inbound email to the right team | Classify | Good, with a fixed list of teams |
| Tidy a field technician’s dictated report | Refine or edit text | Good |
| Add up the line items on an invoice | Basic math | Avoid. Do the sum in Swift |
| Answer questions about a 40-page contract | Understand text | Too long for one session. See below |
How do you test it on your own tasks?
Model quality depends on your documents, so build a small test set before you commit to the feature. For each task, collect 20 to 50 real examples with personal details removed, and write down the right answer before you run anything:
| Task | Example input | Pass rule |
|---|---|---|
| Summarize | Customer visit notes, 150 to 400 words | The summary includes every fact a person marked as required and states nothing false |
| Extract | Supplier invoice emails | All five fields match exactly |
| Classify | Inbound emails | The team matches the one a person chose |
Then measure two things on real devices:
- Pass rate per task. Run each task on at least one AFM Core phone and one AFM Core Advanced phone. Apple says you often get the best quality by tuning a feature to the specific model present.
- Response time. Apple suggests Xcode Instruments for timing requests, and its Foundation Models template shows each request and the tokens it used. Apple’s guide on managing the context window explains how to record with it. Test on the oldest phone you support.
Keep the test set and run it again after every iOS update. Apple updates the on-device model as part of the operating system: AFM 2 came with iOS 26.0, AFM 2.1 with iOS 26.4 and AFM 3 with iOS 27, and Apple has a page on updating prompts for new model versions.
Swift: guided generation for field extraction
With guided generation, you describe the output as a Swift type marked @Generable, and the framework uses constrained sampling so the model can only produce a valid instance of that type. For business data, that removes the parsing step entirely. This code compiles against the iOS 26 SDK:
import Foundation
import FoundationModels
@Generable(description: "Fields from a supplier invoice email")
struct InvoiceFields {
var supplierName: String
@Guide(description: "The invoice number exactly as written")
var invoiceNumber: String
@Guide(description: "The total amount due, as a number")
var total: Decimal
@Guide(.anyOf(["USD", "GBP", "EUR", "AED", "AUD", "INR"]))
var currency: String
@Guide(description: "Due date as YYYY-MM-DD, or nil if the email gives none")
var dueDate: String?
}
enum AIFeatureError: Error { case modelUnavailable }
func extractInvoice(from email: String) async throws -> InvoiceFields {
// Older iPhones, Apple Intelligence turned off, or a model still downloading.
guard SystemLanguageModel.default.isAvailable else {
throw AIFeatureError.modelUnavailable
}
let session = LanguageModelSession(instructions: """
Extract invoice details from the email. Copy values exactly \
as written. If the email gives no due date, leave it out.
""")
let response = try await session.respond(
to: email,
generating: InvoiceFields.self,
options: GenerationOptions(sampling: .greedy)
)
return response.content
}
Notes on the code:
.anyOflimits the currency to the codes your accounts system accepts, so the model can’t invent one.- Greedy sampling, in Apple’s words, “always produces the same output for a given input”. That makes test runs repeatable.
- The model copies the total from the email and does no arithmetic. If you need to check the total against the line items, do that sum in Swift.
- Apple notes the model generates properties in the order you declare them, which matters when one field depends on another.
Sorting emails works the same way with an enum:
@Generable
enum Department {
case accounts, sales, support, other
}
func route(_ email: String) async throws -> Department {
let session = LanguageModelSession(instructions: "Pick the team that should handle this email.")
return try await session.respond(to: email, generating: Department.self).content
}
When you need a cloud model: Apple’s 5.1.2(i) consent rule
The on-device context window, 4K to 8K tokens, is the limit you hit first. Apple’s own answer is to split long text into chunks, summarize each chunk in a fresh session, then summarize the summaries. That works for a long report and is a poor fit for questions that need the whole contract in view at once. For those, you have two cloud options.
Apple’s Private Cloud Compute model arrived with iOS 27. It has a 32K-token context and adjustable reasoning, and switching a session to it is a one-line change. Each person gets a daily request limit, which they can raise with an iCloud+ upgrade, and your app needs a managed entitlement that Apple grants against eligibility requirements.
A third-party model, such as one from OpenAI, Anthropic or Google, called through your own server, brings App Review Guideline 5.1.2(i) into play. Apple clarified it on 13 November 2025, and it now reads: “You must clearly disclose where personal data will be shared with third parties, including with third-party AI, and obtain explicit permission before doing so.”
The SwiftUI consent pattern below follows that wording and compiles against the iOS 26 SDK. App Review makes the final call on any given screen, so treat it as a starting point:
import SwiftUI
enum AIConsent: String {
case notAsked, allowed, declined
}
struct CloudSummaryButton: View {
// One key per provider, so switching provider means asking again.
@AppStorage("consent.openai.v1") private var consent: AIConsent = .notAsked
@State private var askingForConsent = false
let note: String
var body: some View {
Button("Summarize with cloud AI") {
if consent == .allowed { send() } else { askingForConsent = true }
}
.sheet(isPresented: $askingForConsent) {
ConsentSheet(
provider: "OpenAI",
sentData: "The text of this note, including any names, phone numbers or addresses in it",
onAllow: { consent = .allowed; askingForConsent = false; send() },
onDecline: { consent = .declined; askingForConsent = false }
)
}
}
private func send() {
// Only reached after an explicit yes. Call your server here.
}
}
struct ConsentSheet: View {
let provider: String
let sentData: String
let onAllow: () -> Void
let onDecline: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Send this note to \(provider)?").font(.title2.bold())
Text("To write the summary, the app sends the following to \(provider), a company outside this app:")
Text(sentData).bold()
Text("\(provider) processes it under its own privacy policy. You can change this later in Settings.")
.font(.footnote)
.foregroundStyle(.secondary)
HStack {
Button("Don't send", action: onDecline).buttonStyle(.bordered)
Spacer()
Button("Send to \(provider)", action: onAllow).buttonStyle(.borderedProminent)
}
}
.padding()
.presentationDetents([.medium])
.interactiveDismissDisabled()
}
}
struct AISettingsRow: View {
@AppStorage("consent.openai.v1") private var consent: AIConsent = .notAsked
var body: some View {
Toggle("Send notes to OpenAI for summaries", isOn: Binding(
get: { consent == .allowed },
set: { consent = $0 ? .allowed : .declined }
))
}
}
What it does, step by step:
- Names the provider and says exactly what data leaves the device.
- Asks before the first send.
send()only runs after a yes. - Gives “Don’t send” the same size of button as “Send”.
- Stores the answer per provider, so a new provider means a new question.
- Lets people withdraw consent in Settings.
- Keeps a path for people who say no, such as the on-device summary.
Where does it fall short for business apps?
- Long documents. Anything near or above the context window needs chunking, Private Cloud Compute or a third-party model.
- One request at a time per session. Apple’s docs say a second call before the first finishes causes a runtime error, so check
isRespondingor use separate sessions. - Device coverage. Older iPhones and every Android phone need another path. Apple suggests a server model or a custom on-device model as the backup, and we compare Apple’s frameworks for custom models in Core ML vs Core AI.
- Moving models. You can’t pin a model version, so the test set above becomes part of regular maintenance.
- Apple’s acceptable use requirements. They rule out making decisions “without human supervision that have a material impact on individual rights, in high-risk domains, including in employment, medical, legal, or finance”. An app that screens job applicants or approves claims needs a person in the loop.
Getting it built
Our AI-native apps service builds features like these in Swift, starting at $15,000, with the details on our pricing page.