Workflow agentique Foundation Models : LLM in-app vs outillage
Une application Swift sur iOS 26 a deux LLMs qui la touchent, à des couches très différentes. L’un est le modèle on-device que l’utilisateur exécute via le LanguageModelSession de l’application. L’autre est l’agent que le développeur a exécuté via Claude Code, Cursor ou Codex CLI pour écrire l’application en premier lieu. Confondre ces deux LLMs est une erreur d’architecture récurrente dans le développement agentique sur Apple. Ce ne sont pas le même problème ; ils ne partagent pas le même modèle de sécurité ; ils ne partagent pas la même histoire de déploiement ; et les patterns qui fonctionnent pour l’un échouent activement pour l’autre.
Le LLM runtime est une fonctionnalité livrée à l’utilisateur. Le LLM d’outillage est un stylet que tient le développeur. Le modèle runtime vit derrière les attentes de confidentialité de l’utilisateur, les contrôles de disponibilité du système et la revue de l’App Store. Le modèle d’outillage vit derrière la clé API du développeur, les permissions du système de fichiers de l’IDE et une revue de code dont le développeur est responsable. Les deux stacks se croisent rarement, et lorsqu’elles le font (un serveur MCP que le développeur utilise pour piloter le domaine de l’application pendant le développement et que l’application runtime pourrait également exposer pour l’automatisation par l’utilisateur final), la frontière de confiance se déplace et l’architecture doit le reconnaître.
Cet article nomme cette distinction et la question de routage qui en découle : quel LLM doit servir quelle capacité, et qu’est-ce que chacun doit à l’utilisateur.
TL;DR
- Le LLM runtime est Foundation Models (
SystemLanguageModel.defaultplus le protocoleTool). L’inférence est locale, le modèle est livré avec l’OS, l’application exécute l’appel pour le compte de l’utilisateur.1 - Le LLM d’outillage est ce que le développeur a choisi : Claude dans Claude Code, GPT dans Cursor, Codex CLI pour Swift. L’inférence est distante (l’infrastructure d’Anthropic ou le fournisseur Claude configuré, OpenAI, etc.), le modèle est là où l’hôte l’a placé, le développeur pilote l’agent.
- Les deux LLMs ne partagent ni la sécurité, ni le déploiement, ni les budgets de latence, ni la responsabilité. Une capacité qui a du sens à une couche a souvent la mauvaise forme à l’autre.
- Le même serveur MCP que le développeur utilise pendant une session Claude Code n’est pas automatiquement la bonne surface pour l’automatisation agentique destinée à l’utilisateur final. La frontière de confiance change ; ce qui était un outil contrôlé par le développeur devient un outil contrôlé par l’utilisateur (ou par le système).
Deux stacks, le même mot « LLM »
La collision se produit dans des conversations comme celle-ci. Quelqu’un dit « on devrait ajouter un LLM à l’app ». Que cela signifie une fonctionnalité que l’utilisateur invoque (rédige-moi un résumé de méditation, peaufine ce brouillon, classe cette photo) ou un outil que le développeur câble dans sa propre boucle d’itération (laisser Claude Code écrire la migration, laisser Cursor refactorer la vue) n’est pas clair d’après la phrase. Les deux sont des ajouts de LLM. Ce n’est pas la même décision d’ingénierie.
Foundation Models est une stack. Le modèle vit dans SystemLanguageModel.default, dispose d’une fenêtre de contexte fixe, s’exécute sur Apple silicon, ne quitte jamais l’appareil, et est conditionné à l’éligibilité Apple Intelligence de l’utilisateur.1 Le développeur de l’application contraint les entrées via les types @Generable, expose les capacités de l’application via le protocole Tool et livre un binaire qui appelle le modèle quand la fonctionnalité se déclenche. L’utilisateur invoque la fonctionnalité ; l’OS fournit le modèle ; l’application les assemble.
Claude Code, Cursor, Codex CLI et tout autre IDE agentique forment une stack différente. Le modèle vit là où le fournisseur LLM hôte l’exécute (les serveurs d’Anthropic pour Claude, ceux d’OpenAI pour GPT, etc.). L’IDE est l’hôte. Les serveurs MCP sont des outils que le modèle de l’hôte peut appeler. La machine du développeur dispose d’un accès au système de fichiers, d’un accès au shell, et de tout ce que l’IDE a choisi d’exposer d’autre. Le développeur invoque l’agent ; l’agent atteint le système de fichiers du développeur ; la sortie atterrit dans le projet du développeur.2
Le même mot « LLM », des rayons d’impact très différents.
Six axes où les deux stacks divergent
Six propriétés rendent la divergence concrète :
| Propriété | LLM runtime (Foundation Models) | LLM d’outillage (Claude Code, Cursor, Codex CLI) |
|---|---|---|
| Où s’exécute l’inférence | Sur l’appareil (Apple silicon) | Sur l’infrastructure du fournisseur LLM |
| Qui exécute l’appel | L’application, en réponse à une action de l’utilisateur | Le développeur, pendant la boucle d’itération |
| Qui est responsable | Le développeur de l’application (revue App Store) | Le développeur (ses commits, sa revue de code) |
| Ce que touche le modèle | Les données de l’application à l’intérieur du sandbox de l’application | Le système de fichiers du développeur, son shell, ses outils MCP |
| Frontière de confiance | Utilisateur → application → modèle on-device | Développeur → IDE → modèle distant + serveurs MCP |
| Coût d’un mauvais usage | Vie privée, plantage de l’application, rejet App Store | Mauvais code, fuite de sécurité, build cassé |
La frontière de confiance est la ligne porteuse. Le LLM runtime opère à l’intérieur du sandbox de l’application, sous les attentes de confidentialité de l’utilisateur ; le LLM d’outillage opère à l’intérieur de la machine du développeur, sous l’autorité du développeur. Un pattern comme laisser le LLM exécuter une commande shell est normal en outillage (Claude Code le fait constamment via son outil Bash)3 et inenvisageable en runtime : Foundation Models n’a pas d’outil Bash, et le protocole Tool est une fonction Swift typée que le développeur de l’application a écrite et passe en revue.1
La ligne du coût d’un mauvais usage est la conséquence de mal placer la frontière de confiance. Un LLM runtime qui exfiltre les données utilisateur vers un serveur est une violation de la vie privée et un rejet de directives. Un LLM d’outillage qui exfiltre le code source du développeur vers un fournisseur LLM est, selon le contrat du développeur, soit un comportement attendu, soit une fuite. Les deux comptent ; ils comptent pour des raisons différentes.
Le serveur MCP qui se trouve entre les deux
L’endroit le plus net pour voir la frontière se déplacer est lorsqu’un seul serveur MCP est utilisé par les deux stacks. Get Bananas livre un serveur MCP qui expose des opérations de liste de courses : lire les éléments, ajouter des éléments, marquer comme complet. Le même serveur s’exécute à deux endroits.4
Dans la session Claude Code du développeur pendant l’itération, le serveur MCP est un outil que l’agent du développeur appelle pour manipuler la propre liste du développeur. Le serveur s’exécute contre un fichier JSON dans iCloud Drive. Le développeur a câblé le serveur dans sa configuration d’hôte MCP ; l’hôte sait l’appeler ; l’agent lit/écrit des éléments de courses dans le cadre de tâches de développement plus larges.
Dans une surface agentique destinée à l’utilisateur final (par exemple un utilisateur Claude Desktop externe pointant vers une liste partagée), le même serveur MCP a des obligations différentes. L’appelant n’est plus Blake-le-développeur avec une confiance complète sur le système de fichiers ; l’appelant est un utilisateur final dont l’authentification, l’autorisation et la vérification d’intention ne sont pas la responsabilité du développeur. Le serveur MCP doit faire respecter ces garde-fous (ou refuser de s’exposer) avant que cette surface ne devienne sûre.
La même méthode JSON-RPC, add_item, servie à un développeur via un transport stdio local sans authentification, a la bonne forme. Servie à un hôte joignable depuis Internet pour le compte d’un utilisateur final arbitraire sans authentification, elle constitue un risque pour l’intégrité des données. Le serveur MCP est le même code ; le déploiement environnant change tout.
Telle est la règle de routage pour les serveurs MCP dans le développement agentique sur Apple. Le serveur est un contrat typé sur un domaine. Sa place dans la stack (outil de développeur vs surface utilisateur final) est une décision de déploiement, pas une décision de protocole. Faites une revue de code du déploiement ; ne supposez pas que les valeurs par défaut permissives du protocole sont les bonnes valeurs par défaut du déploiement.
Le protocole Tool on-device n’est pas un serveur MCP
Une confusion fréquente : Foundation Models a un protocole Tool, et MCP a des appels d’outils. Sont-ils identiques ? Non, et la différence importe pour le routage.
Le protocole Tool de Foundation Models est une API Swift que le développeur de l’application implémente :1
struct WaterEntryLookup: Tool {
let name = "lookup_water_entries"
let description = "Look up water intake entries for a given date range."
@Generable struct Arguments { ... }
func call(arguments: Arguments) async throws -> String { ... }
}
L’outil s’exécute à l’intérieur du processus de l’application. Le modèle que l’outil sert est le SystemLanguageModel de l’appareil. Les arguments et les sorties sont des types Swift. Le développeur passe en revue l’implémentation, l’App Store passe en revue l’application. L’utilisateur invoque une fonctionnalité ; la session de l’application appelle l’outil ; le modèle local utilise le résultat.
Un outil MCP est une méthode JSON-RPC exposée par un serveur MCP, qui est un processus séparé auquel le LLM hôte (Claude, GPT, etc.) se connecte :2
{
"name": "add_item",
"description": "Add an item to the shopping list.",
"inputSchema": {"type": "object", "properties": {"name": {"type": "string"}}}
}
L’outil s’exécute en dehors du processus de l’agent, dans le langage que le développeur a choisi, parlant JSON via stdio ou Streamable HTTP. Le modèle est là où l’hôte l’a placé. Les arguments sont des JSON validés contre le schéma. La responsabilité revient à celui qui a déployé le serveur MCP.
Les deux protocoles résolvent des problèmes qui se chevauchent avec des portées différentes :
| Décision | Tool Foundation Models |
Outil MCP |
|---|---|---|
| Appelant | Le modèle de langage on-device | Un agent externe (Claude, GPT, Cursor, etc.) |
| Où il s’exécute | À l’intérieur du processus de l’application, on-device | Un processus séparé auquel l’hôte se connecte |
| Langage du schéma | Types Swift @Generable |
JSON Schema |
| Posture de confiance | L’application en est propriétaire ; posture de confidentialité de l’utilisateur | Le développeur ou le fournisseur en est propriétaire ; autorité de l’agent |
| Cadence de mise à jour | Mise à jour de l’application | Redéploiement du serveur |
La règle de routage est simple : si la capacité sert les fonctionnalités LLM propres à l’application pour les utilisateurs finaux, elle va dans un Tool Foundation Models. Si la capacité sert un agent externe (développeur ou utilisateur final) opérant entre processus, elle va dans un outil MCP. Certaines applications ont besoin des deux ; la même fonction Swift peut soutenir les deux adaptateurs, mais les adaptateurs vivent à des couches de stack différentes et sont livrés via des cycles de release différents.5
Les hooks sont l’endroit où le LLM d’outillage gagne sa place
Le rayon d’impact du LLM d’outillage fait des hooks la primitive de sécurité porteuse. Le système de hooks de Claude Code exécute des scripts sur des événements de cycle de vie (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop).6 Un développeur iOS utilisant Claude Code met en place des hooks non parce que l’agent est malveillant, mais parce que l’autorité de l’agent est large : écriture sur le système de fichiers, exécution shell, commits git, push.
Les patterns qui méritent leur place dans un hook dans le travail agentique sur Apple :
Un blocage PreToolUse sur les commandes Bash qui correspondent à xcodebuild ou xcrun sans approbation explicite. Claude Code peut exécuter des builds, effacer des simulateurs, invoquer des étapes de signature ou d’export, ou muter l’état du projet généré si vous le laissez faire. Le hook transforme « l’agent a exécuté un build » en « l’agent a demandé à exécuter un build et a reçu un oui ». Ralentir l’agent sur les actions irréversibles est le bon compromis pour la confiance du développeur.
Un validateur PostToolUse sur chaque appel d’outil Edit ou Write contre les fichiers .pbxproj. Le fichier de projet Xcode est édité par l’humain mais toxique pour l’agent ; une seule mauvaise ligne casse silencieusement le build pour chaque développeur de l’équipe. Un hook qui exécute plutil -lint (ou un contrôle structurel similaire) sur chaque écriture .pbxproj avant de committer fait la différence entre « l’agent a écrit la migration en cinq minutes » et « l’agent a écrit la migration et quarante-cinq minutes de git bisect ».
Un hook Stop qui exécute swift build (ou la commande de build appropriée) avant de laisser l’agent déclarer une tâche terminée. Les agents sont entraînés sur ce à quoi « terminé » ressemble dans une conversation. Le hook fait que « terminé » signifie « le build compile encore », qui est la seule définition qui compte pour livrer.
Le LLM runtime n’a besoin de rien de tout cela. Foundation Models n’a ni shell, ni git, ni fichier de projet, ni configuration de serveur MCP. Le Tool on-device est la fonction Swift que le développeur de l’application a écrite ; l’utilisateur invoque une fonctionnalité ; rien ne s’échappe du sandbox ou des entitlements de l’application à moins que la propre implémentation Tool de l’application ne le fasse.
L’asymétrie est le point essentiel. Le LLM d’outillage a plus d’autorité et a besoin de plus de garde-fous. Le LLM runtime a moins d’autorité par construction. Apple a fait le travail de rendre le LLM runtime sûr ; le développeur fait le travail de rendre le LLM d’outillage sûr.
Règles d’architecture
Trois règles architecturales découlent de la distinction runtime/outillage.
Choisissez la couche par capacité, pas par application. Une application de méditation pourrait utiliser Foundation Models pour la synthèse in-app (LLM runtime, on-device, livré avec l’application) et exposer un serveur MCP que le développeur utilise avec Claude Code pour importer en masse l’historique des sessions pendant l’itération. Les deux LLMs servent des tâches différentes à des couches différentes. Les traiter comme une seule décision produit un moins bon résultat aux deux couches que de les traiter comme deux.
Faites une revue de code de la portée du LLM d’outillage. Une session Claude Code avec un accès complet au système de fichiers et des serveurs MCP distants est un environnement de développement puissant et une généreuse surface d’attaque. La mitigation n’est pas « faire confiance à l’agent » ; la mitigation est : des hooks, des permissions à portée limitée et un développeur qui lit le diff. L’agent travaille pour vous ; l’agent n’est pas vous.
Livrez l’ensemble Tool du LLM runtime comme une API stable. Les outils Foundation Models font partie du contrat binaire de votre application. Supprimer ou renommer un outil entre les versions est un changement comportemental pour les utilisateurs qui s’appuyaient sur la fonctionnalité. Traitez les définitions d’outils comme des affordances d’UI, pas comme des helpers internes.
Ce que je construirais différemment dans ma stack
Deux patterns que les applications du cluster livrent ou souhaiteraient avoir livrés.
Construisez d’abord la couche de domaine ; laissez les outils runtime et les serveurs MCP d’outillage envelopper les mêmes fonctions Swift. Le pattern à double adaptateur de App Intents vs MCP s’étend naturellement aux outils du LLM runtime. Une méthode de domaine logWater(amount:caller:) est enveloppée par un AppIntent (surface Apple Intelligence), un outil MCP (surface agent externe) et un Tool Foundation Models (surface LLM runtime in-app). Trois adaptateurs de protocole, une fonction de domaine, trois classes d’appelants (agent système, agent externe, modèle on-device) avec trois obligations différentes. La fonction ne sait pas quel appelant l’a invoquée ; les adaptateurs portent les signaux de confiance.
Traitez les serveurs MCP de l’agent comme du code, pas comme de la configuration. Un .mcp.json référencé dans un projet iOS est une surface de confiance de portée et de précédence (couvert dans Le repo ne devrait pas voter sur sa propre confiance). Claude Code résout la portée du serveur MCP comme local > projet > utilisateur, et les serveurs à portée projet demandent l’approbation du développeur avant d’être utilisés. L’agent lit la configuration et se connecte aux serveurs que le développeur approuve ; le développeur passe en revue la configuration et les serveurs. Ajouter un serveur MCP à un projet est une revue de code, pas une retouche de configuration.
Quand Foundation Models est le bon choix et quand le LLM d’outillage l’est
L’arbre de décision sur lequel les articles du cluster convergent :
La capacité est-elle une fonctionnalité qu'un utilisateur final invoque dans votre application ?
├── Oui → LLM runtime (Foundation Models ou LLM cloud derrière une surface compatible Apple Intelligence)
│ Utilisez le protocole Tool pour les appels d'outils internes à l'application.
│ Utilisez App Intents pour les capacités que l'agent système doit pouvoir atteindre.
└── Non → Cela fait partie de la boucle d'itération du développeur.
├── La capacité est-elle locale à la machine d'un seul développeur ? → LLM d'outillage
│ Utilisez Claude Code, Cursor ou Codex CLI directement.
│ Enveloppez les utilitaires partagés en serveurs MCP derrière des hooks.
└── La capacité est-elle partagée à travers l'équipe ? → LLM d'outillage avec serveurs MCP partagés
Déployez le serveur MCP à un endroit que l'équipe peut atteindre.
Faites une revue de code du serveur comme du code de production ; placez les outils dangereux derrière une approbation explicite.
La décision produit rarement une égalité. Quand elle le fait (la même capacité pourrait légitimement servir à la fois les utilisateurs finaux et les développeurs), la réponse est deux adaptateurs, pas une surface partagée, parce que les postures de confiance et les cadences de mise à jour sont assez différentes pour qu’une seule surface essayant de servir les deux compromette les deux.
Ce que ce pattern signifie pour les applications livrées sur iOS 26+
Trois enseignements.
-
Deux LLMs, deux stacks. Le LLM runtime (Foundation Models, on-device) est l’agent de l’utilisateur opérant sur ses données à l’intérieur de votre application. Le LLM d’outillage (Claude Code, Cursor, Codex CLI) est l’agent du développeur opérant sur la machine du développeur pour construire l’application. Ils partagent le mot « LLM » et presque rien d’autre.
-
La frontière de confiance est l’architecture. Où le modèle s’exécute, qui l’exécute et ce qu’il touche définissent les obligations. Les patterns qui correspondent à une frontière échouent activement à l’autre.
-
Les serveurs MCP portent la frontière. Le même serveur est un outil de développeur dans un déploiement et une surface utilisateur final dans un autre. Le protocole ne change pas ; le déploiement, oui, et c’est le déploiement qui a besoin de l’attention d’ingénierie.
Le cluster Apple Ecosystem complet : App Intents typés pour Apple Intelligence ; serveurs MCP pour les agents inter-LLM ; la question de routage entre les deux ; Foundation Models pour le LLM on-device et le protocole Tool, avec cas d’usage et adaptateurs personnalisés en frères et sœurs d’adéquation à la charge de travail et de spécialisation ; Live Activities pour la machine à états de l’écran verrouillé iOS ; le contrat runtime watchOS sur Apple Watch ; les coulisses de SwiftUI pour le substrat du framework ; le modèle mental spatial de RealityKit pour les scènes visionOS ; la discipline de schéma SwiftData pour la persistance ; les patterns Liquid Glass pour la couche visuelle ; livraison multiplateforme pour la portée multi-appareils. Le hub se trouve dans la série Apple Ecosystem. Pour un contexte iOS-avec-agents-LLM plus large, consultez le guide de développement d’agents iOS.
FAQ
Quelle est la différence entre Foundation Models et Claude Code d’un point de vue architectural ?
Foundation Models est une fonctionnalité runtime : le LLM est livré avec iOS 26, s’exécute sur l’appareil de l’utilisateur via SystemLanguageModel.default, et est invoqué quand le LanguageModelSession de l’application se déclenche. L’application exécute l’appel pour le compte de l’utilisateur. Claude Code est un outil de développement : le LLM s’exécute sur l’infrastructure d’Anthropic (ou le fournisseur Claude configuré), la machine du développeur héberge l’IDE, et l’agent a accès au système de fichiers du développeur, à son shell et à ses serveurs MCP. Le développeur pilote l’agent ; l’agent aide à construire l’application.
Le même serveur MCP doit-il servir à la fois mon agent et mes utilisateurs finaux ?
Probablement pas. Le même contrat JSON-RPC peut avoir la bonne forme pour les deux, mais les déploiements diffèrent : stdio côté développeur sans authentification est normal pour un outil de développeur, et un risque pour une surface utilisateur final. Le protocole est réutilisable ; le déploiement, non. Si vous exposez le même serveur aux deux, traitez-le comme deux déploiements derrière une seule base de code, pas comme une seule surface pour les deux audiences.
Pourquoi le LLM d’outillage a-t-il besoin de hooks alors que le LLM runtime n’en a pas besoin ?
Le LLM d’outillage a un accès au système de fichiers, un accès au shell, des serveurs MCP et une autorité d’exécution de code arbitraire sur la machine du développeur. Le LLM runtime (Foundation Models) a ce que les implémentations Tool de l’application exposent, à l’intérieur du sandbox de l’application, sans shell. Le rayon d’impact est asymétrique. Les hooks donnent au développeur une revue pré-exécution et une validation post-exécution sur l’autorité large. Le LLM runtime n’en a pas besoin parce que son autorité est contrainte par construction.
Une seule fonction de domaine Swift peut-elle servir à la fois des cas d’usage LLM runtime et LLM d’outillage ?
Oui, et c’est le bon pattern. L’approche à double adaptateur (une fonction Swift, plusieurs wrappers de protocole) s’étend depuis App Intents vs MCP pour inclure les outils Foundation Models. La fonction ne sait pas quel appelant l’a invoquée ; les adaptateurs portent le schéma, les signaux de confiance et les obligations spécifiques au protocole. Trois adaptateurs, une méthode de domaine.
Où s’inscrivent les LLMs cloud hébergés (OpenAI, API Anthropic direct) dans ce tableau ?
Les LLMs cloud appelés depuis l’intérieur d’une application au runtime constituent une troisième catégorie : LLM runtime avec inférence hors-appareil. Ils partagent la posture de confiance Foundation Models « l’application exécute l’appel pour le compte de l’utilisateur » mais perdent l’histoire de confidentialité on-device et l’histoire de disponibilité fournie par l’OS. L’arbre de décision s’étend : les LLMs runtime cloud sont appropriés pour les capacités qui dépassent réellement l’enveloppe du modèle on-device (grand contexte, raisonnement de pointe, multimodal à grande échelle) et acceptables pour les attentes de confidentialité de l’utilisateur (avec divulgation transparente). Foundation Models est le choix par défaut quand la charge de travail correspond ; le cloud est l’escalade quand ce n’est pas le cas.
Références
-
Analyse de l’auteur dans Foundation Models On-Device LLM: The Tool Protocol, 30 avril 2026, couvrant
SystemLanguageModel,LanguageModelSession, le protocoleTool, les macros@Generable/@Guide, et la génération contrainte. ↩↩↩↩ -
Anthropic, « Model Context Protocol » et « MCP Specification: Tools (2025-06-18) ». Exposition d’outils JSON-RPC, architecture hôte/serveur, et les transports stdio + Streamable HTTP. ↩↩
-
Anthropic, « Claude Code reference: Hooks ». Événements de cycle de vie PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop ; la surface de validation qui enveloppe la large autorité du LLM d’outillage. ↩
-
Analyse de l’auteur dans Two Agent Ecosystems, One Shopping List, 29 avril 2026. Le pattern base de code unique, déploiement multiple. ↩
-
Analyse de l’auteur dans App Intents vs MCP: The Routing Question, 30 avril 2026. Le pattern à double adaptateur (une méthode de domaine Swift, deux wrappers de protocole) étendu dans cet article à un pattern à triple adaptateur avec Foundation Models comme troisième classe d’appelant. ↩
-
Anthropic, « Hooks reference ». Événements de cycle de vie, matchers, forme des commandes, et le rôle des hooks comme validation pré-exécution face à l’autorité de l’agent. ↩