博客 • AI / App Intents
iOS 27 Siri AI 开放更多能力后,App Actions 的 JSON 数据到底如何流转?从用户指令到 API 执行完整解析
一条 Siri 指令能执行,是因为它先变成 App Intent 的参数,再在 AppIntent 的 perform() 里决定走本机还是打你的 API。系统不把整段语音原样发给服务器。
Siri 算不算 Agent,写在 上一篇。本篇只跟一条指令:短语怎么对上 Intent,参数怎么变成 JSON,校验通过之后才调用 API。
- 短语对上 App Shortcut,而不是把语音当自由文本执行
- 参数分三种:内建类型、编译期固定的 AppEnum、要查询的 AppEntity
- 实体只交出稳定 id,查询用这个 id 找回你的数据
- 你自己记一份参数 JSON,这不是 Apple 的线上协议
- resolved 为 false 或 Schema 失败时,不打 API,把对话交回 Siri
先记住这一点:语音不是请求体。Intent 填好的参数才是。下面按「短语 → 参数类型 → 实体 id → 你的 JSON → API」走一遍。
一条指令经过的五步
官方入口是 App Intents。说明见 App Intents 入门。Siri、快捷指令和应用内按钮走的是同一套 Intent,差别在谁填参数。
- 1短语命中
你在
AppShortcutsProvider里登记口语句。系统用这句话选中某个 Intent,不是把原话交给模型自由发挥。 - 2填参数
Intent 上的
@Parameter告诉系统要什么值、必填还是可选。缺了会向用户追问,而不是猜一个发出去。 - 3解析实体
用户数据用
EntityQuery按id解析。参数里放的是实体,不是一段描述它的文本。 - 4执行
perform() 里才读到已经解析好的值。本机能做完的就在这里做完。
- 5回给 Siri
用
IntentResult或对话返回结果。失败也要有一句能说出口的原因,不要只在服务器日志里留错。
参数分三种
参数类型见 为 App Intent 添加参数。选错类型,后面的 JSON 就会不稳定。
| 类型 | 适合 | 进 JSON 时 |
|---|---|---|
| 字符串、数字、日期 | 数量、备注这种简单输入 | 原样放进 parameters |
AppEnum | 编译期就固定的选项,例如到店取还是配送 | 用枚举值,不要把展示文案当主键 |
AppEntity | 会变的用户数据,例如某件商品 | 只放解析后的 id |
固定集合用 AppEnum。会随用户增删的用 AppEntity 加查询。把会变的列表写成枚举,选项一过期,短语就对不上。
实体只带走 id
系统要的是可显示、可查询的实体。你的数据库仍是数据源。实体上至少要有稳定 id 和给人看的名字。
{
"entity": "OrderItem",
"id": "sku_42",
"display": "Oat milk"
}
查询实现 entities(for identifiers:),用 id 找回对象。找不到就不要编一个 id 继续。
你自己的参数 JSON
下面这份是你在 perform() 里落盘、再决定要不要打 API 的契约。它不是 Apple 的请求格式,系统也不会替你读这个文件。
{
"intent": "StartOrder",
"source": "siri",
"parameters": {
"item_id": "sku_42",
"quantity": 1
},
"resolved": true
}
intent用 Intent 类型名,方便和快捷指令里的动作对上。item_id用实体 id,不用口头说法。说法会变,id 不该变。resolved为 false 表示还没解析完,或用户取消了追问。这时不打 API。- 不要把原始语音、定位轨迹或令牌写进这份 JSON。
什么时候打 API
- 1本机能完成
只改本机状态的动作,在 perform() 里做完,不必出网。
- 2先校验
要用服务器时,先用 Schema 校验上面的 JSON。缺 item_id、quantity 小于 1,都停在设备上。
- 3再出网
校验通过且 resolved 为 true,才把 parameters 发给你的 API。服务器再按 id 查自己的记录,不信任展示名。
- 4失败说人话
API 拒绝或超时,用 Intent 对话告诉用户没完成。不要让 Siri 说已经成功。
第三方 App 怎么声明 Intent、失败怎么回,是下一篇的题目。本篇停在这条数据路径。
和旧文怎么分工
| Siri 是不是 Agent | 本篇 | |
|---|---|---|
| 回答 | 系统会不会自己规划并调用工具 | 一条指令从短语到 API 经过哪些 JSON |
| 不要在这里找 | 又一篇产品发布稿 | 把语音原文当成可以落盘的请求体 |
硬件和系统功能的产品叙事见 iPhone 18 为什么不只是硬件。那边不拆参数字段。
在 JSONNote 里检查这条 JSON
- 1格式化
用 JSON 格式化 打开这份参数记录,确认没有尾逗号。
- 2用 Schema 卡住缺字段
把下面的 Schema 贴进 JSON Schema。缺 intent、item_id,或 quantity 不是正整数,都不应发到 API。
- 3再验一条样例
用 JSON 校验 贴一条真实样例。重点看
item_id是不是空字符串。
{
"$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()。