Apple Foundation Models

1 week ago 24
  • Claude for Foundation Models는 Apple Foundation Models 프레임워크에서 Claude를 서버 측 언어 모델로 쓰게 하는 Swift 패키지이며, LanguageModelSession API로 응답, 스트리밍, 가이드 생성, 도구 호출을 동일하게 다룸
  • 요청은 앱에서 Claude API로 직접 전송되며, Apple은 요청 경로에 없고 프롬프트나 응답을 보지 못함
  • 패키지는 OS 27 베타의 Foundation Models 서버 측 언어 모델 API를 대상으로 하는 베타이며, 일반 제공 전 API가 바뀔 수 있음
  • 개발 중에는 API 키를 직접 전달할 수 있지만, 출시 앱에 키를 포함하면 추출될 수 있어 프로덕션에서는 프록시를 통해 요청해야 함
  • Apple 온디바이스 모델은 빠르고 비공개이며 오프라인에서 작동하고, Claude는 더 큰 컨텍스트, 프런티어 추론, 웹 검색·코드 실행 같은 서버 측 도구가 필요할 때 쓰임

개요

  • Claude for Foundation Models는 Apple의 Foundation Models 프레임워크에서 Claude를 서버 측 언어 모델로 사용할 수 있게 하는 Swift 패키지
  • 패키지는 Claude를 프레임워크의 LanguageModel 프로토콜에 맞추며, Apple 온디바이스 모델에 쓰는 LanguageModelSession API를 그대로 사용함
    • respond(to:), 스트리밍, 가이드 생성, 도구 호출이 같은 방식으로 작동함
  • 요청은 앱에서 Claude API로 직접 이동하며, Apple은 요청 경로에 없고 프롬프트나 응답을 보지 못함
  • 사용량은 Anthropic 계정에 표준 API 가격으로 청구되며, 앱은 Claude와 Apple 온디바이스 모델 중 어떤 모델을 각 세션에 넘길지 결정함
  • 이 패키지는 범용 Messages API 클라이언트가 아니며, 공개 표면은 Foundation Models 제공자 적합성과 관련 설정 타입인 ClaudeLanguageModel, ClaudeModel, AuthMode, ClaudeServerTool임

베타 및 요구 사항

  • 패키지는 OS 27 베타에서 도입된 Foundation Models 서버 측 언어 모델 API를 대상으로 하며, 일반 제공 전 API 변경이 가능함
  • 실행 대상은 iOS 27, macOS 27, visionOS 27, watchOS 27이며 모두 베타 상태임
  • 개발 환경에는 Xcode 27 베타가 필요함
  • 개발용으로 Claude Console에서 발급한 Claude API 키가 필요하며, 프로덕션 옵션은 인증 방식에 따라 달라짐

설치와 기본 사용

  • Package.swift에 ClaudeForFoundationModels 패키지를 추가함
dependencies: [ .package(url: "https://github.com/anthropics/ClaudeForFoundationModels.git";, from: "0.1.0") ]
  • Xcode에서는 File > Add Package Dependencies… 메뉴에서 저장소 URL을 입력할 수 있음
  • 타깃 의존성에 ClaudeForFoundationModels를 추가한 뒤 FoundationModels와 함께 임포트함
import FoundationModels import ClaudeForFoundationModels
  • ClaudeLanguageModel이 진입점이며, 이를 LanguageModelSession에 넘겨 다른 Foundation Models 제공자처럼 사용함
import FoundationModels import ClaudeForFoundationModels let model = ClaudeLanguageModel( name: .sonnet4_6, auth: .apiKey(ProcessInfo.processInfo.environment["ANTHROPIC_API_KEY"] ?? "") ) let session = LanguageModelSession(model: model) let response = try await session.respond(to: "Plan a 4-day trip to Buenos Aires.") print(response.content)
  • 초기화자는 baseURL, timeout, serverTools도 받으며, baseURL 기본값은 https://api.anthropic.com
  • 저장소의 Examples/ClaudeExample은 터미널로 채팅 턴을 스트리밍하는 실행 가능한 명령줄 타깃이며, --search 플래그로 해당 턴의 서버 측 웹 검색을 활성화함
  • 예제 실행에는 macOS 27 호스트가 필요함

모델과 기능

  • 모델 식별자는 ClaudeModel 값이며, 컴파일된 상수를 쓰거나 아직 패키지에 들어 있지 않은 ID를 명시적 기능과 함께 구성함
ClaudeLanguageModel(name: .opus4_8, auth: auth)
  • 상수는 API 모델 ID를 반영하며, .opus4_8은 claude-opus-4-8에 해당하고 각 모델의 기능 정보를 함께 가짐
  • 새 모델은 패키지 릴리스에서 새 상수로 제공되며, 현재 목록은 Xcode의 ClaudeModel과 Models overview에서 확인함
  • 각 ClaudeModel은 샘플링 파라미터, 노력 수준, 적응형 사고, 구조화 출력, 이미지 입력 등 허용 기능을 선언함
  • 패키지는 모델이 거부하는 필드를 보내면 하드 오류가 발생하기 때문에, 선언된 기능을 기준으로 요청 필드를 결정함
  • 아직 컴파일되지 않은 ID에는 모델이 허용하는 기능을 직접 선언해야 하며, 기능을 추측하는 축약 방식은 의도적으로 없음
let model = ClaudeModel( id: "claude-experimental-x", capabilities: .init(samplingParams: false, effortLevels: [.low, .high]) ) ClaudeLanguageModel(name: model, auth: auth)
  • 노력 수준

    • fixedEffort:로 모든 요청의 Claude effort level을 고정할 수 있음
    • fixedEffort:는 프레임워크의 요청별 추론 힌트보다 우선하며, 프레임워크 추론 수준이 high에서 멈추기 때문에 .xhigh 또는 .max를 요청하는 유일한 방법임
    • effort가 전송되지 않으면 API 기본값은 high임
    ClaudeLanguageModel(name: .opus4_8, auth: auth, fixedEffort: .xhigh)
    • 지정한 수준은 해당 모델이 허용하는 값이어야 함
    • 각 ClaudeModel은 low, medium, high, xhigh, max 중 어떤 수준을 받는지 선언하며, 일부 모델은 effort를 전혀 받지 않음
  • Claude와 온디바이스 모델 선택

    • Apple 온디바이스 모델은 빠르고 비공개이며 오프라인에서 작동하지만, 가벼운 작업에 맞춰진 크기임
    • 더 큰 컨텍스트, 프런티어 추론, 웹 검색과 코드 실행 같은 서버 측 도구가 필요할 때 Claude로 전환
    • 두 모델 모두 같은 LanguageModelSession API를 사용하므로 model: 인자만 바꿔 전환함

인증

  • 자격 증명은 auth: 파라미터로 설정함
  • 개발용 API 키

    • 개발 중에는 API 키를 직접 전달할 수 있음
    ClaudeLanguageModel(name: .sonnet4_6, auth: .apiKey("YOUR_API_KEY"))
    • 앱에 포함된 키는 배포 바이너리에서 추출될 수 있으며, 키를 추출한 사용자는 해당 계정으로 과금되는 요청을 만들 수 있음
    • .apiKey는 개발 전용으로 쓰고, 출시 전에는 프록시로 전환해야 함
  • 프로덕션 프록시

    • 프로덕션에서는 .proxied로 자체 백엔드를 통해 요청을 라우팅함
    • baseURL의 릴레이가 서버 측에서 Claude API 자격 증명을 추가하므로 앱에는 키가 포함되지 않음
    • 제공한 headers는 모든 요청에 전송되며, 프록시가 호출자를 인증하는 데 사용할 수 있음
    • 프록시에 별도 헤더가 필요 없으면 [:]를 전달함
    ClaudeLanguageModel( name: .sonnet4_6, auth: .proxied(headers: ["X-App-Token": "..."]), baseURL: URL(string: "https://api.yourapp.com/claude";)! )

응답 처리

  • 스트리밍

    • streamResponse(to:)는 응답을 점진적으로 반환함
    • 각 요소는 델타가 아니라 지금까지의 응답을 누적한 스냅샷
    let stream = session.streamResponse(to: "Summarize today's top science stories.") for try await partial in stream { print(partial.content) }
  • 구조화 출력

    • 타입에 @Generable을 붙이고 generating:으로 요청하면, 모델이 구조화 출력으로 해당 타입의 값을 반환함
    @Generable struct Trip { @Guide(description: "Destination city") var destination: String @Guide(description: "Length in days") var days: Int } let response = try await session.respond(to: "Plan a trip to Tokyo.", generating: Trip.self) print(response.content.destination)
    • 구조화 출력에는 해당 기능을 가진 모델이 필요하며, 컴파일된 모든 상수는 이를 지원함
    • 선택한 모델이 구조화 출력을 지원하지 않으면 패키지는 조용히 성능을 낮추지 않고 LanguageModelError.unsupportedGenerationGuide를 던짐

도구와 멀티모달

  • 클라이언트 측 도구

    • 프레임워크의 tools: 배열은 그대로 작동함
    • 타입을 Tool에 맞추고 LanguageModelSession에 넘기면, Claude가 도구를 호출할 때 프레임워크가 기기에서 해당 도구를 실행함
    let session = LanguageModelSession(model: model, tools: [FindRestaurantsTool()])
  • 서버 측 도구

    • 서버 도구인 웹 검색, 웹 가져오기, 코드 실행은 Anthropic 인프라에서 단일 왕복 안에 실행되며, 기기에서 프레임워크가 호출할 작업이 없음
    • 서버 도구는 serverTools:로 모델별 설정함
    let model = ClaudeLanguageModel( name: .sonnet4_6, auth: auth, serverTools: [ .webSearch(maxUses: 5), .codeExecution, ] )
    • .webSearch와 .webFetch는 선택적으로 allowedDomains, blockedDomains, maxUses를 받음
    • 서버 도구 활동은 트랜스크립트에서 ClaudeServerToolSegment 커스텀 세그먼트로 드러남
    • serverTools는 LanguageModelSession이 아니라 ClaudeLanguageModel에 설정되며, 세션 타입이 Apple 소유이기 때문임
    • 대화별로 다른 서버 도구 구성이 필요하면 여러 ClaudeLanguageModel 인스턴스를 만들어야 함
  • 이미지 입력

    • 이미지 입력 기능을 가진 모델은 프레임워크의 비전 기능을 선언함
    • 이미지 콘텐츠는 프레임워크의 표준 세션 API로 전달하며, 패키지가 이를 Claude API의 이미지 형식으로 변환함
    • 이미지 요구 사항은 Vision 문서를 따름

오류 처리와 제한 사항

  • 오류 매핑

    • 패키지는 맞는 항목이 있을 때 Claude API 오류를 Apple의 LanguageModelError 사례로 매핑함
    • 컨텍스트 창 초과는 .contextSizeExceeded, HTTP 429는 .rateLimited, 설정된 제한 시간을 넘긴 요청은 .timeout으로 드러남
    • 프레임워크에 대응 항목이 없는 제공자 오류는 ClaudeError로 드러남
    • 제품 흐름 제어에는 패턴 매칭을 사용할 수 있음
    do { let response = try await session.respond(to: prompt) print(response.content) } catch ClaudeError.missingCredential { // Prompt for an API key. } catch let error as LanguageModelError { // Framework-shaped errors (rate limits, guardrails, context length, decoding). } catch { // Transport errors. }
    • 일반적인 패턴은 .rateLimited를 잡아 해당 턴을 SystemLanguageModel로 폴백하거나, 요청을 큐에 넣거나, 재시도 수단을 표시하는 방식임
  • Foundation Models 프로토콜 밖 기능

    • 패키지는 Foundation Models 제공자 프로토콜이 표현할 수 있는 Messages API 기능만 노출함
    • Apple 프로토콜에 표현 방식이 없는 기능은 이 패키지를 통해 사용할 수 없음
    • 프롬프트 캐싱 제어는 불가능하며, 패키지가 프롬프트 캐싱을 자동 적용하지만 캐시 TTL과 중단점 위치는 설정할 수 없음
    • 중지 시퀀스는 사용할 수 없음
    • 배치 처리는 사용할 수 없음
    • Files API는 사용할 수 없음
    • 토큰 카운팅은 사용할 수 없음
    • 베타 헤더는 사용할 수 없음

라이선스와 기여

  • 패키지는 Apache 2.0 라이선스를 따름
  • 버그 리포트는 GitHub 이슈로 받을 수 있음
  • 베타 기간에는 외부 풀 리퀘스트를 받지 않음
Read Entire Article