
Apple Intelligence를 내 앱 Look에 적용한 방법
요약
macOS용 키보드 런처인 Look 앱에 Apple Intelligence의 Foundation Models를 활용하여 온디바이스 AI 기능을 통합한 사례를 소개합니다. 개인정보 보호, 비용 절감, 빠른 응답 속도를 위해 클라우드 대신 로컬 모델을 선택했으며, 추상화 계층을 통해 확장성을 확보했습니다.
핵심 포인트
- Apple Foundation Models를 활용한 온디바이스 AI 구현
- 개인정보 보호, 비용 효율성, 저지연성을 위한 로컬 모델 선택
- AI 기능이 검색 성능을 저해하지 않도록 'Best Effort' 원칙 적용
- 추상화 계층을 설계하여 향후 클라우드 모델로의 교체 용이성 확보
이것은 Apple의 Foundation Models 프레임워크를 사용하여 내 macOS 앱인 Look에 온디바이스 AI (on-device AI)를 추가한 방법에 대한 작은 이야기입니다. 무엇이 좋았는지, 무엇이 힘들었는지, 실제 코드, 그리고 모델이 아직 작음에도 불구하고 지금 이 기술을 기반으로 구축하는 것이 왜 실제로 좋은 기회라고 생각하는지를 공유하고 싶습니다.
먼저, Look이란 무엇인가요?
Look은 macOS를 위한 키보드 런처 (keyboard launcher)입니다. 단축키를 누르고 타이핑하면 앱, 파일, 폴더를 매우 빠르게 찾아줍니다. 검색 코어는 Rust로 작성되어 매우 빠릅니다.
하지만 문제는 사람들이 키워드로 생각하지 않는다는 점입니다. 그들은 질문으로 생각합니다. 예를 들어 "지난주에 다운로드한 그 PDF"라거나, "240의 18%는 얼마인가" 또는 "게르니카를 그린 사람은 누구인가"와 같은 식입니다. 일반적인 키워드 검색은 이에 대해 실제로 도움을 줄 수 없습니다.
그래서 저는 Apple Intelligence를 사용하여 Look에 작은 AI 레이어를 추가했습니다. 저의 단 하나의 규칙은 간단했습니다: AI는 최선의 노력(best effort)이어야 하며, 검색을 차단하거나 느리게 해서는 절대 안 된다는 것입니다. 만약 모델을 사용할 수 없거나, 준비되지 않았거나, 혹은 단순히 실패하더라도 Look은 이전과 똑같이 작동합니다. 아무것도 망가지지 않습니다.
왜 클라우드 LLM이 아닌 온디바이스인가요?
런처의 경우 세 가지가 매우 중요합니다. 개인정보 보호 (private) (사용자의 파일 이름이 절대 Mac을 떠나지 않아야 함), 무료 (free) (저는 이 도구를 하루에 100번 정도 사용하는데, 토큰당 비용을 지불할 수는 없습니다), 그리고 빠른 시작 (start fast) (네트워크 왕복 시간이 없어야 함)입니다. Apple의 Foundation Models는 깔끔한 Swift API와 함께 로컬에서 실행되는 약 3B 모델을 제공합니다. 런처에게는 그야말로 완벽한 형태입니다.
참조: https://developer.apple.com/documentation/foundationmodels
실제로 Look에 어떻게 통합했는가
먼저 중요한 결정 사항이 하나 있습니다. Look에서는 모든 Foundation Models (기반 모델) 코드가 하나의 프로바이더(provider) 타입 뒤에 존재합니다. 앱의 나머지 부분은 FoundationModels를 직접 임포트(import)하지 않으며, 제가 만든 작은 추상화 계층(abstraction)하고만 통신합니다. 따라서 온디바이스 모델(on-device model)은 교체 가능한 하나의 "티어(tier)"일 뿐이며, 나중에 모든 코드를 수정하지 않고도 클라우드 모델을 추가할 수 있습니다.
1. 항상 가용성을 먼저 확인하세요
Apple Intelligence가 항상 존재하는 것은 아닙니다. 사용자의 하드웨어가 구형일 수도 있고, 기능을 켜지 않았을 수도 있으며, 모델이 아직 다운로드 중일 수도 있습니다. 이 모든 상황은 SystemLanguageModel.default.availability를 통해 확인할 수 있으며, 모든 케이스를 반드시 처리해야 합니다.
#if canImport(FoundationModels)
import FoundationModels
#endif
...
여기서의 핵심 기술은 두 개의 레이어입니다. #if canImport(FoundationModels)는 앱이 더 낮은 배포 대상(deployment target)에서도 _컴파일(compile)_될 수 있게 해주며, #available(macOS 26, *)는 _런타임(runtime)_을 보호합니다. Look에서는 모든 AI 진입점(entry point)이 availability.isAvailable을 확인하고, 사용 불가능할 경우 단순히 nil을 반환합니다. 설정(Settings)의 AI 토글은 녹색 체크 표시나 그 이유를 보여주지만, 검색 기능 자체는 절대 중단되지 않습니다.
참조: https://developer.apple.com/documentation/foundationmodels/systemlanguagemodel
2. @Generable을 사용한 구조화된 출력 (이 부분이 가장 핵심입니다)
자, 이제 Foundation Models가 진정으로 빛을 발하는 부분입니다. 모델의 텍스트를 수동으로 파싱(parsing)하는 대신, @Generable과 @Guide를 사용하여 출력의 _형태(shape)_를 기술하기만 하면 프레임워크가 정확히 해당 타입으로 결과를 돌려줍니다. Look에서 저는 이를 사용하여 "송장이 들어있는 폴더"와 같은 모호한 쿼리(query)를 제 Rust 엔진이 실행할 수 있는 타입화된 계획(typed plan)으로 변환하는 데 사용합니다.
@available(macOS 26, *)
@Generable
private struct EngineQueryPlan {
...
JSON 프롬프트 엔지니어링(prompt engineering), 파싱(parsing), 또는 모델에게 "유효한 JSON으로 답변해 주세요"라고 간청할 필요가 없습니다. 그저 타입이 지정되고 검증된 구조체(struct)를 얻게 될 뿐입니다. 솔직히 말해서, 이 방식은 버그의 한 카테고리 전체를 제거해 줍니다.
Look에서는 이것을 오직 구조(rescue) 용도로만 실행합니다. 빠른 로컬 검색(local search)이 결과가 0개일 때, 자연어 쿼리(natural language query)를 엔진 문법(engine grammar)으로 다시 작성하여 재검색합니다. 만약 로컬 검색에서 이미 무언가를 찾았다면, 모델은 실행되지 않습니다. 따라서 이미 괜찮은 쿼리에 대해 지연 시간(latency)을 지불할 필요가 없습니다.
3. 짧은 답변 스트리밍 (Streaming short answers)
인라인 답변 카드(예: "노르웨이의 수도는 어디인가요")의 경우, 텍스트가 단어별로 나타나도록 응답을 스트리밍(stream)하며, 답변이 작고 런처(launcher) 크기에 적합하게 유지되도록 길이를 제한합니다.
func answer(query: String) -> AsyncThrowingStream<String, Error>? {
AsyncThrowingStream { continuation in
let task = Task {
...
가져다 쓸 만한 두 가지 작은 디테일이 있습니다. 스트리밍되는 각 snapshot.content는 (차이값(delta)이 아닌) 누적된(cumulative) 답변이며, 온디바이스 모델(on-device model)은 Look에서 최후의 fallback입니다. 계산기와 웹 소스를 먼저 시도하며, 다른 어떤 것도 적중하지 않았을 때만 모델이 실행됩니다.
참조: https://developer.apple.com/documentation/foundationmodels/languagemodelsession
4. 지연 시간을 숨기기 위한 프리웜 (Prewarm to hide the latency)
모델에 대한 첫 번째 호출은 눈에 띄는 시작 비용(startup cost)이 발생합니다. 런처는 항상 열리고 닫히기 때문에, 창이 열리는 순간이나 쿼리가 문장처럼 보이기 시작하는 순간 상주 세션(resident session)을 prewarm() 합니다.
@MainActor
final class AppleIntelligenceWarmer {
static let shared = AppleIntelligenceWarmer()
...
참조: https://developer.apple.com/documentation/foundationmodels/languagemodelsession/prewarm()
장점 (진정으로 훌륭한 점)
- 기본적으로 프라이버시 보호 (Private by default). 모든 것이 Mac에서 실행됩니다. 사용자가 입력하는 모든 파일 이름을 확인해야 하는 런처(launcher) 앱에게 이것은 있으면 좋은 기능(nice to have) 정도가 아니라, 제가 AI를 출시하기로 마음먹은 결정적인 이유입니다.
- 한계 비용 제로 (Zero marginal cost). API 키도, 과금도, 속도 제한(rate limit)도 없습니다. 적합한 모든 쿼리에 대해 모델을 실행하면서도 비용 측정기를 지켜볼 필요가 없습니다.
- 정말 훌륭한 Swift API.
@Generable가이드 생성(guided generation)이 핵심입니다. 모델로부터 타입이 지정되고 검증된 구조체(struct)를 직접 받아오는 기능은 정말 좋습니다. - 이미 기기에 탑재되어 있음. 제 앱에 수 기가바이트 규모의 모델을 번들로 포함하지 않습니다. OS가 가중치(weights)를 배포하고 업데이트합니다.
- 깔끔하고 조합 가능함 (Clean and composable). 세션(Sessions), 지침(instructions), 스트리밍(streaming), 옵션(options), 프리웜(prewarm). 이 요소들이 결합되어 하나의 실제 기능으로 딱 들어맞습니다.
단점 (솔직히 여전히 아쉬운 점)
- 가용성(Availability)은 계속 변하는 목표입니다. macOS 26과 지원되는 하드웨어가 필요하며, 사용자가 이를 활성화해야 하고, 모델이 여전히 다운로드 중일 수도 있습니다. 사용자 중 상당수는 이를 사용하지 못할 것입니다. 따라서 AI가 없는 경로(no-AI path)를 예외가 아닌 기본값(default)으로 설계해야 합니다.
- 작은 모델입니다. 약 3B(30억 파라미터) 규모는 분류(classification), 재작성(rewriting), 짧은 사실적 답변에는 훌륭하지만, 추론(reasoning), 긴 글쓰기 또는 니치한 지식(niche knowledge) 측면에서는 대규모 클라우드 모델보다 확실히 약합니다. 기능을 작은 모델이 잘 수행할 수 있는 범위로 한정하세요.
- 첫 사용 시 지연 시간(First use latency). 프리웜(prewarm) 없이는 첫 번째 토큰(token) 생성 속도가 느립니다. 프리웜을 사용하더라도 온디바이스 추론(on-device inference)은 공짜가 아닙니다. 100ms 미만의 도구를 목표로 한다면 이는 반드시 고려해야 할 예산(budget) 항목입니다.
- 가드레일(Guardrails)이 예상치 못한 상황을 만들 수 있습니다. 생성 과정이 안전 가드레일에 의해 거부되거나 중단될 수 있습니다. 이러한 오류를 포착하여 자연스럽게 기능 수준을 낮추는(degrade) 처리를 해야 합니다. Look에서는 단순히 원시 쿼리(raw query)로 되돌아가는 방식을 사용합니다.
- macOS 26 전용이며 API가 아직 초기 단계입니다. 계속해서 변화할 완전히 새로운 환경(surface) 위에서 구축하고 있는 것입니다.
#if canImport와#available을 복잡하게 사용하는 것은 초기 도입자(early adopter)가 지불해야 하는 대가입니다.
지금 이를 기반으로 구축하는 것이 위험이 아닌 기회인 이유

좋습니다, 제가 말하고자 하는 핵심은 이것입니다. 로컬 모델은 계속 좋아질 것이며, 제 코드는 변경할 필요가 없습니다. Apple은 OS 업데이트를 통해 온디바이스 가중치(on-device weights)를 배포하고 업그레이드합니다. 제가 오늘 작성한 동일한 LanguageModelSession 호출은 1년 후 더 똑똑하고 빠른 모델에 의해 지원될 것입니다. 제 노력 없이, 무료로 말이죠. 제가 정의한 @Generable 플랜은 동일한 타입을 계속 반환하되, 단지 더 정확한 내용으로 채워질 뿐입니다.
그것은 정말로 계산법을 바꿉니다. 파운데이션 모델 (Foundation Models)을 조기에 도입하는 것은 오늘날의 작은 모델이 모든 것에 충분히 훌륭할 것이라는 도박이 아닙니다. 왜냐하면 분명히 그렇지 않기 때문입니다. 그것은 당신의 발밑의 바닥(the floor)이 올라갈 것이라는 도박입니다. 통합 작업(제공자 추상화 (provider abstraction), 가용성 처리 (availability handling), 프리웜 (prewarm), 폴백 설계 (fallback design))이 어려운 부분이며, 이는 일회성 비용입니다. 일단 Look이 파운데이션 모델 (Foundation Models)을 유창하게 구사하게 되면, 모든 OS 업데이트는 조용한 기능 업그레이드가 됩니다.
그래서 저는 오늘 Look에 온디바이스 AI (on-device AI)를 출시합니다. 3B 모델이 잘 수행할 수 있는 범위로 엄격히 제한하며, 항상 선택 사항이고, 절대 차단(blocking)하지 않습니다. 그리고 저는 이를 지금 당장 완벽하게 만들어야 하는 기능이 아니라, 점진적으로 키워나갈 인프라 (infrastructure)로 취급합니다. 만약 여러분이 Mac 앱을 만들고 있다면, 지금이 기회입니다. API가 아직 초기 단계일 때 배관 작업 (plumbing)을 제대로 해두고, 모델의 개선 사항을 무료로 누리십시오.
읽어주셔서 감사합니다. 직접 써보고 싶다면, Look을 내려받아 설정 (Settings)에서 AI 토글을 켜보세요.
참고 링크
-
Foundation Models 프레임워크: https://developer.apple.com/documentation/foundationmodels
-
SystemLanguageModel: https://developer.apple.com/documentation/foundationmodels/systemlanguagemodel
-
LanguageModelSession: https://developer.apple.com/documentation/foundationmodels/languagemodelsession
-
가이드 생성 (Guided generation) (@Generable / @Guide): https://developer.apple.com/documentation/foundationmodels/generating-swift-data-structures-with-guided-generation
-
HIG: 생성형 AI (Generative AI): https://developer.apple.com/design/human-interface-guidelines/generative-ai
-
WWDC25, Foundation Models 프레임워크 소개: https://developer.apple.com/videos/play/wwdc2025/286/
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기