Foundation Models ב-iOS 26: המדריך המלא לבינה מלאכותית על המכשיר עם Swift

איך להשתמש ב-Foundation Models framework של Apple ב-iOS 26 לבניית תכונות בינה מלאכותית על המכשיר עם Swift — כולל Guided Generation, Tool Calling, סטרימינג ב-SwiftUI ודוגמאות קוד מעשיות.

מבוא: בינה מלאכותית על המכשיר — בלי שרת, בלי עלויות, בלי פשרות על פרטיות

תארו לעצמכם שאתם יכולים להוסיף יכולות בינה מלאכותית לאפליקציית ה-iOS שלכם — סיכום טקסט, חילוץ ישויות, יצירת תוכן, סיווג — בלי לשלם אגורה על שרתים, בלי מפתחות API, ובלי שנתוני המשתמש יוצאים מהמכשיר. נשמע כמו חלום? ובכן, ב-WWDC 2025 Apple הפכה את זה למציאות, ואני חייב לומר — זה אחד הדברים הכי מרגשים שקרו לפיתוח iOS בשנים האחרונות.

עם ה-Foundation Models framework החדש ב-iOS 26, מפתחי Swift מקבלים גישה ישירה למודל שפה גדול (LLM) של כ-3 מיליארד פרמטרים — אותו מודל שמניע את Apple Intelligence — ישירות מקוד Swift. הפריימוורק מציע API נקי, אינטגרציה מושלמת עם SwiftUI, ותכונות ייחודיות כמו Guided Generation ו-Tool Calling שבאמת מנצלות את היתרונות של שפת Swift בצורה חכמה.

אז בואו נצלול פנימה. במדריך הזה נעבור על כל מה שצריך לדעת: בדיקת זמינות, שימוש בסיסי, הוראות מערכת, יצירת פלט מובנה עם @Generable ו-@Guide, קריאת כלים, סטרימינג תגובות ב-SwiftUI, מגבלות ושיטות עבודה מומלצות.

דרישות מערכת ובדיקת זמינות

לפני שנתחיל לכתוב קוד, חשוב להבין אילו מכשירים בכלל תומכים ב-Foundation Models framework. לא כל מכשיר יכול להריץ את המודל (וזה הגיוני — מדובר ב-LLM שרץ מקומית), ולכן בדיקת זמינות בזמן ריצה היא קריטית.

דרישות חומרה ותוכנה

  • מערכת הפעלה: iOS 26 ומעלה, iPadOS 26+, macOS 26+ (Tahoe), או visionOS 26+
  • חומרה: שבב Apple Silicon — A17 Pro ומעלה ל-iPhone, M1 ומעלה ל-Mac ו-iPad
  • Apple Intelligence: המשתמש חייב להפעיל את Apple Intelligence בהגדרות המכשיר
  • Xcode: גרסה 26 ומעלה

בדיקת זמינות בקוד

מכיוון שהזמינות תלויה במכשיר, באזור ובהגדרות המשתמש, חובה לבדוק אותה בזמן ריצה. הנה הדפוס שאני ממליץ עליו:

import FoundationModels
import SwiftUI

struct AIFeatureView: View {
    private let model = SystemLanguageModel.default

    var body: some View {
        switch model.availability {
        case .available:
            // המודל זמין — הצג את התכונה
            AIContentView()
        case .unavailable(.deviceNotEligible):
            Text("המכשיר שלך לא תומך ב-Apple Intelligence")
        case .unavailable(.appleIntelligenceNotEnabled):
            Text("יש להפעיל את Apple Intelligence בהגדרות")
        case .unavailable(.modelNotReady):
            ProgressView("המודל נטען...")
        default:
            Text("התכונה לא זמינה כרגע")
        }
    }
}

הטיפוס SystemLanguageModel.default מייצג את מודל השפה שזמין על הפלטפורמה. מה שנחמד פה זה שהמאפיין availability מחזיר ערך enum שמסביר בדיוק למה המודל לא זמין, ככה שאפשר להציג למשתמש הודעה ברורה ומותאמת במקום סתם "משהו לא עובד".

שימוש בסיסי: LanguageModelSession

הדרך הפשוטה ביותר לתקשר עם המודל היא דרך LanguageModelSession. זהו אובייקט שמנהל את ההתקשרות עם המודל, שומר היסטוריית שיחה (transcript), ומאפשר שליחת פרומפטים וקבלת תגובות.

דוגמה מינימלית

import FoundationModels

func generateResponse() async throws -> String {
    let session = LanguageModelSession()
    let response = try await session.respond(to: "ספר לי בדיחה על מתכנתים")
    return response.content
}

וזהו. שלוש שורות קוד ויש לכם תגובה ממודל AI שרץ לחלוטין על המכשיר. אין מפתחות API, אין חשבון ענן, אין עלויות שימוש. כשראיתי את זה בפעם הראשונה, הפשטות פשוט הפתיעה אותי.

שמירת הקשר שיחה

LanguageModelSession הוא stateful — הוא שומר את כל הפרומפטים והתגובות ב-transcript. מה שזה אומר בפועל? שאפשר לנהל שיחה רב-תורית בלי לנהל את ההיסטוריה בעצמכם:

let session = LanguageModelSession()

let response1 = try await session.respond(to: "מהי שפת Swift?")
// התגובה הראשונה

let response2 = try await session.respond(to: "תן לי דוגמת קוד לזה")
// המודל זוכר את ההקשר ויודע שמדובר ב-Swift

נקודה חשובה: לא ניתן לשלוח בקשה חדשה בזמן שהמודל עדיין מגיב. אם אתם צריכים כמה בקשות במקביל, פשוט צרו מספר מופעי LanguageModelSession.

הוראות מערכת (Instructions)

הוראות מערכת הן הדרך לתת למודל הקשר, אישיות ומגבלות — בדומה ל-system prompt בפלטפורמות אחרות. הן מוגדרות בעת יצירת ה-session ומשפיעות על כל התגובות שלו.

הגדרת הוראות עם Instructions

let session = LanguageModelSession(instructions: """
    You are an expert iOS development assistant.
    Answer briefly and clearly.
    Provide Swift code examples when relevant.
    Do not answer questions unrelated to development.
    """)

let response = try await session.respond(to: "איך מגדירים State ב-SwiftUI?")

שימוש ב-InstructionsBuilder

אפשר גם להגדיר הוראות בצורה דקלרטיבית באמצעות DSL, שזה מרגיש מאוד "סוויפטי":

@State var session = LanguageModelSession {
    """
    You are a personal fitness coach.
    Help users build a personalized workout plan.
    """
}

טיפ חשוב (וזה משהו שחוסך הרבה כאב ראש): Apple ממליצה לכתוב את ההוראות באנגלית כדי לקבל את התוצאות הטובות ביותר, גם אם הפרומפט עצמו בשפה אחרת. המודל פשוט מותאם טוב יותר לאנגלית בהקשר של instructions.

Guided Generation: פלט מובנה עם @Generable ו-@Guide

אוקיי, אז הנה אחת התכונות שהכי התרגשתי ממנה. Guided Generation מאפשר לקבל פלט מובנה וטיפוסי (type-safe) ישירות כטיפוסי Swift. במקום לפרסר מחרוזות JSON מבולגנות ולקוות לטוב, פשוט מגדירים struct עם המאקרו @Generable והמודל מייצר את הנתונים ישירות בפורמט הנכון.

איך זה עובד?

הטכנולוגיה מאחורי הקלעים נקראת constrained decoding. בגדול, המודל "נאלץ" לייצר פלט תקין שתואם את מבנה ה-Swift שהגדרתם, ברמת הטוקן. זה מבטיח תקינות מבנית מלאה, בלי שום צורך בולידציה ידנית מצדכם.

דוגמה בסיסית

import FoundationModels

@Generable
struct MovieReview {
    @Guide(description: "The movie title in Hebrew")
    var title: String

    @Guide(description: "Rating from 1 to 5")
    @Guide(.range(1...5))
    var rating: Int

    @Guide(description: "A brief review in 2-3 sentences")
    var review: String

    @Guide(description: "List of genres")
    @Guide(.count(1...3))
    var genres: [String]
}

func analyzeMovie() async throws -> MovieReview {
    let session = LanguageModelSession()
    let response = try await session.respond(
        to: "Analyze the movie Oppenheimer",
        generating: MovieReview.self
    )
    return response.content
}

התוצאה היא אובייקט MovieReview מלא עם ערכים תקינים — הדירוג יהיה תמיד בטווח 1-5, ורשימת הז׳אנרים תכיל 1-3 פריטים. אין exceptions של פרסור, אין nil לא צפוי. פשוט עובד.

המאקרו @Guide לאילוצים מתקדמים

@Guide מאפשר להגדיר אילוצים על כל שדה בנפרד. הנה סיכום האילוצים הזמינים:

  • @Guide(description:) — תיאור טקסטואלי שמסביר למודל מה לייצר
  • @Guide(.range(min...max)) — טווח ערכים מספריים
  • @Guide(.count(n)) — מספר מדויק של פריטים במערך
  • @Guide(.count(min...max)) — טווח מספר פריטים
  • @Guide(.anyOf([options])) — בחירה מתוך אפשרויות מוגדרות מראש

סדר המאפיינים חשוב!

וזו נקודה שקל לפספס: המודל מייצר את המאפיינים בסדר שבו הם מוגדרים ב-struct. זה אומר שערך של מאפיין מוקדם יכול להשפיע על מאפיינים מאוחרים יותר. למשל, אם הגדרתם title לפני summary, הסיכום ייווצר בהתאם לכותרת. חשבו על זה כמו chain of thought — המודל בונה כל שדה על בסיס מה שכבר ייצר.

מבנים מקוננים

Guided Generation תומך גם במבנים מקוננים, וזה פותח אפשרויות מאוד מעניינות. רק שימו לב שכל הטיפוסים המקוננים צריכים גם הם להיות מסומנים עם @Generable:

@Generable
struct TripItinerary {
    @Guide(description: "An exciting trip name")
    var title: String

    @Guide(description: "Trip description")
    var description: String

    @Guide(.count(3))
    var days: [DayPlan]
}

@Generable
struct DayPlan {
    @Guide(description: "Day title, e.g. Day 1: Arrival")
    var title: String

    @Guide(description: "List of activities for this day")
    @Guide(.count(2...4))
    var activities: [String]
}

Tool Calling: הרחבת יכולות המודל

המודל על המכשיר מוגבל מטבעו — אין לו גישה לאינטרנט, למידע עדכני, או לנתונים מהאפליקציה שלכם. וזה בדיוק הגיוני, כי הוא רץ מקומית. אז איך מגשרים על הפער הזה? כאן נכנס Tool Calling לתמונה.

עם Tools, אתם מאפשרים למודל "לקרוא" לפונקציות בקוד שלכם כדי לקבל מידע או לבצע פעולות. זה עובד בצורה דומה ל-function calling ב-API-ים אחרים, אבל הכל מתרחש על המכשיר.

הגדרת כלי

כלי מוגדר על ידי ציות לפרוטוקול Tool:

import FoundationModels
import CoreLocation

struct FindNearbyRestaurantsTool: Tool {
    let name = "find_nearby_restaurants"
    let description = "Find restaurants near the user current location"

    @Generable
    struct Arguments {
        @Guide(description: "Type of cuisine, e.g. Italian, Japanese")
        var cuisineType: String

        @Guide(description: "Maximum distance in kilometers")
        @Guide(.range(1...50))
        var maxDistance: Int
    }

    func call(arguments: Arguments) async throws -> some ToolOutput {
        let restaurants = await searchRestaurants(
            cuisine: arguments.cuisineType,
            radius: arguments.maxDistance
        )
        return "Found \(restaurants.count) \(arguments.cuisineType) restaurants nearby"
    }
}

שימוש בכלי עם Session

let tools: [any Tool] = [FindNearbyRestaurantsTool()]

let session = LanguageModelSession(
    instructions: "You help users find restaurants nearby.",
    tools: tools
)

let response = try await session.respond(
    to: "מצא לי מסעדות איטלקיות בקרבת מקום"
)

מה שיפה פה זה שהמודל מזהה אוטומטית שהוא צריך להשתמש בכלי, מייצר את הארגומנטים המתאימים (באמצעות Guided Generation!), קורא לפונקציה call, ובונה תגובה על סמך התוצאה. אתם לא צריכים לנהל את הזרימה הזו — הכל קורה מאחורי הקלעים.

סטרימינג תגובות ב-SwiftUI

בכנות, אף אחד לא אוהב לבהות במסך ריק בזמן שהמודל חושב. במקום לחכות שהמודל יסיים לייצר את כל התגובה, אפשר להציג אותה בזמן אמת באמצעות סטרימינג. זה יוצר חוויית משתמש הרבה יותר טובה, במיוחד לתגובות ארוכות.

סטרימינג טקסט פשוט

import SwiftUI
import FoundationModels

struct ChatView: View {
    @State private var prompt = ""
    @State private var output = ""
    @State private var isGenerating = false

    var body: some View {
        VStack {
            ScrollView {
                Text(output)
                    .padding()
                    .frame(maxWidth: .infinity, alignment: .leading)
            }

            HStack {
                TextField("Ask something...", text: $prompt)
                    .textFieldStyle(.roundedBorder)

                Button("Send") {
                    generate()
                }
                .disabled(isGenerating || prompt.isEmpty)
            }
            .padding()
        }
    }

    private func generate() {
        Task {
            isGenerating = true
            output = ""
            let session = LanguageModelSession()
            let stream = session.streamResponse(to: prompt)
            for try await partial in stream {
                output = partial.content
            }
            isGenerating = false
        }
    }
}

סטרימינג פלט מובנה

והנה החלק שבאמת מרשים: הסטרימינג עובד גם עם פלט מובנה. במקום לקבל טוקנים גולמיים, מקבלים snapshots — אובייקטים חלקיים מטיפוס PartiallyGenerated שמתמלאים בהדרגה:

@Generable
struct RecipeSuggestion {
    @Guide(description: "Recipe name")
    var name: String

    @Guide(description: "List of ingredients")
    var ingredients: [String]

    @Guide(description: "Step by step cooking instructions")
    var instructions: [String]
}

struct RecipeView: View {
    @State private var recipe: RecipeSuggestion.PartiallyGenerated?
    @State private var isGenerating = false

    var body: some View {
        VStack(alignment: .leading) {
            if let name = recipe?.name {
                Text(name)
                    .font(.title)
                    .animation(.easeIn, value: name)
            }

            if let ingredients = recipe?.ingredients {
                ForEach(ingredients, id: \.self) { ingredient in
                    Text("• \(ingredient)")
                }
            }

            if let steps = recipe?.instructions {
                ForEach(Array(steps.enumerated()), id: \.offset) { index, step in
                    Text("\(index + 1). \(step)")
                }
            }
        }
        .task {
            await generateRecipe()
        }
    }

    private func generateRecipe() async {
        let session = LanguageModelSession()
        do {
            let stream = session.streamResponse(
                to: "Give me a pasta recipe with tomato sauce",
                generating: RecipeSuggestion.self
            )
            for try await partial in stream {
                recipe = partial
            }
        } catch {
            print("Error: \(error)")
        }
    }
}

ה-UI מתעדכן בזמן אמת — קודם מופיע שם המתכון, אחר כך המרכיבים מתווספים אחד אחד, ולבסוף ההוראות. אגב, Apple ממליצה להשתמש באנימציות ומעברים של SwiftUI כדי ליצור חוויה חלקה — וזה באמת עושה הבדל גדול בתחושה של המשתמש.

הגדרות מתקדמות: Temperature ודגימה

רוצים לשלוט על כמה "יצירתי" המודל יהיה? אפשר לעשות את זה באמצעות GenerationOptions:

let options = GenerationOptions(
    sampling: .random(top: 10, seed: 42),
    temperature: 0.7
)

let response = try await session.respond(
    to: "Write a short story about a robot",
    options: options
)
  • temperature — ערך גבוה יותר = תגובות יצירתיות ומגוונות יותר. ערך נמוך = תגובות צפויות ועקביות
  • sampling: .greedy — תמיד בוחר את התשובה הסבירה ביותר (דטרמיניסטי)
  • sampling: .random(top:seed:) — דגימה אקראית מתוך top-k האפשרויות, עם seed לשחזור תוצאות

לפי הניסיון שלי, temperature של 0.5-0.7 עובד טוב לרוב המשימות. ערכים גבוהים מדי (מעל 1.0) יכולים לגרום לתוצאות מוזרות, במיוחד עם מודל בגודל הזה.

חימום מוקדם של המודל

טעינת המודל לזיכרון לוקחת זמן, וזה יכול ליצור עיכוב מורגש בפעם הראשונה. אם אתם יודעים שתצטרכו אותו בקרוב, אפשר לחמם אותו מראש:

let session = LanguageModelSession()

// חימום מוקדם — טוען את המודל לזיכרון
try await session.prewarm(promptPrefix: "Generate a recipe")

// עכשיו הקריאה הראשונה תהיה מהירה יותר
let response = try await session.respond(to: "Generate a pasta recipe")

המתודה prewarm(promptPrefix:) טוענת את המודל לזיכרון עם רמז לגבי סוג הפרומפט הצפוי. שווה להפעיל את זה כבר בשלב טעינת המסך שבו התכונה נמצאת.

מגבלות שחשוב להכיר

למרות ש-Foundation Models framework הוא כלי חזק, יש מגבלות שחייבים להכיר לפני שקופצים למים. והעדיף לדעת אותן מראש מאשר לגלות אותן באמצע פיתוח:

  • טקסט בלבד: המודל תומך רק בקלט ופלט טקסטואלי. אין תמיכה בתמונות, אודיו, PDF או קבצים אחרים (לפחות לא בגרסה הזו)
  • מגבלת טוקנים: 4,096 טוקנים לקלט ופלט ביחד. זה לא הרבה, אז תכננו בהתאם
  • לא מיועד לידע כללי: המודל מצטיין בסיכום, חילוץ ישויות, סיווג ויצירת תוכן. הוא לא מיועד להיות צ׳אטבוט לידע כללי כמו ChatGPT
  • יכולת מוגבלת: כמודל בגודל 3 מיליארד פרמטרים, הוא פחות חזק ממודלים גדולים. צפו להזיות ולמגבלות בלוגיקה מורכבת
  • שפה: המודל עובד הכי טוב באנגלית. ההוראות מומלצות באנגלית, אבל הפרומפטים יכולים להיות בשפת המשתמש
  • אין חיפוש אינטרנט: המודל לא יכול לחפש באינטרנט, להריץ קוד, או לבצע פעולות אגנטיות עצמאיות
  • מנגנוני בטיחות: Apple הטמיעה guardrails שחוסמים תוכן רגיש, אך אלה עלולים לייצר false positives. בדקו את הפרומפטים שלכם היטב

שיטות עבודה מומלצות

אחרי שעברנו על כל התכונות, הנה עשר המלצות שיעזרו לכם להפיק את המרב מהפריימוורק הזה:

  1. בדקו תמיד זמינות — לא כל מכשיר תומך. הציגו UI חלופי מתאים ולא סתם הודעת שגיאה גנרית
  2. כתבו הוראות באנגלית — גם אם האפליקציה בעברית. ההוראות פשוט עובדות טוב יותר באנגלית
  3. העדיפו Guided Generation — פלט מובנה אמין יותר מפרסור טקסט חופשי, ומונע בעיות פרסור מעצבנות
  4. חשבו על סדר מאפיינים — מאפיינים מוקדמים ב-@Generable struct משפיעים על מאפיינים מאוחרים
  5. השתמשו בסטרימינג — חוויית המשתמש טובה משמעותית כשרואים תגובה מתעדכנת בזמן אמת
  6. חממו מראש — קראו ל-prewarm אם אתם יודעים שתצטרכו את המודל בקרוב
  7. אל תסמכו על ידע כללי — השתמשו ב-Tools לספק מידע ספציפי למודל. הוא לא ויקיפדיה
  8. טפלו בשגיאות — ה-session יכול לזרוק שגיאות בגלל שפה לא נתמכת או חריגה ממגבלת טוקנים
  9. שמרו על פרומפטים קצרים — עם מגבלת 4,096 טוקנים, כל מילה חשובה
  10. בדקו על מכשירים אמיתיים — הביצועים והזמינות משתנים בין מכשירים, וה-Simulator לא תמיד מייצג נכון

שאלות נפוצות

האם Foundation Models framework דורש חיבור לאינטרנט?

לא. המודל רץ לחלוטין על המכשיר. אין צורך בחיבור לאינטרנט, אין עלויות שרת, ואין שליחת נתונים לענן. כל העיבוד מתבצע מקומית, מה שמבטיח פרטיות מלאה ומאפשר שימוש גם במצב טיסה.

מה ההבדל בין Foundation Models לבין שימוש ב-API של OpenAI או Claude?

Foundation Models רץ על המכשיר ומציע פרטיות מוחלטת, ללא עלויות ועם latency נמוך. מצד שני, המודל קטן יותר (כ-3B פרמטרים) ופחות חזק מ-GPT-4 או Claude. בקיצור — הוא מיועד למשימות ממוקדות כמו סיכום, סיווג ויצירת תוכן קצר, לא לשיחות מורכבות או ידע כללי רחב.

אילו מכשירי iPhone תומכים ב-Foundation Models?

רק מכשירים עם שבב A17 Pro ומעלה, כלומר iPhone 15 Pro ומעלה, עם iOS 26 מותקן ו-Apple Intelligence מופעל. מכשירי iPhone 15 הרגילים ומטה אינם תומכים.

האם אפשר להתאים אישית את המודל לאפליקציה שלי?

כן! Apple מציעה מנגנון Adapters — אימון מותאם שמתמחה את המודל ביכולות ספציפיות. כל Adapter תופס כ-160MB ויש לארח אותו על שרת חיצוני להורדה דרך Background Assets framework. שימו לב שכל Adapter תואם לגרסה ספציפית של מודל המערכת, כך שתצטרכו לעדכן אותו עם כל שדרוג.

מה אפשר לבנות עם Foundation Models framework?

המודל מצטיין במגוון משימות: יצירת תוכן (טקסטים, דיאלוגים, תיאורים), סיכום מאמרים, חילוץ ישויות (שמות, מיקומים, תאריכים), סיווג תוכן, ניתוח סנטימנט, הצעות חיפוש חכמות, יצירת חידונים ומשחקי טריוויה, ומדריך משתמש אינטראקטיבי באפליקציה. האפשרויות רחבות — המגבלה העיקרית היא מגבלת הטוקנים וגודל המודל.

אודות הכותב Editorial Team

Our team of expert writers and editors.