FoundationModels : LLM sur appareil (iOS 26)
Modèles d'intégration du modèle de langage Apple sur appareil 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és, et le streaming instantané de snapshots — le tout exécuté localement pour la confidentialité et le fonctionnement hors ligne.
Quand activer
- Construire des fonctionnalités pilotées par IA avec 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'entrées en langage naturel
- Mettre en œuvre un appel d'outils personnalisé pour des actions IA spécifiques à un domaine
- Diffuser des réponses structurées pour des mises à jour d'interface en temps réel
- Besoin de IA respectueuse de la vie privée (aucune donnée ne quitte l'appareil)
Modèle de base — 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("Appareil non é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 non prêt")
case .unavailable(let other):
Text("Modèle indisponible : \(other)")
}
}
}
Modèle de base — Session simple
// 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.
Proposez des suggestions de 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: "Et pour 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 (« Aider à extraire des événements de calendrier »)
- Définir des préférences de style (« Répondre aussi brièvement que possible »)
- Ajouter des mesures de sécurité (« Répondre par « Je ne peux pas t'aider avec ça » pour les demandes dangereuses »)
Modèle de base — Génération guidée avec @Generable
Générer 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ère un chat de refuge mignon",
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 dans un tableaudescription:— guidance sémantique pour la génération
Modèle de base — Appel d'outils
Permettre au modèle d'invoquer du code personnalisé pour des tâches spécifiques à un 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 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'outils
do {
let answer = try await session.respond(to: "Trouve une recette de soupe à la 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
}
}
Modèle de base — Streaming instantané de snapshots
Diffuser des réponses structurées pour une interface en temps réel avec les types PartiallyGenerated :
@Generable
struct TripIdeas {
@Guide(description: "Idées pour les prochains voyages")
var ideas: [String]
}
let stream = session.streamResponse(
to: "Quelles sont des idées de voyages excitantes ?",
generating: TripIdeas.self
)
for try await partial in stream {
// partial: TripIdeas.PartiallyGenerated (toutes les propriétés sont Optionnelles)
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 ; fonctionnement hors ligne |
| Limite de 4 096 jetons | Contrainte du modèle sur appareil ; découper les grandes données sur plusieurs sessions |
| Streaming instantané de snapshots (pas de deltas) | Adapté à la sortie structurée ; chaque snapshot 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 simultanées ; créer plusieurs sessions si nécessaire |
response.content (pas .output) | API correcte — toujours accéder aux résultats via la propriété .content |
Meilleures 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 prompts - 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 - Découpez les entrées volumineuses en morceaux — la limite de 4 096 jetons s'applique aux instructions + prompt + sortie combinés
- Utilisez
@Generablepour une sortie structurée — garanties plus fortes 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-modèles à éviter
- Créer des sessions sans vérifier
model.availabilityd'abord - Envoyer des entrées dépassant la fenêtre de contexte de 4 096 jetons
- Tenter des requêtes simultanées 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
@Generablefonctionnerait - Construire une logique complexe en plusieurs étapes dans un seul prompt — diviser en plusieurs prompts ciblés
- 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 les applications sensibles à la vie privée
- 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 appel d'outils (recherche, calcul, consultation)