Blog • Foundation Models

Apple Intelligence 2026 : le JSON échangé entre Foundation Models et App Intents

En 2026, la même app a deux entrées. Une LanguageModelSession sur l'appareil décode une valeur typée, et le système appelle perform() sur un App Intent. Ce que vous enregistrez n'est aucune de ces deux valeurs brute. C'est une enveloppe d'échange à vous.

Le récit produit est dans pourquoi l'iPhone 18 est plus que du matériel. Siri deviendra-t-elle un agent : voir Siri AI deviendra-t-elle un agent IA. Cet article ne traite que l'enveloppe : quels champs enregistrer, et quand ne pas lancer l'action.

Retenez d'abord ceci : Le framework transforme un type Generable en schéma, puis décode une valeur. Cela reste dans la session du modèle. L'enveloppe sert à enregistrer et à comparer avant de lancer l'action. Ensuite : deux contrats, les champs, un JSON, quatre raisons de s'arrêter.

Deux contrats, deux appels

Comment le modèle sur l'appareil remplit une valeur typée : voir Generable. Le type devient un schéma, le modèle le remplit, le framework décode une valeur. Un type statique utilise @Generable. Sans type statique, la session peut renvoyer GeneratedContent pour un GenerationSchema. Les deux s'écrivent dans l'enveloppe sous content.

Un App Intent est un autre appel. Les paramètres sont sur @Parameter. Voir Ajouter des paramètres à un App Intent. Quand le système appelle perform(), il n'y a pas de LanguageModelSession et pas de content Generable.

  1. 1
    La session produit le contenu

    respond(to:generating:) renvoie une Response. Tant que la génération n'est pas finie, la valeur est PartiallyGenerated et des champs peuvent être vides. Il n'y a pas encore de paramètres à exécuter.

  2. 2
    Projeter les paramètres

    Copiez dans parameters seulement les champs que l'Intent accepte. Un rationale ajouté par le modèle reste dans content. Les noms peuvent coincider. Ce n'est pas le même objet.

  3. 3
    Écrire l'enveloppe avant d'exécuter

    Enregistrez source, sessionId, schemaVersion, complete, content, intent et parameters dans un seul JSON. Si complete n'est pas true, n'appelez pas perform().

Les champs de l'enveloppe

Ces clés appartiennent à votre enveloppe. Ce ne sont pas des champs de la valeur décodée par Apple.

ChampQui l'écritRôle
sourceVotre appfoundation-models ou app-intent. Indique quelle entrée a produit la valeur.
sessionIdVotre appSeule une session de modèle en a un, par exemple lm_01. Un appel système met null.
schemaVersionVotre appLa génération de votre liste de champs Generable. Cet exemple utilise 3. Incrémentez-la si les champs changent. Ne rejouez pas une ancienne enveloppe dans le nouvel Intent.
generableVotre appLe nom du type, par exemple OrderDraft. Un appel direct du système met null.
completeVous le copiez depuis l'état de générationfalse signifie que la génération continue et que les champs peuvent encore changer. Seul true permet de projeter et d'envisager l'exécution.
contentValeur décodée du modèleL'objet décodé. Il peut avoir plus de champs que l'action, par exemple rationale. Un appel système met null.
intentVotre appL'identifiant de l'App Intent que vous allez appeler, ou que le système appelle, par exemple PlaceOrderIntent.
parametersVotre projection, ou les arguments du systèmeL'objet passé à perform(). Tant que ce n'est pas fini, mettez null. Lors d'un appel système, ce sont les arguments déjà fournis.

content et parameters peuvent partager des noms de champs. Ce sont deux objets. Si vous passez content tel quel à perform(), un rationale ajouté par le modèle entre dans l'action.

Un JSON à enregistrer

L'enveloppe et le schéma ci-dessous sont votre contrat, pas le format réseau d'Apple. JSON Schema dans JSONNote vérifie les types, les enums et les clés requises. Il ne peut pas dire que l'exécution n'est permise que si complete est true. Cette décision reste dans l'app.

L'enveloppe une fois la génération finie. rationale reste dans content et n'est pas dans 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"
  }
}
Collez l'enveloppe dans le premier champ et ce schéma dans le second. Réglez Fonctionnement sur Vérifiez avec 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 ne reste que dans content. La correspondance des types de paramètres est dans champs d'action de l'app et JSON Schema. Cet article ne répète pas ce tableau.

Pas de perform tant que ce n'est pas fini

La génération n'est pas finie. quantity manque encore, parameters reste null.
{
  "source": "foundation-models",
  "sessionId": "lm_01",
  "schemaVersion": 3,
  "generable": "OrderDraft",
  "complete": false,
  "content": {
    "itemId": "sku_42"
  },
  "intent": "PlaceOrderIntent",
  "parameters": null
}

Cette enveloppe passe le schéma ci-dessus, parce que parameters peut être null. Une forme valide n'est pas une raison d'exécuter. PartiallyGenerated signifie que des jetons suivants peuvent encore modifier des champs déjà présents. Attendez que complete soit true, puis projetez parameters depuis le content complet. Si parameters est un objet alors que la génération n'est pas finie, le schéma l'accepte aussi.

EnveloppePourquoi s'arrêter
complete est falseDes jetons suivants peuvent encore modifier des champs déjà présents.
schemaVersion n'est pas la liste de champs actuelleL'ancien content ne correspond pas à l'Intent actuel.
Pour foundation-models, parameters a une clé absente de contentLa projection ne doit pas inventer une valeur que le modèle n'a pas écrite.
Pour app-intent, content n'est pas nullLes arguments du système ne sont pas une sortie du modèle. Ne les recopiez pas dans content pour faire croire à une génération.

Un JSON diff montre une clé en trop. Ce contrôle ne vaut que si source est foundation-models. Lors d'un appel système, content est null : vous ne pouvez pas exiger que chaque clé de parameters ait figuré dans content.

Comment Tool rejoint App Intent

Un Tool de Foundation Models est appelé par votre session. Voir Étendre la génération avec l'appel d'outils. Les Arguments reçus par call(arguments:) sont aussi Generable. Écrivez-les d'abord dans content. perform() ne se discute qu'après la projection vers parameters.

Quand le système appelle l'Intent directement, mettez source à app-intent, et sessionId, generable et content à null. parameters sont les valeurs déjà fournies. N'inventez pas de sessionId pour déguiser l'appel en sortie du modèle.

Foundation Models ToolApp Intent
Qui appelleVotre LanguageModelSessionSiri, Raccourcis, Spotlight
EntréeArguments GenerableValeurs sur @Parameter
Méthode que vous implémentezcall(arguments:)perform()
source dans l'enveloppefoundation-modelsapp-intent

Ce que les autres articles couvrent

Articles produit et SiriL'article sur les champs d'actionCet article
Répond àPourquoi c'est plus que du matériel, et si Siri devient un agentQuels champs peuvent entrer dans l'actionQuel JSON se place entre la valeur du modèle et les paramètres de l'action
Ne cherchez pas iciUn autre compte-rendu de lancementLa correspondance AppEnum et id d'entitéPasser content tel quel en entrée de perform()

Vérifier l'enveloppe dans JSONNote

  1. 1
    Choisir la bonne opération

    Ouvrez JSON Schema. Réglez Fonctionnement sur Vérifiez avec Schema. Collez l'enveloppe dans le premier champ et le schéma ci-dessus dans le second. source vaut foundation-models ou app-intent. complete est un booléen. parameters est un objet ou null.

  2. 2
    Opposer trois documents invalides

    Mettez source à siri, complete à la chaîne true, ou supprimez parameters. Les trois échouent. L'enveloppe inachevée, avec complete à false et parameters à null, passe. Réussir ne veut pas dire appeler perform().

  3. 3
    Comparer les deux objets

    Ouvrez JSON Comparer Diff. Collez content dans le premier champ et parameters dans le second. rationale ne doit apparaître que dans le premier. Une clé seulement dans le second vient de la projection, pas du modèle. Ce diff ne vaut que si source est foundation-models.

Questions fréquentes

La sortie Generable peut-elle aller directement à perform() ?

Non. La sortie s'écrit dans content. perform() ne reçoit que les parameters projetés. L'enveloppe garde les deux pour les comparer.

Si le schéma passe, peut-on exécuter l'action ?

Pas encore. Ce schéma ne vérifie que les types, les enums et les clés requises. complete à false et parameters à null reste une forme valide. Avant d'exécuter, complete doit être true et, sur l'entrée modèle, parameters ne doit pas contenir une clé absente de content.

Tool et App Intent sont-ils le même appel ?

Non. Un Tool est appelé par LanguageModelSession. Un App Intent est appelé par Siri, Raccourcis ou Spotlight. La même tâche peut exister des deux côtés. Les deux entrées passent d'abord par cette enveloppe.

Si schemaVersion change, peut-on rejouer un ancien journal ?

Pas tel quel. La version marque la génération de votre liste de champs Generable. Après un changement de champs, l'ancien content ne correspond plus à l'Intent actuel. Arrêtez-vous, écrivez une correspondance explicite, puis décidez d'exécuter.

Est-ce le même article que celui sur les champs d'action et JSON Schema ?

Non. Cet article aligne les types de paramètres en une liste de champs. Celui-ci décrit l'enveloppe entre la valeur du modèle et cette liste : entrée, achèvement, version, et content séparé de parameters.

Conclusion

Foundation Models et App Intents sont deux entrées. L'enveloppe met l'entrée, l'achèvement, la version du schéma, content et parameters dans un seul JSON, pour pouvoir s'arrêter avant perform().

La décision : content reste dans l'enveloppe ; perform() ne reçoit que parameters ; pas d'exécution si complete est false ; pas de rejeu si schemaVersion ne correspond pas ; parameters ne contient pas une clé absente de content.

Ensuite : faites passer ce JSON par le schéma, puis comparez content et parameters.

Retour au blog