博客 • Foundation Models

Apple Intelligence 2026 開發者生態變化:Foundation Models、App Intents 與 JSON 數據交換機制詳解

2026 年,同一個 App 會同時接到兩套入口:設備上的 LanguageModelSession 按類型解碼出一份內容,系統則調用 App Intent 的 perform()。要落盤的不是這兩份裏的任何一份原樣,而是你自己的交換信封。

產品敘事見 iPhone 18 爲什麼不只是硬件。Siri 會不會變成 Agent,見 Siri AI 會成爲 AI Agent 嗎。本篇只寫信封:哪些字段要落盤,以及什麼情況下不能執行。

先記住這一點:框架把 Generable 收成 schema,再解碼成值。這隻發生在模型會話裏。你要保存、對賬、再決定要不要執行,靠的是另一份信封。下面按「兩份合同 → 信封字段 → 一份 JSON → 四種停」拆開。

兩份合同不是一次調用

設備上的模型怎樣按類型填值,見 Generable。類型會收成 schema,模型填完,框架再解碼。靜態類型用 @Generable。沒有靜態類型時,會話可以按 GenerationSchema 返回 GeneratedContent。兩種結果寫進信封時都叫 content。

App Intent 是另一條調用鏈。參數寫在 @Parameter 上,說明見 爲 App Intent 添加參數。系統調用 perform() 時沒有 LanguageModelSession,也就沒有 Generable 的 content。

  1. 1
    會話產出內容

    respond(to:generating:) 返回 Response。生成還沒結束時,對應的是 PartiallyGenerated,字段可以仍爲空。這時還沒有一份能執行的參數。

  2. 2
    投影出參數

    只把 Intent 接受的字段抄進 parameters。模型多寫的 rationale 留在 content。兩份對象可以同名,但不能是同一個對象。

  3. 3
    先寫信封再執行

    source、sessionId、schemaVersion、complete、content、intent、parameters 落成一份 JSON。complete 不是 true,就不調用 perform()。

信封裏有哪些字段

下面這些鍵是你自己的信封,不是 Apple 解碼結果裏的字段。

字段誰來寫作用
source你的 Appfoundation-models 或 app-intent。標明這次值從哪條入口來。
sessionId你的 App只有模型會話纔有,例如 lm_01。系統調用時寫成 null。
schemaVersion你的 App你給 Generable 字段表標的代際。這份示例是 3。字段變了就加一,舊信封不能直接重放。
generable你的 App類型名,例如 OrderDraft。系統直接調用時寫成 null。
complete你從生成狀態抄下false 表示還在生成,字段還會變。true 才允許往下投影並考慮執行。
content模型解碼結果模型解碼出的對象,可以比動作多字段,例如 rationale。系統調用時寫成 null。
intent你的 App將要調用或系統正在調用的 App Intent 標識,例如 PlaceOrderIntent。
parameters你的投影,或系統入參交給 perform() 的對象。未完成時寫成 null。系統調用時就是系統傳入的參數。

content 和 parameters 可以有相同的字段名,但它們是兩份對象。把 content 原樣送進 perform(),模型多寫的 rationale 會進動作。

一份能落盤的交換 JSON

下面這份信封和 Schema 是你的契約,不是 Apple 的線上格式。JSONNote 的 JSON Schema 會檢查類型、枚舉和必填。complete 爲 true 才允許執行,這層 Schema 表達不了,要在 App 裏判斷。

生成完成後的信封。rationale 留在 content,parameters 裏沒有它。
{
  "source": "foundation-models",
  "sessionId": "lm_01",
  "schemaVersion": 3,
  "generable": "OrderDraft",
  "complete": true,
  "content": {
    "itemId": "sku_42",
    "quantity": 1,
    "fulfillment": "pickup",
    "rationale": "User asked for pickup."
  },
  "intent": "PlaceOrderIntent",
  "parameters": {
    "itemId": "sku_42",
    "quantity": 1,
    "fulfillment": "pickup"
  }
}
第一欄貼信封,第二欄貼這份 Schema。操作改成用 Schema 校驗。
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["source", "sessionId", "schemaVersion", "generable", "complete", "content", "intent", "parameters"],
  "properties": {
    "source": { "enum": ["foundation-models", "app-intent"] },
    "sessionId": { "type": ["string", "null"] },
    "schemaVersion": { "type": "integer" },
    "generable": { "type": ["string", "null"] },
    "complete": { "type": "boolean" },
    "content": { "type": ["object", "null"] },
    "intent": { "type": "string" },
    "parameters": { "type": ["object", "null"] }
  }
}

rationale 只留在 content。動作參數的類型對照見 App 動作字段與 JSON Schema。本篇不重複那張表。

沒完成就不要 perform

生成未完成。quantity 還沒有,parameters 保持 null。
{
  "source": "foundation-models",
  "sessionId": "lm_01",
  "schemaVersion": 3,
  "generable": "OrderDraft",
  "complete": false,
  "content": {
    "itemId": "sku_42"
  },
  "intent": "PlaceOrderIntent",
  "parameters": null
}

這封信可以通過上面的 Schema,因爲 parameters 允許 null。形狀通過也不執行。PartiallyGenerated 表示後面的 token 還會改已有字段。等 complete 變成 true,再從完整的 content 投影 parameters。未完成時就算把 parameters 寫成對象,Schema 同樣不會攔住。

信封爲什麼停
complete 爲 false後面的 token 還會改已有字段。
schemaVersion 不是當前字段表舊 content 對不上現在的 Intent。
foundation-models 的 parameters 多出 content 沒有的鍵投影不能發明模型沒寫過的值。
app-intent 的 content 不是 null系統入參不是模型輸出。不要把它寫回 content,僞裝成生成結果。

多出來的鍵用 JSON 對比看。這個檢查只用於 source 爲 foundation-models 的信封。系統調用時 content 是 null,不能要求 parameters 的每個鍵都在 content 裏出現過。

Tool 和 App Intent 怎麼交接

Foundation Models 的 Tool 由你的會話調用。說明見 用工具調用擴展生成。call(arguments:) 收到的 Arguments 也是 Generable。先寫入 content,投影成 parameters 之後,才談得上 perform()。

系統直接調用 Intent 時,source 寫成 app-intent,sessionId、generable、content 寫成 null,parameters 用系統已經傳入的值。不要編一個 sessionId,把這次調用僞裝成模型生成。

Foundation Models ToolApp Intent
誰調用你的 LanguageModelSessionSiri、快捷指令、Spotlight
入參Generable 的 Arguments@Parameter 上的參數
你實現的方法call(arguments:)perform()
信封裏的 sourcefoundation-modelsapp-intent

和另外幾篇怎麼分工

產品與 Siri 兩篇動作字段那篇本篇
回答爲什麼不只是硬件;Siri 會不會變成 Agent哪些字段能進這個動作模型值和動作參數之間落哪一份 JSON
不要在這裏找又一篇發佈稿AppEnum 和實體 id 的類型對照把 content 原樣當成 perform() 的入參

在 JSONNote 裏對上這封信

  1. 1
    選對操作

    打開 JSON Schema。操作選「用 Schema 校驗」。第一欄貼信封,第二欄貼上面的 Schema。source 只能是 foundation-models 或 app-intent。complete 必須是布爾。parameters 必須是對象或 null。

  2. 2
    撞三條壞數據

    source 寫成 siri,或 complete 寫成字符串 true,或刪掉 parameters。這三條都會失敗。未完成那封信(complete 爲 false,parameters 爲 null)會通過。通過也不要調用 perform()。

  3. 3
    對比兩份對象

    打開 JSON 對比 Diff。第一欄貼 content,第二欄貼 parameters。rationale 只該出現在第一欄。第二欄多出來的鍵是投影寫的,不是模型寫的。這個對比只用於 source 爲 foundation-models 的信封。

常見問題

Generable 的輸出能不能直接交給 perform()?

不能。輸出寫進 content。perform() 只接收投影后的 parameters。信封把兩份都留下,用來對賬。

Schema 通過了,就可以執行嗎?

還不行。這份 Schema 只檢查類型、枚舉和必填。complete 爲 false、parameters 爲 null 時形狀仍然合法。執行前要看到 complete 爲 true,並且在模型這條入口上,parameters 沒有 content 裏不存在的鍵。

Tool 和 App Intent 是同一次調用嗎?

不是。Tool 由 LanguageModelSession 調用。App Intent 由 Siri、快捷指令或 Spotlight 調用。同一件業務可以兩邊都做,入參都先落進這份信封。

schemaVersion 變了,舊日誌還能重放嗎?

不能直接重放。版本號是你給 Generable 字段表標的代際。字段變了,舊 content 對不上現在的 Intent。先停住,做一次明確的映射,再決定要不要執行。

和動作字段與 JSON Schema 那篇是同一篇嗎?

不是。那篇把參數類型對齊成一張字段表。本篇寫模型值和那張表之間要落盤的信封:入口、完成狀態、版本,以及 content 和 parameters 分開。

總結

Foundation Models 和 App Intents 是兩套入口。交換信封把入口、完成狀態、schema 版本、content 和 parameters 放在同一份 JSON 裏,是爲了在 perform() 之前能停下來。

直接結論:content 留在信封裏;perform() 只接收 parameters;complete 爲 false 不執行;schemaVersion 對不上不重放;parameters 不能出現 content 裏沒有的鍵。

下一步:先讓這封交換 JSON 通過 Schema,再用對比看 content 和 parameters。

返回博客