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.