FoundationModels : LLM sur appareil (iOS 26)
Schémas d'intégration du modèle de langage sur appareil d'Apple dans les applications à l'aide du framework FoundationModels. Couvre la génération de texte, la sortie structurée avec @Generable, l'appel d'outils personnalisé et le streaming de captures instantanées — le tout exécuté localement pour la confidentialité et le support hors ligne.
Quand activer
- Construire des fonctionnalités basées sur l'IA à l'aide d'Apple Intelligence sur appareil
- Générer ou résumer du texte sans dépendance au cloud
- Extraire des données structurées à partir d'une entrée en langage naturel
- Implémenter un appel d'outils personnalisé pour des actions IA spécifiques à un domaine
- Streamer des réponses structurées pour des mises à jour d'interface utilisateur en temps réel
- Besoin d'une IA préservant la confidentialité (aucune donnée ne quitte l'appareil)
Schéma principal — Vérification de disponibilité
Vérifiez toujours la disponibilité du modèle avant de créer une session :
struct GenerativeView: View {
private var model = SystemLanguageModel.default
var body: some View {
switch model.availability {
case .available:
ContentView()
case .unavailable(.deviceNotEligible):
Text("L'appareil n'est pas éligible pour Apple Intelligence")
case .unavailable(.appleIntelligenceNotEnabled):
Text("Veuillez activer Apple Intelligence dans Réglages")
case .unavailable(.modelNotReady):
Text("Le modèle est en cours de téléchargement ou pas prêt")
case .unavailable(let other):
Text("Modèle indisponible : \(other)")
}
}
}
Schéma principal — Session de base
// Tour unique : créer une nouvelle session à chaque fois
let session = LanguageModelSession()
let response = try await session.respond(to: "Quel est un bon mois pour visiter Paris ?")
print(response.content)
// Tours multiples : réutiliser la session pour le contexte de conversation
let session = LanguageModelSession(instructions: """
Vous êtes un assistant culinaire.
Suggérez des recettes en fonction des ingrédients.
Gardez les suggestions brèves et pratiques.
""")
let first = try await session.respond(to: "J'ai du poulet et du riz")
let followUp = try await session.respond(to: "Qu'en est-il d'une option végétarienne ?")
Points clés pour les instructions :
- Définir le rôle du modèle ("Vous êtes un mentor")
- Spécifier ce qu'il doit faire ("Aidez à extraire des événements de calendrier")
- Définir les préférences de style ("Répondez aussi brièvement que possible")
- Ajouter des mesures de sécurité ("Répondez par 'Je ne peux pas vous aider avec ça' pour les demandes dangereuses")
Schéma principal — Génération guidée avec @Generable
Générez des types Swift structurés au lieu de chaînes brutes :
1. Définir un type Generable
@Generable(description: "Informations de profil de base sur un chat")
struct CatProfile {
var name: String
@Guide(description: "L'âge du chat", .range(0...20))
var age: Int
@Guide(description: "Un profil d'une phrase sur la personnalité du chat")
var profile: String
}
2. Demander une sortie structurée
let response = try await session.respond(
to: "Générez un joli chat à adopter",
generating: CatProfile.self
)
// Accéder directement aux champs structurés
print("Nom : \(response.content.name)")
print("Âge : \(response.content.age)")
print("Profil : \(response.content.profile)")
Contraintes @Guide prises en charge
.range(0...20)— plage numérique.count(3)— nombre d'éléments du tableaudescription:— guidance sémantique pour la génération
Schéma principal — Appel d'outils
Laissez le modèle invoquer du code personnalisé pour des tâches spécifiques au domaine :
1. Définir un outil
struct RecipeSearchTool: Tool {
let name = "recipe_search"
let description = "Rechercher des recettes correspondant à un terme donné et renvoyer une liste de résultats."
@Generable
struct Arguments {
var searchTerm: String
var numberOfResults: Int
}
func call(arguments: Arguments) async throws -> ToolOutput {
let recipes = await searchRecipes(
term: arguments.searchTerm,
limit: arguments.numberOfResults
)
return .string(recipes.map { "- \($0.name): \($0.description)" }.joined(separator: "\n"))
}
}
2. Créer une session avec des outils
let session = LanguageModelSession(tools: [RecipeSearchTool()])
let response = try await session.respond(to: "Trouve-moi des recettes de pâtes")
3. Gérer les erreurs d'outil
do {
let answer = try await session.respond(to: "Trouve une recette de soupe tomate.")
} catch let error as LanguageModelSession.ToolCallError {
print(error.tool.name)
if case .databaseIsEmpty = error.underlyingError as? RecipeSearchToolError {
// Gérer une erreur d'outil spécifique
}
}
Schéma principal — Streaming de captures instantanées
Streamer des réponses structurées pour une interface utilisateur en temps réel avec les types PartiallyGenerated :
@Generable
struct TripIdeas {
@Guide(description: "Idées de voyages à venir")
var ideas: [String]
}
let stream = session.streamResponse(
to: "Quelles sont des idées de voyage excitantes ?",
generating: TripIdeas.self
)
for try await partial in stream {
// partial : TripIdeas.PartiallyGenerated (toutes les propriétés Optional)
print(partial)
}
Intégration SwiftUI
@State private var partialResult: TripIdeas.PartiallyGenerated?
@State private var errorMessage: String?
var body: some View {
List {
ForEach(partialResult?.ideas ?? [], id: \.self) { idea in
Text(idea)
}
}
.overlay {
if let errorMessage { Text(errorMessage).foregroundStyle(.red) }
}
.task {
do {
let stream = session.streamResponse(to: prompt, generating: TripIdeas.self)
for try await partial in stream {
partialResult = partial
}
} catch {
errorMessage = error.localizedDescription
}
}
}
Décisions de conception clés
| Décision | Justification |
|---|---|
| Exécution sur appareil | Confidentialité — aucune donnée ne quitte l'appareil ; fonctionne hors ligne |
| Limite de 4 096 tokens | Contrainte du modèle sur appareil ; segmenter les grandes données sur plusieurs sessions |
| Streaming de captures instantanées (pas de deltas) | Adapté aux sorties structurées ; chaque capture est un état partiel complet |
Macro @Generable | Sécurité à la compilation pour la génération structurée ; génère automatiquement le type PartiallyGenerated |
| Une seule requête par session | isResponding empêche les requêtes concurrentes ; créer plusieurs sessions si nécessaire |
response.content (pas .output) | API correcte — toujours accéder aux résultats via la propriété .content |
Bonnes pratiques
- Vérifiez toujours
model.availabilityavant de créer une session — gérez tous les cas d'indisponibilité - Utilisez
instructionspour guider le comportement du modèle — elles ont priorité sur les invites - Vérifiez
isRespondingavant d'envoyer une nouvelle requête — les sessions gèrent une requête à la fois - Accédez à
response.contentpour les résultats — pas.output - Divisez les grandes entrées en morceaux — la limite de 4 096 tokens s'applique aux instructions + invite + sortie combinés
- Utilisez
@Generablepour les sorties structurées — garanties plus solides que l'analyse de chaînes brutes - Utilisez
GenerationOptions(temperature:)pour ajuster la créativité (plus élevé = plus créatif) - Surveillez avec Instruments — utilisez Xcode Instruments pour profiler les performances des requêtes
Anti-schémas à éviter
- Créer des sessions sans vérifier d'abord
model.availability - Envoyer des entrées dépassant la fenêtre de contexte de 4 096 tokens
- Tenter des requêtes concurrentes sur une seule session
- Utiliser
.outputau lieu de.contentpour accéder aux données de réponse - Analyser des réponses sous forme de chaînes brutes alors qu'une sortie structurée avec
@Generablefonctionnerait - Construire une logique multi-étapes complexe dans une seule invite — diviser en plusieurs invites ciblées
- Supposer que le modèle est toujours disponible — l'éligibilité de l'appareil et les réglages varient
Quand utiliser
- Génération de texte sur appareil pour des applications sensibles à la confidentialité
- Extraction de données structurées à partir d'entrées utilisateur (formulaires, commandes en langage naturel)
- Fonctionnalités assistées par IA qui doivent fonctionner hors ligne
- Interface utilisateur en streaming qui affiche progressivement le contenu généré
- Actions IA spécifiques à un domaine via l'appel d'outils (recherche, calcul, consultation)