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。請預先規劃,否則會話會拋出例外。 - 需要iOS 26與一台支援Apple Intelligence的裝置。低於這道門檻,這套框架根本不存在。
這套框架是什麼,又不是什麼
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 Intent,是形狀相同卻表面各異的東西:一項具名、有描述、有型別的能力。能力只設計一次,就能透過兩者同時對外開放。
可用性:不能省略的檢查
模型並非隨時都在。在不支援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。在使用者即將動作的畫面上值得這麼做,若只是臆測性地呼叫則是浪費。
上下文視窗,以及它不再夠用的那個界點
SystemLanguageModel.default.contextSize會回報模型運作所在的token預算,而這份預算是共用的:提示加回應合起來必須塞得進去6。相對於雲端模型,這個數字偏小,在真實輸入上您很快就會感受到。一份長文件、一整段聊天歷史、一個臃腫的工具結果:任何一個都可能撐爆預算,讓respond拋出例外。
隨之而來的有兩種失敗模式,而兩者都該由您來預防。第一種是緩慢的蔓延:一個多輪會話不斷累積文字記錄,直到再多一輪就溢位。處理方式是為不相關的工作另起全新會話,並讓每一輪的輸入保持精簡。第二種是單一過大的請求:一份20頁的PDF就是塞不下,沒得商量。請把它切塊、對各塊做摘要,再對這些摘要進行推理(LLM工程師熟知的map-reduce),或者接受這個任務的形狀本就不適合裝置端模型。
對於這套框架真正攸關的那個決定——何時留在裝置端、何時該離開——上下文視窗是最乾淨俐落的訊號。
何時不該使用Foundation Models
這套框架免費、私密又離線,讓人忍不住到處都想用它。請克制。當以下情況出現時,跳過它、伸手去拿更大的方案:
- 您需要真正的推理,或廣度足夠的世界知識。 裝置端模型在設計上就是小的。開放式推理、程式碼生成,以及深度分析,都屬於前沿雲端模型的範疇。拿這些去問裝置端模型,得到的會是自信滿滿卻錯誤的答案。
- 輸入塞不進上下文視窗,而切塊又會摧毀其語意。有些任務需要一次看到全貌。
- 您需要一個自己掌控的模型: 特定的檢查點、一個微調版本、自訂權重,或跨作業系統更新仍維持確定性的版本控管。Apple是按自己的時程出貨並更新模型,而不是您的。
- 您低於iOS 26,或身處不符資格的裝置上。 框架根本就不在那兒,而可用性檢查會在每一次執行時這麼告訴您。
對於這套框架未涵蓋的裝置端情境(自訂模型、您自己的權重、在裝置上訓練),底下那一層是Core ML與Apple的MLX。對於那些確實需要規模的情境,隱私邊界後方的一套雲端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。它在設計上就偏小,因此長文件與長篇多輪歷史都會超出它。請為這個上限預作規劃,否則會話會拋出例外。
Foundation Models能離線運作嗎?它會把資料送給Apple嗎?
它完全在裝置端、透過Neural Engine執行。沒有資料離開裝置,也不需要網路往返——這正是它適合用在過去需要雲端LLM加上隱私審查的那類功能上的原因1。
裝置端模型能在生成過程中呼叫我自己的程式碼嗎?
可以。Tool協定讓模型得以在生成期間呼叫您的程式碼,以取得資料或執行動作,再將結果摺回它的回答之中4。
我什麼時候不該使用Foundation Models?
當您需要一個前沿模型時,跳過它、伸手去拿更大的方案:開放式推理、程式碼生成、長文件分析,或世界知識。Apple打造這個裝置端模型,是為了應用程式內聚焦的語言任務,所以拿它去要求通用智慧,得到的會是自信滿滿卻錯誤的答案1。
-
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. ↩