Foundation Models LLM on-device : le protocole Tool
Le contrat LLM on-device qu’Apple a livré à la WWDC 2025 soulève une question de routage immédiate : quand LanguageModelSession est-il la bonne réponse, quand est-ce AppIntent, quand est-ce MCP, et quand est-ce aucun des trois.
iOS 26 livre un modèle de langage de 3 milliards de paramètres sur chaque appareil compatible Apple Intelligence.1 Apple appelle le framework Foundation Models. Le framework est local. L’inférence est optimisée pour Apple silicon et s’exécute on-device ; le réseau n’est pas dans le chemin d’appel. Le modèle réside dans SystemLanguageModel.default, votre app obtient une LanguageModelSession, et la surface typée qui permet à cette session de faire un travail utile est le protocole Tool.
Le protocole Tool est la partie qui compte pour les développeurs d’apps. Sans lui, le LLM on-device est un endpoint de chat completion sans aucune connexion aux données de votre app, aux données de votre utilisateur ni au reste du système. Avec lui, le modèle peut appeler des fonctions Swift typées, recevoir des résultats typés en retour et raisonner sur la réponse au tour suivant. La génération on-device augmentée d’outils est la véritable capacité du framework. La surface conversationnelle est la démonstration.
TL;DR
- Foundation Models met à disposition de chaque appareil éligible à Apple Intelligence un LLM de 3 milliards de paramètres sur
SystemLanguageModel.default. Le modèle est local ; l’inférence est optimisée pour Apple silicon et s’exécute on-device ; le réseau est hors du chemin d’appel. - Le protocole Tool est le contrat entre le modèle et votre app. Un tool déclare des
Argumentstypés, retourne unOutputtypé, et est lié à uneLanguageModelSessionà la construction. - Les annotations
GenerableetGuidepermettent au modèle de produire directement des valeurs Swift typées, et non de simples chaînes. Le décodeur fait partie du framework, pas de votre code. - La règle de routage entre Foundation Models, App Intents et MCP est qui exécute le modèle et où. Foundation Models = votre app exécute le modèle on-device. App Intents = Apple Intelligence exécute le modèle on-device et route vers votre app. MCP = un hôte externe exécute le modèle où il le souhaite et atteint votre app via un serveur de tools.
Ce que le framework fournit réellement
Trois primitives portent le framework : le modèle, la session et le tool.2
SystemLanguageModel. Une référence au modèle de fondation on-device. L’instance par défaut est liée à l’appareil de l’utilisateur, disponible sur le matériel éligible à Apple Intelligence, et expose des vérifications de capacités que l’app lit au runtime pour décider si le modèle est disponible. Le framework prend en charge la configuration via SystemLanguageModel(useCase:guardrails:), des adapters personnalisés, et GenerationOptions, mais vous ne choisissez pas d’identifiants de modèles cloud arbitraires comme vous le feriez avec OpenAI ou Anthropic ; Apple livre et met à jour le modèle on-device à chaque version d’OS, et le framework vous remet la version actuellement installée.
LanguageModelSession. Un objet à état qui conserve l’état de la conversation entre les appels. La session prend un system prompt à la construction, accumule les tours utilisateur/assistant au fil du temps et expose des méthodes async pour générer des réponses. Les sessions sont légères à créer et jetables ; vous en créez une par tâche, pas une par app. Une app de méditation crée une session pour « résume mes 7 derniers jours de pratique » ; une app de recettes crée une session différente pour « convertis cette recette pour deux personnes au lieu de quatre ».
Tool (le protocole). Un protocole Swift qui déclare un name, une description, un type Arguments, un type Output et une fonction async call(arguments:). Les tools sont liés à une session à la construction (LanguageModelSession(tools: [...], instructions: ...)). Quand le modèle décide qu’il a besoin d’un tool, il émet un appel structuré ; le framework décode les arguments, exécute le tool, encode le résultat et le réinjecte dans la session pour le tour suivant. Le modèle ne voit pas Swift ; le framework gère le marshalling.
Les exigences complètes du protocole : name: String, description: String, un type associé Arguments conforme à ConvertibleFromGeneratedContent, un type associé Output conforme à PromptRepresentable, et une méthode async call(arguments:). La macro @Generable sur la struct Arguments génère gratuitement la conformance ConvertibleFromGeneratedContent ; pour Output, String et GeneratedContent sont déjà conformes. Les exemples documentés par Apple retournent String ou [String].
La forme du protocole Tool, condensée :
import FoundationModels
struct WaterEntryLookup: Tool {
let name = "lookup_water_entries"
let description = "Look up water intake entries for a given date range."
@Generable
struct Arguments {
@Guide(description: "Start date in ISO-8601 format")
let startDate: String
@Guide(description: "End date in ISO-8601 format")
let endDate: String
}
func call(arguments: Arguments) async throws -> String {
let entries = try store.entries(
from: ISO8601DateFormatter().date(from: arguments.startDate) ?? .now,
to: ISO8601DateFormatter().date(from: arguments.endDate) ?? .now
)
let totalMl = entries.reduce(0) { $0 + $1.amountMl }
return "Found \(entries.count) entries totalling \(totalMl)ml."
}
}
Le modèle voit une description du tool et une forme d’argument issue d’un schéma de génération. Le code Swift voit une entrée typée et une sortie typée. La frontière de décodage/encodage est la partie qu’Apple prend en charge. La sortie d’un tool peut être une String ou un objet GeneratedContent ; l’exemple ci-dessus retourne String puisque le raisonnement du modèle au tour suivant en est le consommateur.
Generable et Guide : sortie typée sans parser
Le même système d’annotations qui rend les arguments des tools typés permet aussi au modèle de produire directement des valeurs Swift typées.3 Une struct @Generable déclare sa forme ; le framework contraint la sortie du modèle à correspondre.
@Generable
struct PracticeSummary {
@Guide(description: "Single-sentence headline summarizing the user's week")
let headline: String
@Guide(description: "Total practice duration this week in minutes")
let totalMinutes: Int
@Guide(description: "Three short observations as bullet points")
let observations: [String]
}
let session = LanguageModelSession(instructions: "You are a meditation coach.")
let summary = try await session.respond(
to: "Summarize this week of practice given the entries.",
generating: PracticeSummary.self
)
L’appel retourne un Response<PracticeSummary> dont le content est un PracticeSummary typé. Pas de parsing JSON dans votre code, pas de string-matching pour « headline: », pas de plan B quand le modèle a renvoyé un objet malformé. Le framework utilise un échantillonnage contraint pour maintenir la sortie token par token du modèle structurellement alignée avec le schéma, de sorte qu’une sortie structurellement invalide ne franchit pas la frontière. La session ci-dessus ne prend aucun tool car la sortie typée et l’appel d’outils sont des capacités indépendantes ; une session peut utiliser @Generable pour la forme de la réponse, des tools pour l’ancrage, les deux ou aucun des deux.
La surface typée Swift est ce qui distingue le framework des SDK LLM cloud. Les SDK cloud (OpenAI Structured Outputs, Anthropic tool use, autres) prennent également en charge l’échantillonnage contraint, mais la valeur typée que le développeur reçoit est un objet JSON validé par rapport à un schéma, puis décodé en un type Swift Codable dans une étape distincte. Foundation Models fusionne ces étapes : la macro @Generable et le décodeur du framework produisent une valeur Swift typée comme retour direct, les annotations @Guide par champ portant l’intention dans la contrainte de génération. La sortie est typée parce que la génération a été typée par rapport au schéma Swift, et non par rapport à une spécification JSON que le développeur aurait reconstruite en Swift.
Les annotations @Guide sont la manière de communiquer au modèle l’intention par champ sans l’écrire dans le prompt. La description générée devient partie intégrante de la contrainte de génération. Les guides au niveau du champ gardent le prompt épuré et le schéma proche des données.
La question du routage, en trois variantes
Apple offre désormais trois surfaces de protocole qu’une app peut utiliser pour exposer son domaine à un modèle de langage. Elles routent vers des exécuteurs différents.
Foundation Models (LanguageModelSession). Votre app charge le modèle on-device et exécute l’inférence. Les tools que la session peut appeler sont des tools que le code de votre app définit. Le modèle ne quitte jamais l’appareil. L’utilisateur ne l’invoque pas via Siri ; le code de votre app le fait. Le cas d’usage est à l’intérieur de votre app : une app de méditation qui utilise le LLM pour résumer une semaine, une app de recettes qui adapte une recette pour moins de portions, un suivi d’hydratation qui transforme « j’ai bu un verre au déjeuner » en une entrée structurée.
App Intents. Apple Intelligence exécute un LLM pour le compte de l’utilisateur (l’agent first-party d’Apple) et route les appels de capacités vers les types AppIntent de votre app. Votre app n’exécute pas le modèle. Vous déclarez des actions typées via le framework App Intents, et la pile système d’Apple décide quand les invoquer en fonction d’une requête utilisateur, d’une recherche Spotlight, d’une commande Siri ou d’une orchestration Shortcuts. Couvert en détail dans App Intents Are Apple’s New API to Your App.4
MCP. Un hôte externe (Claude Desktop, Claude Code, Cursor, ChatGPT) exécute le modèle choisi par le développeur. Votre app expose un serveur que le modèle de l’hôte peut appeler. Le modèle s’exécute là où l’hôte l’exécute ; les appels de tools traversent un transport JSON-RPC. Couvert dans Two Agent Ecosystems, One Shopping List et la synthèse sur la question du routage dans App Intents vs MCP.5
La décision de routage se résume à qui est l’agent.
┌──────────────────────────────────┐
│ Who is the language model? │
└────┬─────────────┬─────────────┬──┘
│ │ │
┌────────┴────┐ ┌──────┴──────┐ ┌────┴──────┐
│ Your app's │ │ Apple │ │ External │
│ own use of │ │ Intelligence│ │ host's │
│ LLM │ │ agent │ │ agent │
└──────┬──────┘ └──────┬──────┘ └────┬──────┘
│ │ │
▼ ▼ ▼
Foundation Models App Intents MCP
+ Tool protocol + AppEntity + tools/list
(on-device, your (system runs (host runs
app runs model) the model) the model)
Une app de méditation qui résume la semaine de l’utilisateur utilise Foundation Models parce que l’app elle-même veut appeler le modèle et présenter un résultat dans l’app. La capacité « enregistrer une session de 5 minutes » de la même app utilise App Intents pour que Siri puisse l’invoquer. La capacité « montre-moi mes dernières entrées de journal de méditation » de la même app, utilisée par une session Claude Code, passe par MCP. Trois exécuteurs différents, trois obligations différentes, une couche de domaine partagée en dessous.
Budgets d’inférence : ce que le framework attend de vous
Faire tourner un LLM on-device n’est pas gratuit. Apple silicon gère l’inférence, mais le modèle a tout de même une fenêtre de contexte, un budget de tokens et une latence en temps réel qui dépend de l’appareil. Trois contraintes structurent la conception avec le framework :6
La disponibilité est par appareil. Tous les appareils iOS 26 n’ont pas Apple Intelligence. Les iPhone plus anciens, les appareils verrouillés et les appareils où l’utilisateur a désactivé Apple Intelligence retournent un état non disponible depuis SystemLanguageModel.default.availability. Du code qui appelle LanguageModelSession sans vérifier la disponibilité fait remonter une erreur de génération au runtime ; le bon pattern est de brancher l’UI sur l’état de disponibilité en amont et de présenter un parcours sans LLM quand l’état n’est pas disponible. Traitez le modèle comme un feature flag, pas comme une garantie.
La latence n’est pas négligeable. La latence du premier token sur le matériel iPhone 16 Pro est utilisable pour les interactions in-app dans nos tests sur Return ; les générations longues et les chaînes d’appels d’outils ne sont pas instantanées. Les patterns d’UI qui fonctionnent pour le streaming LLM cloud fonctionnent ici aussi ; ne bloquez pas le main thread, montrez une sortie progressive et concevez pour le cas où l’utilisateur navigue ailleurs en pleine génération.
Les fenêtres de contexte sont plus petites que dans le cloud. Le modèle on-device a une fenêtre de contexte plus petite que les modèles cloud de la classe GPT-4. Les longs documents nécessitent un résumé ou un découpage. Les longs historiques de conversation nécessitent un nettoyage. Les sorties de tools qui retournent de gros payloads structurés devraient retourner une référence (un ID, une clé) que le tour suivant peut récupérer à la demande, et non l’intégralité du payload inline.
L’ensemble des contraintes ressemble à la conception pour un runtime edge bas de gamme, et non à un modèle frontier dans le cloud. Les facilités du framework rendent l’expérience plus agréable ; les limites physiques sous-jacentes, elles, ne bougent pas.
Quand recourir à Foundation Models
Les meilleurs ajustements du framework se trouvent là où la génération on-device à faible friction est le produit :
Reformatage et réécriture. Transformer une note libre de l’utilisateur en une entrée structurée, peaufiner un brouillon de message, résumer une transcription capturée. La tolérance à la latence est modérée ; la sensibilité des données est élevée ; l’inférence cloud est disproportionnée.
Synthèse locale sur des données privées. Une app de fitness qui transforme l’historique d’entraînement d’un utilisateur en un résumé « cette semaine ». Une app de finance qui explique les habitudes de dépenses d’un utilisateur. Une app de journal qui fait émerger des thèmes sur un trimestre d’entrées. Les données ne devraient pas quitter l’appareil ; la réponse devrait apparaître dans l’app ; le prompt est borné.
Appels d’outils légers pour de l’automatisation interne à l’app. Une app qui permet à l’utilisateur de dire « montre-moi le journal de méditation de mardi » et qui utilise un tool pour récupérer les enregistrements sous-jacents, puis met en forme la réponse. L’agent est l’app, le tool est la propre couche de données de l’app, le modèle est local.
Génération conforme à un type. Partout où l’app aurait sinon écrit à la main un parser JSON ou un template de chaîne, @Generable plus @Guide est une surface plus durable.
Quand ne pas recourir à Foundation Models
Le framework est la mauvaise réponse pour plusieurs cas courants :
Tout ce que l’utilisateur pourrait demander à Siri. « Enregistre 250 ml d’eau », « Démarre une méditation de 5 minutes », « Ajoute des bananes à ma liste » relèvent d’App Intents. Apple Intelligence est l’exécuteur ; votre app est la destination. Foundation Models sert à la génération à l’intérieur de l’app, pas aux actions routées par Siri. Si vous construisez la même capacité deux fois (App Intent + LanguageModelSession avec un tool), l’App Intent l’emporte parce que l’utilisateur invoque Siri, pas votre écran in-app.
Tout ce qu’un agent LLM externe devrait piloter. Une session Claude Code qui atteint le domaine de votre app passe par MCP. L’app n’exécute pas le LLM ; l’hôte le fait ; le modèle vit là où l’hôte l’a placé. Foundation Models ne peut pas servir des agents externes.
Raisonnement lourd sur de gros documents. Le modèle on-device est petit. Un contrat de 200 pages, un long contexte de codebase, ou un raisonnement multi-images sur de nombreuses photos relèvent de l’inférence cloud (la vôtre ou celle d’un fournisseur), où la fenêtre de contexte et le nombre de paramètres correspondent à la charge de travail. Les tâches qui dépassent l’enveloppe du framework produisent des erreurs concrètes : fenêtre de contexte dépassée, violations de garde-fous, locales non prises en charge. Faites remonter ces erreurs délibérément plutôt que de concevoir des flux qui dépendent du modèle pour gérer des tâches hors enveloppe.
Workflows multi-appareils et multi-utilisateurs. Le modèle on-device n’a accès qu’à ce que l’app passe dans la session. La synchronisation multi-appareils (état du minuteur de la Watch vers l’iPhone), la collaboration multi-utilisateurs (listes partagées, documents partagés) et tout flux qui bénéficie d’une coordination côté serveur nécessitent un serveur. Le modèle n’est pas une primitive réseau.
Ce que je construirais différemment dans ma stack
Le framework récompense un choix d’architecture spécifique qu’il est facile de rater du premier coup. Les capacités que l’utilisateur invoque via l’UI de l’app et que le LLM devrait consommer comme des tools, et non comme des chemins prose dupliqués.
Une app de méditation pourrait ajouter un volet « bilan hebdomadaire » résumé par LLM. La construction naïve est un seul prompt : « Voici les entrées de l’utilisateur cette semaine, écris un paragraphe. » La meilleure construction définit un tool WeeklyEntries que le modèle peut appeler quand il a besoin de savoir ce qu’il y avait dans la semaine, plus une sortie structurée WeeklySummary via @Generable. La première construction est fragile (le modèle doit ingérer une longue liste d’entrées à chaque appel), coûteuse en tokens et produit de la prose non structurée. La seconde est durable (l’appel d’outil sépare « ce qu’il s’est passé » de « comment en parler »), peu coûteuse (le modèle ne récupère que ce dont il a besoin) et structurée (le résultat est une valeur Swift typée).
Le pattern se compose proprement avec App Intents et MCP. La même requête WeeklyEntries est aussi le corps d’un resolver de paramètre AppIntent et d’un handler de tool MCP. Une fonction Swift ; trois surfaces. Le modèle appelle la même fonction que celle qu’appelle l’utilisateur.
L’autre décision d’architecture : les descriptions des tools font partie du prompt. Le modèle lit Tool.description pour décider s’il faut appeler et quand. Traitez la description comme un docstring que vous attendez d’un futur contributeur ; le modèle est le futur contributeur.
Ce que ce pattern signifie pour la stack Apple sur iOS 26+
Trois enseignements.
-
Le LLM on-device est une fonctionnalité de runtime, pas un backend. Traitez-le comme un framework système avec une fenêtre de contexte et un budget d’inférence on-device, pas comme un service distant. Les décisions d’architecture portent sur la disponibilité, la latence, la discipline de fenêtre de contexte et la sortie structurée.
-
Le protocole Tool est la surface. Sans tools, le modèle est un endpoint de chat completion sans aucune connexion à votre domaine. Avec des tools, le modèle devient une couche de requêtes structurées sur les données de votre app.
-
La règle de routage entre Foundation Models, App Intents et MCP est « qui exécute le modèle ». La génération à l’intérieur de l’app va à Foundation Models. Les capacités routées par Apple Intelligence vont à App Intents. Les capacités d’agent externe vont à MCP. La même fonction de domaine Swift peut être appelée par les trois surfaces.
Trois articles frères vont plus loin à l’intérieur du framework Foundation Models : Foundation Models use cases pour les décisions d’adéquation à la charge de travail, custom adapters pour le fine-tuning du modèle on-device sur les données de l’app, et the agentic workflow pour la séparation entre LLM in-app et tooling.
Le cluster Apple Ecosystem complet : App Intents typés pour Apple Intelligence ; serveurs MCP pour les agents cross-LLM ; la question du routage entre les deux ; Live Activities pour la machine d’états de l’écran verrouillé ; patterns Liquid Glass pour la couche visuelle ; livraison multi-plateformes pour la portée multi-appareils. Le hub se trouve sur la page Apple Ecosystem Series. Pour un contexte plus large sur iOS avec des agents IA, voir le iOS Agent Development guide.
FAQ
Qu’est-ce que le framework Foundation Models dans iOS 26 ?
Foundation Models est le framework d’Apple pour accéder au modèle de langage on-device livré avec les appareils éligibles à Apple Intelligence sur iOS 26 (et iPadOS 26, macOS 26, visionOS 26). Le framework expose SystemLanguageModel, LanguageModelSession et le protocole Tool pour que les apps puissent exécuter des appels LLM typés et on-device sans accès réseau.
Comment fonctionne le protocole Tool ?
Un Tool est un type Swift qui déclare une struct Arguments (annotée avec @Generable et @Guide), une méthode async call(arguments:), ainsi qu’un nom et une description que le modèle utilise pour décider quand appeler. Les tools sont liés à une LanguageModelSession à la construction. Quand le modèle décide qu’il a besoin d’un tool, le framework décode les arguments, exécute l’appel et réinjecte la sortie typée dans la session.
Quelle est la différence entre Foundation Models, App Intents et MCP ?
Foundation Models permet à votre app d’exécuter le LLM on-device pour la génération in-app. App Intents permet à Apple Intelligence (l’agent système) d’appeler les capacités typées de votre app. MCP permet à des hôtes LLM externes (Claude, ChatGPT, etc.) d’appeler les tools typés de votre app via un transport JSON-RPC. Les trois protocoles diffèrent par qui exécute le modèle. La même fonction de domaine Swift peut servir les trois.
Foundation Models peut-il appeler des tools MCP ?
Non. LanguageModelSession.tools accepte les conformers au protocole Tool d’Apple, pas des serveurs de tools MCP. Pour faire le pont entre les deux, vous écririez un Tool Foundation Models dont la méthode call invoque un client MCP. Apple n’a pas livré d’adapter intégré ; le pont serait du code côté app.
Le modèle on-device est-il suffisant pour la production ?
Pour les cas d’usage pour lesquels le framework est conçu (reformatage, résumé, génération structurée sur des données locales, appels d’outils légers), oui. Pour le raisonnement frontier sur de grands contextes, la compréhension multimodale à grande échelle ou le raisonnement multi-documents, non. Le modèle on-device est un modèle de 3 milliards de paramètres avec une fenêtre de contexte plus petite que les LLM cloud ; choisissez des charges de travail qui tiennent dans l’enveloppe.
Références
-
Apple Developer, “Apple Intelligence and machine learning” et la session WWDC 2025 “Meet the Foundation Models framework”. Le chiffre phare du framework (un modèle de langage on-device de 3 milliards de paramètres) provient de l’annonce d’Apple à la WWDC 2025. ↩
-
Apple Developer, “FoundationModels framework”.
SystemLanguageModel,LanguageModelSession,Tool,GeneratedContentet types associés. ↩ -
Apple Developer, “Generating Swift data structures with guided generation” et la référence des macros
@Generable/@Guide. La génération contrainte par type comme capacité de premier ordre via l’échantillonnage contraint. ↩ -
Analyse de l’auteur dans App Intents Are Apple’s New API to Your App, 28 avril 2026. ↩
-
Analyse de l’auteur dans Two Agent Ecosystems, One Shopping List, 29 avril 2026, et App Intents vs MCP: The Routing Question, 30 avril 2026. ↩
-
Apple Developer, “Adopting Apple Intelligence in your app” et “SystemLanguageModel” pour les patterns de
availability. Les sessions WWDC 2025 d’Apple couvrent le chemin d’inférence on-device sur Apple silicon et les contraintes de disponibilité par appareil. ↩