Section 13/171 menit

13. Pola Arsitektur untuk Fitur AI

13. Pola Arsitektur untuk Fitur AI

Pola 1: Layered AI (Multi-Tier Fallback)

swift
// arsitektur: Try on-device first, fallback ke cloud
actor LayeredAI {
    private let onDevice: FoundationModelsService
    private let cloud: CloudAIService
    private let isOnDeviceAvailable: Bool

    init(cloud: CloudAIService) {
        self.cloud = cloud
        self.isOnDeviceAvailable = SystemModel.isAppleIntelligenceAvailable
        self.onDevice = FoundationModelsService()
    }

    func summarize(_ text: String) async throws -> String {
        if isOnDeviceAvailable {
            do {
                return try await onDevice.summarize(text)
            } catch FoundationModelsError.unavailable {
                // fallback
            }
        }
        return try await cloud.summarize(text)
    }
}

Pola 2: Optimistic UI dengan Streaming

swift
// arsitektur: Tampilkan token segera, hapus loading state
@MainActor
@Observable
final class ChatVM {
    var messages: [Message] = []
    var liveText: String = ""

    func send(_ prompt: String, ai: AIService) async {
        let userMsg = Message(role: .user, content: prompt)
        messages.append(userMsg)
        liveText = ""

        for try await chunk in try await ai.stream(prompt: prompt) {
            liveText += chunk
        }

        messages.append(Message(role: .assistant, content: liveText))
        liveText = ""
    }
}

Pola 3: Tool Calling untuk Action

swift
// arsitektur: AI sebagai orchestrator yang panggil tool
struct WeatherTool: Tool {
    static var name = "get_weather"
    static var description = "Dapatkan cuaca untuk kota tertentu"

    @Parameter var city: String

    func call() async throws -> String {
        let weather = try await WeatherAPI.current(city: city)
        return "\(weather.temp)°C, \(weather.condition)"
    }
}

let session = LanguageModelSession(tools: [WeatherTool()])
let response = try await session.respond(to: "Cuaca Jakarta hari ini?")
// Model akan auto-call WeatherTool, lalu compose jawaban

Pola 4: AI sebagai Service, Bukan ViewModel

swift
// arsitektur: Service layer tersendiri untuk AI
protocol AIService: Sendable {
    func summarize(_ text: String) async throws -> String
    func extractEntities(from text: String) async throws -> [Entity]
    func suggestReply(to message: String, history: [Message]) async throws -> String
}

actor ProductionAIService: AIService {
    private let onDevice: FoundationModelsService
    private let cloud: CloudAIService
    // ...
}

actor MockAIService: AIService {
    func summarize(_ text: String) async throws -> String { "Mocked summary" }
    // ...
}

ViewModel @MainActor consume protocol AIService — testable, swappable, isolation jelas.