Блог • AI / App Intents
Как на самом деле течёт JSON App Action, когда iOS 27 открывает больше действий Siri? От фразы к вызову API
Команда Siri выполняется, потому что сначала становится параметрами App Intent, а AppIntent в perform() решает, остаться на устройстве или вызвать ваш API. Система не пересылает сырую фразу на сервер.
Является ли Siri агентом, написано в предыдущей статье. Эта следует за одной командой: как фраза выбирает Intent, как параметры становятся JSON и почему API вызывается только после проверки.
- Фраза совпадает с App Shortcut. Высказывание не выполняется как свободный текст
- Три вида параметров: встроенные типы, AppEnum на этапе компиляции и AppEntity, которую нужно запросить
- Сущность отдаёт стабильный id. Запрос загружает ваши данные по нему
- JSON параметров храните вы. Это не сетевой формат Apple
- Если resolved равен false или схема не прошла, API не вызывайте. Диалог верните Siri
Сначала запомните: Речь — не тело запроса. Заполненные параметры Intent — да. Дальше: фраза, тип параметра, id сущности, ваш JSON, затем API.
Пять шагов одной команды
Официальный вход — App Intents. См. Начало работы с App Intents. Siri, Команды и кнопка в приложении используют один Intent. Они различаются тем, кто заполняет параметры.
- 1Совпасть с фразой
Говоримые фразы вы регистрируете в
AppShortcutsProvider. Система выбирает по ним Intent. Она не отдаёт сырую фразу модели на импровизацию. - 2Заполнить параметры
Каждый
@Parameterу Intent сообщает системе, какое значение нужно и обязательно ли оно. Если значения нет, система спрашивает. Она не угадывает и не отправляет. - 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Сначала проверить
Если нужен сервер, сначала проверьте JSON схемой. Нет item_id или quantity меньше 1 — остановитесь на устройстве.
- 3Затем в сеть
Отправляйте parameters в свой API только после проверки и если resolved равен true. Сервер ищет свою запись по id. Отображаемому имени он не доверяет.
- 4Сказать об ошибке понятно
Если API отклоняет вызов или время вышло, скажите через диалог Intent, что действие не завершилось. Не позволяйте Siri объявить успех.
Как стороннее приложение объявляет Intent и возвращает ошибку — следующая статья. Эта останавливается на пути данных.
Чем это отличается от старых статей
| Siri — это агент? | Эта статья | |
|---|---|---|
| Вопрос | Планирует ли система сама и вызывает ли инструменты | Какой JSON проходит одна команда на пути к API |
| Не ищите здесь | Ещё один анонс продукта | Сырую фразу как тело запроса, которое можно сохранить |
Продуктовый рассказ об оборудовании и системных функциях — в почему iPhone 18 больше, чем обновление железа. Там поля параметров не разбираются.
Проверить этот JSON в JSONNote
- 1Форматировать
Откройте запись параметров в форматировании JSON и убедитесь, что нет висячей запятой.
- 2Остановить пропущенные поля схемой
Вставьте схему ниже в 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 }
}
}
}
}
Вопросы
Система отправляет всю фразу на мой сервер?
Не по этому пути. Сервер должен получить JSON параметров, который вы собираете и проверяете в perform(). Речь остаётся в распознавании на устройстве.
Почему в параметрах нет названия товара?
Названия меняются и совпадают. AppEntity использует стабильный id, запрос загружает объект по нему. API должен принимать только id.
Если схема прошла, можно вызывать API?
Смотрите ещё resolved. Верная форма при неразрешённой сущности значит, что человек ещё не выбрал объект. Вызов API превратит уточнение в неверный заказ.
Как разделить локальную работу и сетевой вызов?
То, что меняет только локальные данные, заканчивается в perform(). То, чему нужен ваш бэкенд, пишет JSON параметров, проверяет его и затем вызывает. Оба пути возвращают результат через IntentResult.
Команда с параметрами, заполненными вручную, идёт тем же путём?
Да, это тот же AppIntent. Разница в том, кто заполняет параметры: Siri по фразе, Команды — человек или предыдущее действие. Разрешение сущности, JSON и затвор API те же.
Итог
Путь одной команды: фраза выбирает Intent, параметры заполняются по типу, сущность сжимается до id, вы пишете JSON, API вызывается только после проверки, и диалог возвращает результат Siri.
Прямой вывод: не загружайте сырую фразу. Не вызывайте API, пока id не разрешён. Скажите об ошибке человеку, а не оставляйте её только в журнале сервера.
Дальше: зафиксируйте этот JSON параметров схемой, прежде чем подключать его к perform().