Capacitor 앱에서 Apple Intelligence를 사용하려면 설치하세요 @capgo/capacitor-llm, 호출 setModel({ path: 'Apple Intelligence' }), 확인하세요 getReadiness(), 그리고 채팅을 생성하여 응답을 스트리밍하세요 textFromAi 이벤트. 내부적으로 이 플러그인은 iOS 26과 함께 도입된 Apple의 Foundation Models 프레임워크를 사용하며, API 키 없이, 요청당 비용 없이, 데이터가 기기를 벗어나지 않는 방식으로 Apple의 온디바이스 언어 모델을 실행합니다.
이 가이드는 프레임워크가 제공하는 기능, 기기 요구 사항, 완전한 TypeScript 통합, 4,096-token 컨텍스트 윈도우, 오류 처리, App Review 참고 사항, 그리고 동일한 code이 Android에서 실행되는 방식을 다룹니다.
Apple Intelligence가 앱 개발자에게 제공하는 것
iOS 26에서 Apple은 Foundation Models를 통해 Foundation Models 프레임워크입니다. Swift에서는 SystemLanguageModel 및 LanguageModelSession을(를) 사용합니다. 이 플러그인은 이를 래핑하여 웹 code에서도 사용할 수 있게 합니다:
| Foundation Models 개념 | 플러그인 대응 |
|---|---|
SystemLanguageModel.default.availability |
getReadiness() |
LanguageModelSession |
createChat() id 반환 |
session.streamResponse(to:) |
sendMessage() 및 textFromAi 이벤트 |
| 생성 중 발생하는 에러 | generationError 이벤트와 거부된 sendMessage |
모델은 약 30억 개의 파라미터를 가집니다. 요약, 재작성, 추출, 분류 및 짧은 형식의 생성에 강점이 있습니다. 개방형 지식 질문에서 대형 클라우드 모델을 대체할 수는 없으며, Apple도 자체 가이드에서 이를 명시하고 있습니다. 사용자가 이미 보유한 텍스트를 중심으로 기능을 설계하세요.
기기 및 OS 요구 사항
| 요구 사항 | 세부 정보 |
|---|---|
| iPhone | iPhone 15 Pro, 15 Pro Max 및 iPhone 16 모델 이상 |
| iPad | iPad mini (A17 Pro), M1 이상 칩 탑재 iPad |
| Mac | Apple silicon Mac (Simulator에서 테스트 시 관련) |
| OS | iOS 26 / iPadOS 26 이상 |
| 설정 | 설정 > Apple Intelligence & Siri에서 Apple Intelligence가 켜져 있어야 합니다 |
| 언어 | 기기 및 Siri 언어가 Apple Intelligence가 지원하는 언어로 설정되어 있어야 합니다 |
| 스토리지 | Apple은 Apple Intelligence 모델을 위해 약 7GB의 여유 공간을 권장합니다 |
| Toolchain | 2026년 4월부터 App Store Connect 업로드에도 필수인 Xcode 26 |
프로젝트가 이전 버전의 Xcode로 빌드되는 경우, 다음을 참조하세요 Capacitor 앱을 위한 Apple의 Xcode 26 요구사항. 앱의 최소 배포 대상은 변경할 필요가 없습니다. 이 플러그인은 iOS 15 이상을 지원하며, iOS 26에서는 Foundation Models에만 영향을 줍니다.
플러그인 설치
bun add @capgo/capacitor-llm
bunx cap sync ios
Capacitor 8과 함께 플러그인 8.x를 사용하세요. Apple Intelligence를 위해 Info.plist 키나 권한(entitlements)이 필요하지 않습니다. 아직 Capacitor 7을 사용 중이라면 Capacitor 8 업그레이드 가이드 가 먼저입니다. 참고 문서: /docs/plugins/llm/.
1단계: 모델 선택 및 사용 가능 여부 확인
setModel({ path: 'Apple Intelligence' }) 시스템 모델을 선택하고 즉시 해결합니다. 실제 사용 가능 여부는 getReadiness()에서 가져오며, Apple의 사용 가능 열거형(enum)을 읽기 쉬운 문자열로 매핑합니다:
readiness 값 |
의미 | 표시할 내용 |
|---|---|---|
ready |
모델 사용 가능 | 해당 기능 |
Device is not eligible for Apple Intelligence |
하드웨어 미지원 | 기능 숨기기 또는 클라우드 폴백 사용 |
Apple Intelligence is not enabled |
사용자가 비활성화함 | 설정에서 활성화하도록 안내 |
Model is not ready |
모델이 아직 다운로드 중이거나 준비 중 | “준비 중”, 나중에 재시도 |
Apple Intelligence requires iOS 26.0 or later |
구형 iOS | 기능 숨기기 |
import { Capacitor } from '@capacitor/core';
import { CapgoLLM } from '@capgo/capacitor-llm';
export type AIState = 'ready' | 'enable-in-settings' | 'preparing' | 'unsupported';
export async function initAppleIntelligence(): Promise<AIState> {
if (Capacitor.getPlatform() !== 'ios') return 'unsupported';
await CapgoLLM.setModel({ path: 'Apple Intelligence' });
const { readiness } = await CapgoLLM.getReadiness();
if (readiness === 'ready') return 'ready';
if (readiness.includes('not enabled')) return 'enable-in-settings';
if (readiness.includes('not ready')) return 'preparing';
return 'unsupported';
}
앱이 포그라운드로 돌아올 때 다시 확인하세요. 사용자는 안내를 보고 Apple Intelligence를 활성화하는 경우가 많으며, 앱이 백그라운드에 있을 때 모델 다운로드가 완료될 수 있습니다.
import { App } from '@capacitor/app';
App.addListener('appStateChange', async ({ isActive }) => {
if (isActive) updateAIState(await initAppleIntelligence());
});
2단계: 지시사항이 포함된 채팅 생성
채팅 하나가 하나에 매핑됩니다 LanguageModelSession, 대화 기록을 유지합니다. 입력한 createChat() 옵션을 받지 않으므로, 첫 번째 메시지의 시작 부분에 지시문을 넣으세요:
const INSTRUCTIONS =
'You summarize meeting notes. Reply with at most 5 bullet points. ' +
'Keep names and dates exactly as written. Do not add information.';
const { id: chatId } = await CapgoLLM.createChat();
작업별로 하나의 채팅을 사용하세요. 계속 커지는 채팅은 아래 설명된 컨텍스트 한도에 도달하게 됩니다.
3단계: 응답을 UI에 스트리밍
iOS에서 각 textFromAi 이벤트는 Foundation Models의 스트리밍 방식에 따라 현재까지의 응답 스냅샷을 포함합니다. Gemini Nano를 사용하는 Android에서는 이벤트가 새 텍스트만 포함합니다. 이 헬퍼는 두 경우 모두를 처리하고 최종 텍스트로 resolve합니다:
import { CapgoLLM } from '@capgo/capacitor-llm';
function mergeChunk(current: string, chunk: string) {
return chunk.startsWith(current) ? chunk : current + chunk;
}
export async function ask(chatId: string, message: string, onText: (t: string) => void) {
let text = '';
let finish!: (value: string) => void;
let fail!: (error: Error) => void;
const done = new Promise<string>((resolve, reject) => {
finish = resolve;
fail = reject;
});
const handles = await Promise.all([
CapgoLLM.addListener('textFromAi', (e) => {
if (e.chatId !== chatId) return;
text = mergeChunk(text, e.text);
onText(text);
}),
CapgoLLM.addListener('aiFinished', (e) => {
if (e.chatId === chatId) finish(text);
}),
CapgoLLM.addListener('generationError', (e) => {
if (!e.chatId || e.chatId === chatId) fail(new Error(e.error));
}),
]);
try {
await CapgoLLM.sendMessage({ chatId, message });
return await done;
} finally {
await Promise.all(handles.map((h) => h.remove()));
}
}
모두 합치기: 기기에 메모 요약
export async function summarizeNotes(notes: string, render: (t: string) => void) {
const state = await initAppleIntelligence();
if (state !== 'ready') throw new Error(`AI unavailable: ${state}`);
const { id } = await CapgoLLM.createChat();
const prompt = `${INSTRUCTIONS}\n\nNotes:\n${notes.slice(0, 8000)}\n\nSummary:`;
return ask(id, prompt, render);
}
이 slice 은 거대한 입력에 대한 단순한 가드입니다. 더 나은 방법은 긴 문서를 청크로 나눠 요약한 후, 각 요약을 새 채팅에서 다시 요약하는 것입니다.
프레임워크 컴포넌트에서 ask 가 실행되는 동안 버튼을 비활성화하세요. 플러그인은 같은 채팅에서 두 번째 sendMessage 요청을 "채팅이 응답 중입니다. 새 질문을 하기 전에 기다려 주세요."라는 메시지로 거부합니다.
4,096 토큰 컨텍스트 윈도우
온디바이스 모델의 컨텍스트 윈도우는 4,096 토큰입니다. 모든 것이 여기에 포함됩니다: 지시사항, 채팅의 모든 이전 턴, 새로운 프롬프트, 그리고 생성 중인 응답. 세션이 이를 초과하면 Foundation Models가 “exceeded context window size” 오류를 발생시키며, 이는 generationError 이벤트와 거부된 sendMessage.
실용적인 규칙:
- 화면마다가 아니라 작업마다 하나의 채팅을 사용하세요.
- 지시사항은 짧고 구체적으로 유지하세요.
- 멀티턴 채팅의 경우, 길어지면 새 채팅을 시작하고 이전 대화의 짧은 요약을 전달하세요.
- 간결한 출력을 요청하세요. 긴 답변도 동일한 예산을 사용합니다.
출력 조정
Apple Intelligence 경로에서 플러그인은 시스템의 기본 생성 설정을 사용합니다. temperature, topk, 그리고 maxTokens 에서 setModel 커스텀 LiteRT-LM 및 MediaPipe 모델 경로에 적용됩니다. Apple 모델의 동작을 제어하려면 프롬프트에 의존하세요. 답변 길이를 지정하고, 형식(불릿, JSON, 한 문장)을 명시하며, 형식이 중요한 경우 짧은 예시 하나를 포함하세요.
Android에서도 동일한 code
모델 선택만 다릅니다:
const path = Capacitor.getPlatform() === 'ios' ? 'Apple Intelligence' : 'Gemini Nano';
await CapgoLLM.setModel({ path });
Android에서는, setModel Gemini Nano가 사용 불가능하면 거부하며, 동일한 플러그인을 통해 다운로드 가능한 Gemma 모델로 폴백할 수 있습니다. 자세한 내용은 Capacitor 앱에서 Gemini Nano 사용법.
테스트
- 실기기: 안정적인 경로입니다. Apple Intelligence가 켜진 iOS 26 지원 iPhone을 사용하세요.
- 시뮬레이터: 호스트 Mac이 Apple silicon 기반 macOS 26에서 Apple Intelligence를 활성화한 경우 모델을 사용할 수 있습니다. 동작과 속도가 휴대폰과 다르므로 하드웨어에서 확인하세요.
- 지원되지 않는 상태: Apple Intelligence를 끄고 '설정에서 활성화' UI를 확인하세요. 또한 구형 iPhone이나 iOS 버전에서 기능이 깔끔하게 숨겨지는지 확인하세요.
앱 심사 및 개인정보 보호
프롬프트와 응답은 기기에 머물러 있으므로, 온디바이스 생성 자체는 개인정보 보호 라벨에 데이터 수집 항목을 추가하지 않습니다. 다만 두 가지는 개발자가 직접 관리해야 합니다:
- Apple은 Foundation Models 프레임워크의 허용 사용 요구사항을 공개합니다. 특히 다른 사용자에게 표시되는 콘텐츠를 생성하는 기능의 경우, 배포 전에 반드시 확인하세요.
- 모델에는 내장된 가드레일이 있어 일부 프롬프트나 출력을 거부할 수 있습니다. 거부는 정상적인 결과로 간주하고 명확한 메시지를 표시하세요.
프롬프트는 웹 code의 일반 문자열이므로, 출시 후에도 Capgo Live Update 사용하기 를 통해 개선할 수 있으며, 새로운 App Store 빌드를 기다릴 필요가 없습니다. 플러그인 업그레이드를 포함한 네이티브 code 변경 사항은 여전히 스토어 릴리스가 필요하며, 이는 Capgo 빌드.
자주 발생하는 오류 및 해결 방법
| 증상 | 예상 원인 | 해결 방법 |
|---|---|---|
readiness “Device is not eligible” 상태 |
iPhone 15 Pro 이전 모델 또는 미지원 iPad | 기능 숨기기 또는 서버 모델 사용 |
readiness “not enabled” 상태 |
사용자가 Apple Intelligence를 꺼둔 경우 | 설정 안내 표시, 재개 시 재확인 |
readiness “Model is not ready” 상태 |
모델 다운로드 중 | 준비 중 상태 표시, 나중에 재시도 |
sendMessage “error deviceNotEligible error” 거부 |
준비 상태 확인 없이 전송 | 게이트 켜기 getReadiness() 먼저 |
| “채팅을 찾을 수 없음” | 새 채팅 전에 생성된 채팅 setModel 호출 |
호출 시 setModel 채팅이 지워지면 새로 만드세요 |
| 채팅 응답 중 | 스트리밍 중 두 번째 메시지 전송 | ~까지 입력 비활성화 aiFinished |
generationError 컨텍스트 윈도우 언급 |
채팅이 너무 깁니다 | 요약과 함께 새 채팅 시작 |
| Foundation Models 관련 빌드 오류 | Xcode 26보다 오래된 버전 | Xcode 업데이트 또는 클라우드 빌드 |
마무리
Apple Intelligence는 iOS 26의 모든 지원 iPhone에 무료, 프라이빗, 오프라인 언어 모델을 제공합니다. Capacitor 앱은 몇 줄의 TypeScript로 이를 사용할 수 있습니다. 모델을 선택하고 UI를 조건부로 getReadiness() 제어하고, 각 작업을 짧은 개별 채팅으로 유지하며, 스냅샷을 UI에 스트리밍하고, 거부 및 컨텍스트 오류를 일반적인 결과로 처리하세요. 하이브리드 앱에서 AI 기능 배포에 대한 더 넓은 관점은 여기서 확인하세요. 왜 Capacitor가 AI 모바일 앱에 적합한지.