博客 • AI / App Intents

iOS 27 Siri AI 開放更多能力後,App Actions 的 JSON 數據到底如何流轉?從用戶指令到 API 執行完整解析

一條 Siri 指令能執行,是因爲它先變成 App Intent 的參數,再在 AppIntent 的 perform() 裏決定走本機還是打你的 API。系統不把整段語音原樣發給服務器。

Siri 算不算 Agent,寫在 上一篇。本篇只跟一條指令:短語怎麼對上 Intent,參數怎麼變成 JSON,校驗通過之後才調用 API。

先記住這一點:語音不是請求體。Intent 填好的參數纔是。下面按「短語 → 參數類型 → 實體 id → 你的 JSON → API」走一遍。

一條指令經過的五步

官方入口是 App Intents。說明見 App Intents 入門。Siri、快捷指令和應用內按鈕走的是同一套 Intent,差別在誰填參數。

  1. 1
    短語命中

    你在 AppShortcutsProvider 裏登記口語句。系統用這句話選中某個 Intent,不是把原話交給模型自由發揮。

  2. 2
    填參數

    Intent 上的 @Parameter 告訴系統要什麼值、必填還是可選。缺了會向用戶追問,而不是猜一個發出去。

  3. 3
    解析實體

    用戶數據用 EntityQuery 按 id 解析。參數裏放的是實體,不是一段描述它的文本。

  4. 4
    執行

    perform() 裏纔讀到已經解析好的值。本機能做完的就在這裏做完。

  5. 5
    回給 Siri

    用 IntentResult 或對話返回結果。失敗也要有一句能說出口的原因,不要只在服務器日誌裏留錯。

參數分三種

參數類型見 爲 App Intent 添加參數。選錯類型,後面的 JSON 就會不穩定。

類型適合進 JSON 時
字符串、數字、日期數量、備註這種簡單輸入原樣放進 parameters
AppEnum編譯期就固定的選項,例如到店取還是配送用枚舉值,不要把展示文案當主鍵
AppEntity會變的用戶數據,例如某件商品只放解析後的 id

固定集合用 AppEnum。會隨用戶增刪的用 AppEntity 加查詢。把會變的列表寫成枚舉,選項一過期,短語就對不上。

實體只帶走 id

系統要的是可顯示、可查詢的實體。你的數據庫仍是數據源。實體上至少要有穩定 id 和給人看的名字。

解析完成後你能記下來的實體字段。id 纔是後續 API 的鍵。
{
  "entity": "OrderItem",
  "id": "sku_42",
  "display": "Oat milk"
}

查詢實現 entities(for identifiers:),用 id 找回對象。找不到就不要編一個 id 繼續。

你自己的參數 JSON

下面這份是你在 perform() 裏落盤、再決定要不要打 API 的契約。它不是 Apple 的請求格式,系統也不會替你讀這個文件。

一條已經解析完的下單指令。resolved 爲 true 才表示實體查詢成功。
{
  "intent": "StartOrder",
  "source": "siri",
  "parameters": {
    "item_id": "sku_42",
    "quantity": 1
  },
  "resolved": true
}

什麼時候打 API

  1. 1
    本機能完成

    只改本機狀態的動作,在 perform() 裏做完,不必出網。

  2. 2
    先校驗

    要用服務器時,先用 Schema 校驗上面的 JSON。缺 item_id、quantity 小於 1,都停在設備上。

  3. 3
    再出網

    校驗通過且 resolved 爲 true,才把 parameters 發給你的 API。服務器再按 id 查自己的記錄,不信任展示名。

  4. 4
    失敗說人話

    API 拒絕或超時,用 Intent 對話告訴用戶沒完成。不要讓 Siri 說已經成功。

第三方 App 怎麼聲明 Intent、失敗怎麼回,是下一篇的題目。本篇停在這條數據路徑。

和舊文怎麼分工

Siri 是不是 Agent本篇
回答系統會不會自己規劃並調用工具一條指令從短語到 API 經過哪些 JSON
不要在這裏找又一篇產品發佈稿把語音原文當成可以落盤的請求體

硬件和系統功能的產品敘事見 iPhone 18 爲什麼不只是硬件。那邊不拆參數字段。

在 JSONNote 裏檢查這條 JSON

  1. 1
    格式化

    用 JSON 格式化 打開這份參數記錄,確認沒有尾逗號。

  2. 2
    用 Schema 卡住缺字段

    把下面的 Schema 貼進 JSON Schema。缺 intent、item_id,或 quantity 不是正整數,都不應發到 API。

  3. 3
    再驗一條樣例

    用 JSON 校驗 貼一條真實樣例。重點看 item_id 是不是空字符串。

參數記錄的 JSON Schema。source 只允許 siri、shortcut、app。
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["intent", "source", "parameters", "resolved"],
  "properties": {
    "intent": { "type": "string", "minLength": 1 },
    "source": { "enum": ["siri", "shortcut", "app"] },
    "resolved": { "type": "boolean" },
    "parameters": {
      "type": "object",
      "required": ["item_id", "quantity"],
      "properties": {
        "item_id": { "type": "string", "minLength": 1 },
        "quantity": { "type": "integer", "minimum": 1 }
      }
    }
  }
}

常見問題

系統會把整段語音發給我的服務器嗎?

不會按這條路徑。服務器收到的應是你在 perform() 裏組裝、並校驗過的參數 JSON。語音留在設備側的識別過程裏。

參數裏爲什麼不直接寫商品名?

名稱會改、會重複。AppEntity 用穩定 id,查詢用這個 id 找回對象。API 也只認 id。

Schema 通過就可以打 API 嗎?

還要看 resolved。形狀對了但實體沒解析完,說明用戶還沒選定對象。這時打 API 會把一次追問變成一次錯誤下單。

本機動作和出網動作怎麼分?

只改本機數據的留在 perform()。要進你的後端的,先寫參數 JSON、校驗,再請求。兩種都要用 IntentResult 把結果說回給用戶。

這和快捷指令裏手填參數是同一條路嗎?

是同一套 AppIntent。差別是誰填參數:Siri 按短語填,快捷指令由用戶或上一個動作填。後面的實體解析、JSON 和 API 門閂相同。

總結

一條指令的數據路徑是:短語選中 Intent,參數按類型填入,實體收成 id,你寫成 JSON,校驗通過纔打 API,再用對話把結果交回 Siri。

直接結論:不要上傳原始語音;id 沒解析完就不請求;失敗要說回給用戶,而不是隻寫服務器日誌。

下一步:先用 Schema 卡住這條參數 JSON,再接到 perform()。

返回博客