Apple Foundation Models: 온디바이스 LLM 프레임워크 완벽 해설
Foundation Models 프레임워크는 앱이 Apple Intelligence를 구동하는 바로 그 온디바이스 대규모 언어 모델에 직접, 무료로, 오프라인으로 접근할 수 있게 해줍니다1. API 키도, 토큰당 과금도, 네트워크 왕복도, 기기 밖으로 빠져나가는 데이터도 없습니다. 예전 같으면 클라우드 LLM 호출과 프라이버시 검토를 의미했던 한 부류의 기능들이, 이제는 비용이 사실상 0에 수렴합니다. 그 대가는 역량입니다. 온디바이스 모델은 작고, 컨텍스트 윈도우는 유한하며, 프레임워크는 자신이 무엇을 하고 무엇을 하지 않을지에 대해 명확한 선을 긋습니다. 그 선을 아는 것이 전부입니다.
이 글은 프레임워크 그 자체에 대한 레퍼런스입니다. 실제로 호출하게 되는 타입들, 이 프레임워크를 쓸 가치가 있게 만드는 단 하나의 기능, 그리고 멈춰 서서 더 큰 무언가로 손을 뻗어야 하는 지점을 다룹니다.
핵심 요약
LanguageModelSession이 진입점입니다. 하나 생성하고,respond(to:)를 호출하면, 텍스트가 돌아옵니다. 여러 턴에 걸친 컨텍스트는 세션 안에 남아 있고, 단일 턴 작업은 매번 새 세션을 받습니다2.- 가이드 생성이야말로 이 프레임워크를 쓰는 이유입니다. Swift 타입에
@Generable을 붙이면, 파싱해야 하는 문자열 대신 채워지고 타입 검증까지 끝난 그 타입을 모델이 반환합니다3. Tool프로토콜을 사용하면 모델이 생성 도중에 여러분의 코드를 호출해 데이터를 가져오거나 어떤 동작을 수행한 뒤, 그 결과를 자신의 답변에 다시 녹여 넣을 수 있습니다4.- 무엇이든 하기 전에
SystemLanguageModel.default.availability를 확인하세요. 자격이 없는 기기에서는, Apple Intelligence가 꺼져 있을 때는, 또는 모델을 내려받는 중에는 모델이 존재하지 않습니다5. - 컨텍스트 윈도우는 실재하며, 작습니다.
SystemLanguageModel.default.contextSize는 프롬프트와 응답이 함께 나눠 쓰는 토큰 예산을 알려줍니다6. 이를 염두에 두고 설계하지 않으면 세션이 오류를 던집니다. - iOS 26과 Apple Intelligence를 지원하는 기기가 필요합니다. 그 기준선 아래에서는 이 프레임워크 자체가 존재하지 않습니다.
이 프레임워크는 무엇이고, 무엇이 아닌가
Foundation Models는 클라우드 엔드포인트를 감싼 래퍼가 아닙니다. 모델은 기기 안에 살고, 운영체제와 함께 배포되며, Neural Engine 위에서 실행됩니다. 이 한 가지 사실이 API의 모든 설계 결정과, 여러분이 이를 사용하며 내리는 모든 결정을 좌우합니다.
여러분이 얻는 것은 텍스트 생성, 요약, 분류, 추출, 짧은 형식의 재작성, 그리고 구조화된 출력입니다. 전부 온디바이스이고 전부 무료입니다. 여러분이 얻지 못하는 것은 프런티어 모델입니다. Apple은 이 온디바이스 모델을 앱 내부의 집중된 언어 작업을 위해 만들었지, 열린 형태의 추론이나 긴 문서 분석, 또는 퀴즈처럼 캐물을 수 있는 세계 지식을 위해 만든 것이 아닙니다. Apple도 그렇게 말하고 있으며, 이 규정이 중요한 이유는 그것이 기대치를 설정하기 때문입니다. 그렇지 않으면 API는 여러분이 그 기대치를 어기도록 내버려 둘 것입니다1.
곤경을 피하게 해주는 사고 모델은 이렇습니다. 온디바이스 모델을, 텍스트를 다듬는 데는 탁월하지만 사실을 아는 데는 형편없는, 빠르고 사적이며 무료인 인턴이라고 여기세요. 재료와 명확한 작업을 손에 쥐여 주세요. 답할 길이 없는 질문은 던지지 마세요.
LanguageModelSession: 진입점
모든 상호작용은 세션에서 시작합니다.
import FoundationModels
let session = LanguageModelSession()
let response = try await session.respond(to: "Summarize this review in one sentence: \(reviewText)")
print(response.content)
세션은 대화 상태를 보관합니다. respond(to:)를 호출할 때마다 진행 중인 트랜스크립트에 내용이 추가되므로, 계속 유지하는 세션은 앞서 오간 내용을 기억합니다. 채팅 기능이라면 바로 그것이 원하는 동작입니다. 서로 독립적인 일회성 작업(이것을 요약해, 저것을 분류해)이라면, 호출마다 새 세션을 만들어 오래된 컨텍스트가 새어 들어와 토큰 예산을 잡아먹지 않게 하세요2.
respond(to:)는 async throws입니다. 모델이 작업하는 동안 일시 중단되고, 요청이 컨텍스트 윈도우를 초과할 때, 모델을 사용할 수 없을 때, 또는 가드레일이 콘텐츠를 거부할 때 오류를 던집니다. 이들 하나하나는 무시해도 되는 예외 상황이 아니라, 여러분이 직접 처리해야 하는 실제 분기입니다.
반응성 좋은 UI를 위해서는 기다리는 대신 스트리밍하세요. streamResponse(to:)는 모델이 출력을 만들어 내는 대로 부분 출력을 내보내며, 3초간의 멈칫거림을 글자가 형성되는 대로 나타나는 텍스트로 바꿔 줍니다7.
가이드 생성: 프레임워크의 값어치를 하는 기능
여기가 입장료가 아깝지 않은 부분입니다. 대부분의 LLM 통합 작업은 코드의 3분의 1을 모델에서 유효한 JSON을 끌어내도록 구슬리는 데 쓰고, 나머지 3분의 2를 그럼에도 실패하는 경우를 막아 내는 데 씁니다. Foundation Models는 그 작업을 통째로 없애 버립니다.
Swift 타입에 @Generable을 붙이고 세션에 그것을 생성하라고 요청하면, 모델은 채워지고 타입 안전성까지 갖춘 그 타입의 인스턴스를 반환합니다3:
@Generable
struct Recipe {
@Guide(description: "The dish name")
let title: String
@Guide(description: "Ingredients, each as 'quantity item'")
let ingredients: [String]
@Guide(description: "Total minutes, start to finish", .range(5...240))
let minutes: Int
}
let session = LanguageModelSession()
let response = try await session.respond(
to: "A weeknight pasta for two.",
generating: Recipe.self
)
let recipe = response.content // a Recipe, not a String
파싱도 없고, JSONDecoder도 없으며, 잘못된 출력에 대비한 재시도 루프도 없습니다. @Guide 매크로는 개별 필드를 제약합니다. 모델이 지시로 읽는 설명, 그리고 숫자 범위나 출력이 반드시 일치해야 하는 정규 표현식 같은 선택적 제한이 그것입니다8. 프레임워크는 5에서 240 사이의 숫자를 달라고 모델에게 정중히 부탁하는 게 아니라, 그 필드가 달리 돌아올 수 없도록 디코딩 자체를 제약합니다.
이것이 강제하는 규율이 진짜 가치입니다. 여러분은 출력 타입을 먼저, Swift로, 컴파일러의 검증을 받으며 설계합니다. 모델은 여러분이 역설계해야 할 산문을 반환하는 대신, 여러분이 정의한 계약을 채웁니다. 추출, 양식 채우기, 그리고 언어를 데이터로 바꾸는 모든 기능에서 가이드 생성은 데모와 출시 가능한 코드를 가르는 차이입니다.
알아 둘 만한 제어 하나. respond(to:generating:)는 includeSchemaInPrompt를 true로 기본 설정하는데, 이는 여러분 타입의 형태를 프롬프트에 주입해 모델이 그쪽으로 기울도록 만듭니다. 모델이 그 형식을 학습 과정에서 또는 세션의 앞선 턴에서 이미 알고 있는 경우가 아니라면 켠 채로 두세요. 모델이 본 적 없는 형식에 대해 토큰을 아끼겠다고 이 옵션을 끄는 것은, 쓰레기 같은 출력을 돌려받는 지름길입니다9.
도구 호출: 모델이 여러분의 코드에 닿게 하기
가이드 생성은 무엇이 나오는지를 빚어냅니다. 도구 호출은 무엇이 들어가는지를 바꿉니다. 도구란 모델이 생성 도중에 호출할 수 있는 여러분 코드의 한 조각으로, 모델은 가지고 있지 않은 정보를 가져오거나 어떤 동작을 수행한 뒤, 그 결과를 사용해 답변을 이어 갑니다4.
도구는 Tool 프로토콜을 따릅니다. name, 모델이 언제 호출할지 판단하려고 읽는 description, @Generable로 선언된 Arguments 타입, 그리고 실제 작업을 수행하는 call(arguments:) 메서드로 이루어집니다4:
struct FindContacts: Tool {
let name = "findContacts"
let description = "Find a specific number of contacts from the address book"
@Generable
struct Arguments {
@Guide(description: "How many contacts to return", .range(1...10))
let count: Int
}
func call(arguments: Arguments) async throws -> [String] {
// Fetch contacts, return formatted names.
}
}
let session = LanguageModelSession(tools: [FindContacts()])
let response = try await session.respond(to: "Draft a dinner invite to three of my contacts.")
흐름은 이렇습니다. 모델이 연락처가 필요하다고 판단하고, 검증된 count로 여러분의 도구를 호출하면, 여러분이 데이터를 반환하고, 모델은 실제 이름을 써서 초대장을 작성합니다. 인수는 가이드 생성과 동일한 메커니즘을 거쳐 타입 검증된 채로 도착하므로, 여러분이 자유 텍스트에서 모델의 의도를 파싱해 낼 일이 결코 없습니다. 도구 설명은 모델이 언제 그 도구로 손을 뻗을지에 대해 여러분이 쥔 유일한 지렛대이므로, 아무런 사전 맥락이 없는 다른 엔지니어가 읽고 올바르게 써야 하는 함수 문서처럼 작성하세요.
이 지점이 또한 Foundation Models가 에이전트 이야기의 나머지 부분과 만나는 이음매입니다. 온디바이스 모델이 호출하는 도구와 Apple Intelligence가 호출하는 App Intent는 형태는 같고 표면만 다릅니다. 이름이 붙고, 설명이 달리고, 타입이 정해진 역량이라는 점에서요. 그 역량을 한 번만 설계하면 양쪽 모두를 통해 노출할 수 있습니다.
가용성: 건너뛸 수 없는 확인
모델이 항상 거기 있는 것은 아닙니다. Apple Intelligence를 지원하지 않는 기기에서는, 사용자가 그것을 꺼 두었을 때는, 그리고 운영체제가 아직 모델 자산을 내려받는 중인 구간에서는 모델이 존재하지 않습니다. 모델이 존재한다고 가정하는 코드를 출시하면, 그것은 여러분이 한 번도 테스트해 보지 못한 일부 사용자 집단에게 크래시를 내거나, 조용히 품질이 떨어지거나, 멈춰 버립니다.
SystemLanguageModel.default.availability를 확인하고 그 사유에 따라 분기하세요5:
switch SystemLanguageModel.default.availability {
case .available:
// Show the intelligence feature.
case .unavailable(.deviceNotEligible):
// Hide it. This device will never have the model.
case .unavailable(.appleIntelligenceNotEnabled):
// Prompt the user to turn on Apple Intelligence.
case .unavailable(.modelNotReady):
// Downloading or otherwise not ready yet. Try again later.
case .unavailable(let other):
// Unknown reason. Fail closed.
}
세 가지 사유는 서로 다른 세 가지 제품 차원의 대응을 요구하며, 이들을 뭉뚱그리는 것이야말로 이런 기능이 고장 난 것처럼 느껴지게 만드는 가장 흔한 원인입니다. deviceNotEligible은 영구적입니다. 기능을 숨기고, 들들 볶지 마세요. appleIntelligenceNotEnabled는 사용자가 제어하는 설정입니다. 한 번 띄우는 안내라면 정당합니다. modelNotReady는 일시적입니다. 다시 시도하되, 오류를 보여 주지는 마세요. 사용 불가 경로를 정상 경로와 똑같은 정성으로 구현하세요. 상당수 기기에게는 그것이 유일한 경로이기 때문입니다.
모델을 사용할 수 있고 요청이 들어올 것을 안다면, 세션에 prewarm()을 호출해 모델을 미리 데워 두면 첫 실제 응답이 더 빨리 도착합니다10. 사용자가 곧 행동을 취할 화면에서는 그만한 값어치가 있지만, 넘겨짚어 호출한다면 낭비입니다.
컨텍스트 윈도우, 그리고 그것이 더는 충분하지 않은 지점
SystemLanguageModel.default.contextSize는 모델이 그 안에서 작업하는 토큰 예산을 알려 주며, 이 예산은 공유됩니다. 프롬프트와 응답이 합쳐서 그 안에 들어가야 합니다6. 그 수치는 클라우드 모델에 비하면 작고, 실제 입력에서 금세 그 한계를 체감하게 됩니다. 긴 문서, 통째로 쌓인 채팅 기록, 비대한 도구 결과 — 이들 중 무엇이든 예산을 터뜨려 respond가 오류를 던지게 만들 수 있습니다.
여기서 두 가지 실패 양상이 따라오고, 둘 다 여러분이 막아야 할 몫입니다. 첫째는 서서히 차오르는 잠식입니다. 여러 턴이 이어지는 세션은 트랜스크립트를 쌓아 가다가 한 턴이 더해지는 순간 넘쳐 버립니다. 서로 무관한 작업에는 새 세션으로 시작하고 턴마다의 입력을 가볍게 유지함으로써 관리하세요. 둘째는 한 번에 지나치게 큰 단일 요청입니다. 20페이지짜리 PDF는 들어가지 않습니다, 끝. 그것을 잘게 나누고, 조각들을 요약한 뒤, 그 요약들 위에서 추론하거나(LLM 엔지니어라면 잘 아는 맵리듀스), 아니면 그 작업이 온디바이스 모델에는 맞지 않는 형태라는 것을 받아들이세요.
컨텍스트 윈도우는 이 프레임워크에서 정작 중요한 결정, 즉 언제 온디바이스에 머물고 언제 그것을 벗어날지를 가르는 가장 깔끔한 신호입니다.
Foundation Models를 쓰지 말아야 할 때
이 프레임워크는 무료이고, 사적이며, 오프라인이라서 어디에나 손을 뻗고 싶어집니다. 참으세요. 다음과 같은 경우에는 그 너머로 손을 뻗으세요.
- 진짜 추론이나 폭넓은 세계 지식이 필요할 때. 온디바이스 모델은 설계상 작습니다. 열린 형태의 추론, 코드 생성, 깊이 있는 분석은 프런티어 클라우드 모델의 몫입니다. 그것들을 온디바이스 모델에게 요구하면 자신감 넘치는 틀린 답이 나옵니다.
- 입력이 컨텍스트 윈도우에 들어가지 않고, 잘게 나누면 의미가 망가지는 경우. 어떤 작업은 모든 것을 한꺼번에 봐야만 합니다.
- 여러분이 통제하는 모델이 필요할 때: 특정 체크포인트, 파인튜닝, 커스텀 가중치, OS 업데이트를 가로지르는 결정론적 버전 관리. Apple은 자신의 일정에 따라 모델을 배포하고 업데이트하지, 여러분의 일정을 따르지 않습니다.
- iOS 26 미만이거나 자격 없는 기기일 때. 프레임워크는 그냥 거기 없으며, 가용성 확인이 실행할 때마다 그 사실을 알려 줄 것입니다.
이 프레임워크가 다루지 않는 온디바이스 사례(커스텀 모델, 여러분만의 가중치, 기기 위에서의 학습)라면, 그 아래 계층은 Core ML과 Apple의 MLX입니다. 정말로 규모가 필요한 사례라면, 프라이버시 경계 뒤에 둔 클라우드 LLM이 여전히 정직한 답입니다. Foundation Models는 그 어느 쪽의 대체재도 아닙니다. 이미 손에 쥔 텍스트를 대상으로 한 집중된 언어 작업에 가장 먼저 손을 뻗기 좋은 도구이고, 그 밖의 모든 것에는 잘못된 선택입니다.
이 프레임워크가 보상하는 기술은 프롬프트 솜씨가 아닙니다. 그것은 범위에 대한 감각입니다. 모델이 잘하는 작업을 먹여 주고, 정확히 필요한 것만 담아내는 @Generable 타입을 설계하며, 작업이 기기의 역량을 넘어서는 순간을 알아차리는 것이죠. 그런 직관을 갖고 만들면 온디바이스 모델은 놀랄 만큼 많은 실제 작업을 공짜로 해냅니다. 그것을 무시하면, 입력이 토큰 하나만큼 길어진 모든 사용자에게 망가지는 기능을 출시하게 됩니다.
자주 묻는 질문
Apple의 Foundation Models 프레임워크는 무료로 쓸 수 있나요?
네. 이 프레임워크는 앱이 Apple Intelligence를 구동하는 바로 그 온디바이스 모델에 직접, 무료로, 오프라인으로 접근할 수 있게 해줍니다. API 키도, 토큰당 과금도, 네트워크 왕복도 없습니다1.
Foundation Models는 어떤 기기와 iOS 버전을 요구하나요?
iOS 26과 Apple Intelligence를 지원하는 기기가 필요합니다. 그 기준선 아래에서는 프레임워크가 존재하지 않으며, 지원되는 OS에서조차 자격 없는 기기에서는, Apple Intelligence가 꺼져 있을 때는, 또는 모델을 내려받는 중에는 모델이 존재하지 않습니다. 사용하기 전에 항상 SystemLanguageModel.default.availability를 확인하세요5.
문자열 대신 구조화되고 타입 안전한 출력을 받으려면 어떻게 하나요?
Swift 타입에 @Generable을 붙이면, 파싱해야 하는 문자열 대신 채워지고 타입 검증까지 끝난 그 타입을 모델이 반환합니다. 이 가이드 생성이야말로 이 프레임워크를 쓸 가치가 있게 만드는 단 하나의 기능입니다3.
Apple 온디바이스 모델의 컨텍스트 윈도우는 얼마나 되나요?
SystemLanguageModel.default.contextSize가 토큰 예산을 알려 주며, 이 예산은 프롬프트와 생성된 응답이 함께 나눠 씁니다6. 설계상 작기 때문에 긴 문서와 여러 턴에 걸친 긴 기록은 이를 초과하게 됩니다. 그 한계를 염두에 두고 설계하지 않으면 세션이 오류를 던집니다.
Foundation Models는 오프라인에서 동작하나요? 그리고 데이터를 Apple로 보내나요?
전적으로 기기 안에서 Neural Engine 위에서 실행됩니다. 어떤 데이터도 기기 밖으로 나가지 않고 네트워크 왕복도 필요하지 않으며, 바로 이 점이 예전 같으면 클라우드 LLM과 프라이버시 검토가 필요했던 기능에 적합하게 만들어 줍니다1.
온디바이스 모델이 생성 도중에 제 코드를 호출할 수 있나요?
네. Tool 프로토콜을 사용하면 모델이 생성 중에 여러분의 코드를 호출해 데이터를 가져오거나 어떤 동작을 수행한 뒤, 그 결과를 자신의 답변에 다시 녹여 넣을 수 있습니다4.
Foundation Models를 쓰지 말아야 할 때는 언제인가요?
프런티어 모델이 필요할 때, 즉 열린 형태의 추론, 코드 생성, 긴 문서 분석, 또는 세계 지식이 필요할 때는 그 너머로 손을 뻗으세요. Apple은 이 온디바이스 모델을 앱 내부의 집중된 언어 작업을 위해 만들었으므로, 일반 지능을 요구하면 자신감 넘치는 틀린 답이 나옵니다1.
-
Apple Developer, “Foundation Models” framework overview. Apple describes the framework as access to the on-device model that powers Apple Intelligence, suited to focused language tasks such as text generation, summarization, classification, and structured output rather than open-ended reasoning or world knowledge. ↩↩↩↩↩
-
Apple Developer, “LanguageModelSession” and “Generating content and performing tasks with Foundation Models”. A session holds multi-turn context; Apple’s guidance is to create a new session for each distinct single-turn interaction. ↩↩
-
Apple Developer, “Generable” and “Prompting an on-device foundation model”. The
@Generablemacro lets the framework return a populated, type-checked Swift value rather than a string. ↩↩↩ -
Apple Developer, “Tool” protocol. Defines
protocol Tool<Arguments, Output>: Sendablewith requiredname,description, andparameters: GenerationSchema, pluscall(arguments:) async throws -> Output. TheArgumentstype conforms toConvertibleFromGeneratedContentand is typically declared@Generable. ↩↩↩↩ -
Apple Developer, “SystemLanguageModel.Availability” and its
UnavailableReason. Cases:.availableand.unavailable(...)with reasonsdeviceNotEligible,appleIntelligenceNotEnabled, andmodelNotReady.SystemLanguageModel.default.isAvailableis the convenience boolean. ↩↩↩ -
Apple Developer, “SystemLanguageModel.contextSize”. An instance property (reached through
SystemLanguageModel.default) documented as the maximum context size, representing the total tokens across input prompt and generated response. ↩↩↩ -
Apple Developer, “LanguageModelSession.streamResponse(to:)”. Streams partial generated output as the model produces it, for incremental UI updates. ↩
-
Apple Developer, “Guide(description:_:)”. A peer macro that attaches a natural-language description and optional constraints (numeric ranges, regular-expression guides) to a
@Generableproperty. Requires iOS 26.0+. ↩ -
Apple Developer, “respond(to:schema:includeSchemaInPrompt:options:)”.
includeSchemaInPromptdefaults totrue; Apple’s discussion recommends keeping the default unless the model already knows the expected format. ↩ -
Apple Developer, “LanguageModelSession.prewarm()”. Asks the framework to load model resources ahead of a known upcoming request to reduce first-response latency. ↩
-
Author’s related analysis: On-Device LLMs with Apple’s Foundation Models, Custom Adapters for Foundation Models, Foundation Models Use Cases, and Agentic Workflows on Foundation Models. The App Intents and tool-surface argument is developed in App Intents Are Apple’s New API to Your App. ↩