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.
- content est l'objet décodé par le modèle
- parameters est l'objet passé à perform()
- Quand complete est false, parameters reste null
- Si schemaVersion change, une ancienne enveloppe ne se rejoue pas telle quelle
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.
- 1La 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.
- 2Projeter 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É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.
| Champ | Qui l'écrit | Rôle |
|---|---|---|
source | Votre app | foundation-models ou app-intent. Indique quelle entrée a produit la valeur. |
sessionId | Votre app | Seule une session de modèle en a un, par exemple lm_01. Un appel système met null. |
schemaVersion | Votre app | La 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. |
generable | Votre app | Le nom du type, par exemple OrderDraft. Un appel direct du système met null. |
complete | Vous le copiez depuis l'état de génération | false 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. |
content | Valeur décodée du modèle | L'objet décodé. Il peut avoir plus de champs que l'action, par exemple rationale. Un appel système met null. |
intent | Votre app | L'identifiant de l'App Intent que vous allez appeler, ou que le système appelle, par exemple PlaceOrderIntent. |
parameters | Votre projection, ou les arguments du système | L'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.
{
"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": "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
{
"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.
| Enveloppe | Pourquoi s'arrêter |
|---|---|
| complete est false | Des jetons suivants peuvent encore modifier des champs déjà présents. |
| schemaVersion n'est pas la liste de champs actuelle | L'ancien content ne correspond pas à l'Intent actuel. |
| Pour foundation-models, parameters a une clé absente de content | La projection ne doit pas inventer une valeur que le modèle n'a pas écrite. |
| Pour app-intent, content n'est pas null | Les 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 Tool | App Intent | |
|---|---|---|
| Qui appelle | Votre LanguageModelSession | Siri, Raccourcis, Spotlight |
| Entrée | Arguments Generable | Valeurs sur @Parameter |
| Méthode que vous implémentez | call(arguments:) | perform() |
| source dans l'enveloppe | foundation-models | app-intent |
Ce que les autres articles couvrent
| Articles produit et Siri | L'article sur les champs d'action | Cet article | |
|---|---|---|---|
| Répond à | Pourquoi c'est plus que du matériel, et si Siri devient un agent | Quels champs peuvent entrer dans l'action | Quel JSON se place entre la valeur du modèle et les paramètres de l'action |
| Ne cherchez pas ici | Un autre compte-rendu de lancement | La correspondance AppEnum et id d'entité | Passer content tel quel en entrée de perform() |
Vérifier l'enveloppe dans JSONNote
- 1Choisir 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.
- 2Opposer 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().
- 3Comparer 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.