Claude を Apple の Foundation Models framework から呼ぶ — 公式 Swift パッケージでオンデバイスと Claude を同じ API で切り替える

Anthropic が公式 Swift パッケージ ClaudeForFoundationModels を公開しました。Claude を Apple の Foundation Models framework の『サーバサイド言語モデル』として組み込み、LanguageModel プロトコルに準拠させることで、Apple のオンデバイスモデルと同じ LanguageModelSession API(respond(to:)・ストリーミング・@Generable による構造化出力・ツール呼び出し)でそのまま Claude を駆動できます。iOS 27 / macOS 27 / visionOS 27 / watchOS 27(いずれもベータ)対応。本記事では、導入・認証(開発は APIキー、本番は proxy)・オンデバイス↔Claude の使い分け・サーバサイドツール・機能制約までを Swift のコード付きで解説します。

Anthropic が公式 Swift パッケージ ClaudeForFoundationModels を公開しました。これは Claude を Apple の Foundation Models framework の「サーバサイド言語モデル」として組み込むもので、Claude を framework の LanguageModel プロトコルに準拠させます。つまり、Apple のオンデバイスモデルを叩くのと同じ LanguageModelSession API(respond(to:)・ストリーミング・構造化出力・ツール呼び出し)で、そのまま Claude を駆動できます。iOS 27 / macOS 27 / visionOS 27 / watchOS 27(いずれもベータ)対応。iOS 開発から Claude を使う道が、Apple 純正フレームワークの流儀のまま開けたことになります。本記事では、導入・認証・使い分け・ツールを実装目線で整理します。

到達点

  • ClaudeForFoundationModelsLanguageModelSession API のまま Claude を呼べる仕組みを理解する
  • オンデバイスモデル ↔ Claude を model: の差し替えだけで切り替える設計を掴む
  • 認証の**開発(APIキー)と本番(proxy)**の違いと、鍵を漏らさない構成
  • サーバサイドツール(web search / web fetch / code execution)の組み込み方
  • Apple のプロトコルで表現できない機能(制約)を把握する

何が嬉しいのか

Apple の Foundation Models framework は、アプリからオンデバイスモデルを統一 API で使うための仕組みです。ClaudeForFoundationModels の要点は、その同じ API で Claude(サーバサイド)も呼べるようにしたこと。

  • リクエストはアプリ → Claude API に直接飛ぶ。Apple はリクエスト経路に介在せず、プロンプトも応答も見ません
  • 課金は自分の Anthropic アカウントに標準 API 価格で載る
  • どのモデルを使うかはアプリが決める。セッションごとに「オンデバイス」か「Claude」かを渡すだけ

一番のうまみは、「軽い・速い・オフライン・プライベート」なオンデバイスモデルと、「大きなコンテキスト・フロンティア推論・サーバサイドツール」を持つ Claude を、同じ LanguageModelSession の作法で使い分けられる点です。UI 側のコードを書き換えずに、モデルだけ差し替えられます。

導入

SwiftPM で追加します。

// Package.swift
dependencies: [
  .package(url: "https://github.com/anthropics/ClaudeForFoundationModels.git", from: "0.1.0")
]

FoundationModels と並べて import します。

import FoundationModels
import ClaudeForFoundationModels

要件は iOS 27 / macOS 27 / visionOS 27 / watchOS 27(すべてベータ)Xcode 27(ベータ)、開発用の Claude API キーです。まだベータで、OS 27 ベータで入った「サーバサイド言語モデル API」を対象にしているため、GA までに API が変わる可能性があります。

クイックスタート

エントリポイントは 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)

respond(to:) も、この後で見るストリーミング・構造化出力・ツールも、すべて Apple の framework のメソッドそのままです。Claude 固有の呼び出しは出てきません。

モデル選択と effort

モデル ID は ClaudeModel の値です。コンパイル済み定数(.opus4_8claude-opus-4-8)を使うのが基本で、各定数はそのモデルの capabilities(サンプリングパラメータ・effort・adaptive thinking・構造化出力・画像入力の可否)を持っています。パッケージはこれを見て送ってよいフィールドだけを送る(モデルが拒否するフィールドを送ると hard error になるため)。

effort を固定したいときは fixedEffort: を使います。.xhigh / .max を要求できるのはこの経路だけ(framework 側の reasoning レベルは high 止まり)です。

ClaudeLanguageModel(name: .opus4_8, auth: auth, fixedEffort: .xhigh)

オンデバイスと Claude の使い分け

Apple のオンデバイスモデルは速く・プライベートで・オフラインでも動くが、軽量タスク向けのサイズです。大きなコンテキスト・フロンティア推論・サーバサイドツールが要るときに Claude へ上げる。両者は同じ LanguageModelSession API なので、切り替えは model: 引数の差し替えだけです。

// 軽いタスク → Apple のオンデバイスモデル
let localSession = LanguageModelSession(model: SystemLanguageModel.default)

// 重いタスク → Claude に上げる(UI 側の呼び出しは同じ)
let claudeSession = LanguageModelSession(
  model: ClaudeLanguageModel(name: .sonnet4_6, auth: auth)
)

認証:開発は APIキー、本番は proxy

ここは必ず押さえるべきポイントです。

開発:.apiKey

ClaudeLanguageModel(name: .sonnet4_6, auth: .apiKey("YOUR_API_KEY"))

ただし アプリに埋め込んだ鍵は出荷バイナリから抽出可能で、抜かれればあなたのアカウントに課金されるリクエストを誰でも投げられます。.apiKey開発専用です。

本番:.proxied

本番は自分のバックエンド経由にします。baseURL のリレーがサーバ側で Claude の資格情報を付与するので、アプリは鍵を一切持ちませんheaders は毎リクエストに付くので、proxy 側で呼び出し元を認可できます。

ClaudeLanguageModel(
  name: .sonnet4_6,
  auth: .proxied(headers: ["X-App-Token": "..."]),
  baseURL: URL(string: "https://api.yourapp.com/claude")!
)

proxy は標準の Messages API リクエストを受け取り、x-api-key を付けて https://api.anthropic.com に転送するだけです。リリース前に必ず proxy に切り替える——これが唯一の安全な出荷経路です。

ストリーミングと構造化出力

ストリーミングstreamResponse(to:)。各要素は差分ではなく**「ここまでの累積スナップショット」**です。

let stream = session.streamResponse(to: "Summarize today's top science stories.")
for try await partial in stream {
  print(partial.content)   // 累積スナップショット
}

構造化出力は Apple 流に @Generable を付けた型を generating: で要求するだけ。裏で Claude の structured outputs が使われます。

@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 を投げます(コンパイル済み定数はすべて対応)。

ツール:クライアント側とサーバ側

クライアント側ツールは framework の tools: がそのまま効きます。型を Tool に準拠させて渡せば、Claude が呼んだときに端末上で実行されます。

let session = LanguageModelSession(model: model, tools: [FindRestaurantsTool()])

サーバサイドツール(web search / web fetch / code execution)は、Anthropic 側で 1 往復のうちに実行され、端末側で呼ぶものはありません。ClaudeLanguageModelserverTools: で設定します。

let model = ClaudeLanguageModel(
  name: .sonnet4_6,
  auth: auth,
  serverTools: [
    .webSearch(maxUses: 5),
    .codeExecution,
  ]
)

.webSearch / .webFetchallowedDomains / blockedDomains / maxUses を任意で受けます。serverTools はセッションでなく ClaudeLanguageModel 側に付く(セッション型は Apple のものだから)ので、会話ごとにツールを変えたいなら複数の ClaudeLanguageModel を作る構成になります。

エラー処理とフォールバック

パッケージは Claude API のエラーを Apple の LanguageModelError寄せて返します。コンテキスト超過 → .contextSizeExceeded、HTTP 429 → .rateLimited、タイムアウト → .timeout。framework に対応がないものは ClaudeError として出ます。

do {
  let response = try await session.respond(to: prompt)
  print(response.content)
} catch ClaudeError.missingCredential {
  // APIキーの入力を促す
} catch let error as LanguageModelError {
  // レート制限・ガードレール・コンテキスト長・デコードなど
} catch {
  // 通信エラー
}

定番は、.rateLimited を捕まえてそのターンだけ SystemLanguageModel(オンデバイス)にフォールバックする、あるいはキュー投入・リトライ導線を出す、というパターンです。ここでも「同じ API」であることが効いてきます。

制約(表現できない機能)

このパッケージは Foundation Models の provider プロトコルで表現できる範囲だけを公開します。Apple のプロトコルに対応表現がない機能は使えません

  • プロンプトキャッシュの制御(キャッシュ自体は自動適用されるが、TTL やブレークポイント位置は設定不可)
  • stop sequences
  • Batch processing
  • Files API
  • トークンカウント
  • ベータヘッダ

また ClaudeForFoundationModels汎用の Messages API クライアントではありません。公開面は provider 準拠と設定型(ClaudeLanguageModel / ClaudeModel / AuthMode / ClaudeServerTool)に限られます。生の Messages API が要るなら、別言語の Client SDK を使う話になります。

まとめ

ClaudeForFoundationModels は、「Apple の Foundation Models framework の作法のまま Claude を呼ぶ」ための公式 Swift パッケージです。LanguageModel プロトコルに準拠しているので、respond(to:)・ストリーミング・@Generable 構造化出力・ツール呼び出しがオンデバイスモデルと同じコードで書け、model: の差し替えだけでオンデバイス↔Claude を切り替えられます。

iOS 開発の実務としての勘所は 3 つ — 軽いタスクはオンデバイス、重い/ツールが要るタスクは Claude に上げる、鍵は本番で必ず proxy に逃がす、レート制限はオンデバイスへフォールバックする。まだ OS 27 ベータ前提の beta ですが、「Apple 純正の LLM 抽象の上で、必要なときだけ Claude のフロンティア性能とサーバサイドツールを借りる」——という設計は、iOS アプリに賢さを載せるうえで筋のいい選択肢です。GA を待たずに、検証プロジェクトで触っておく価値があります。