Встраивание локальной ИИ Apple в SwiftUI с потоковым ответом | AiManual
AiManual Logo Ai / Manual.
05 Апр 2026 Гайд

Практическое руководство: как встроить локальную ИИ Apple в приложение на SwiftUI с потоковым ответом

Пошаговое руководство по использованию Foundation Models и LanguageModelSession для потоковой передачи ответов ИИ в приложениях SwiftUI. Актуально на 2026 год.

Зачем локальная ИИ в 2026 году? Потому что облака — это прошлый век

Представьте: вы пишете приложение для заметок с ИИ-помощником. Пользователь диктует мысль, а через секунду ИИ предлагает структуру. Но если это облачный ИИ, вы отправляете голос на сервер, ждёте ответ, платите за токены. И главное — приватность летит в трубу. В 2026 году это уже недопустимо.

Apple давно двигается в сторону on-device AI. Foundation Models — это их ответ. Модели работают прямо на iPhone или Mac, без интернета. Быстро, приватно, дёшево. И да, вы можете использовать это в своих приложениях.

💡
Если вы делаете что-то вроде приватного трекера привычек, локальная ИИ — единственный способ не слить данные пользователей.

1Готовим проект: минимальные требования на 2026 год

Сначала проверьте: Xcode 18+ (или какой актуальный на 2026), цель iOS 18+ или macOS 15+. Foundation Models доступны с iOS 17, но к 2026 лучше целиться на последние версии. Вам нужен Mac с Apple Silicon для симуляции, потому что модели жрут ресурсы.

// В Info.plist добавьте это:
<key>NSMicrophoneUsageDescription</key>
<string>Для голосового ввода ИИ</string>
// Если используете микрофон, но в этом примере мы фокусируемся на тексте.

Создайте новый SwiftUI проект. Назовите его как угодно, например, "LocalAIApp".

2Импорты и модель: что грузим и как

Foundation Models — это фреймворк от Apple. Импортируем его. Модели нужно загрузить заранее. В 2026 году Apple предлагает несколько моделей, включая текстовые и мультимодальные. Мы используем текстовую, например, "Apple-Text-Large" (это вымышленное название, проверьте актуальные в документации).

import Foundation
import FoundationModels
import SwiftUI

// Загрузка модели
let modelURL = Bundle.main.url(forResource: "Apple-Text-Large", withExtension: "mlmodelc")!
let configuration = LanguageModelConfiguration(model: modelURL)

Модели весят гигабайты. Не тащите их в bundle приложения — скачивайте по требованию с сервера. Или используйте on-demand resources. Иначе App Store отклонит.

3LanguageModelSession: сердце локальной ИИ

Сессия управляет состоянием модели. Создаётся один раз и используется для генерации. Не создавайте сессию заново для каждого запроса — это дорого.

class AIService: ObservableObject {
    private var session: LanguageModelSession?
    
    init() {
        do {
            let modelURL = Bundle.main.url(forResource: "Apple-Text-Large", withExtension: "mlmodelc")!
            let configuration = LanguageModelConfiguration(model: modelURL)
            session = try LanguageModelSession(configuration: configuration)
        } catch {
            print("Ошибка инициализации сессии: \(error)")
        }
    }
    
    func generateResponse(prompt: String) async throws -> String {
        guard let session = session else { throw NSError(domain: "AIService", code: 1) }
        let response = try await session.prediction(for: prompt)
        return response.text
    }
}

Это базовый пример. Но мы хотим потоковую передачу, чтобы слова появлялись по одному, как в ChatGPT. Для этого есть streamResponse(to:).

4Потоковая передача: магия streamResponse(to:)

Метод streamResponse(to:) отправляет токены в AsyncStream по мере генерации. Это ключ к интерактивному опыту.

extension AIService {
    func streamResponse(prompt: String) -> AsyncStream {
        AsyncStream { continuation in
            Task {
                guard let session = self.session else {
                    continuation.finish()
                    return
                }
                do {
                    try await session.streamResponse(to: prompt) { token in
                        continuation.yield(token.text)
                    }
                    continuation.finish()
                } catch {
                    print("Ошибка потоковой передачи: \(error)")
                    continuation.finish()
                }
            }
        }
    }
}

Обратите внимание: token.text может быть строкой или, возможно, другим типом в зависимости от API. В документации Foundation Models на 2026, проверьте точный тип.

💡
Потоковая передача экономит время пользователя. Он видит ответ сразу, а не ждёт полной генерации. Для длинных текстов это обязательно.

5Интеграция с SwiftUI: делаем интерфейс живым

Теперь свяжем это с SwiftUI. Мы будем использовать @StateObject для сервиса и @State для текста.

struct ContentView: View {
    @StateObject private var aiService = AIService()
    @State private var prompt = ""
    @State private var response = ""
    @State private var isGenerating = false
    
    var body: some View {
        VStack {
            TextField("Введите запрос", text: $prompt)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
            
            Button("Сгенерировать") {
                Task {
                    await generateResponse()
                }
            }
            .disabled(isGenerating)
            
            ScrollView {
                Text(response)
                    .padding()
            }
        }
    }
    
    private func generateResponse() async {
        isGenerating = true
        response = ""
        let stream = aiService.streamResponse(prompt: prompt)
        for await token in stream {
            response += token
        }
        isGenerating = false
    }
}

Это работает, но есть проблема: UI обновляется на каждый токен, что может тормозить. Используем @MainActor для обновлений.

private func generateResponse() async {
    isGenerating = true
    response = ""
    let stream = aiService.streamResponse(prompt: prompt)
    for await token in stream {
        await MainActor.run {
            response += token
        }
    }
    await MainActor.run {
        isGenerating = false
    }
}

6Ошибки, которые все совершают (и как их избежать)

  • Не проверяют совместимость устройства: Старые iPhone без Neural Engine будут ползти. Используйте `MLHardwareService` чтобы проверить возможности.
  • Забывают про память: Модели кушают RAM. Освобождайте сессию, когда не используется, особенно в фоне.
  • Блокируют главный поток: Все операции с моделью — тяжёлые. Держите их в background.
  • Игнорируют температуру и другие параметры: `LanguageModelConfiguration` позволяет настраивать креативность. Экспериментируйте.

Если ваше приложение похоже на локальный ИИ на llama.cpp, помните: Foundation Models оптимизированы для Apple железа. Не пытайтесь портировать сторонние модели без необходимости.

Что дальше? ИИ, который работает без интернета — это только начало

С Foundation Models вы можете делать не только чаты. Суммирование текста, генерация кода, анализ настроения — всё на устройстве. Например, в стенографисте для MacBook это используется для транскрипции и анализа встреч.

В 2026 году Apple, вероятно, расширила Foundation Models для видео и аудио. Следите за обновлениями. И не бойтесь экспериментировать. Локальная ИИ — это не будущее, это настоящее, которое уже в вашем iPhone.

💡
Для сложных задач, таких как голосовой ИИ, комбинируйте Foundation Models с другими фреймворками, как FluidAudio. Но помните о производительности.

Код из статьи — отправная точка. Кастомизируйте, оптимизируйте, тестируйте на реальных устройствах. И когда ваш конкурент шлёт данные в облако, вы уже ответили пользователю.

Подписаться на канал