Foundation Models 代理工作流程:應用程式內 vs 工具型 LLM
iOS 26 上的 Swift 應用程式有兩種 LLM 在不同層級接觸它。一種是使用者透過應用程式的 LanguageModelSession 執行的裝置端模型。另一種是開發者透過 Claude Code、Cursor 或 Codex CLI 執行以撰寫應用程式的代理。將這兩種 LLM 混為一談,是 Apple 代理開發中反覆出現的架構錯誤。它們不是同一個問題;它們不共享安全模型;它們不共享部署故事;對其中一者有效的模式對另一者反而會徹底失敗。
執行時 LLM 是交付給使用者的功能。工具型 LLM 是開發者手中的觸控筆。執行時模型存在於使用者的隱私期望、系統的可用性檢查以及 App Store 審核之後。工具型模型存在於開發者的 API 金鑰、IDE 的檔案系統權限,以及開發者負責的程式碼審查之後。這兩個堆疊很少交集,而當它們交集時(例如開發者在開發期間用來操作應用程式領域的 MCP 伺服器,執行時應用程式也可能將其暴露給終端使用者自動化),信任邊界就會移動,架構必須認知到這一點。
本文點出這個區別以及隨之而來的路由問題:哪一種 LLM 應該服務哪一種能力,以及每一種對使用者各自負有什麼義務。
TL;DR
- 執行時 LLM 是 Foundation Models(
SystemLanguageModel.default加上Tool協定)。推論在本地端執行,模型隨作業系統出貨,應用程式代表使用者執行該呼叫。1 - 工具型 LLM 是開發者選擇的任何工具:Claude Code 中的 Claude、Cursor 中的 GPT、Codex CLI for Swift。推論是遠端的(Anthropic 的基礎設施或設定的 Claude 供應商、OpenAI 等),模型在主機放置之處,開發者驅動代理。
- 兩種 LLM 不共享安全性、部署、延遲預算或責任歸屬。在某一層合理的能力,在另一層往往是錯誤的形狀。
- 開發者在 Claude Code 工作階段中使用的同一個 MCP 伺服器並非自動就是終端使用者代理自動化的正確介面。信任邊界改變了;原本由開發者控制的工具變成由使用者控制(或系統控制)的工具。
兩個堆疊,共用「LLM」這個詞
衝突發生在這樣的對話中。有人說「我們應該為應用程式加入一個 LLM」。從這句話無法判斷這是指使用者調用的功能(幫我寫一份冥想摘要、潤飾這段草稿、為這張照片分類),還是開發者接到自己迭代迴圈中的工具(讓 Claude Code 寫遷移、讓 Cursor 重構視圖)。兩者都是加入 LLM。但兩者並非相同的工程決策。
Foundation Models 是其中一個堆疊。模型存在於 SystemLanguageModel.default,具有固定的脈絡視窗,在 Apple 晶片上執行,永不離開裝置,並由使用者的 Apple Intelligence 資格控管。1應用程式開發者透過 @Generable 型別約束輸入,透過 Tool 協定暴露應用程式能力,並出貨在功能觸發時呼叫模型的二進位檔。使用者調用功能;作業系統提供模型;應用程式將兩者縫合在一起。
Claude Code、Cursor、Codex CLI 以及任何其他代理 IDE 構成另一個堆疊。模型存在於主機 LLM 供應商執行之處(Anthropic 的伺服器執行 Claude、OpenAI 的伺服器執行 GPT 等)。IDE 是主機。MCP 伺服器是主機的模型可以呼叫的工具。開發者的機器具有檔案系統存取、shell 存取以及 IDE 選擇暴露的其他任何權限。開發者調用代理;代理伸入開發者的檔案系統;輸出落到開發者的專案中。2
同一個「LLM」字眼,但波及範圍截然不同。
兩個堆疊歧異的六個面向
六個屬性使得這個分歧具體化:
| 屬性 | 執行時 LLM(Foundation Models) | 工具型 LLM(Claude Code、Cursor、Codex CLI) |
|---|---|---|
| 推論在哪裡執行 | 裝置端(Apple 晶片) | 在 LLM 供應商的基礎設施上 |
| 誰執行呼叫 | 應用程式,回應使用者操作 | 開發者,在迭代迴圈中 |
| 誰負責任 | 應用程式開發者(App Store 審核) | 開發者(他們的提交、他們的程式碼審查) |
| 模型接觸什麼 | 應用程式沙盒內的應用程式資料 | 開發者的檔案系統、shell、MCP 工具 |
| 信任邊界 | 使用者 → 應用程式 → 裝置端模型 | 開發者 → IDE → 遠端模型 + MCP 伺服器 |
| 誤用的代價 | 隱私、應用程式當機、App Store 拒絕 | 糟糕的程式碼、安全洩漏、損壞的建置 |
信任邊界是承重的那一列。執行時 LLM 在使用者隱私期望下於應用程式沙盒內運作;工具型 LLM 在開發者授權下於開發者機器內運作。像「讓 LLM 執行 shell 命令」這樣的模式在工具中是常態(Claude Code 透過其 Bash 工具不斷這麼做)3,但在執行時則完全不可行:Foundation Models 沒有 Bash 工具,而 Tool 協定是應用程式開發者撰寫並審查的型別化 Swift 函式。1
誤用代價那一列是搞錯信任邊界的後果。將使用者資料外傳到伺服器的執行時 LLM,是侵犯隱私且違反指南而被拒絕的行為。將開發者原始碼外傳到 LLM 供應商的工具型 LLM,則視開發者合約而定,要嘛是預期行為,要嘛是洩漏。兩者都重要;但理由不同。
介於中間的 MCP 伺服器
最清晰看到邊界移動的位置,是當單一 MCP 伺服器同時被兩個堆疊使用時。Get Bananas 出貨一個 MCP 伺服器,暴露購物清單操作:讀取項目、新增項目、標記完成。同一個伺服器在兩個地方執行。4
在開發者的 Claude Code 工作階段進行迭代時,MCP 伺服器是開發者的代理呼叫的工具,用以操作開發者自己的清單。伺服器針對 iCloud Drive 中的 JSON 檔案執行。開發者將伺服器接入其 MCP 主機設定;主機知道要呼叫它;代理將購物項目的讀寫作為更大開發任務的一部分。
在終端使用者代理介面(例如外部 Claude Desktop 使用者指向共享清單)中,同一個 MCP 伺服器負有不同義務。呼叫者不再是擁有完整檔案系統信任的開發者 Blake;呼叫者是一位終端使用者,其身份驗證、授權和意圖審核並非開發者的責任。MCP 伺服器必須強制執行這些防護(或拒絕暴露自己),那個介面才能變得安全。
同一個 JSON-RPC 方法 add_item,透過本地 stdio 傳輸無驗證地提供給開發者,是正確的形狀。透過網際網路可達的主機,代表任意終端使用者在無驗證下提供,則是資料完整性的危害。MCP 伺服器是同樣的程式碼;周遭的部署改變了一切。
這就是 Apple 代理開發中 MCP 伺服器的路由規則。伺服器是針對某個領域的型別化合約。它在堆疊中位於何處(開發者工具 vs 終端使用者介面)是部署決策,而非協定決策。對部署進行程式碼審查;不要假設協定的寬鬆預設值就是部署的正確預設值。
裝置端的 Tool 協定不是 MCP 伺服器
一個常見的混淆:Foundation Models 有 Tool 協定,而 MCP 也有工具呼叫。它們一樣嗎?不一樣,而且這個差異對路由很重要。
Foundation Models 的 Tool 協定是應用程式開發者實作的 Swift API:1
struct WaterEntryLookup: Tool {
let name = "lookup_water_entries"
let description = "Look up water intake entries for a given date range."
@Generable struct Arguments { ... }
func call(arguments: Arguments) async throws -> String { ... }
}
工具在應用程式行程內執行。工具服務的模型是裝置的 SystemLanguageModel。引數和輸出是 Swift 型別。開發者審查實作,App Store 審查應用程式。使用者調用功能;應用程式的工作階段呼叫工具;本地模型使用結果。
MCP 工具是 MCP 伺服器暴露的 JSON-RPC 方法,而 MCP 伺服器是主機 LLM(Claude、GPT 等)連接的獨立行程:2
{
"name": "add_item",
"description": "Add an item to the shopping list.",
"inputSchema": {"type": "object", "properties": {"name": {"type": "string"}}}
}
工具在代理行程之外執行,以開發者選擇的任何語言撰寫,透過 stdio 或 Streamable HTTP 傳輸 JSON。模型在主機放置之處。引數是針對綱要驗證過的 JSON。責任在於部署 MCP 伺服器的人。
兩種協定以不同的範圍解決重疊的問題:
| 決策 | Foundation Models Tool |
MCP 工具 |
|---|---|---|
| 呼叫者 | 裝置端語言模型 | 外部代理(Claude、GPT、Cursor 等) |
| 在哪裡執行 | 應用程式行程內,裝置端 | 主機連接的獨立行程 |
| 綱要語言 | Swift @Generable 型別 |
JSON Schema |
| 信任姿態 | 應用程式擁有它;使用者的隱私姿態 | 開發者或廠商擁有它;代理的權限 |
| 更新節奏 | 應用程式更新 | 伺服器重新部署 |
路由規則很直接:如果該能力服務應用程式自己的 LLM 功能給終端使用者,就放進 Foundation Models 的 Tool。如果該能力服務跨行程運作的外部代理(開發者或終端使用者),就放進 MCP 工具。有些應用程式兩者都需要;同一個 Swift 函式可以支撐兩種轉接器,但這些轉接器位於不同的堆疊層級,並透過不同的發布週期出貨。5
Hooks 是工具型 LLM 立足之處
工具型 LLM 的波及範圍使得 hooks 成為承重的安全基元。Claude Code 的 hook 系統在生命週期事件(PreToolUse、PostToolUse、UserPromptSubmit、SessionStart、Stop)上執行腳本。6使用 Claude Code 的 iOS 開發者設定 hooks,並非因為代理是惡意的,而是因為代理的權限很廣:檔案系統寫入、shell 執行、git 提交、推送。
在 Apple 代理工作中值得佔據 hook 槽位的模式:
在符合 xcodebuild 或 xcrun 但未經明確核准的 Bash 命令上設置 PreToolUse 阻擋。Claude Code 如果你允許,可以執行建置、清除模擬器、調用簽署或匯出步驟,或變更生成的專案狀態。Hook 將「代理執行了建置」變成「代理請求執行建置並獲得同意」。在不可逆操作上減慢代理速度,是換取開發者信心的正確權衡。
在所有針對 .pbxproj 檔案的 Edit 或 Write 工具呼叫上設置 PostToolUse 驗證器。Xcode 專案檔由人手編輯,但對代理有毒;一個錯誤的行就會悄悄破壞團隊每位開發者的建置。在每次 .pbxproj 寫入後、提交前執行 plutil -lint(或類似的結構檢查)的 hook,正是「代理在五分鐘內寫好遷移」與「代理寫好遷移加上四十五分鐘的 git bisect」之間的差異。
在讓代理宣告任務完成之前執行 swift build(或適當的建置命令)的 Stop hook。代理被訓練成在對話中辨認何謂完成。Hook 讓「完成」意味著「建置仍可編譯」,這才是出貨唯一重要的定義。
執行時 LLM 不需要這些。Foundation Models 沒有 shell、沒有 git、沒有專案檔、沒有 MCP 伺服器設定。裝置端的 Tool 是應用程式開發者撰寫的任何 Swift 函式;使用者調用功能;除非應用程式自己的 Tool 實作這麼做,否則沒有東西會逃出應用程式的沙盒或權限。
這個不對稱正是重點。工具型 LLM 擁有更多權限,需要更多防護。執行時 LLM 在構造上權限較少。Apple 已經做了讓執行時 LLM 安全的工作;開發者則做讓工具型 LLM 安全的工作。
架構規則
從執行時/工具型的區別衍生出三條架構規則。
逐能力選層,而非逐應用程式選層。冥想應用程式可能使用 Foundation Models 進行應用程式內摘要(執行時 LLM、裝置端、隨應用程式出貨),同時暴露一個 MCP 伺服器,供開發者在迭代期間搭配 Claude Code 批次匯入工作階段歷史記錄。兩種 LLM 在不同層級服務不同工作。將它們視為一個決策,會在兩個層級都產生比視為兩個決策更糟的結果。
對工具型 LLM 的觸及範圍進行程式碼審查。擁有完整檔案系統存取和遠端 MCP 伺服器的 Claude Code 工作階段是強大的開發環境,也是慷慨的攻擊面。緩解措施不是「信任代理」;緩解措施是 hooks、範圍化權限,以及一位閱讀差異的開發者。代理為你工作;代理不是你。
將執行時 LLM 的 Tool 集合作為穩定的 API 出貨。Foundation Models 工具是應用程式二進位合約的一部分。在版本之間移除或重新命名工具,對依賴該功能的使用者而言是行為變更。將工具定義視為 UI 元素,而非內部輔助函式。
我會在自己的堆疊中以何種方式不同地建構
兩個本叢集應用程式正在出貨或希望出貨的模式。
先建構領域層;讓執行時工具和工具型 MCP 伺服器包裝同一批 Swift 函式。App Intents vs MCP 的雙轉接器模式自然延伸至執行時 LLM 工具。一個 logWater(amount:caller:) 領域方法,可由 AppIntent(Apple Intelligence 介面)、MCP 工具(外部代理介面)和 Foundation Models Tool(應用程式內執行時 LLM 介面)各自包裝。三個協定轉接器、一個領域函式、三類呼叫者(系統代理、外部代理、裝置端模型)各帶三種不同義務。函式不知道是哪個呼叫者調用它;轉接器攜帶信任訊號。
將代理的 MCP 伺服器視為程式碼,而非設定。iOS 專案中參照的 .mcp.json 是一個範圍與優先順序的信任介面(於 儲存庫不應為自身信任投票 中涵蓋)。Claude Code 將 MCP 伺服器範圍解析為 local > project > user,專案範圍的伺服器在使用前會提示開發者核准。代理讀取設定並連接到開發者核准的伺服器;開發者審查設定和伺服器。將 MCP 伺服器加入專案是程式碼審查,不是設定微調。
何時 Foundation Models 才是對的,以及何時工具型 LLM 才是對的
本叢集文章匯聚出的決策樹:
Is the capability a feature an end user invokes inside your app?
├── Yes → Runtime LLM (Foundation Models or cloud LLM behind an Apple Intelligence-aware surface)
│ Use the Tool protocol for app-internal tool calls.
│ Use App Intents for capabilities the system agent should reach.
└── No → It is part of the developer's iteration loop.
├── Is the capability local to one developer's machine? → Tooling LLM
│ Use Claude Code, Cursor, or Codex CLI directly.
│ Wrap shared utilities as MCP servers behind hooks.
└── Is the capability shared across the team? → Tooling LLM with shared MCP servers
Deploy the MCP server somewhere the team can reach.
Code review the server like production code; gate dangerous tools behind explicit approval.
這個決策很少產生平手。當它產生平手時(同一能力可能合理地同時服務終端使用者與開發者),答案是兩個轉接器,而非一個共享介面,因為信任姿態和更新節奏的差異夠大,一個試圖同時服務兩者的介面會在兩邊都妥協。
此模式對於在 iOS 26+ 出貨的應用程式意味著什麼
三個重點。
-
兩種 LLM,兩個堆疊。執行時 LLM(Foundation Models、裝置端)是使用者的代理,在你的應用程式內針對其資料運作。工具型 LLM(Claude Code、Cursor、Codex CLI)是開發者的代理,在開發者的機器上運作以建構應用程式。它們共用「LLM」這個詞,幾乎沒有其他共通之處。
-
信任邊界就是架構。模型在哪裡執行、誰執行它,以及它接觸什麼,定義了義務。適用於某個邊界的模式對另一個邊界反而會徹底失敗。
-
MCP 伺服器承載邊界。同一個伺服器在某個部署中是開發者工具,在另一個部署中是終端使用者介面。協定不變;部署改變,而部署正是需要工程關注的部分。
完整的 Apple 生態系叢集:用於 Apple Intelligence 的型別化 App Intents;用於跨 LLM 代理的 MCP 伺服器;兩者之間的 路由問題;用於裝置端 LLM 與 Tool 協定的 Foundation Models,以 使用案例 與 自訂轉接器 作為工作負載適配與專業化的姊妹篇;用於 iOS 鎖定畫面狀態機的 Live Activities;Apple Watch 上的 watchOS 執行時 合約;用於框架基板的 SwiftUI 內部結構;用於 visionOS 場景的 RealityKit 空間心智模型;用於持久化的 SwiftData 綱要紀律;用於視覺層的 Liquid Glass 模式;用於跨裝置觸及的 多平台出貨。中樞位於 Apple 生態系列。如需更廣泛的 iOS 與 AI 代理脈絡,請參閱 iOS 代理開發指南。
FAQ
從架構觀點來看,Foundation Models 與 Claude Code 有什麼差別?
Foundation Models 是執行時功能:LLM 隨 iOS 26 出貨,透過 SystemLanguageModel.default 在使用者裝置上執行,並在應用程式的 LanguageModelSession 觸發時被調用。應用程式代表使用者執行該呼叫。Claude Code 是開發工具:LLM 在 Anthropic 的基礎設施(或設定的 Claude 供應商)上執行,開發者的機器託管 IDE,代理可存取開發者的檔案系統、shell 和 MCP 伺服器。開發者驅動代理;代理協助建構應用程式。
同一個 MCP 伺服器應該同時服務我的代理和我的終端使用者嗎?
可能不應該。同一個 JSON-RPC 合約的形狀對兩者都可能正確,但部署不同:對開發者工具而言,開發者端 stdio 無驗證是常態;對終端使用者介面而言,則是危險。協定可重用;部署不可重用。如果你確實將同一伺服器暴露給兩者,請將其視為單一程式碼基底背後的兩個部署,而非為兩種受眾使用的單一介面。
為什麼工具型 LLM 需要 hooks,而執行時 LLM 不需要?
工具型 LLM 在開發者的機器上擁有檔案系統存取、shell 存取、MCP 伺服器,以及任意程式碼執行權限。執行時 LLM(Foundation Models)只擁有應用程式 Tool 實作所暴露的東西,在應用程式沙盒內,沒有 shell。波及範圍是不對稱的。Hooks 為開發者在廣泛權限上提供執行前審查與執行後驗證。執行時 LLM 不需要它們,因為其權限在構造上就受限。
單一 Swift 領域函式可以同時服務執行時與工具型 LLM 的使用案例嗎?
可以,而且這正是正確的模式。雙轉接器作法(一個 Swift 函式、多個協定包裝器)從 App Intents vs MCP 延伸,涵蓋 Foundation Models 工具。函式不知道是哪個呼叫者調用它;轉接器攜帶綱要、信任訊號與協定特定的義務。三個轉接器,一個領域方法。
託管雲端 LLM(OpenAI、Anthropic API 直連)在這幅圖中位居何處?
在執行時從應用程式內呼叫的雲端 LLM 是第三類:具有裝置外推論的執行時 LLM。它們共享 Foundation Models 的「應用程式代表使用者執行該呼叫」信任姿態,但失去裝置端隱私故事與作業系統提供的可用性故事。決策樹延伸:當工作負載確實超出裝置端模型的封套(大型脈絡、前沿推理、大規模多模態),且對使用者隱私期望可接受(伴隨透明揭露),雲端執行時 LLM 才適切。當工作負載適合時,Foundation Models 是預設;當不適合時,雲端是升級選擇。
參考資料
-
作者於 Foundation Models 裝置端 LLM:Tool 協定 中的分析,2026 年 4 月 30 日,涵蓋
SystemLanguageModel、LanguageModelSession、Tool協定、@Generable/@Guide巨集,以及受約束的生成。 ↩↩↩↩ -
Anthropic,「Model Context Protocol」 與 「MCP 規範:Tools(2025-06-18)」。JSON-RPC 工具暴露、主機/伺服器架構,以及 stdio + Streamable HTTP 傳輸。 ↩↩
-
Anthropic,「Claude Code 參考:Hooks」。PreToolUse、PostToolUse、UserPromptSubmit、SessionStart、Stop 生命週期事件;包覆工具型 LLM 廣泛權限的驗證介面。 ↩
-
作者於 兩個代理生態系,一份購物清單 中的分析,2026 年 4 月 29 日。單一程式碼基底、多重部署的模式。 ↩
-
作者於 App Intents vs MCP:路由問題 中的分析,2026 年 4 月 30 日。雙轉接器模式(一個 Swift 領域方法、兩個協定包裝器),在本文中延伸為以 Foundation Models 作為第三類呼叫者類別的三轉接器模式。 ↩
-
Anthropic,「Hooks 參考」。生命週期事件、匹配器、命令形狀,以及 hooks 作為對代理權限的執行前驗證的角色。 ↩