فریم‌ورک Foundation Models در iOS 26: راهنمای کامل هوش مصنوعی روی دستگاه با Swift

راهنمای عملی فریم‌ورک Foundation Models در iOS 26 — از ایجاد Session و تولید ساختاریافته با @Generable و @Guide تا فراخوانی ابزار، پاسخ‌های جریانی و ساخت یک پروژه واقعی تحلیل نظرات با هوش مصنوعی روی دستگاه.

Foundation Models iOS 26: AI روی دستگاه

فریم‌ورک Foundation Models چیست؟

با انتشار iOS 26، اپل یه ابزار فوق‌العاده جذاب رو معرفی کرد: فریم‌ورک Foundation Models. این فریم‌ورک به شما اجازه می‌ده از همون مدل زبانی بزرگ (LLM) که پشت Apple Intelligence هست، مستقیماً توی اپلیکیشن‌تون استفاده کنید. و بهترین قسمتش؟ این مدل با ۳ میلیارد پارامتر کاملاً روی خود دستگاه اجرا می‌شه — بدون نیاز به اینترنت، بدون کلید API و بدون هیچ هزینه‌ای.

اگه با سرویس‌های ابری مثل ChatGPT یا Claude کار کرده باشید، می‌دونید که وابسته به سرورهای قدرتمند هستن. اما مدل اپل مستقیماً روی تراشه‌های A-Series و M-Series دستگاه اجرا می‌شه. صادقانه بگم، این معماری سه تا مزیت کلیدی داره که واقعاً تفاوت ایجاد می‌کنه:

  • حریم خصوصی: تمام داده‌ها روی دستگاه کاربر باقی می‌مونن — هیچ چیزی به سرور ارسال نمی‌شه
  • تأخیر کم: بدون نیاز به رفت‌وبرگشت درخواست با سرور
  • دسترسی آفلاین: حتی توی هواپیما هم کار می‌کنه!

پیش‌نیازها و راه‌اندازی

خب، قبل از اینکه دست به کد بشیم، بذارید ببینیم چی نیاز داریم:

  • Xcode 26 یا بالاتر
  • macOS Tahoe (macOS 26) برای توسعه
  • دستگاه سازگار با Apple Intelligence — یعنی iPhone 15 Pro به بالا، iPad با تراشه M1 به بالا، یا Mac با تراشه M1 به بالا
  • iOS 26، iPadOS 26، یا macOS 26 روی دستگاه مقصد

یه نکته مهم: همه کاربران به Apple Intelligence دسترسی ندارن. پس حتماً یه تجربه جایگزین (fallback) برای دستگاه‌های ناسازگار در نظر بگیرید. این رو جدی بگیرید — اگه این کار رو نکنید، یه بخش قابل‌توجه از کاربران‌تون با صفحه خالی مواجه می‌شن.

افزودن فریم‌ورک به پروژه

شروع کار خیلی ساده‌ست. کافیه فریم‌ورک رو import کنید:

import FoundationModels

همین! هیچ وابستگی خارجی یا تنظیمات اضافی لازم نیست. فریم‌ورک بخشی از سیستم‌عامل هست و تأثیری روی حجم اپلیکیشن شما نداره.

ایجاد Session و استفاده پایه

واحد اصلی تعامل با مدل، کلاس LanguageModelSession هست. هر Session یه مکالمه مستقل با مدل ایجاد می‌کنه و تاریخچه مکالمه رو نگه می‌داره. بذارید با ساده‌ترین مثال شروع کنیم.

ساده‌ترین مثال

import FoundationModels

let session = LanguageModelSession()
let response = try await session.respond(to: "یک داستان کوتاه بگو")
print(response.content)

توی این مثال، یه Session جدید ایجاد می‌کنیم، یه پرامپت می‌فرستیم و پاسخ مدل رو دریافت می‌کنیم. چون عملیات مدل ناهمگام (asynchronous) هست، از try await استفاده می‌کنیم. اگه قبلاً با async/await توی Swift کار کرده باشید، این الگو خیلی آشنا به نظر می‌رسه.

تنظیم دستورالعمل سیستمی

می‌تونید با پارامتر instructions رفتار مدل رو هدایت کنید. مثلاً فرض کنید می‌خواید یه دستیار آشپزی بسازید:

let session = LanguageModelSession(
    instructions: """
    تو یک دستیار آشپزی هستی. فقط درباره غذا و آشپزی
    پاسخ بده. پاسخ‌ها را کوتاه و عملی نگه دار.
    """
)

let response = try await session.respond(
    to: "چطور برنج ایرانی بپزم؟"
)

پیش‌گرم کردن مدل

یه ترفند خیلی خوب: اگه می‌دونید کاربر به‌زودی با مدل تعامل خواهد داشت، می‌تونید مدل رو از قبل آماده کنید:

// مدل را پیش از نیاز بارگذاری کنید
try await session.prewarm(promptPrefix: "Generate a summary")

این کار زمان پاسخ‌دهی اولین درخواست رو به‌طور محسوسی کاهش می‌ده. من توی یکی از پروژه‌هام این کار رو توی onAppear ویوی اصلی انجام دادم و تفاوتش واقعاً قابل‌لمس بود.

بررسی وضعیت پاسخ‌دهی

ویژگی isResponding بهتون اجازه می‌ده بررسی کنید آیا مدل داره پاسخ می‌ده یا نه. خیلی به درد غیرفعال کردن دکمه ارسال توی رابط کاربری می‌خوره:

struct ChatView: View {
    @State private var session = LanguageModelSession()
    @State private var userInput = ""
    @State private var result = ""

    var body: some View {
        VStack {
            Text(result)
            TextField("پیام خود را بنویسید", text: $userInput)
            Button("ارسال") {
                Task {
                    let response = try await session.respond(to: userInput)
                    result = response.content
                }
            }
            .disabled(session.isResponding)
        }
    }
}

تولید ساختاریافته با @Generable و @Guide

خب، اینجاست که قضیه جالب می‌شه! یکی از قدرتمندترین ویژگی‌های فریم‌ورک Foundation Models، قابلیت Guided Generation (تولید هدایت‌شده) هست. به‌جای اینکه متن خام از مدل بگیرید و خودتون تلاش کنید parse-ش کنید (که می‌دونیم چقدر دردسرساز می‌تونه باشه)، مستقیماً خروجی ساختاریافته و type-safe دریافت می‌کنید.

ماکرو @Generable

با افزودن ماکرو @Generable به یه struct یا enum، به کامپایلر می‌گید که یه اسکیما JSON برای اون نوع تولید کنه. بعد مدل از این اسکیما استفاده می‌کنه تا خروجی با ساختار دقیق تولید کنه:

import FoundationModels

@Generable
struct Recipe {
    let name: String
    let ingredients: [String]
    let steps: [String]
    let cookingTimeMinutes: Int
}

let session = LanguageModelSession()
let response = try await session.respond(
    to: "یک دستور پخت قورمه‌سبزی بده",
    generating: Recipe.self
)

// response.content از نوع Recipe است — نه String
print(response.content.name)
print(response.content.ingredients)

یه نکته مهم: تمام propertyهای ذخیره‌شده (stored properties) یه نوع @Generable باید خودشون قابل تولید باشن. انواع اولیه مثل String، Int، Double، Bool، آرایه‌ها و Optionalها بدون مشکل پشتیبانی می‌شن.

ماکرو @Guide برای کنترل دقیق‌تر

حالا اگه بخواید بیشتر دست مدل رو ببندید و کنترل دقیق‌تری داشته باشید، ماکرو @Guide دقیقاً همین کار رو انجام می‌ده:

@Generable
struct QuizQuestion {
    @Guide(description: "سؤال کوییز به زبان فارسی")
    let text: String

    @Guide(.count(4))
    let choices: [String]

    @Guide(.anyOf(["A", "B", "C", "D"]))
    let correctAnswer: String

    @Guide(description: "توضیح مختصر دلیل صحیح بودن جواب")
    let explanation: String
}

بذارید توضیح بدم هر کدوم چیکار می‌کنن:

  • description — یه راهنمای متنی به مدل می‌ده تا بدونه چی ازش انتظار می‌ره
  • .count(4) — تعداد عناصر آرایه رو دقیقاً ۴ تا تعیین می‌کنه
  • .anyOf — مقادیر مجاز رو محدود می‌کنه (فقط همینا قبول هستن)

سایر محدودیت‌های @Guide

فریم‌ورک محدودیت‌های متنوع دیگه‌ای هم داره:

@Generable
struct Product {
    let name: String

    @Guide(.range(1...5))
    let rating: Int

    @Guide(.range(0.0...1000.0))
    let price: Double

    @Guide(.constant("IRR"))
    let currency: String
}
  • .range — محدوده مقادیر عددی رو تعیین می‌کنه (مثلاً امتیاز بین ۱ تا ۵)
  • .constant — یه مقدار ثابت مشخص می‌کنه که مدل حق تغییرش رو نداره

ترتیب propertyها مهمه!

این یه نکته‌ایه که خیلیا ازش غافلن: propertyهای یه نوع @Generable دقیقاً به همون ترتیبی که توی کد تعریف شدن تولید می‌شن. این یعنی چی؟ یعنی اگه مقدار یه property باید بر اساس property قبلی باشه، حتماً اون رو بعدش تعریف کنید. مثلاً اگه name اول تعریف بشه، description بعدی می‌تونه با توجه به نام تولید بشه.

استفاده از Enum با @Generable

enumها هم می‌تونن @Generable باشن و این خیلی کاربردیه — مخصوصاً برای طبقه‌بندی:

@Generable
enum Sentiment {
    case positive
    case negative
    case neutral
}

let session = LanguageModelSession()
let response = try await session.respond(
    to: "این نظر را تحلیل کن: محصول عالی بود!",
    generating: Sentiment.self
)
// response.content == .positive

پاسخ‌های جریانی (Streaming)

اگه تا حالا از ChatGPT استفاده کرده باشید، می‌دونید که دیدن متن به‌تدریج ظاهر شدن چقدر تجربه بهتری نسبت به منتظر موندن برای کل پاسخ ایجاد می‌کنه. خب، Foundation Models هم دقیقاً همین قابلیت رو داره:

let session = LanguageModelSession()

let stream = session.streamResponse(to: "مزایای SwiftUI را توضیح بده")

for try await partial in stream {
    // partial.content شامل متن تولیدشده تا این لحظه است
    print(partial.content)
}

متد streamResponse یه AsyncSequence برمی‌گردونه که هر عنصرش یه snapshot از پاسخ تا اون لحظه‌ست. نتیجه؟ رابط کاربری‌تون زنده‌تر و واکنش‌گراتر به نظر می‌رسه.

ترکیب Streaming با SwiftUI

بذارید ببینیم چطوری Streaming رو توی SwiftUI پیاده‌سازی کنیم:

struct StreamingChatView: View {
    @State private var session = LanguageModelSession()
    @State private var displayText = ""
    @State private var isGenerating = false

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

            Button("تولید محتوا") {
                isGenerating = true
                displayText = ""
                Task {
                    let stream = session.streamResponse(
                        to: "یک مقاله کوتاه درباره Swift بنویس"
                    )
                    for try await partial in stream {
                        displayText = partial.content
                    }
                    isGenerating = false
                }
            }
            .disabled(isGenerating)
        }
    }
}

فراخوانی ابزار (Tool Calling)

ابزارها (Tools) قابلیت‌های مدل رو فراتر از تولید متن می‌برن. با تعریف ابزارهای سفارشی، به مدل اجازه می‌دید به داده‌های خارجی دسترسی داشته باشه، محاسبات انجام بده، یا با APIهای اپلیکیشن شما تعامل کنه.

نکته جالب اینه که فریم‌ورک Foundation Models بخشی از Model Context Protocol (MCP) رو پیاده‌سازی می‌کنه — مشخصاً بخش Tools.

تعریف یک ابزار سفارشی

بذارید یه ابزار هواشناسی ساده بسازیم تا ببینید چطوری کار می‌کنه:

import FoundationModels

struct WeatherTool: Tool {
    let name = "get_weather"
    let description = "Get the current weather for a city"

    @Generable
    struct Input {
        @Guide(description: "Name of the city")
        let city: String
    }

    @Generable
    struct Output {
        let temperature: Double
        let condition: String
    }

    func call(_ input: Input) async throws -> Output {
        // در اینجا از یک API واقعی هواشناسی استفاده کنید
        // این یک مثال ساده‌شده است
        return Output(
            temperature: 25.0,
            condition: "آفتابی"
        )
    }
}

استفاده از ابزار در Session

let session = LanguageModelSession(
    tools: [WeatherTool()]
)

let response = try await session.respond(
    to: "هوای تهران چطوره؟"
)
// مدل به‌صورت خودکار WeatherTool را فراخوانی می‌کند
// و نتیجه را در پاسخ خود قرار می‌دهد
print(response.content)

مدل بر اساس متن ورودی کاربر خودش تصمیم می‌گیره آیا باید ابزاری رو فراخوانی کنه یا نه. اگه تشخیص بده ابزار مناسبی وجود داره، اون رو فراخوانی می‌کنه و نتیجه رو توی پاسخ نهایی ادغام می‌کنه. یه جورایی شبیه Function Calling توی OpenAI هست اگه باهاش آشنا باشید.

مدیریت خطا و محدودیت‌ها

کار با مدل‌های زبانی همیشه با یه درجه عدم قطعیت همراهه — این طبیعت LLMهاست. پس مدیریت خطای درست خیلی مهمه.

محدودیت توکن

مدل Foundation Models محدودیت ۴,۰۹۶ توکن (تقریباً ۳,۰۰۰ کلمه) برای ورودی و خروجی به‌صورت ترکیبی داره. این یعنی هرچی پرامپت‌تون طولانی‌تر باشه، فضای کمتری برای پاسخ باقی می‌مونه. پس پرامپت‌ها رو کوتاه و متمرکز نگه دارید.

بررسی دسترسی

import FoundationModels

// بررسی در دسترس بودن مدل
if SystemLanguageModel.default.isAvailable {
    let session = LanguageModelSession()
    // ادامه کار...
} else {
    // نمایش پیام جایگزین
    print("این ویژگی به Apple Intelligence نیاز دارد")
}

مدیریت خطاهای تولید

do {
    let response = try await session.respond(
        to: prompt,
        generating: Recipe.self
    )
    // استفاده از پاسخ
} catch let error as GenerationError {
    switch error {
    case .modelNotAvailable:
        print("مدل در دسترس نیست")
    case .contextLengthExceeded:
        print("متن ورودی بیش از حد طولانی است")
    default:
        print("خطای تولید: \(error)")
    }
} catch {
    print("خطای غیرمنتظره: \(error)")
}

محدودیت‌هایی که باید بدونید

  • بدون Fine-tuning: نمی‌تونید مدل رو آموزش بدید، ولی می‌تونید از آداپتورهای LoRA برای تخصصی‌سازی استفاده کنید (که خودش یه مقاله جداگانه می‌خواد)
  • نامناسب برای ریاضیات و کدنویسی: خود اپل صراحتاً گفته از مدل برای محاسبات ریاضی یا تولید کد استفاده نکنید. برای این کارها بهتره از Tool Calling استفاده کنید
  • کیفیت متغیر زبانی: مدل با انگلیسی بهترین عملکرد رو داره و کیفیت برای سایر زبان‌ها (از جمله فارسی) ممکنه متفاوت باشه
  • Sessionهای موازی: نمی‌تونید توی یه Session همزمان دو درخواست بفرستید، ولی می‌تونید چند Session مجزا بسازید
  • مصرف منابع: تولیدهای مکرر و حجیم ممکنه CPU/GPU زیادی مصرف کنن — حتماً نتایج رو کش کنید

پروژه عملی: ساخت دستیار هوشمند تحلیل نظرات

خب، وقتشه همه چیزهایی که یاد گرفتیم رو کنار هم بذاریم و یه پروژه واقعی بسازیم. می‌خوایم یه دستیار هوشمند بسازیم که نظرات کاربران رو تحلیل و دسته‌بندی کنه. این پروژه ترکیبی از @Generable، @Guide، مدیریت خطا و SwiftUI هست.

import FoundationModels
import SwiftUI

// تعریف ساختار خروجی
@Generable
struct ReviewAnalysis {
    @Guide(description: "Overall sentiment of the review")
    let sentiment: ReviewSentiment

    @Guide(description: "Key topics mentioned in the review")
    @Guide(.count(1...5))
    let topics: [String]

    @Guide(.range(1...10))
    let satisfactionScore: Int

    @Guide(description: "A brief one-line summary of the review")
    let summary: String
}

@Generable
enum ReviewSentiment {
    case positive
    case negative
    case mixed
    case neutral
}

// ViewModel
@Observable
class ReviewAnalyzerViewModel {
    var analysisResult: ReviewAnalysis?
    var isAnalyzing = false
    var errorMessage: String?

    private let session = LanguageModelSession(
        instructions: """
        You are a review analysis assistant. Analyze user reviews
        and provide structured feedback about sentiment, topics,
        and satisfaction level.
        """
    )

    func analyze(review: String) async {
        guard SystemLanguageModel.default.isAvailable else {
            errorMessage = "Apple Intelligence در این دستگاه موجود نیست"
            return
        }

        isAnalyzing = true
        errorMessage = nil

        do {
            let response = try await session.respond(
                to: "Analyze this review: \(review)",
                generating: ReviewAnalysis.self
            )
            analysisResult = response.content
        } catch {
            errorMessage = "خطا در تحلیل: \(error.localizedDescription)"
        }

        isAnalyzing = false
    }
}

// SwiftUI View
struct ReviewAnalyzerView: View {
    @State private var viewModel = ReviewAnalyzerViewModel()
    @State private var reviewText = ""

    var body: some View {
        NavigationStack {
            Form {
                Section("نظر کاربر") {
                    TextEditor(text: $reviewText)
                        .frame(minHeight: 100)
                }

                Button("تحلیل نظر") {
                    Task { await viewModel.analyze(review: reviewText) }
                }
                .disabled(
                    reviewText.isEmpty || viewModel.isAnalyzing
                )

                if viewModel.isAnalyzing {
                    ProgressView("در حال تحلیل...")
                }

                if let result = viewModel.analysisResult {
                    Section("نتیجه تحلیل") {
                        LabeledContent("احساس", value: "\(result.sentiment)")
                        LabeledContent("امتیاز رضایت", value: "\(result.satisfactionScore)/10")
                        LabeledContent("خلاصه", value: result.summary)
                    }

                    Section("موضوعات") {
                        ForEach(result.topics, id: \.self) { topic in
                            Text(topic)
                        }
                    }
                }

                if let error = viewModel.errorMessage {
                    Section {
                        Text(error).foregroundStyle(.red)
                    }
                }
            }
            .navigationTitle("تحلیلگر نظرات")
        }
    }
}

این پروژه نشون می‌ده چطور می‌شه با ترکیب تمام قابلیت‌هایی که یاد گرفتیم، یه ویژگی هوشمند واقعی و قابل استفاده بسازیم. می‌تونید این رو به‌عنوان نقطه شروع برای پروژه‌های پیچیده‌تر استفاده کنید.

بهترین شیوه‌ها (Best Practices)

بعد از کار کردن با Foundation Models، این نکات رو رعایت کنید تا بیشترین بهره رو ببرید:

  1. structهای @Generable رو ساده نگه دارید: از تودرتوی عمیق و تعداد زیاد propertyها اجتناب کنید. مدل ۳ میلیارد پارامتری با ساختارهای ساده بهتر کار می‌کنه
  2. از @MainActor استفاده کنید: عملیات AI رو روی thread پس‌زمینه اجرا کنید و به‌روزرسانی UI رو روی Main Thread انجام بدید
  3. نتایج رو کش کنید: اگه پرامپت‌های تکراری دارید، نتایج قبلی رو ذخیره کنید — مصرف بیهوده منابع خوب نیست
  4. پرامپت‌ها رو به انگلیسی بنویسید: حتی اگه اپلیکیشن‌تون فارسیه، پرامپت‌ها و دستورالعمل‌ها به انگلیسی نتایج بهتری می‌دن. این رو از تجربه شخصی می‌گم
  5. همیشه fallback داشته باشید: با SystemLanguageModel.default.isAvailable وجود مدل رو بررسی کنید و یه تجربه جایگزین مناسب ارائه بدید
  6. از prewarm استفاده کنید: اگه می‌دونید کاربر به‌زودی از AI استفاده می‌کنه، مدل رو پیش‌گرم کنید — تفاوتش محسوسه
  7. محدودیت توکن رو مدیریت کنید: با حداکثر ۴,۰۹۶ توکن، پرامپت‌ها رو کوتاه و متمرکز نگه دارید

پرسش‌های متداول (FAQ)

آیا فریم‌ورک Foundation Models رایگانه؟

بله، کاملاً رایگانه. چون مدل روی خود دستگاه اجرا می‌شه، هیچ هزینه‌ای برای توسعه‌دهنده یا کاربر نداره. نه کلید API می‌خواد، نه اشتراک، نه حساب کاربری خاصی.

تفاوت Foundation Models با Core ML چیه؟

Core ML یه فریم‌ورک عمومی برای اجرای مدل‌های یادگیری ماشین (مثل طبقه‌بندی تصاویر و پیش‌بینی) هست. ولی Foundation Models مختص مدل‌های زبانی بزرگ (LLM) و تولید متنه. Foundation Models از مدل آموزش‌دیده خود اپل استفاده می‌کنه، در حالی که Core ML بهتون اجازه می‌ده مدل‌های سفارشی خودتون رو اجرا کنید.

آیا می‌شه از Foundation Models آفلاین استفاده کرد؟

بله! تمام پردازش‌ها روی دستگاه انجام می‌شه و هیچ نیازی به اتصال اینترنت نیست. این واقعاً یکی از بزرگ‌ترین مزایای این فریم‌ورک نسبت به سرویس‌های ابری مثل OpenAI API هست.

کدوم دستگاه‌ها پشتیبانی می‌کنن؟

فقط دستگاه‌های سازگار با Apple Intelligence: iPhone 15 Pro و بالاتر، iPad با تراشه M1 به بالا، و Mac با تراشه M1 به بالا. دستگاه باید iOS 26، iPadOS 26 یا macOS 26 داشته باشه.

آیا Foundation Models از زبان فارسی پشتیبانی می‌کنه؟

مدل از چندین زبان پشتیبانی می‌کنه، ولی بهترین عملکرد رو با انگلیسی داره. تجربه من نشون می‌ده که اگه دستورالعمل‌های سیستمی رو به انگلیسی بنویسید و فقط متن ورودی کاربر فارسی باشه، نتایج خیلی بهتر می‌شه. کیفیت خروجی فارسی ممکنه گاهی متغیر باشه، ولی در کل قابل قبوله.

درباره نویسنده Daniel Okafor

Daniel is a former Spotify iOS engineer (2019-2024) who worked on the Now Playing surface and the in-app podcast player. He shipped the SwiftUI rewrite of the lyrics view to over 600 million users and contributed several fixes upstream to swift-collections. His writing tends toward the unglamorous corners of iOS work: build-time regressions in Xcode 16, why SwiftData still isn't ready for production sync scenarios, and how to instrument a real app with os_signpost without drowning in noise. He spent two years before Spotify at a fintech startup in Berlin building a banking app on top of Solaris API. Daniel now freelances out of Lisbon and maintains a small open-source library for type-safe deep links in SwiftUI. He has 9 years of native iOS experience.