Apple Foundation Models:裝置端LLM框架完整解析
Foundation Models框架讓應用程式得以直接、免費、離線地存取為Apple Intelligence提供動力的同一個裝置端大型語言模型1。不需要API金鑰,沒有按token計費,沒有網路往返,也沒有任何資料離開裝置。對於過去意味著一套雲端LLM加上一輪隱私審查的那類功能,如今成本幾乎歸零。代價在於能力:裝置端模型體積小、上下文視窗有限,而框架對自己願意與不願意做的事劃下了明確界線。摸清這些界線,就是這場遊戲的全部。
本文是這套框架本身的參考指南:您實際會呼叫的型別、讓它值得一用的那項關鍵功能,以及您應該就此打住、轉而尋求更大方案的那個臨界點。
太長不看
LanguageModelSession是進入點。建立一個會話,呼叫respond(to:),取回文字。多輪對話的上下文保存在會話中;單輪工作則每次取得一個全新會話2。- 引導式生成正是使用這套框架的理由。 為Swift型別加上
@Generable註記,模型便會回傳該型別本身——已填入內容且通過型別檢查——而非一段您還得自行解析的字串3。 Tool協定讓模型得以在生成過程中呼叫您的程式碼,以取得資料或執行動作,再將結果摺回它的回答之中4。- 動手之前,先檢查
SystemLanguageModel.default.availability。在不符資格的裝置上、Apple Intelligence關閉時,或模型正在下載期間,該模型都不存在5。 - 上下文視窗是真實存在且偏小的。
SystemLanguageModel.default.contextSize會回報提示與回應共用的token預算6。裝置端的預算是4K token;Private Cloud Compute模型則把它提高到32K14。請預先規劃,否則會話會拋出例外。 - 需要iOS 26與一台支援Apple Intelligence的裝置。低於這道門檻,這套框架根本不存在。iOS 27的beta版則在同一套API上加入了圖片輸入、逐請求的工具呼叫控制,以及Private Cloud Compute上的伺服器模型121314。
這套框架是什麼,又不是什麼
Foundation Models並非對雲端端點的一層包裝。模型就活在裝置上,隨作業系統一同出貨,並透過Neural Engine執行。這個單一事實,驅動了API中的每一項設計決策,以及您運用它時所做的每一個決定。
您能得到的:文字生成、摘要、分類、抽取、短篇改寫,以及結構化輸出,全都在裝置端完成,全都免費。您得不到的:一個前沿模型。Apple打造這個裝置端模型,是為了應用程式內聚焦的語言任務,而非開放式推理、長文件分析,也不是供您拿來測驗的世界知識。Apple自己也是這麼定位的,而這樣的定位之所以重要,是因為它設定了預期——否則這套API會放任您去違背它1。
能讓您避開麻煩的心智模型是:把裝置端模型當成一位快速、私密、免費的實習生——他極擅長雕琢文字,卻極不擅長知道事實。交給他材料和一個明確的任務。別問他那些他根本無從回答的問題。
LanguageModelSession:進入點
每一次互動都從一個會話開始。
import FoundationModels
let session = LanguageModelSession()
let response = try await session.respond(to: "Summarize this review in one sentence: \(reviewText)")
print(response.content)
會話保存著對話狀態。每一次呼叫respond(to:)都會附加到持續累積的文字記錄上,因此一個您持續保留的會話會記得先前的內容。對於聊天功能,這正是您要的。但對於彼此獨立的一次性任務(摘要這個、分類那個),請為每次呼叫建立一個全新會話,免得陳舊的上下文滲入,白白吃掉您的token預算2。
respond(to:)是async throws。它在模型工作時暫停,並在請求超出上下文視窗、模型無法使用,或防護機制拒絕內容時拋出例外。上述每一種情況,都是您要處理的真實分支,而非可以忽略的邊角案例。
要打造反應靈敏的UI,請用串流取代等待。streamResponse(to:)會在模型產出時逐步交付部分輸出,將原本三秒的卡頓,化為隨著成形而逐漸浮現的文字7。
引導式生成:讓這套框架值回票價的功能
接下來這部分,值回入場的票價。多數LLM整合工作,有三分之一的程式碼花在哄騙模型吐出有效的JSON,另外三分之二則用來防範它仍然失敗的那些時刻。Foundation Models刪掉了這份工作。
為Swift型別加上@Generable註記,要求會話生成它,模型便會回傳該型別的一個實例——已填入內容且型別安全3:
@Generable
struct Recipe {
@Guide(description: "The dish name")
let title: String
@Guide(description: "Ingredients, each as 'quantity item'")
let ingredients: [String]
@Guide(description: "Total minutes, start to finish", .range(5...240))
let minutes: Int
}
let session = LanguageModelSession()
let response = try await session.respond(
to: "A weeknight pasta for two.",
generating: Recipe.self
)
let recipe = response.content // a Recipe, not a String
不必解析。沒有JSONDecoder。不必為了畸形輸出而設重試迴圈。@Guide巨集約束個別欄位:一段模型會當成指示來讀的描述,以及可選的限制,例如數值範圍,或輸出必須符合的正規表示式8。框架不是客客氣氣地請模型給一個介於5到240之間的數字;它約束的是解碼過程,讓這個欄位根本不可能以其他形式回傳。
它所強制建立的這份紀律,才是真正的價值所在。您先在Swift裡設計輸出型別,由編譯器替您把關。模型填的是一份您所定義的契約,而非一段您得逆向工程的散文。對於抽取、表單填寫,以及任何把語言轉成資料的功能,引導式生成正是「示範品」與「可出貨程式碼」之間的分野。
有一個值得知道的控制項:respond(to:generating:)會把includeSchemaInPrompt預設為true,將您型別的結構注入提示之中,使模型偏向它。除非模型已經從訓練、或從會話中較早的對話得知該格式,否則請保持開啟;為了在一個模型沒見過的格式上省token而把它關掉,正是讓您收到一堆垃圾的方式9。
工具呼叫:讓模型觸及您的程式碼
引導式生成形塑的是輸出的內容。工具呼叫改變的則是輸入的內容。所謂工具,是一段您的程式碼,模型可以在生成過程中加以呼叫,以取得它沒有的資訊或執行某個動作,再運用結果繼續它的回答4。
工具須符合Tool協定:一個name、一段模型用來判斷何時呼叫它的description、一個@Generable的Arguments型別,以及一個負責實際工作的call(arguments:)方法4:
struct FindContacts: Tool {
let name = "findContacts"
let description = "Find a specific number of contacts from the address book"
@Generable
struct Arguments {
@Guide(description: "How many contacts to return", .range(1...10))
let count: Int
}
func call(arguments: Arguments) async throws -> [String] {
// Fetch contacts, return formatted names.
}
}
let session = LanguageModelSession(tools: [FindContacts()])
let response = try await session.respond(to: "Draft a dinner invite to three of my contacts.")
流程是這樣的:模型判定它需要聯絡人,以一個經過驗證的count呼叫您的工具,您回傳資料,模型再用真實姓名寫出邀請函。引數透過同一套引導式生成機制,以通過型別檢查的形式抵達,因此您永遠不必從自由文字中去解析模型的意圖。工具的描述,是您唯一能左右「模型何時伸手取用它」的槓桿,所以請把它寫得像一份函式文件——要讓另一位毫無背景脈絡的工程師讀完後就能正確使用。
這也是Foundation Models與其餘代理故事接合的縫合處。裝置端模型呼叫的工具,與Apple Intelligence呼叫的App Intent11,是形狀相同卻表面各異的東西:一項具名、有描述、有型別的能力。能力只設計一次,就能透過兩者同時對外開放。
可用性:不能省略的檢查
模型並非隨時都在。在不支援Apple Intelligence的裝置上、使用者已將其關閉時,以及作業系統仍在下載模型資產的那段期間,它都不存在。若您出貨的程式碼假設模型一定在,它就會當機、悄悄降級,或對著一群您從未測試過的使用者卡住不動。
請檢查SystemLanguageModel.default.availability,並依其原因分支處理5:
switch SystemLanguageModel.default.availability {
case .available:
// Show the intelligence feature.
case .unavailable(.deviceNotEligible):
// Hide it. This device will never have the model.
case .unavailable(.appleIntelligenceNotEnabled):
// Prompt the user to turn on Apple Intelligence.
case .unavailable(.modelNotReady):
// Downloading or otherwise not ready yet. Try again later.
case .unavailable(let other):
// Unknown reason. Fail closed.
}
這三種原因要求三種不同的產品回應,而把它們混為一談,正是這類功能讓人覺得「壞了」的最常見原因。deviceNotEligible是永久性的:隱藏該功能,別再嘮叨。appleIntelligenceNotEnabled是使用者自己掌控的一項設定:出現一次性提示是合理的。modelNotReady則是暫時性的:重試即可,別顯示錯誤。請以對待順利路徑同等的用心去打造「不可用」的路徑,因為對於相當一部分裝置而言,它是唯一的路徑。
當模型可用、且您已知有一個請求即將到來時,對會話呼叫prewarm()會預先暖機,讓第一次真正的回應更快落地10。在使用者即將動作的畫面上值得這麼做,若只是臆測性地呼叫則是浪費。
動手做:一個檔案完成一項完整功能
上面這些零件,能用比多數網路層處理單一端點還少的程式碼,組成一項真實功能。下面的範例是一個完整、可編譯的SwiftUI畫面,把自由格式的會議筆記轉成結構化的待辦事項:可用性檢查、@Generable輸出型別、一次引導式生成呼叫,以及三種「不可用」分支的完整處理。當中每一個符號,都來自前文記錄過的框架介面2358。
import SwiftUI
import FoundationModels
@Generable
struct ActionItems {
@Guide(description: "One-sentence summary of the meeting")
let summary: String
@Guide(description: "Concrete follow-up tasks, each starting with a verb")
let tasks: [String]
@Guide(description: "How urgent the follow-ups are overall", .anyOf(["low", "medium", "high"]))
let urgency: String
}
struct MeetingNotesView: View {
@State private var notes = ""
@State private var result: ActionItems?
@State private var errorMessage: String?
var body: some View {
Form {
TextField("Paste meeting notes", text: $notes, axis: .vertical)
.lineLimit(6...12)
Button("Extract action items") {
Task { await extract() }
}
.disabled(notes.isEmpty)
if let result {
Section(result.summary) {
ForEach(result.tasks, id: \.self) { Text($0) }
Text("Urgency: \(result.urgency)")
}
}
if let errorMessage {
Text(errorMessage).foregroundStyle(.secondary)
}
}
}
private func extract() async {
switch SystemLanguageModel.default.availability {
case .available:
do {
let session = LanguageModelSession()
let response = try await session.respond(
to: "Extract the action items from these notes: \(notes)",
generating: ActionItems.self
)
result = response.content
} catch {
errorMessage = "The model could not process these notes."
}
case .unavailable(.appleIntelligenceNotEnabled):
errorMessage = "Turn on Apple Intelligence in Settings to use this feature."
case .unavailable(.modelNotReady):
errorMessage = "The model is still downloading. Try again shortly."
case .unavailable:
errorMessage = "This feature needs an Apple Intelligence-capable device."
}
}
}
在這麼小的範例裡,有三個細節值得留意。輸出型別就是API:ActionItems精確定義了這項功能會產出什麼,而urgency上的@Guide約束意味著那個字串不可能回傳三個許可值以外的任何東西8。會話之所以每次呼叫都重新建立,是因為每一次抽取都彼此獨立;一個被保留下來的會話,會把先前的筆記一路拖進token預算裡2。至於那些不可用分支,產生的是三種不同的使用者體驗,而非一則籠統的錯誤訊息——這正是「誠實降級的功能」與「看起來就是壞了的功能」之間的分野。把這個檔案貼進一個iOS 26專案,在支援Apple Intelligence的裝置上執行,它就能運作。
上下文視窗,以及它不再夠用的那個界點
SystemLanguageModel.default.contextSize會回報模型運作所在的token預算,而這份預算是共用的:提示加回應合起來必須塞得進去6。相對於雲端模型,這個數字偏小,在真實輸入上您很快就會感受到。一份長文件、一整段聊天歷史、一個臃腫的工具結果:任何一個都可能撐爆預算,讓respond拋出例外。
隨之而來的有兩種失敗模式,而兩者都該由您來預防。第一種是緩慢的蔓延:一個多輪會話不斷累積文字記錄,直到再多一輪就溢位。處理方式是為不相關的工作另起全新會話,並讓每一輪的輸入保持精簡。第二種是單一過大的請求:一份20頁的PDF就是塞不下,沒得商量。請把它切塊、對各塊做摘要,再對這些摘要進行推理(LLM工程師熟知的map-reduce),或者接受這個任務的形狀本就不適合裝置端模型。
對於這套框架真正攸關的那個決定——何時留在裝置端、何時該離開——上下文視窗是最乾淨俐落的訊號。數字如今已經公開:裝置端模型在4K token的預算內運作,而Private Cloud Compute上的伺服器模型把上限拉到32K14。前面關於切塊的一切建議,都請放在這兩個數字的脈絡下閱讀。
iOS 27的beta版帶來了什麼
以上描述的,都是iOS 26出貨時的框架樣貌,而這一切至今依然成立。iOS 27的beta版沿著四個方向擴充同一套介面,沒有任何一項會打破iOS 26的心智模型12。
提示可以放圖片了。 裝置端模型獲得了Vision能力:您在提示中與文字並列插入一份圖片附件,模型便會就兩者一起作答。新增的型別是Attachment、ImageAttachmentContent與ImageReference,而附件接受UIImage、NSImage、CGImage、Core Image型別、CoreVideo像素緩衝區,以及檔案URL1213。圖片不限尺寸與長寬比,但它們花的是與文字同一份token預算,因此裝置端那道4K視窗很快就會變成設計上的限制13。完整說明請見iOS 27的Foundation Models圖片輸入。
工具呼叫多了一道節流閥。 GenerationOptions新增了可逐請求設定的toolCallingMode,用來控制模型如何與您掛上的工具互動;Vision框架也直接提供現成的OCRTool與BarcodeReaderTool實作,掛到會話上即可,不必自己寫辨識程式碼15。行為細節請見iOS 27的工具呼叫控制。
更大的模型,只差一行。 PrivateCloudComputeLanguageModel讓同一套API去跑Apple在Private Cloud Compute上的伺服器模型,需要一項權限(entitlement),換來的是32K上下文視窗,以及裝置端模型所沒有的推理能力1214。引導式生成與工具的用法完全不變;切換模型就只是會話的model引數。
會話有了更多控制面。 beta版新增了ContextOptions、TranscriptErrorHandlingPolicy、動態設定檔(DynamicInstructions、LanguageModelSession.DynamicProfile),以及一套自訂語言模型供應者協定(LanguageModel、LanguageModelExecutor),讓會話得以驅動您自備的模型,而非系統內建的那一個12。watchOS也在27.0加入了支援平台名單12。
值得記住的定位是:iOS 26的程式碼在iOS 27上編譯與行為完全一致。beta版拓寬的是提示能承載什麼、模型能在哪裡執行;它們並未改變這套框架的本質。
何時不該使用Foundation Models
這套框架免費、私密又離線,讓人忍不住到處都想用它。請克制。當以下情況出現時,跳過它、伸手去拿更大的方案:
- 您需要真正的推理,或廣度足夠的世界知識。 裝置端模型在設計上就是小的。開放式推理、程式碼生成,以及深度分析,都屬於前沿雲端模型的範疇。拿這些去問裝置端模型,得到的會是自信滿滿卻錯誤的答案。
- 輸入塞不進上下文視窗,而切塊又會摧毀其語意。有些任務需要一次看到全貌。
- 您需要一個自己掌控的模型: 特定的檢查點、一個微調版本、自訂權重,或跨作業系統更新仍維持確定性的版本控管。Apple是按自己的時程出貨並更新模型,而不是您的。
- 您低於iOS 26,或身處不符資格的裝置上。 框架根本就不在那兒,而可用性檢查會在每一次執行時這麼告訴您。
對於這套框架未涵蓋的裝置端情境(自訂模型、您自己的權重、在裝置上訓練),底下那幾層分別是:固定的轉換後模型交給Core ML,開放權重模型與您自己擁有的微調版本交給MLX,而當您需要對特化與排程有明確掌控時,則是iOS 27的Core AI。對於那些確實需要規模的情境,Private Cloud Compute,或隱私邊界後方的一套雲端LLM,仍然是誠實的答案。Foundation Models並不能取代其中任何一個。對於您手邊既有文字上的聚焦語言工作,它是正確的第一選擇;對於其他一切,它則是錯誤的選擇。
這套框架所獎賞的本事,不是提示工程的巧手,而是對範疇的品味:餵給模型它擅長的任務、設計出恰好捕捉您所需內容的@Generable型別,並認出工作量已超出裝置負荷的那一刻。帶著這些直覺去打造,裝置端模型就會免費地完成出乎意料大量的真實工作。忽略它們,您出貨的功能就會對每一個輸入恰好多出一個token的使用者壞掉。
常見問題
Apple的Foundation Models框架可以免費使用嗎?
可以。這套框架讓應用程式得以直接、免費、離線地存取為Apple Intelligence提供動力的同一個裝置端模型。沒有API金鑰、沒有按token計費,也沒有網路往返1。
Foundation Models需要哪些裝置與iOS版本?
它需要iOS 26與一台支援Apple Intelligence的裝置。低於這道門檻,框架根本不存在;而即使在受支援的作業系統上,在不符資格的裝置上、Apple Intelligence關閉時,或模型下載期間,該模型仍會缺席。使用前請務必檢查SystemLanguageModel.default.availability5。
我要如何取得結構化、型別安全的輸出,而非一段字串?
為Swift型別加上@Generable註記,模型便會回傳該型別本身——已填入內容且通過型別檢查——而非一段您還得自行解析的字串。這項引導式生成,正是讓這套框架值得一用的那唯一一項功能3。
Apple裝置端模型的上下文視窗有多大?
SystemLanguageModel.default.contextSize會回報token預算,而它由提示與生成的回應共用6。裝置端模型提供4K token;Private Cloud Compute模型則提供32K14。長文件與長篇多輪歷史都會超出裝置端的預算,因此請為這個上限預作規劃,否則會話會拋出例外。
Foundation Models能離線運作嗎?它會把資料送給Apple嗎?
它完全在裝置端、透過Neural Engine執行。沒有資料離開裝置,也不需要網路往返——這正是它適合用在過去需要雲端LLM加上隱私審查的那類功能上的原因1。
裝置端模型能在生成過程中呼叫我自己的程式碼嗎?
可以。Tool協定讓模型得以在生成期間呼叫您的程式碼,以取得資料或執行動作,再將結果摺回它的回答之中4。
我什麼時候不該使用Foundation Models?
當您需要一個前沿模型時,跳過它、伸手去拿更大的方案:開放式推理、程式碼生成、長文件分析,或世界知識。Apple打造這個裝置端模型,是為了應用程式內聚焦的語言任務,所以拿它去要求通用智慧,得到的會是自信滿滿卻錯誤的答案1。
iOS 27為Foundation Models增加了什麼?
iOS 27的beta版加入了圖片輸入(提示中的附件,可由UIImage、CGImage、像素緩衝區等建立)、透過GenerationOptions逐請求控制工具呼叫、現成的OCRTool與BarcodeReaderTool兩項Vision工具,以及讓同一套API去跑Apple 32K上下文伺服器模型的PrivateCloudComputeLanguageModel12131415。iOS 26的程式碼原封不動即可執行。
-
Apple Developer, “Foundation Models” framework overview. Apple describes the framework as access to the on-device model that powers Apple Intelligence, suited to focused language tasks such as text generation, summarization, classification, and structured output rather than open-ended reasoning or world knowledge. ↩↩↩↩↩
-
Apple Developer, “LanguageModelSession” and “Generating content and performing tasks with Foundation Models”. A session holds multi-turn context; Apple’s guidance is to create a new session for each distinct single-turn interaction. ↩↩↩↩
-
Apple Developer, “Generable” and “Prompting an on-device foundation model”. The
@Generablemacro lets the framework return a populated, type-checked Swift value rather than a string. ↩↩↩↩ -
Apple Developer, “Tool” protocol. Defines
protocol Tool<Arguments, Output>: Sendablewith requiredname,description, andparameters: GenerationSchema, pluscall(arguments:) async throws -> Output. TheArgumentstype conforms toConvertibleFromGeneratedContentand is typically declared@Generable. ↩↩↩↩ -
Apple Developer, “SystemLanguageModel.Availability” and its
UnavailableReason. Cases:.availableand.unavailable(...)with reasonsdeviceNotEligible,appleIntelligenceNotEnabled, andmodelNotReady.SystemLanguageModel.default.isAvailableis the convenience boolean. ↩↩↩↩ -
Apple Developer, “SystemLanguageModel.contextSize”. An instance property (reached through
SystemLanguageModel.default) documented as the maximum context size, representing the total tokens across input prompt and generated response. ↩↩↩ -
Apple Developer, “LanguageModelSession.streamResponse(to:)”. Streams partial generated output as the model produces it, for incremental UI updates. ↩
-
Apple Developer, “Guide(description:_:)”. A peer macro that attaches a natural-language description and optional constraints (numeric ranges, regular-expression guides) to a
@Generableproperty. Requires iOS 26.0+. ↩↩↩ -
Apple Developer, “respond(to:schema:includeSchemaInPrompt:options:)”.
includeSchemaInPromptdefaults totrue; Apple’s discussion recommends keeping the default unless the model already knows the expected format. ↩ -
Apple Developer, “LanguageModelSession.prewarm()”. Asks the framework to load model resources ahead of a known upcoming request to reduce first-response latency. ↩
-
Author’s related analysis: On-Device LLMs with Apple’s Foundation Models, Custom Adapters for Foundation Models, Foundation Models Use Cases, and Agentic Workflows on Foundation Models. The App Intents and tool-surface argument is developed in App Intents Are Apple’s New API to Your App. ↩
-
Apple Developer, “Foundation Models” framework topics as of July 2026. The types marked beta for the 27.0 releases include
Attachment,ImageAttachmentContent, andImageReference(prompt attachments);ContextOptionsandTranscriptErrorHandlingPolicy;DynamicInstructionsandLanguageModelSession.DynamicProfile(dynamic profiles);PrivateCloudComputeLanguageModelwith thecom.apple.developer.private-cloud-computeentitlement; and the custom provider surfaceLanguageModel,LanguageModelCapabilities, andLanguageModelExecutor. The framework’s platform list adds watchOS 27.0 (beta). ↩↩↩↩↩↩↩ -
Apple, WWDC26 session 241, “What’s new in the Foundation Models framework”. Image attachments “can be created from a variety of types including UIImage, NSImage, CGImage, Core Image types, CoreVideo Pixel Buffers, and file URLs”; “the model supports images in any size and aspect ratio,” and “larger images will consume more tokens and incur more latency.” ↩↩↩↩
-
Apple, WWDC26 session 319, “Build with the new Apple Foundation Model on Private Cloud Compute”. “The on-device model offers 4k, and with PCC you get 32K”; the session demonstrates switching from the on-device model to the PCC server model by changing one line, with guided generation and tool calling working the same on both. ↩↩↩↩↩↩
-
Apple Developer, “GenerationOptions.ToolCallingMode” (iOS 27 beta; the
toolCallingModeproperty and theinit(samplingMode:temperature:maximumResponseTokens:toolCallingMode:)initializer), and the Vision framework’s “OCRTool” and “BarcodeReaderTool” (iOS 27 beta), which conform to the Foundation ModelsToolprotocol. ↩↩