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...