솔직히 말할게요. iOS 개발자로서 AI 기능을 앱에 넣으려면 항상 외부 API 키를 발급받고, 클라우드 서버에 데이터를 보내고, 사용량 요금을 걱정해야 했잖아요. 그런데 iOS 26에서 등장한 Foundation Models 프레임워크가 이 판을 완전히 뒤집어 놨습니다.
Apple Intelligence를 구동하는 바로 그 30억 파라미터 온디바이스 언어 모델을 — API 키 없이, 클라우드 비용 없이, 인터넷 연결 없이 — 여러분의 앱에서 직접 쓸 수 있게 된 거예요. 게다가 완전 무료입니다.
이 글에서는 Foundation Models 프레임워크의 핵심 기능을 실전 코드와 함께 하나하나 짚어봅니다. LanguageModelSession 기본 사용법부터 @Generable로 구조화된 출력 받기, Tool Calling으로 모델 확장하기, 스트리밍 응답 처리, 그리고 실전에서 꼭 알아야 할 주의사항까지 — 이 글 하나면 온디바이스 AI 개발을 바로 시작할 수 있을 거예요.
Foundation Models 프레임워크란?
Foundation Models 프레임워크는 WWDC 2025에서 공개된 Apple의 온디바이스 AI 프레임워크입니다. iOS 26, iPadOS 26, macOS 26(Tahoe), visionOS 26에서 사용할 수 있어요.
핵심 아이디어는 놀라울 정도로 간단합니다. Apple Silicon(A17 Pro 이상, M1 이상)에 최적화된 약 30억(3B) 파라미터의 언어 모델이 기기에 내장되어 있고, 이걸 Swift API로 직접 호출할 수 있다는 거죠. 처음 이 소식을 들었을 때 솔직히 좀 흥분했어요.
기존의 클라우드 기반 LLM(ChatGPT, Claude 등)과 비교하면 차이가 확 드러납니다.
| 특성 | 클라우드 LLM | Foundation Models (온디바이스) |
|---|---|---|
| 처리 위치 | 원격 서버 | 사용자 기기 내부 |
| 인터넷 필요 | 필수 | 불필요 (오프라인 동작) |
| 응답 지연 | 2~5초 | ~0.6ms/토큰 (첫 토큰), 30토큰/초 |
| 비용 | API 호출당 과금 | 완전 무료 |
| 프라이버시 | 데이터가 서버로 전송 | 데이터가 기기를 떠나지 않음 |
| 모델 크기 | 수백~수천억 파라미터 | ~30억 파라미터 |
물론 3B 모델이 GPT-4나 Claude 같은 대형 모델만큼 똑똑하진 않습니다. 그건 사실이에요. 하지만 요약, 분류, 엔티티 추출, 감성 분석, 텍스트 변환 같은 집중적인 작업에는 충분히 강력합니다. 그리고 무엇보다 — 사용자 데이터가 기기를 절대 떠나지 않는다는 건 프라이버시 측면에서 엄청난 장점이에요.
개발 환경 요구사항
코드를 작성하기 전에 환경부터 확인하세요. 이 부분을 건너뛰면 나중에 "왜 안 되지?" 하고 시간 낭비하게 됩니다. (저도 처음에 시뮬레이터에서 돌리려다가 30분을 날렸어요.)
- Xcode 26 이상
- macOS 26 (Tahoe) 이상
- 물리적 기기 필수 — 시뮬레이터에서는 Foundation Models가 동작하지 않습니다
- 호환 기기: iPhone 15 Pro 이상, M1 이상의 iPad/Mac, Apple Intelligence 호환 visionOS 기기
- 기기에서 Apple Intelligence가 활성화되어 있어야 합니다 (설정 → Apple Intelligence)
- 충분한 배터리와 저장 공간 (모델 다운로드 필요)
중요: 시뮬레이터에서 테스트할 수 없다는 점은 개발 워크플로우에 꽤 큰 영향을 미칩니다. 좀 불편하긴 하지만, 반드시 USB로 연결된 실제 기기에서 테스트하세요.
LanguageModelSession: 첫 번째 AI 호출
Foundation Models의 모든 상호작용은 LanguageModelSession에서 시작합니다. 세션은 모델과의 "대화 컨텍스트"라고 생각하면 됩니다.
가장 간단한 텍스트 생성
import FoundationModels
// 세션 생성 및 텍스트 생성
let session = LanguageModelSession()
let response = try await session.respond(to: "SwiftUI의 장점을 세 가지로 요약해줘")
print(response.content) // 생성된 텍스트 출력
이게 전부입니다. 진짜로요. import 한 줄, 세션 생성 한 줄, 응답 요청 한 줄. API 키도 없고, 네트워크 설정도 없어요. 처음 이 코드를 실행했을 때 "이게 된다고?" 하면서 놀랐던 기억이 나네요.
Instructions로 모델 행동 정의하기
실전에서는 모델에게 역할과 행동 지침을 미리 알려줘야 합니다. 이게 바로 instructions 파라미터의 역할이에요.
let session = LanguageModelSession(
instructions: """
You are a friendly iOS development assistant.
Always respond in Korean.
Keep responses concise — maximum 3 sentences.
Focus on practical, actionable advice.
"""
)
let response = try await session.respond(
to: "SwiftData에서 마이그레이션하는 방법이 뭐야?"
)
여기서 꼭 기억해야 할 베스트 프랙티스가 있어요.
- Instructions는 영어로 작성하세요. Apple의 온디바이스 모델은 영어 instructions에서 가장 정확한 결과를 냅니다. 사용자 프롬프트는 한국어로 보내도 괜찮아요.
- 역할, 출력 형식, 행동 제한을 명확하게 정의하세요.
- Instructions는 정적으로 유지하세요. 사용자 입력을 instructions에 삽입하면 프롬프트 인젝션 공격에 취약해집니다.
- 예시를 포함하면 일관성이 높아집니다. 기대하는 입출력 형식의 예시를 instructions에 넣어주면 결과가 훨씬 안정적이에요.
단일 턴 vs. 멀티 턴 대화
세션의 사용 방식은 크게 두 가지입니다.
단일 턴: 요약, 분류, 번역 같은 독립적인 작업에는 매번 새 세션을 만드세요.
// 단일 턴 — 매번 새 세션
func summarize(_ text: String) async throws -> String {
let session = LanguageModelSession(
instructions: "Summarize the following text in one sentence in Korean."
)
let response = try await session.respond(to: text)
return response.content
}
멀티 턴: 대화형 어시스턴트처럼 이전 맥락을 유지해야 할 때는 같은 세션을 재사용합니다.
// 멀티 턴 — 세션 재사용
class ChatViewModel: ObservableObject {
private let session = LanguageModelSession(
instructions: "You are a helpful cooking assistant. Respond in Korean."
)
func sendMessage(_ message: String) async throws -> String {
let response = try await session.respond(to: message)
return response.content
}
}
한 가지 주의할 점이 있는데요. 컨텍스트 윈도우가 4,096 토큰(입력 + 출력 합산)으로 제한되어 있습니다. 꽤 빡빡하죠? 멀티 턴 대화가 길어지면 이전 맥락이 잘릴 수 있으니, 대화가 길어질수록 핵심 정보를 instructions에 미리 포함시키는 전략이 필요합니다.
모델 사용 가능 여부 확인하기
모든 기기에서 Foundation Models를 사용할 수 있는 건 아닙니다. 앱에서 AI 기능을 제공하기 전에 반드시 사용 가능 여부를 확인하고, 불가능할 때의 폴백을 준비하세요. 이 단계를 빼먹으면 사용자 경험이 엉망이 됩니다.
import FoundationModels
let model = SystemLanguageModel.default
let availability = model.availability
switch availability {
case .available:
// 모델 사용 가능 — AI 기능 활성화
print("온디바이스 AI 준비 완료")
case .unavailable(.deviceNotEligible):
// 기기가 Apple Intelligence를 지원하지 않음
print("이 기기에서는 AI 기능을 사용할 수 없습니다")
case .unavailable(.appleIntelligenceNotEnabled):
// Apple Intelligence가 비활성화됨
print("설정에서 Apple Intelligence를 활성화해주세요")
case .unavailable(.modelNotReady):
// 모델이 아직 다운로드/준비 중
print("AI 모델을 준비 중입니다. 잠시 후 다시 시도해주세요")
default:
print("AI 기능을 사용할 수 없습니다")
}
이 확인 로직은 앱 실행 초기 또는 AI 기능 화면 진입 시 수행하고, 사용 불가능한 경우 사용자에게 명확한 안내를 제공하면 됩니다.
@Generable과 @Guide: 구조화된 출력의 핵심
자, 여기서부터 Foundation Models의 진짜 힘이 드러납니다. 개인적으로 이 기능이 가장 인상적이었어요.
일반 텍스트 생성도 편리하지만, 실제 앱에서는 구조화된 데이터가 필요하잖아요. JSON을 파싱하고 에러를 처리하는 지저분한 코드 대신, @Generable 매크로를 쓰면 모델이 Swift 타입에 딱 맞는 데이터를 직접 생성합니다.
@Generable 기본 사용법
import FoundationModels
@Generable
struct MovieReview {
@Guide(description: "The sentiment of the review: positive, negative, or neutral")
var sentiment: String
@Guide(description: "A one-sentence summary of the review in Korean")
var summary: String
@Guide(description: "A confidence score between 0.0 and 1.0")
var confidence: Double
}
let session = LanguageModelSession(
instructions: "You are a movie review analyzer. Analyze the sentiment and summarize the review."
)
let review = try await session.respond(
to: "이 영화 정말 대박이었어요! 연기도 스토리도 완벽했고, 특히 마지막 반전이 소름돋았습니다.",
generating: MovieReview.self
)
print(review.sentiment) // "positive"
print(review.summary) // "연기와 스토리, 반전이 뛰어난 훌륭한 영화라는 긍정적 리뷰"
print(review.confidence) // 0.95
내부적으로 @Generable은 Constrained Decoding이라는 기법을 사용합니다. 모델이 자유롭게 텍스트를 생성하는 게 아니라, 토큰 수준에서 Swift 타입의 스키마에 맞는 유효한 출력만 생성하도록 강제하는 거예요. 더 이상 "모델이 올바른 JSON을 반환하길 기도"할 필요가 없습니다. 솔직히 이것만으로도 이 프레임워크를 쓸 가치가 있다고 봐요.
@Guide로 출력 정밀하게 제어하기
@Guide 매크로는 각 프로퍼티에 제약 조건을 설정하여 모델의 출력을 정밀하게 제어합니다.
@Generable
struct RecipeIdea {
@Guide(description: "Name of the recipe in Korean")
var name: String
@Guide(description: "Difficulty level", .anyOf(["쉬움", "보통", "어려움"]))
var difficulty: String
@Guide(description: "List of main ingredients", .count(5))
var ingredients: [String]
@Guide(description: "Estimated cooking time in minutes", .range(5...180))
var cookingTime: Int
@Guide(description: "Step-by-step instructions")
var steps: [String]
}
@Guide가 제공하는 주요 제약 옵션을 정리하면 이렇습니다.
| 제약 옵션 | 설명 | 예시 |
|---|---|---|
description: |
자연어로 필드 설명 제공 | @Guide(description: "사용자 이름") |
.anyOf([...]) |
허용되는 값 목록으로 제한 | .anyOf(["긍정", "부정", "중립"]) |
.count(n) |
배열의 정확한 길이 지정 | .count(3) |
.range(min...max) |
숫자 값의 범위 제한 | .range(1...10) |
프로퍼티 선언 순서가 중요합니다
이건 처음에 몰라서 한참 헤맸는데요. @Generable 타입의 프로퍼티는 소스 코드에 선언된 순서대로 생성됩니다. 즉, 앞에서 생성된 프로퍼티의 값이 뒤에 오는 프로퍼티의 생성에 영향을 미칩니다.
// 좋은 예 — answer가 먼저 생성되고, explanation이 answer를 참고
@Generable
struct QuizResult {
@Guide(description: "The correct answer")
var answer: String
@Guide(description: "Explanation of why this is the correct answer")
var explanation: String
}
// 나쁜 예 — explanation이 먼저 생성되어 answer 없이 설명을 만들게 됨
@Generable
struct QuizResultBad {
@Guide(description: "Explanation of why this is the correct answer")
var explanation: String
@Guide(description: "The correct answer")
var answer: String
}
만약 explanation이 answer에 의존한다면, 반드시 answer를 먼저 선언해야 합니다. 사소해 보이지만 결과 품질에 꽤 큰 차이를 만들어요.
중첩 Generable 타입
복잡한 데이터 구조도 중첩된 @Generable 타입으로 깔끔하게 표현할 수 있습니다.
@Generable
struct DayPlan {
@Guide(description: "Title for this day")
var title: String
@Guide(description: "List of activities for the day")
var activities: [Activity]
}
@Generable
struct Activity {
@Guide(description: "Name of the activity")
var name: String
@Guide(description: "Estimated duration in hours", .range(0.5...8.0))
var duration: Double
@Guide(description: "Brief description")
var description: String
}
@Generable
struct TravelItinerary {
@Guide(description: "An exciting name for the trip")
var tripName: String
@Guide(description: "Daily plans", .count(3))
var days: [DayPlan]
}
스트리밍 응답으로 UX 향상하기
사용자가 빈 화면을 보면서 응답을 기다리는 건 최악의 경험이죠. 아무리 빠른 온디바이스 모델이라도 긴 응답은 시간이 걸립니다. 스트리밍을 사용하면 모델이 생성하는 대로 실시간으로 UI를 업데이트할 수 있어요.
일반 텍스트 스트리밍
let session = LanguageModelSession()
// streamResponse로 스트리밍 요청
for try await partialResponse in session.streamResponse(to: "서울 여행 가이드를 작성해줘") {
// 부분 응답이 도착할 때마다 UI 업데이트
print(partialResponse.content)
}
구조화된 출력 스트리밍
여기서 한 번 더 놀라게 되는데요. @Generable 타입도 스트리밍이 됩니다. @Generable 매크로는 자동으로 PartiallyGenerated라는 타입을 생성하는데, 원래 구조체의 모든 프로퍼티를 옵셔널로 만든 미러 타입이에요.
import SwiftUI
import FoundationModels
struct ItineraryView: View {
@State private var partialItinerary: TravelItinerary.PartiallyGenerated?
@State private var isGenerating = false
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
if let tripName = partialItinerary?.tripName {
Text(tripName)
.font(.largeTitle)
.bold()
}
if let days = partialItinerary?.days {
ForEach(Array(days.enumerated()), id: \.offset) { index, day in
if let title = day.title {
Text("Day \(index + 1): \(title)")
.font(.title2)
}
if let activities = day.activities {
ForEach(Array(activities.enumerated()), id: \.offset) { _, activity in
if let name = activity.name {
Text("• \(name)")
}
}
}
}
}
}
.padding()
}
.task {
await generateItinerary()
}
}
func generateItinerary() async {
isGenerating = true
let session = LanguageModelSession(
instructions: "You are a travel planner. Create detailed itineraries in Korean."
)
do {
let stream = session.streamResponse(
to: "부산 3일 여행 일정을 만들어줘",
generating: TravelItinerary.self
)
for try await partial in stream {
partialItinerary = partial
}
} catch {
print("생성 실패: \(error)")
}
isGenerating = false
}
}
이렇게 하면 여행 일정의 각 항목이 생성되는 순간 바로 화면에 나타납니다. 사용자는 기다림 없이 콘텐츠를 읽기 시작할 수 있어요. SwiftUI의 선언적 특성과 정말 찰떡궁합이죠.
Tool Calling: 모델의 능력 확장하기
온디바이스 3B 모델은 세상의 모든 걸 알진 못합니다. 실시간 날씨 정보나 앱 내 데이터베이스 같은 외부 데이터에 접근할 수 없죠. 하지만 Tool Calling을 사용하면, 모델이 필요할 때 여러분이 정의한 Swift 함수를 자동으로 호출하여 정보를 가져올 수 있습니다.
이건 단순한 텍스트 생성을 넘어서 에이전틱(agentic) 기능을 구축하는 핵심이에요. 솔직히 이 부분이 가장 흥미로웠습니다.
Tool 구현하기
import FoundationModels
// Tool 프로토콜을 채택하여 도구 정의
struct WeatherTool: Tool {
let name = "getCurrentWeather"
let description = "Gets the current weather for a specified city"
// 입력 인수 정의 — @Generable 사용
@Generable
struct Arguments {
@Guide(description: "The name of the city to get weather for")
var city: String
}
// 도구 실행 로직
func call(arguments: Arguments) async throws -> ToolOutput {
// 실제 앱에서는 WeatherKit 등을 사용
let weatherData = await fetchWeather(for: arguments.city)
return ToolOutput("\(arguments.city): \(weatherData.temperature)°C, \(weatherData.condition)")
}
private func fetchWeather(for city: String) async -> (temperature: Int, condition: String) {
// WeatherKit API 호출 로직
return (temperature: 22, condition: "맑음")
}
}
Tool을 세션에 등록하기
let session = LanguageModelSession(
instructions: """
You are a helpful travel assistant.
Use the weather tool to provide accurate weather information.
Always respond in Korean.
""",
tools: [WeatherTool()]
)
let response = try await session.respond(
to: "내일 서울 날씨 어때? 우산 챙겨야 할까?"
)
print(response.content)
// 모델이 자동으로 WeatherTool을 호출하고, 결과를 바탕으로 답변 생성
모델은 사용자의 질문을 분석해서 어떤 Tool이 필요한지 자동으로 판단하고, 인수를 생성하고, Tool을 실행한 뒤 그 결과를 자연어 답변에 통합합니다. 개발자가 "언제 Tool을 호출할지"를 직접 코딩할 필요가 없어요. 거의 마법 같달까요.
여러 Tool 함께 사용하기
struct RestaurantSearchTool: Tool {
let name = "searchRestaurants"
let description = "Search for restaurants near a location"
@Generable
struct Arguments {
@Guide(description: "Location to search near")
var location: String
@Guide(description: "Type of cuisine")
var cuisine: String
}
func call(arguments: Arguments) async throws -> ToolOutput {
// MapKit 또는 자체 API 호출
return ToolOutput("검색 결과: \(arguments.location) 근처 \(arguments.cuisine) 맛집 3곳 발견")
}
}
// 여러 Tool 등록
let session = LanguageModelSession(
instructions: "You are a local guide assistant. Use available tools to help users. Respond in Korean.",
tools: [WeatherTool(), RestaurantSearchTool()]
)
let response = try await session.respond(
to: "강남에서 이탈리안 레스토랑 추천해주고, 오늘 날씨도 알려줘"
)
// 모델이 두 Tool을 모두 호출하여 종합적인 답변 생성
프레임워크가 복잡한 병렬 및 직렬 Tool 호출 그래프를 알아서 처리해주기 때문에, 개발자는 각 Tool의 로직에만 집중하면 됩니다.
성능 최적화 전략
온디바이스 모델이라고 해서 성능을 신경 쓰지 않아도 되는 건 아닙니다. 오히려 기기 자원을 직접 사용하기 때문에 더 신경 써야 할 수도 있어요. 몇 가지 최적화 전략을 알아두면 사용자 경험이 크게 달라집니다.
Prewarming으로 초기 지연 줄이기
class AIFeatureViewModel: ObservableObject {
private var session: LanguageModelSession?
func prepareModel() async {
// 사용자가 AI 기능을 사용할 것으로 예상되는 시점에 미리 호출
let newSession = LanguageModelSession(
instructions: "You are a helpful assistant."
)
try? await newSession.prewarm()
session = newSession
}
}
prewarm()은 모델에 필요한 리소스를 메모리에 미리 로드합니다. AI 기능 화면에 진입하기 직전이나, 앱이 Foundation Models에 크게 의존하는 경우 앱 실행 시 호출하면 첫 응답 속도가 눈에 띄게 빨라져요.
@Generable 모델은 꼭 필요한 필드만
이건 실전에서 정말 중요한 팁입니다. 모델은 @Generable 타입의 모든 프로퍼티를 채웁니다 — UI에서 사용되든 안 되든요. 예를 들어 상세한 steps 배열을 선언해놨는데 미리보기 화면에서는 제목만 보여준다면, 모델이 불필요한 단계들을 생성하느라 시간과 자원을 낭비하게 됩니다.
화면과 컨텍스트에 맞게 @Generable 모델을 분리하세요.
// 목록 화면용 — 가볍게
@Generable
struct RecipePreview {
var name: String
var difficulty: String
var cookingTime: Int
}
// 상세 화면용 — 상세하게
@Generable
struct RecipeDetail {
var name: String
var difficulty: String
var cookingTime: Int
var ingredients: [String]
var steps: [String]
var tips: String
}
배터리와 자원 고려하기
빈번하거나 대량의 생성 요청은 CPU/GPU 사용량을 높입니다. 다음 전략을 고려해보세요.
- 결과 캐싱: 동일한 입력에 대한 결과를 캐시하여 반복 생성을 피하세요
- 배치 처리: 가능하다면 여러 요청을 묶어서 처리하세요
- 사용자 트리거: 자동 생성보다는 사용자가 명시적으로 요청할 때 생성하는 게 낫습니다
실전 예제: AI 일기 앱
자, 이제 지금까지 배운 개념을 종합해서 실전 예제를 하나 만들어 봅시다. 일기를 분석하고 감정을 추출하는 AI 일기 앱이에요.
import SwiftUI
import FoundationModels
// 감정 분석 결과 모델
@Generable
struct DiaryAnalysis {
@Guide(description: "Primary emotion", .anyOf(["기쁨", "슬픔", "분노", "불안", "평온", "감사", "설렘"]))
var primaryEmotion: String
@Guide(description: "Emotion intensity from 1 to 10", .range(1...10))
var intensity: Int
@Guide(description: "A warm, empathetic one-sentence reflection in Korean")
var reflection: String
@Guide(description: "A practical self-care suggestion in Korean")
var suggestion: String
}
struct DiaryAnalysisView: View {
@State private var diaryText = ""
@State private var analysis: DiaryAnalysis?
@State private var isAnalyzing = false
@State private var isAvailable = false
var body: some View {
NavigationStack {
Form {
Section("오늘의 일기") {
TextEditor(text: $diaryText)
.frame(minHeight: 150)
}
if isAvailable {
Section {
Button("감정 분석하기") {
Task { await analyzeDiary() }
}
.disabled(diaryText.isEmpty || isAnalyzing)
}
}
if let analysis {
Section("분석 결과") {
LabeledContent("주요 감정", value: analysis.primaryEmotion)
LabeledContent("강도", value: "\(analysis.intensity)/10")
Text(analysis.reflection)
.foregroundStyle(.secondary)
Text("💡 \(analysis.suggestion)")
.padding()
.background(.blue.opacity(0.1))
.clipShape(RoundedRectangle(cornerRadius: 8))
}
}
}
.navigationTitle("AI 일기장")
.task {
isAvailable = SystemLanguageModel.default.availability == .available
}
}
}
func analyzeDiary() async {
isAnalyzing = true
defer { isAnalyzing = false }
let session = LanguageModelSession(
instructions: """
You are an empathetic diary companion.
Analyze the emotional content of diary entries.
Be warm and supportive in reflections.
Provide practical, actionable self-care suggestions.
"""
)
do {
analysis = try await session.respond(
to: diaryText,
generating: DiaryAnalysis.self
)
} catch {
print("분석 실패: \(error)")
}
}
}
이 예제에서는 @Generable과 @Guide를 활용해서 감정 유형은 지정된 목록에서만, 강도는 1~10 범위에서만 생성되도록 제어하고 있어요. 사용자가 일기를 쓰면 온디바이스에서 즉시 분석이 이루어지고, 개인적인 일기 내용이 외부 서버로 전송되지 않습니다. 프라이버시가 특히 중요한 일기 앱 같은 경우에 Foundation Models가 딱 맞는 셈이죠.
알아두어야 할 제한사항
Foundation Models 프레임워크는 강력하지만 만능은 아닙니다. 실전에서 삽질하지 않으려면 이 제한사항들을 꼭 알아두세요.
- 텍스트 전용 입력: 현재는 텍스트만 입력할 수 있습니다. 이미지, 오디오, 비디오, PDF 같은 멀티모달 입력은 아직 지원되지 않아요.
- 범용 지식 챗봇이 아닙니다: 요약, 분류, 추출 같은 작업에 최적화되어 있어요. 세계 상식이나 위키피디아 같은 지식을 묻는 용도로는 적합하지 않습니다.
- 코드 생성과 수학 계산은 피하세요: Apple 공식 문서에서도 이 용도로는 권장하지 않습니다. 3B 모델의 한계라고 보면 돼요.
- 4,096 토큰 컨텍스트 제한: 입력과 출력을 합쳐서 4K 토큰입니다. 긴 문서를 통째로 넣으면 잘릴 수 있으니 주의하세요.
- 가드레일 오탐지: Apple의 안전 가드레일이 때때로 무해한 콘텐츠를 민감한 콘텐츠로 잘못 판단할 수 있습니다. 프롬프트를 꼼꼼하게 테스트하세요.
- 모델 버전 고정 불가: Apple이 OS 업데이트와 함께 모델을 업데이트하는데, 특정 버전을 고정할 수 없어요. 업데이트 후 동작이 달라질 수 있다는 점을 염두에 두세요.
- 시뮬레이터 미지원: 반드시 물리적 기기에서 테스트해야 합니다. 번거롭지만 어쩔 수 없는 부분이에요.
자주 묻는 질문 (FAQ)
Foundation Models 프레임워크는 무료인가요?
네, 완전 무료입니다. API 키도 필요 없고, 사용량 과금도 없어요. Apple 개발자 프로그램 회원이면 누구나 사용할 수 있습니다. 모든 추론이 기기 내에서 처리되니까 서버 비용도 당연히 발생하지 않죠.
어떤 기기에서 사용할 수 있나요?
iPhone 15 Pro 이상, M1 칩 이상의 iPad와 Mac, 그리고 Apple Intelligence를 지원하는 visionOS 기기에서 사용할 수 있습니다. 기기에서 Apple Intelligence가 활성화되어 있어야 하고, iOS 26 이상이 설치되어 있어야 해요. 그리고 앞서 말했듯이 시뮬레이터에서는 안 되니까 실제 기기를 꼭 준비하세요.
한국어를 지원하나요?
네, 지원합니다. Apple Intelligence는 2025년 4월부터 한국어를 공식 지원하고 있어요. Foundation Models 프레임워크로 한국어 텍스트를 생성하고 분석하는 데 문제 없습니다. 다만, Instructions(시스템 프롬프트)는 영어로 작성하는 게 가장 정확한 결과를 얻는 데 도움이 됩니다.
CloudKit이나 서버 사이드 Swift와 함께 사용할 수 있나요?
Foundation Models 프레임워크는 순수하게 온디바이스 기술이라서 서버 사이드에서는 사용할 수 없습니다. 서버에서 AI 기능이 필요하다면 클라우드 기반 LLM API를 별도로 사용해야 해요. 다만, 앱 내에서 Foundation Models로 처리한 결과를 CloudKit 등을 통해 동기화하는 건 당연히 가능합니다.
기존 Core ML 모델과 어떻게 다른가요?
Core ML은 사전 훈련된 머신러닝 모델(이미지 분류, 객체 탐지 등)을 기기에서 실행하는 프레임워크이고, Foundation Models는 범용 언어 모델(LLM)에 대한 접근을 제공합니다. Core ML은 특정 작업에 맞춰 훈련된 모델을 실행하고, Foundation Models는 자연어 프롬프트로 다양한 텍스트 작업을 처리해요. 둘은 상호 보완적인 관계라서 같은 앱에서 함께 사용하는 것도 전혀 문제없습니다.