Foundation Models Framework 완벽 가이드 (iOS 26+)

Foundation Models Framework 완벽 가이드 (iOS 26+)

1. 개요 및 기능 정의

Foundation Models Framework란?

Foundation Models Framework는 WWDC 2025에서 발표된 Apple의 새로운 프레임워크로, Apple Intelligence의 핵심인 약 30억 개 파라미터의 온디바이스 LLM에 개발자가 직접 접근할 수 있게 해줍니다.

핵심 특징

특징 설명
온디바이스 실행 모든 처리가 디바이스에서 이루어져 프라이버시 보장
오프라인 지원 인터넷 연결 없이도 작동
무료 추론 API 호출 비용 없음
Swift 네이티브 3줄의 코드로 시작 가능
Guided Generation 타입 안전한 구조화된 출력
Tool Calling 앱 기능과 모델 연동

주요 사용 사례

  • 텍스트 요약 및 추출
  • 콘텐츠 분류 및 태깅
  • 시맨틱 검색
  • 게임 NPC 대화 생성
  • 개인화된 퀴즈 생성
  • 자연어 검색 기능
  • 앱 내 가이드/도우미

⚠️ 주의: 이 모델은 일반 세계 지식이나 고급 추론을 위한 범용 챗봇이 아닙니다. 디바이스 규모의 실용적 작업에 최적화되어 있습니다.


2. 다른 AI 서비스와의 비교

항목 Foundation Models OpenAI API / Claude API
실행 위치 온디바이스 (로컬) 클라우드 서버
프라이버시 ✅ 데이터가 디바이스를 떠나지 않음 ❌ 서버로 데이터 전송
인터넷 필요 ❌ 오프라인 가능 ✅ 필수
비용 무료 토큰당 과금
지연 시간 낮음 (~150ms with prewarm) 네트워크 의존
모델 크기 ~3B 파라미터 GPT-4: ~1.8T, Claude: 비공개
세계 지식 제한적 광범위
고급 추론 제한적 뛰어남
컨텍스트 윈도우 ~4,096 토큰 128K+ 토큰
다국어 지원 10개 언어 100+ 언어
앱 크기 영향 없음 (시스템 모델) SDK 추가 필요

언제 Foundation Models를 사용해야 할까?

Foundation Models 적합:

  • 프라이버시가 중요한 경우
  • 오프라인 기능이 필요한 경우
  • 빠른 응답이 필요한 경우
  • API 비용을 절감하고 싶은 경우
  • 간단한 텍스트 처리 작업

클라우드 AI 적합:

  • 복잡한 추론이 필요한 경우
  • 광범위한 세계 지식이 필요한 경우
  • 긴 컨텍스트 처리가 필요한 경우
  • 최신 정보가 필요한 경우

3. 사용 조건 및 요구사항

하드웨어 요구사항

디바이스 최소 칩셋
iPhone A17 Pro 이상 (iPhone 15 Pro/Pro Max, iPhone 16 시리즈)
iPad M1 이상
Mac M1 이상 (Apple Silicon)
Vision Pro M2

소프트웨어 요구사항

  • iOS 26.0+ / iPadOS 26.0+ / macOS 26.0 (Tahoe)+ / visionOS 26.0+
  • Apple Intelligence 활성화 (설정 → 일반 → Apple Intelligence)
  • 온디바이스 모델 다운로드 완료 (~1.6GB)

지원 언어

현재 지원: English, French, German, Italian, Portuguese (Brazil), Spanish, Chinese (Simplified), Japanese, Korean

예정: Chinese (Traditional), Danish, Dutch, Norwegian, Swedish, Portuguese (Portugal), Vietnamese, Turkish

가용성 확인 코드

import FoundationModels

let model = SystemLanguageModel.default

switch model.availability {
case .available:
    // 사용 가능
    print("Foundation Models 사용 가능")
    
case .unavailable(let reason):
    switch reason {
    case .deviceNotEligible:
        print("디바이스가 지원되지 않습니다")
    case .appleIntelligenceNotEnabled:
        print("Apple Intelligence를 활성화해주세요")
    case .modelNotReady:
        print("모델 다운로드 중입니다")
    @unknown default:
        print("알 수 없는 이유로 사용 불가")
    }
}

4. 주요 기능 및 API

4.1 기본 텍스트 생성

import FoundationModels

// 세션 생성
let session = LanguageModelSession()

// 응답 요청
let response = try await session.respond(to: "한국의 수도는 어디인가요?")
print(response.content)

4.2 Instructions (시스템 프롬프트)

let session = LanguageModelSession {
    """
    당신은 친절한 요리 도우미입니다.
    레시피를 단계별로 설명해주세요.
    """
}

let response = try await session.respond(to: "김치찌개 만드는 법 알려줘")

4.3 Guided Generation (@Generable)

구조화된 Swift 타입으로 응답 받기:

import FoundationModels

@Generable
struct Recipe {
    @Guide(description: "요리 이름")
    let name: String
    
    @Guide(description: "재료 목록")
    let ingredients: [String]
    
    @Guide(description: "조리 시간 (분)")
    let cookingTime: Int
    
    @Guide(description: "난이도", .anyOf(["쉬움", "보통", "어려움"]))
    let difficulty: String
    
    @Guide(.count(5))  // 정확히 5단계
    let steps: [String]
}

let session = LanguageModelSession()
let result = try await session.respond(
    to: "불고기 레시피를 알려줘",
    generating: Recipe.self
)

let recipe: Recipe = result.content
print("요리: \(recipe.name)")
print("재료: \(recipe.ingredients.joined(separator: ", "))")

4.4 @Guide 매크로 옵션

@Generable
struct Example {
    // 설명 추가
    @Guide(description: "사용자 이름")
    let name: String
    
    // 범위 지정
    @Guide(.range(1...5))
    let rating: Int
    
    // 배열 개수 지정
    @Guide(.count(3))
    let tags: [String]
    
    // 최소 개수
    @Guide(.count(atLeast: 2))
    let options: [String]
    
    // 최대 개수
    @Guide(.count(atMost: 10))
    let items: [String]
    
    // 범위 지정 (배열)
    @Guide(.count(2...5))
    let choices: [String]
    
    // 허용 값 지정
    @Guide(.anyOf(["옵션1", "옵션2", "옵션3"]))
    let selected: String
}

4.5 스트리밍 응답

let session = LanguageModelSession()

// 텍스트 스트리밍
let stream = session.streamResponse(to: "긴 이야기를 들려줘")
for try await partialText in stream {
    print(partialText) // 점진적으로 출력
}

// 구조화된 데이터 스트리밍
let recipeStream = session.streamResponse(
    to: "파스타 레시피",
    generating: Recipe.self
)

for try await partial in recipeStream {
    // partial은 Recipe.PartiallyGenerated 타입
    // 각 프로퍼티가 Optional로 제공됨
    if let name = partial.name {
        print("요리명: \(name)")
    }
}

4.6 Tool Calling

모델이 앱의 기능을 호출하도록 허용:

import FoundationModels
import CoreLocation
import WeatherKit

struct WeatherTool: Tool {
    let name = "getWeather"
    let description = "특정 도시의 현재 날씨를 조회합니다"
    
    @Generable
    struct Arguments {
        @Guide(description: "도시 이름")
        let city: String
    }
    
    func call(arguments: Arguments) async throws -> ToolOutput {
        // WeatherKit 또는 API 호출
        let weather = try await fetchWeather(for: arguments.city)
        return ToolOutput("\(arguments.city): \(weather.temperature)°C, \(weather.condition)")
    }
    
    private func fetchWeather(for city: String) async throws -> (temperature: Double, condition: String) {
        // 실제 구현
        return (25.0, "맑음")
    }
}

// Tool 사용
let session = LanguageModelSession(tools: [WeatherTool()])
let response = try await session.respond(to: "서울 날씨 어때?")
print(response.content) // "서울: 25.0°C, 맑음"

4.7 다중 턴 대화

@State var session = LanguageModelSession {
    "당신은 친절한 쇼핑 도우미입니다."
}

// 첫 번째 질문
let response1 = try await session.respond(to: "노트북을 사고 싶어요")

// 컨텍스트가 유지됨
let response2 = try await session.respond(to: "예산은 200만원이에요")

// 이전 대화 참조
let response3 = try await session.respond(to: "추천해주세요")

// 대화 기록 확인
for entry in session.transcript {
    switch entry {
    case .prompt(let prompt):
        print("사용자: \(prompt)")
    case .response(let response):
        print("AI: \(response)")
    case .instructions, .toolCalls, .toolOutput:
        break
    @unknown default:
        break
    }
}

4.8 성능 최적화 (Prewarm)

struct ContentView: View {
    @State var session = LanguageModelSession()
    
    var body: some View {
        VStack {
            // UI 구성
        }
        .onAppear {
            // 모델 미리 로드
            session.prewarm()
        }
    }
}

// 특정 프롬프트 프리픽스로 프리웜
session.prewarm(promptPrefix: "레시피를 생성해주세요:")

5. 예시 코드: 완전한 앱 구현

5.1 기본 채팅 앱

import SwiftUI
import FoundationModels

struct ChatView: View {
    @State private var session = LanguageModelSession {
        "당신은 친절하고 도움이 되는 AI 어시스턴트입니다."
    }
    @State private var inputText = ""
    @State private var isLoading = false
    
    private let model = SystemLanguageModel.default
    
    var body: some View {
        VStack {
            // 가용성 체크
            switch model.availability {
            case .available:
                chatInterface
            case .unavailable(.appleIntelligenceNotEnabled):
                Text("설정에서 Apple Intelligence를 활성화해주세요")
            case .unavailable(.modelNotReady):
                ProgressView("모델 준비 중...")
            case .unavailable(.deviceNotEligible):
                Text("이 기기는 지원되지 않습니다")
            case .unavailable:
                Text("사용할 수 없습니다")
            }
        }
        .onAppear {
            session.prewarm()
        }
    }
    
    private var chatInterface: some View {
        VStack {
            // 대화 기록
            ScrollView {
                LazyVStack(alignment: .leading, spacing: 12) {
                    ForEach(session.transcript) { entry in
                        switch entry {
                        case .prompt(let prompt):
                            HStack {
                                Spacer()
                                Text(prompt.content)
                                    .padding()
                                    .background(Color.blue)
                                    .foregroundColor(.white)
                                    .cornerRadius(12)
                            }
                        case .response(let response):
                            HStack {
                                Text(response.content)
                                    .padding()
                                    .background(Color.gray.opacity(0.2))
                                    .cornerRadius(12)
                                Spacer()
                            }
                        default:
                            EmptyView()
                        }
                    }
                }
                .padding()
            }
            
            // 입력 필드
            HStack {
                TextField("메시지 입력...", text: $inputText)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .disabled(isLoading)
                
                Button(action: sendMessage) {
                    Image(systemName: isLoading ? "hourglass" : "paperplane.fill")
                }
                .disabled(inputText.isEmpty || isLoading)
            }
            .padding()
        }
    }
    
    private func sendMessage() {
        let message = inputText
        inputText = ""
        isLoading = true
        
        Task {
            do {
                let _ = try await session.respond(to: message)
            } catch {
                print("Error: \(error)")
            }
            isLoading = false
        }
    }
}

5.2 구조화된 퀴즈 생성기

import SwiftUI
import FoundationModels

@Generable
struct QuizQuestion {
    @Guide(description: "퀴즈 질문")
    let question: String
    
    @Guide(.count(4))
    let choices: [String]
    
    @Guide(description: "정답 (choices 중 하나)")
    let answer: String
    
    @Guide(description: "정답 해설")
    let explanation: String
}

@Observable
class QuizGenerator {
    private let session = LanguageModelSession {
        """
        당신은 교육용 퀴즈를 생성하는 전문가입니다.
        질문은 명확하고 선택지는 구분 가능해야 합니다.
        """
    }
    
    var currentQuestion: QuizQuestion?
    var isGenerating = false
    
    func generateQuestion(topic: String) async {
        isGenerating = true
        defer { isGenerating = false }
        
        do {
            let result = try await session.respond(
                to: "\(topic)에 대한 4지선다 퀴즈를 만들어주세요",
                generating: QuizQuestion.self
            )
            currentQuestion = result.content
        } catch {
            print("퀴즈 생성 실패: \(error)")
        }
    }
}

struct QuizView: View {
    @State private var generator = QuizGenerator()
    @State private var topic = "한국 역사"
    @State private var selectedAnswer: String?
    @State private var showResult = false
    
    var body: some View {
        VStack(spacing: 20) {
            TextField("주제 입력", text: $topic)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
            Button("퀴즈 생성") {
                Task {
                    await generator.generateQuestion(topic: topic)
                    selectedAnswer = nil
                    showResult = false
                }
            }
            .disabled(generator.isGenerating)
            
            if generator.isGenerating {
                ProgressView("퀴즈 생성 중...")
            }
            
            if let question = generator.currentQuestion {
                VStack(alignment: .leading, spacing: 16) {
                    Text(question.question)
                        .font(.headline)
                    
                    ForEach(question.choices, id: \.self) { choice in
                        Button(action: {
                            selectedAnswer = choice
                            showResult = true
                        }) {
                            HStack {
                                Text(choice)
                                Spacer()
                                if showResult {
                                    if choice == question.answer {
                                        Image(systemName: "checkmark.circle.fill")
                                            .foregroundColor(.green)
                                    } else if choice == selectedAnswer {
                                        Image(systemName: "xmark.circle.fill")
                                            .foregroundColor(.red)
                                    }
                                }
                            }
                            .padding()
                            .background(Color.gray.opacity(0.1))
                            .cornerRadius(8)
                        }
                        .disabled(showResult)
                    }
                    
                    if showResult {
                        Text("해설: \(question.explanation)")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }
                }
            }
        }
        .padding()
    }
}

6. AppIntents + Widget + Foundation Models 연동

6.1 App Intent 정의

import AppIntents
import FoundationModels

// 일일 명언 생성 Intent
struct GenerateDailyQuoteIntent: AppIntent {
    static var title: LocalizedStringResource = "오늘의 명언 생성"
    static var description = IntentDescription("AI가 생성한 오늘의 명언을 보여줍니다")
    
    @Parameter(title: "주제", default: "동기부여")
    var topic: String
    
    static var parameterSummary: some ParameterSummary {
        Summary("'\(\.$topic)' 주제의 명언 생성")
    }
    
    func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
        let model = SystemLanguageModel.default
        
        guard model.availability == .available else {
            return .result(
                value: "서비스를 사용할 수 없습니다",
                dialog: "Apple Intelligence가 활성화되지 않았습니다."
            )
        }
        
        let session = LanguageModelSession {
            "당신은 명언을 생성하는 전문가입니다. 짧고 인상적인 한 문장을 생성해주세요."
        }
        
        let response = try await session.respond(to: "\(topic) 주제로 명언을 하나 만들어줘")
        
        return .result(
            value: response.content,
            dialog: IntentDialog(stringLiteral: response.content)
        )
    }
}

6.2 구조화된 Intent (Generable 활용)

import AppIntents
import FoundationModels

@Generable
struct TaskSummary {
    let title: String
    let priority: String
    let estimatedMinutes: Int
    let suggestion: String
}

struct SummarizeTasksIntent: AppIntent {
    static var title: LocalizedStringResource = "할 일 요약"
    static var description = IntentDescription("오늘의 할 일을 AI가 분석하고 요약합니다")
    
    @Parameter(title: "할 일 목록")
    var tasks: [String]
    
    func perform() async throws -> some IntentResult & ReturnsValue<String> {
        guard SystemLanguageModel.default.availability == .available else {
            return .result(value: "AI를 사용할 수 없습니다")
        }
        
        let session = LanguageModelSession {
            "당신은 생산성 전문가입니다. 할 일을 분석하고 우선순위를 제안해주세요."
        }
        
        let prompt = """
        다음 할 일들을 분석해주세요:
        \(tasks.enumerated().map { "\($0 + 1). \($1)" }.joined(separator: "\n"))
        """
        
        let result = try await session.respond(
            to: prompt,
            generating: [TaskSummary].self
        )
        
        let summaries = result.content
        let summary = summaries.map { 
            "[\($0.priority)] \($0.title) (~\($0.estimatedMinutes)분): \($0.suggestion)" 
        }.joined(separator: "\n")
        
        return .result(value: summary)
    }
}

// App Shortcuts 등록
struct MyAppShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: GenerateDailyQuoteIntent(),
            phrases: [
                "오늘의 명언 \(.applicationName)",
                "\(.applicationName)에서 명언 생성",
                "명언 들려줘 \(.applicationName)"
            ],
            shortTitle: "오늘의 명언",
            systemImageName: "quote.bubble"
        )
        
        AppShortcut(
            intent: SummarizeTasksIntent(),
            phrases: [
                "할 일 요약 \(.applicationName)",
                "\(.applicationName) 오늘 뭐해야 해"
            ],
            shortTitle: "할 일 요약",
            systemImageName: "checklist"
        )
    }
}

6.3 Widget에서 Foundation Models 사용

import WidgetKit
import SwiftUI
import FoundationModels
import AppIntents

// Widget Entry
struct QuoteEntry: TimelineEntry {
    let date: Date
    let quote: String
    let topic: String
    let isPlaceholder: Bool
    
    static var placeholder: QuoteEntry {
        QuoteEntry(
            date: Date(),
            quote: "오늘도 좋은 하루 되세요!",
            topic: "동기부여",
            isPlaceholder: true
        )
    }
}

// Timeline Provider
struct QuoteProvider: AppIntentTimelineProvider {
    typealias Entry = QuoteEntry
    typealias Intent = QuoteConfigurationIntent
    
    func placeholder(in context: Context) -> QuoteEntry {
        .placeholder
    }
    
    func snapshot(for configuration: QuoteConfigurationIntent, in context: Context) async -> QuoteEntry {
        if context.isPreview {
            return .placeholder
        }
        return await generateEntry(topic: configuration.topic ?? "동기부여")
    }
    
    func timeline(for configuration: QuoteConfigurationIntent, in context: Context) async -> Timeline<QuoteEntry> {
        let entry = await generateEntry(topic: configuration.topic ?? "동기부여")
        
        // 1시간마다 새로고침
        let nextUpdate = Calendar.current.date(byAdding: .hour, value: 1, to: Date())!
        
        return Timeline(entries: [entry], policy: .after(nextUpdate))
    }
    
    private func generateEntry(topic: String) async -> QuoteEntry {
        let model = SystemLanguageModel.default
        
        guard model.availability == .available else {
            return QuoteEntry(
                date: Date(),
                quote: "AI 서비스를 사용할 수 없습니다",
                topic: topic,
                isPlaceholder: false
            )
        }
        
        do {
            let session = LanguageModelSession {
                "짧고 인상적인 명언을 한 문장으로 생성해주세요."
            }
            
            let response = try await session.respond(to: "\(topic) 주제의 명언")
            
            return QuoteEntry(
                date: Date(),
                quote: response.content,
                topic: topic,
                isPlaceholder: false
            )
        } catch {
            return QuoteEntry(
                date: Date(),
                quote: "명언을 불러올 수 없습니다",
                topic: topic,
                isPlaceholder: false
            )
        }
    }
}

// Widget Configuration Intent
struct QuoteConfigurationIntent: WidgetConfigurationIntent {
    static var title: LocalizedStringResource = "명언 설정"
    static var description = IntentDescription("명언의 주제를 선택하세요")
    
    @Parameter(title: "주제", default: "동기부여")
    var topic: String?
}

// Widget View
struct QuoteWidgetView: View {
    var entry: QuoteEntry
    
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                Image(systemName: "quote.opening")
                    .foregroundColor(.secondary)
                Text(entry.topic)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            
            Text(entry.quote)
                .font(.system(.body, design: .serif))
                .multilineTextAlignment(.leading)
            
            Spacer()
            
            Text(entry.date, style: .time)
                .font(.caption2)
                .foregroundColor(.secondary)
        }
        .padding()
        .redacted(reason: entry.isPlaceholder ? .placeholder : [])
    }
}

// Widget 정의
struct QuoteWidget: Widget {
    let kind = "QuoteWidget"
    
    var body: some WidgetConfiguration {
        AppIntentConfiguration(
            kind: kind,
            intent: QuoteConfigurationIntent.self,
            provider: QuoteProvider()
        ) { entry in
            QuoteWidgetView(entry: entry)
                .containerBackground(.fill.tertiary, for: .widget)
        }
        .configurationDisplayName("오늘의 명언")
        .description("AI가 생성한 명언을 위젯에서 확인하세요")
        .supportedFamilies([.systemSmall, .systemMedium])
    }
}

6.4 Interactive Widget + Foundation Models

import WidgetKit
import SwiftUI
import AppIntents
import FoundationModels

// 버튼 액션 Intent
struct RefreshQuoteIntent: AppIntent {
    static var title: LocalizedStringResource = "새 명언 생성"
    
    @Parameter(title: "주제")
    var topic: String
    
    init() {
        self.topic = "동기부여"
    }
    
    init(topic: String) {
        self.topic = topic
    }
    
    func perform() async throws -> some IntentResult {
        // Widget 타임라인 새로고침
        WidgetCenter.shared.reloadTimelines(ofKind: "QuoteWidget")
        return .result()
    }
}

// Interactive Widget View
struct InteractiveQuoteView: View {
    var entry: QuoteEntry
    
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text(entry.quote)
                .font(.system(.body, design: .serif))
            
            Spacer()
            
            // 새로고침 버튼 (iOS 17+)
            Button(intent: RefreshQuoteIntent(topic: entry.topic)) {
                Label("새로 생성", systemImage: "arrow.clockwise")
                    .font(.caption)
            }
            .buttonStyle(.bordered)
        }
        .padding()
    }
}

7. 사용된 Method 정리

SystemLanguageModel

메서드/프로퍼티 설명 사용 예시
.default 기본 시스템 언어 모델 let model = SystemLanguageModel.default
.availability 모델 가용성 상태 model.availability == .available
.contentTagging 콘텐츠 태깅 특화 모델 LanguageModelSession(model: .contentTagging)

LanguageModelSession

메서드 설명 사용 예시
init() 기본 세션 생성 LanguageModelSession()
init(instructions:) 시스템 프롬프트와 함께 생성 LanguageModelSession { "..." }
init(tools:) Tool과 함께 생성 LanguageModelSession(tools: [MyTool()])
init(transcript:) 이전 대화 기록으로 생성 LanguageModelSession(transcript: savedTranscript)
respond(to:) 텍스트 응답 요청 try await session.respond(to: "질문")
respond(to:generating:) 구조화된 응답 요청 try await session.respond(to: "...", generating: MyType.self)
streamResponse(to:) 스트리밍 텍스트 응답 session.streamResponse(to: "...")
streamResponse(to:generating:) 스트리밍 구조화된 응답 session.streamResponse(generating: MyType.self) { "..." }
prewarm() 모델 미리 로드 session.prewarm()
prewarm(promptPrefix:) 특정 프롬프트로 미리 로드 session.prewarm(promptPrefix: "요약해줘:")
.transcript 대화 기록 for entry in session.transcript { }
.isResponding 응답 중 여부 if session.isResponding { }

@Generable 매크로

기능 설명 사용 예시
@Generable 구조체를 생성 가능하게 표시 @Generable struct MyType { }
.PartiallyGenerated 스트리밍용 부분 타입 MyType.PartiallyGenerated

@Guide 매크로

옵션 설명 사용 예시
description: 프로퍼티 설명 @Guide(description: "이름")
.range() 숫자 범위 @Guide(.range(1...10))
.count() 배열 정확한 개수 @Guide(.count(5))
.count(atLeast:) 최소 개수 @Guide(.count(atLeast: 2))
.count(atMost:) 최대 개수 @Guide(.count(atMost: 10))
.anyOf() 허용 값 목록 @Guide(.anyOf(["A", "B", "C"]))

Tool Protocol

요소 설명 사용 예시
name Tool 식별자 let name = "myTool"
description Tool 설명 let description = "..."
Arguments 인자 타입 (@Generable) @Generable struct Arguments { }
call(arguments:) 실행 메서드 func call(arguments:) async throws -> ToolOutput
ToolOutput 반환 타입 ToolOutput("결과")

GenerationOptions

옵션 설명 사용 예시
temperature 창의성 (0.0-2.0) GenerationOptions(temperature: 0.7)
sampling 샘플링 방식 .greedy, .random(...)

8. 유용하지만 사용하지 않은 Method

Transcript 관련

메서드/타입 설명 사용 사례
Transcript 전체 대화 기록 타입 대화 저장/복원
Transcript.Entry 개별 항목 (prompt, response, toolCalls 등) 대화 분석
session.transcript.tokenCount 현재 토큰 수 컨텍스트 윈도우 관리

에러 처리

타입 설명 사용 사례
LanguageModelSession.GenerationError 생성 에러 에러 핸들링
.exceededContextWindowSize 컨텍스트 초과 세션 리셋
.unsupportedLanguage 미지원 언어 언어 검증
LanguageModelSession.ToolCallError Tool 호출 에러 Tool 디버깅

Guardrails (안전 가드레일)

옵션 설명 사용 사례
Guardrails.default 기본 안전 필터 일반 사용
SafetyAssessment 안전성 평가 결과 콘텐츠 필터링

Instructions Builder

기능 설명 사용 예시
Instructions { } 복잡한 지시 구성 다중 조건 프롬프트
조건부 지시 if/else로 지시 분기 동적 시스템 프롬프트

Prompt Builder

기능 설명 사용 예시
Prompt { } 구조화된 프롬프트 복잡한 프롬프트 구성
예시 포함 Few-shot 학습 Prompt { Example(...) }

Adapters (특화 모델)

어댑터 설명 사용 사례
.contentTagging 콘텐츠 태깅 특화 분류 작업
.summarization 요약 특화 텍스트 요약

Dynamic Schema

기능 설명 사용 사례
GenerationSchema 런타임 스키마 정의 동적 구조 생성
GeneratedContent 동적 결과 타입 유연한 응답 처리

Tool Context (Beta 26.1+)

기능 설명 사용 사례
ToolContext Tool 호출 컨텍스트 세션 상태 접근
context.instructions 현재 지시 확인 조건부 Tool 로직
context.transcript 대화 기록 접근 이전 대화 참조

9. 베스트 프랙티스

성능 최적화

// 1. Prewarm 활용
session.prewarm() // viewDidAppear 또는 onAppear에서

// 2. 불필요한 프로퍼티 제거
// @Generable 타입에서 UI에 표시하지 않는 프로퍼티는 제거

// 3. isResponding 체크
Button("전송") { }
    .disabled(session.isResponding)

// 4. 스트리밍으로 체감 속도 개선
let stream = session.streamResponse(to: prompt)
for try await partial in stream {
    // 점진적 UI 업데이트
}

에러 처리

do {
    let response = try await session.respond(to: prompt)
} catch LanguageModelSession.GenerationError.exceededContextWindowSize {
    // 새 세션 생성
    session = LanguageModelSession()
} catch LanguageModelSession.GenerationError.unsupportedLanguage {
    // 언어 변경 안내
} catch {
    // 일반 에러 처리
}

Fallback 전략

func getAIResponse(prompt: String) async -> String {
    let model = SystemLanguageModel.default
    
    // 1차: Foundation Models
    if model.availability == .available {
        if let response = try? await session.respond(to: prompt) {
            return response.content
        }
    }
    
    // 2차: 클라우드 API (필요시)
    if let cloudResponse = try? await cloudAPI.generate(prompt) {
        return cloudResponse
    }
    
    // 3차: 기본 응답
    return "죄송합니다. 지금은 응답할 수 없습니다."
}

10. 참고 자료

Discussion

Loading comments...