Foundation Models 커스텀 어댑터: 언제 학습시켜야 하는가
Apple의 어댑터 문서는 그 경로를 좁게 정의합니다. 대부분의 프롬프트 엔지니어링, 가이드 생성, 도구에는 기본 시스템 모델을 사용하고, 작업이 모델 가중치 특화를 필요로 하며 팀이 Python 모델 학습에 익숙한 경우에만 커스텀 Adapter를 학습시키라는 것입니다.14
같은 타입에 대한 Apple 자체 문서는 다음과 같이 그대로 인용합니다. “어댑터는 많은 저장 공간을 소비하며 대부분의 앱에는 권장되지 않습니다.”1 이 클러스터의 이전 포스트인 Foundation Models Use Cases는 대부분의 앱이 따라야 할 레일을 다뤘습니다. 이 포스트는 세 번째 레일입니다. 즉, 커스텀 어댑터를 학습시키고, 패키징하고, 출시하는 운영 라이프사이클과, 언제 사용하지 말아야 하는지에 대한 Apple의 명시적 지침을 다룹니다.
TL;DR
- Apple의 툴킷은 학습 방법을 LoRA로 식별합니다. 기본 가중치는 동결된 채로 두고 어댑터 가중치만 학습시킵니다.2
- 각 어댑터는 단일 시스템 모델 버전에 바인딩됩니다. Apple이 기본 모델을 업데이트하면 어댑터를 다시 학습시켜야 합니다.3
- Apple의 권장 사항은, 그들의 표현 그대로 다음과 같습니다. “대부분의 프롬프트 엔지니어링, 가이드 생성, 도구에는 기본 시스템 모델을 사용하세요. 모델을 특화시켜야 한다면 커스텀 Adapter를 학습시키세요… 커스텀 어댑터는 Python로 foundation 모델을 학습시키는 데 익숙한 경우에만 사용하세요.”1
- 어댑터 파일은 크고, 메인 앱 번들에 포함되어서는 안 되며, 호스팅된 에셋 팩과 Background Assets를 통해 온디맨드로 전달됩니다.23
- Apple은 프롬프트 엔지니어링이나 도구 호출이 작업에 실패한 후, 또는 기존의 파인튜닝된 서버 LLM, 주제별 전문성, 스타일/형식/정책 준수, 또는 지연 시간 목표가 비용을 정당화할 때만 어댑터를 고려하라고 말합니다.2
어댑터란 실제로 무엇인가
SystemLanguageModel.Adapter는 struct이며, iOS, iPadOS, Mac Catalyst, macOS, visionOS의 26.0 이상에서 사용할 수 있습니다.4 이 타입에 대한 Apple의 설명은 다음과 같습니다.
“대부분의 프롬프트 엔지니어링, 가이드 생성, 도구에는 기본 시스템 모델을 사용하세요. 모델을 특화시켜야 한다면 커스텀 Adapter를 학습시켜 시스템 모델 가중치를 변경하고 커스텀 작업에 최적화하세요. 커스텀 어댑터는 Python로 foundation 모델을 학습시키는 데 익숙한 경우에만 사용하세요.”4
메커니즘은 문서화되어 있습니다. Apple의 어댑터 학습 가이드는 다음과 같이 직접 언급합니다.2
“시스템 모델은 LoRA(Low-Rank Adaptation)로 알려진 매개변수 효율적 파인튜닝(PEFT) 접근 방식을 사용합니다. LoRA에서는 원본 모델 가중치가 동결되고, ‘어댑터’라고 하는 작은 학습 가능한 가중치 행렬이 모델의 네트워크를 통해 임베드됩니다. 학습 중에는 어댑터 가중치만 업데이트되어 학습할 매개변수 수를 크게 줄입니다.”
LoRA는 공개된 논문 이력이 있는 공개 기술입니다.5 Apple의 문서화된 표면은 툴킷, .fmadapter 내보내기, 에셋 팩 번들링, Background Assets 전달, 그리고 SystemLanguageModel.Adapter를 통한 런타임 로딩입니다.234
타입의 API 표면
Apple은 다음과 같은 Adapter 표면을 나열합니다.4
init(fileURL: URL) throws: “파일 URL로부터 어댑터를 생성합니다.”init(name: String) throws: “background assets 프레임워크에서 다운로드된 어댑터를 생성합니다.”func compile() async throws: “LanguageModelSession에서 사용하기 전에 어댑터를 준비합니다. 어댑터에 draft 모델이 있는 경우 이 메서드를 호출해야 합니다.”var creatorDefinedMetadata: [String : Any]: “어댑터 메타데이터의 creator defined 필드에서 읽은 값입니다.”static func removeObsoleteAdapters() throws: “현재 시스템 모델과 더 이상 호환되지 않는 모든 obsolete 어댑터를 제거합니다.”static func compatibleAdapterIdentifiers(name: String) -> [String]: “현재 시스템 모델과 호환되는 모든 어댑터 식별자를 가져옵니다.”enum AssetError: 에셋 관련 실패에 대한 오류 타입.
SystemLanguageModel에는 어댑터를 위한 짝지어진 이니셜라이저가 있습니다. convenience init(adapter: SystemLanguageModel.Adapter, guardrails: SystemLanguageModel.Guardrails)이며, 설명은 “어댑터를 사용하여 모델의 기본 버전을 생성합니다.”입니다.6
배포 전용 엔타이틀먼트 키는 com.apple.developer.foundation-model-adapter입니다. “앱이 Foundation Models 프레임워크에 대한 커스텀 어댑터를 활성화할 수 있는지 여부를 나타내는 Boolean 값입니다.”6 학습이나 로컬 Xcode 테스트에는 필요하지 않지만, App Store에 출시하기 전에는 필요합니다.3
Apple의 “어댑터를 언제 고려할 것인가” 기준
툴킷 페이지는 구체적인 도입 신호를 제시합니다.2
- “LLM와 함께 사용하기에 적합한 데이터셋이 있거나” 이미 파인튜닝된 서버 기반 LLM를 사용하고 있고 온디바이스 동등성을 원하는 경우.
- “모델이 주제별 전문가가 되어야 합니다.”
- “모델이 특정 스타일, 형식, 또는 정책을 준수해야 합니다.”
- “프롬프트 엔지니어링이 작업에 필요한 정확도나 일관성을 달성하지 못합니다.”
- “추론 시 더 낮은 지연 시간을 원합니다. 프롬프트 엔지니어링 솔루션이 매 호출마다 예제가 포함된 긴 프롬프트를 필요로 하는 경우, 해당 작업에 특화된 어댑터는 최소한의 프롬프트만 제공합니다.”
같은 가이드는 또한 감수해야 할 비용을 나열합니다.2
- 대상 기술을 보여주는 프롬프트와 응답 쌍의 데이터셋.
- 어댑터의 품질을 평가하는 프로세스.
- 서버에서 어댑터를 앱으로 로드하는 프로세스.
그리고 저장 공간 비용도 있습니다. “각 어댑터는 앱에서 약 160MB의 저장 공간을 차지합니다. 다른 큰 에셋과 마찬가지로, 어댑터는 앱의 메인 번들에 포함되어서는 안 됩니다. 여러 어댑터 버전이 있으면 앱이 너무 커져서 사용자가 설치하기 어렵기 때문입니다.”2
프레임워크의 권장 사항은, Apple이 두 곳에서 다시 언급한 바, 기본적으로 프롬프트 엔지니어링과 도구 호출을 사용하고 위의 기준이 충족될 때만 어댑터를 사용하는 것입니다.
Apple의 형식에 따른 학습
Apple은 툴킷이 Python 샘플 코드, 특정 시스템 모델 버전에 대한 모델 에셋, .fmadapter 내보내기 유틸리티, 에셋 팩 번들링 유틸리티를 포함한다고 설명합니다.2
데이터셋 요구 사항은 jsonl 프롬프트/응답 쌍이며, 기본 작업의 경우 약 100-1,000 샘플, 복잡한 작업의 경우 5,000개 이상입니다. Schema.md는 가이드 생성과 AI 안전성 필드를 다룹니다.2
하드웨어 요구 사항: “Apple silicon이 탑재되고 최소 32GB 메모리가 있는 Mac, 또는 Linux GPU 머신.” Python 3.11 이상.2
Apple의 데이터 품질 규칙은 단순합니다. 양보다 질이 우선입니다.2
학습은 툴킷의 train_adapter 진입점에서 호출됩니다.
python -m examples.train_adapter \
--train-data /path/to/train.jsonl \
--eval-data /path/to/valid.jsonl \
--epochs 5 \
--learning-rate 1e-3 \
--batch-size 4 \
--checkpoint-dir /path/to/my_checkpoints/
선택적으로, 어댑터를 학습시킨 후 일치하는 draft 모델을 학습시킬 수 있습니다.2 draft 모델은 시스템 기본 모델의 더 작은 버전으로, 공개된 추론 가속화 기술인 speculative decoding을 가능하게 합니다.7 Apple의 표현은 다음과 같습니다. “draft 모델을 학습시키지 않기로 선택하면, 어댑터의 사용 사례에서 speculative decoding을 사용할 수 없게 됩니다.”2
단일 버전 제약
어댑터에 대해 운영상 가장 중요한 사실은 특정 시스템 모델 버전에 바인딩된다는 것입니다.3
“각 어댑터는 단일 특정 시스템 모델 버전과 호환됩니다. 모든 새로운 기본 모델 버전에 대해 새 어댑터를 학습시켜야 합니다. 호환되는 어댑터 없이 사용자의 디바이스에서 앱이 실행되면 런타임 오류가 발생합니다.”
2026년 5월 4일 기준으로, Apple의 툴킷 표는 Beta 0.1.0과 Beta 0.2.0이 제거되었으며, 26.0.0이 첫 번째 정식 툴킷 버전이라고 나열합니다. Apple의 케이던스 규칙은 시스템 모델 업데이트마다 하나의 툴킷입니다.2 전체 진술은 다음과 같습니다. “모든 시스템 모델 업데이트에 대해 새 툴킷이 출시됩니다. 시스템 모델은 iOS, macOS, visionOS에서 공유되며, 시스템 모델 업데이트는 해당 플랫폼의 OS 업데이트의 일부로 발생합니다(다만 모든 OS 업데이트에 모델 업데이트가 있는 것은 아닙니다).”2
운영상의 함의는 다음과 같습니다. 어댑터를 출시하는 앱 팀은 Apple의 케이던스로 운영되는 모델 업데이트 라이프사이클을 구독하는 것입니다. 각 기본 모델 업그레이드는 재학습, 재평가, 재출시를 위한 강제 함수입니다.
에셋 팩으로 패키징
Apple의 규칙은 다음과 같습니다. 어댑터 파일은 앱 번들에 포함하기에는 너무 큽니다. App Store Connect나 자체 서버를 통해 호스팅한 다음, 디바이스 호환 어댑터를 온디맨드로 다운로드하세요.3
툴킷은 .fmadapter 패키지를 생성하며, 이는 또한 Background Assets 에셋 팩으로 번들됩니다. Xcode 16 이상의 ba-package 명령줄 도구가 번들링 작업을 수행하며, 툴킷이 이를 호출합니다.3
호스팅 선택지:3
- Apple-Hosted, Managed. Apple이 에셋을 호스팅하며, OS가 다운로드 라이프사이클을 관리합니다.
- Self-Hosted, Managed. 자체 서버에서 호스팅하며, OS가 다운로드 라이프사이클을 관리합니다.
- Self-Hosted, Unmanaged. 자체 호스팅하고 라이프사이클도 직접 관리합니다.
필수 Info.plist 키는 호스팅 선택에 따라 다릅니다.3 Apple-Hosted Managed는 BAHasManagedAssetPacks, BAAppGroupID, BAUsesAppleHosting이 필요하며, Self-Hosted Managed는 처음 두 개가 필요하고, Self-Hosted Unmanaged는 어떤 것도 필요하지 않습니다. 각 경로에는 또한 Xcode가 생성하는 asset-downloader 익스텐션 타깃이 있습니다.
런타임에서 적합한 어댑터 선택하기
asset-downloader 익스텐션의 BackgroundDownloadHandler.swift가 생성될 때, Xcode는 shouldDownload(_:) 콜백을 연결합니다. 어댑터 에셋에 대한 Apple의 예제 본문은 다음과 같습니다.3
func shouldDownload(_ assetPack: AssetPack) -> Bool {
if assetPack.id.hasPrefix("mygameshader") {
return true
}
return SystemLanguageModel.Adapter.isCompatible(assetPack)
}
Apple의 샘플은 문서화된 유일한 런타임 검사입니다. SystemLanguageModel.Adapter.isCompatible(assetPack) 표현식은 샘플이 어댑터 에셋 팩에 대해 반환하는 것이며, 호출은 샘플이 보여주는 것 이상으로는 불투명한 것으로 취급해야 합니다.3
다운로드 로딩 및 추적
에셋이 디바이스에 있으면 로드 경로는 다음과 같습니다.3
SystemLanguageModel.Adapter.removeObsoleteAdapters()
let adapter = try SystemLanguageModel.Adapter(name: "myAdapter")
생성은 디바이스에 호환되는 어댑터가 캐싱되어 있지 않으면 다운로드를 시작합니다. UX에 대한 Apple의 메모는 다음과 같습니다. “어댑터는 데이터 크기가 클 수 있기 때문에 다운로드하는 데 시간이 걸릴 수 있으며, 특히 사용자가 Wi-Fi나 셀룰러 네트워크를 사용 중인 경우 더욱 그렇습니다. 사용자가 네트워크 연결이 없으면 어댑터를 즉시 사용할 수 없습니다.”3
상태 시퀀스는 AssetPackManager에서 옵니다.3
let assetpackIDList = SystemLanguageModel.Adapter.compatibleAdapterIdentifiers(name: name)
if let assetPackID = assetpackIDList.first {
let statusUpdates = AssetPackManager.shared.statusUpdates(forAssetPackWithID: assetPackID)
for await status in statusUpdates {
switch status {
case .began(let assetPack): ...
case .paused(let assetPack): ...
case .downloading(let assetPack, let progress): ...
case .finished(let assetPack): ...
case .failed(let assetPack, let error): ...
@unknown default: ...
}
}
}
문서화된 다섯 가지 DownloadStatusUpdate 케이스: .began, .paused, .downloading, .finished, .failed.3 프레임워크의 @unknown default 분기는 Apple이 향후 SDK 버전에서 케이스를 추가할 수 있기 때문에 필수입니다.
상태가 .finished에 도달한 후, 어댑터는 세션에 연결할 준비가 됩니다.
let adaptedModel = SystemLanguageModel(adapter: adapter)
let session = LanguageModelSession(model: adaptedModel)
Draft 모델과 그 속도 제한
어댑터가 draft 모델과 함께 출시된 경우, adapter.compile()을 호출하면 사용을 위해 준비됩니다. Apple의 문서는 이를 별도의, 계산적으로 비싼 단계로 명시합니다.3
“디바이스가 어댑터의 새 버전을 처음 다운로드할 때,
compile()호출은 draft 모델을 완전히 컴파일하고 디바이스에 저장합니다. 앱의 후속 실행 동안,compile()호출은 저장된 컴파일된 draft 모델을 확인하고 존재하면 즉시 반환합니다.”
공개된 속도 제한이 있습니다.3
“속도 제한은 모든 앱과 프로세스 간에 공유되는 디바이스 리소스를 보호합니다. 프레임워크가 새 컴파일이 필요하다고 판단하면, macOS를 제외한 모든 플랫폼에서 컴파일 프로세스를 앱당, 일당 3개의 draft 모델 컴파일로 속도 제한합니다.”
속도 제한은 macOS를 제외하며, 다른 플랫폼에서는 새 draft 모델 컴파일이 앱당 일당 세 번의 컴파일로 제한됩니다.3 Apple은 작업이 앱 시작을 차단하지 않도록 Background Tasks로 스케줄링된 작업 내에서 컴파일을 실행할 것을 권장합니다.3
Apple의 Xcode 테스트 경고: Xcode를 통해 시작하면 앱 UUID가 변경되므로, 매 시작마다 전체 컴파일이 실행되어 속도 제한에 걸릴 수 있습니다.3
테스트와 시뮬레이터 제약
어댑터 테스트는 물리적 디바이스가 필요합니다. Apple은 명시적으로 말합니다. “어댑터 테스트에는 물리적 디바이스가 필요하며 시뮬레이터에서는 지원되지 않습니다.”3
Xcode에서의 로컬 테스트의 경우, 이름이 아닌 파일 URL에서 초기화합니다.3
let localURL = URL(filePath: "absolute/path/to/my_adapter.fmadapter")
let adapter = try SystemLanguageModel.Adapter(fileURL: localURL)
출시의 경우, Apple은 어댑터 파일을 로컬 테스트용으로만 가져오고, 출시 전에 제거하고 어댑터를 온디맨드로 다운로드하라고 말합니다.3
운영 측면에서 이 경로의 비용은 얼마인가
라이프사이클을 종합하면, 커스텀 어댑터를 출시하는 앱은 다음에 가입하는 셈입니다.
- Python 학습 인프라. 최소 Apple silicon이 탑재되고 32GB 메모리가 있는 Mac, 또는 Linux GPU 머신.2
- Apple 시계에 맞춘 재학습 케이던스. 모든 시스템 모델 업데이트는 새로운 어댑터와 새로운 툴킷 버전을 의미합니다.3
- 서빙 스택. App Store Connect를 통한 Apple 호스팅 에셋 팩이거나, 또는 asset-downloader 통합을 실행하는 자체 서버.3
- 저장 공간의 버전별 어댑터. 야생에 여러 기본 모델 버전이 있다는 것은 여러 어댑터가 호스팅되며, 디바이스가 일치하는 것을 가져온다는 것을 의미합니다.3
- 엔타이틀먼트 게이트. Apple Developer Program 멤버십의 Account Holder가 이를 요청하며, 승인 없이는 출시할 수 없습니다.2
- 어댑터 버전당 160MB 비용. 앱 번들에는 없지만, 다운로드 후 사용자의 디바이스에 있습니다.2
- 물리적 디바이스 테스트. 시뮬레이터는 어댑터를 실행하지 않습니다.3
이것이 운영 비용의 단순한 형태입니다. 도입 신호가 충족될 때의 이점은 다음과 같습니다. 온디바이스 모델이 최소한의 프롬프트와 더 낮은 지연 시간으로 작업에 특화됩니다. 이미 파인튜닝된 서버 측 추론에 비용을 지불하고 있고 온디바이스 동등성을 원하는 앱의 경우, 이것이 단순한 형태의 트레이드오프입니다.
핵심 요약
- 어댑터는 Apple의 문서화된 기술상 LoRA입니다. 동결된 기본 가중치, 모델의 네트워크를 통한 작은 학습 가능한 행렬, 학습 중에는 어댑터 가중치만 업데이트됩니다.2
- 시스템 모델 버전당 하나의 어댑터, 예외 없음. OS 출시에 묶인 재학습을 계획하세요.3
.fmadapter흐름은 엔드 투 엔드입니다. Python로 학습시키고, 툴킷으로 패키징하고, Background Assets 에셋 팩으로 호스팅하고, 앱에서 이름으로 로드하고, 백그라운드 작업에서 draft 모델을 컴파일합니다.- Apple 자체가 대부분의 앱은 이 경로를 택하지 말라고 권장합니다. 두 개의 별도 Apple 문서 페이지에서 대부분의 사용 사례에 대해 이를 만류합니다.1 툴킷 페이지의 기준을 읽어보세요. 답은 기본적으로 “아니오”입니다.
- 하드웨어에서 테스트하세요. 시뮬레이터는 어댑터를 실행하지 않습니다. 물리적 디바이스 세션과
Background Tasks프레임워크의 컴파일 슬롯을 중심으로 테스트 계획을 수립하세요.
전체 Apple Ecosystem 클러스터: 내장 특화를 위한 결정 기준, 프레임워크의 핵심에 있는 Tool 프로토콜, 인앱과 툴링 LLM 사이의 에이전틱 워크플로 분할, 더 넓은 라우팅 질문에 대한 App Intents vs MCP. 허브는 Apple Ecosystem Series에 있습니다. AI 에이전트가 포함된 더 넓은 iOS 컨텍스트는 iOS Agent Development guide를 참조하세요.
FAQ
내 앱이 실제로 커스텀 어댑터가 필요한지 어떻게 알 수 있나요?
Apple은 대부분의 프롬프트 엔지니어링, 가이드 생성, 도구에 기본 모델을 권장하며, 툴킷 가이드는 어댑터가 가파른 학습 및 재학습 요구 사항을 가진다고 말합니다. Apple의 어댑터 신호가 적용되지 않는 한 기본 답은 “아니오”입니다.24
엔타이틀먼트는 실제로 무엇을 게이팅하나요?
Apple은 학습이나 로컬 테스트가 아닌, 어댑터를 배포할 때 엔타이틀먼트가 필요하다고 문서화합니다.23
어댑터의 크기는 얼마이며 어디에 저장되나요?
Apple의 문서화된 수치는 다음과 같습니다. “각 어댑터는 앱에서 약 160MB의 저장 공간을 차지합니다.”2 어댑터는 앱 번들에 저장되지 않습니다. Apple은 Apple 서버(managed) 또는 자체 서버(managed 또는 unmanaged)에 호스팅된 Background Assets를 통해 이를 라우팅하며, 디바이스는 현재 시스템 모델과 일치하는 버전을 다운로드합니다.3
Apple이 기본 모델을 업데이트하면 어떻게 되나요?
Apple이 기본 모델을 업데이트하면, 해당 모델 버전에 대해 호환되는 어댑터를 학습시키세요. 그렇지 않으면 호환되는 어댑터 없는 디바이스에서 앱이 런타임 오류를 만날 수 있습니다.23
어댑터와 .contentTagging의 관계는 무엇인가요?
.contentTagging은 Apple이 관리하며 프레임워크에 내장되어 있습니다. 이는 내부적으로 특화된 사용 사례이지, 개발자가 학습시키는 공식 Adapter 타입이 아닙니다. 공식 타입은 이 포스트에서 다루는 것이며, 사용 사례는 동반 포스트에서 다룹니다.
draft 모델을 반드시 학습시켜야 하나요?
Apple은 draft 모델 학습을 건너뛰는 결과로 다음만을 문서화합니다. 해당 어댑터 사용 사례에 대해 speculative decoding을 사용할 수 없게 됩니다.2
References
-
Apple Developer, “SystemLanguageModel.Adapter”. 타입 설명, 대부분의 앱에 대한 사용 비권장, “커스텀 어댑터는 Python로 foundation 모델을 학습시키는 데 익숙한 경우에만 사용하세요.” 2026-05-04 조회. ↩↩↩↩
-
Apple Developer, “Get started with Foundation Models adapter training”. 툴킷 개요, LoRA 메커니즘, 하드웨어 요구 사항, 데이터셋 형식, 학습 CLI, draft 모델 옵션, 툴킷 버전 표, 엔타이틀먼트 요청 흐름. 2026-05-04 조회. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩
-
Apple Developer, “Loading and using a custom adapter with Foundation Models”. 에셋 팩 호스팅, Info.plist 키,
shouldDownload(_:)예제, 상태 시퀀스, 속도 제한, 시뮬레이터 제외, 단일 버전 호환성 제약. 2026-05-04 조회. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple Developer, “SystemLanguageModel.Adapter”. Struct API 표면:
init(fileURL:),init(name:),compile(),creatorDefinedMetadata,removeObsoleteAdapters(),compatibleAdapterIdentifiers(name:),AssetError. 2026-05-04 조회. ↩↩↩↩↩↩ -
Hu et al., “LoRA: Low-Rank Adaptation of Large Language Models”, arXiv:2106.09685. Apple이 사용하는 기술이 참조하는 원본 LoRA 논문. ↩
-
Apple Developer, “SystemLanguageModel”.
init(adapter:guardrails:)convenience 이니셜라이저와com.apple.developer.foundation-model-adapter엔타이틀먼트 설명. 2026-05-04 조회. ↩↩ -
Leviathan et al., “Fast Inference from Transformers via Speculative Decoding”, arXiv:2211.17192, and Chen et al., “Accelerating Large Language Model Decoding with Speculative Sampling”, arXiv:2302.01318. Apple의 draft 모델이 사용하는 speculative decoding 기술로, 어댑터 학습 가이드에 직접 인용됨. ↩