
Foundation Modelsのマルチモーダル機能で画像解析してみた
Foundation Modelsフレームワークではかねてよりテキスト生成ができていた。しかし、クラウドLLMではよく使われる「画像を入力して解析させる」使い方はできなかった。
WWDC26でFoundation Modelsにマルチモーダル機能が新たに追加され、画像をプロンプトに組み合わせられるようになった。どんな画像解析ができるのか気になり試してみることにした。
本記事では、Foundation Modelsのマルチモーダル機能を使って画像解析をおこなう手順を紹介する。同じような検証をしてみたい方の参考になれば幸いだ。
検証環境
- MacBook Pro (Apple M2 Pro)
- macOS Tahoe 26.4.1
- Xcode 27.0 Beta
- iPhone 17 Pro Simulator(iOS 27.0 Beta)
- iPhone 16e 実機(iOS 27.0 Beta)
Foundation Modelsのマルチモーダル機能について
Foundation Modelsフレームワークは、WWDC25で登場したApple Intelligenceを搭載したデバイスでオンデバイス推論を実現するフレームワークだ。少し前にリルオッサ氏が「try! Swift Tokyo 2026」でFoundation Modelsを使って日記の内容を絵文字に置き換える方法を紹介していた。
テキスト生成だけでなく、画像を含むマルチモーダルなプロンプトにも対応している。画像解析に使える主なユースケースとしては以下が考えられる。
- 画像の内容を説明するキャプション生成
- 画像に写っているオブジェクトの識別
- 画像に関する質問への回答(Visual Q&A)
ただし、動作にはApple Intelligenceに対応したデバイスが必要だ。対応デバイスについてはApple公式ページを参照してほしい。
実装手順
手順1:プロジェクトの準備
Xcodeで新しいiOSプロジェクトを作成し、FoundationModelsフレームワークを使用する。追加のSPM依存関係は不要で、システムフレームワークとして利用できる。
Info.plistには特別な設定は不要だが、Apple Intelligenceが有効になっているデバイスを使用する必要がある。
まずはサンプルコードを実行するためにボタンをタップしたら処理を実行してテキストで表示する簡単な画面を追加する。action1() の部分にはこれから説明する処理を追加することを想定している。
import SwiftUI
import FoundationModels
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
Text(text)
Button("Run", action: action1)
}
}
func action1() {
// ここに Foundation Models の処理を追加する
}
}
また解析対象の画像を .xcassets に追加するのを忘れないようにしておこう。ここでは和田家の愛犬「まろにー」の写真を使う。

公園を散歩したときに撮影したもので、私が緑色のTシャツを着て、まろにーを抱いている写真だ。果たしてこの写真を解析させたときにどのような回答を生成するだろうか。
手順2:セッションの作成
SystemLanguageModel.defaultでデバイスのデフォルトモデルを取得する。isAvailableで利用可能かどうかを確認してから使用するようにする。以降のコードはすべてaction1()内に追記していく。
// Apple Intelligence対応デバイスかどうかを確認
guard SystemLanguageModel.default.isAvailable else {
text = "Apple Intelligenceが利用できません"
return
}
let session = LanguageModelSession()
手順3:画像付きプロンプトの構築
手順2で作成したsessionを使ってリクエストを送る。テキストとAttachmentをresult builder構文でまとめて渡す。result builder構文とは、複数の要素をクロージャの中に並べるだけで1つのプロンプトとして構成できるSwiftの記法だ。
現行ベータ版ではAttachmentのイニシャライザは CGImage とファイル URL の2種類のみが実装されている。UIImage を使う場合は .cgImage プロパティで変換してから渡す。
Task {
// 解析対象の画像
let uiImage = UIImage(named: "SampleImage")
// UIImage → CGImage に変換(UIImageはAttachmentに直接渡せない)
guard let cgImage = uiImage?.cgImage else {
text = "画像の読み込みに失敗しました"
return
}
do {
let response = try await session.respond {
"この画像に何が写っていますか?日本語で説明してください。"
Attachment(cgImage)
}
text = response.content
print(response.content)
} catch {
text = "エラー: \(error.localizedDescription)"
print("エラー: \(error)\n\(String(reflecting: error))")
}
}
以下のような解析結果が返ってきた。出力のばらつきを確認するため、同じプロンプトを4回実行した。カッコの中の秒数は実行前後のDate()の差分で計測した処理時間で、長文ほど処理時間が長い傾向があった。
| 回答 | 処理時間 |
|---|---|
| この画像には、人が小さな犬を抱えている様子が写っています。犬は黒と茶色の毛で、鼻が黒く、目が青く、耳が大きく、体は細いです。背景には芝生と木々が見えます。 | 3840.7 ms |
| この画像には、小さな犬が人の腕の中にいます。 | 2736.5 ms |
| この画像には、小さなチワワ犬が人間の腕の中にあります。 | 2584.1 ms |
| この画像には、小さな犬を抱いている人の姿があります。犬は黒と茶色の毛を持っています。背景には緑の木々が見えます。 | 3050.1 ms |
同じ画像・プロンプトでも毎回表現が変わり、「チワワ」と犬種まで判定する回とそうでない回がある。LLMらしい確率的な挙動だが、オンデバイスでも同様の振る舞いをすることが確認できた。
手順4:構造化出力を使った解析
@GenerableマクロをSwiftの構造体や列挙型に付与することで、モデルの出力をその型のインスタンスとして受け取ることができる。フレームワークが型情報をJSONスキーマに変換してモデルに渡す仕組みだ。
@Guideマクロはプロパティの意味をモデルに自然言語で伝えるためのもので、必須ではない。プロパティ名が十分に明確であればモデルが意図を理解できる場合もある。ただし出力品質を上げたい場合や、生成する値の範囲を制御したい場合に使用する。
@Guideのdescriptionは公式ドキュメントのサンプルに倣って英語で記述する。モデルへの指示として英語の方が正確に意図が伝わると考えられるためだ。
@Generable
struct ImageAnalysisResult {
@Guide(description: "A description of the image content")
var description: String
@Guide(description: "A list of detected objects in the image")
var detectedObjects: [String]
@Guide(description: "The dominant colors visible in the image")
var dominantColors: [String]
}
なお、@Generable型の情報はコンテキストウィンドウを消費する。プロパティ数が多い・@Guideの記述が長いほど消費量が増えるため、不要なプロパティは省く・プロパティ名を簡潔にするといった工夫が有効だ。
ImageAnalysisResultはファイルのトップレベル(ContentViewの外)に定義する。
このImageAnalysisResultを使って解析した結果は以下の通りだ。ContentViewにaction2()を追加し、ボタンのアクションをaction1からaction2に切り替えて確認する。
func action2() {
// Apple Intelligence対応デバイスかどうかを確認
guard SystemLanguageModel.default.isAvailable else {
text = "Apple Intelligenceが利用できません"
return
}
let session = LanguageModelSession()
Task {
// 解析対象の画像
let uiImage = UIImage(named: "SampleImage")
// UIImage → CGImage に変換(UIImageはAttachmentに直接渡せない)
guard let cgImage = uiImage?.cgImage else {
text = "画像の読み込みに失敗しました"
return
}
do {
let response = try await session.respond(
generating: ImageAnalysisResult.self
) {
"この画像を解析してください。日本語で説明してください。"
Attachment(cgImage)
}
print(response.content.description)
print(response.content.detectedObjects)
print(response.content.dominantColors)
} catch {
text = "エラー: \(error.localizedDescription)"
print("エラー: \(error)\n\(String(reflecting: error))")
}
}
}
以下の解析結果が得られた。
人がチワワの犬を抱えている様子。
["犬", "人間"]
["黒", "茶色", "緑"]
動作確認
現行ベータ版ではシミュレータで画像解析が動作しないため、実機で確認する(詳細はトラブルシューティングを参照)。
実機でApple Intelligenceが有効になっていることを事前に確認する。
- 設定アプリ →「Apple Intelligence & Siri」→「Apple Intelligence」をオンにする
- 言語・地域が英語(US)など対応言語になっていることを確認する
- モデルのダウンロードが完了するまで待つ
上記の準備ができていれば、ボタンをタップすると数秒後にレスポンスが返ってくる。オンデバイスで処理されるため、外部ネットワークへの通信は発生しない。
注意事項
入力画像のサイズ
フレームワークがモデルへの送信前に自動でスケーリング・カラー変換を行うため、事前の変換は不要だ。ただし画像が大きいほど消費トークン数が増加するため、レスポンス速度やコンテキストウィンドウの観点で大きな画像には注意が必要だ。
日本語プロンプト
プロンプトを日本語で書いても動作するが、レスポンスの言語はプロンプトの指示に依存する。日本語で回答させたい場合は「日本語で答えてください」と明示するとよい。
トラブルシューティング
ModelManagerError 1001 が発生する
iOSシミュレータで実行したところ、以下のようなエラーが発生した。
Error Domain=FoundationModels.LanguageModelError Code=-1
└─ ModelManagerServices.ModelManagerError Code=1001
Vision用モデルコンポーネントが存在しない場合に発生する。SystemLanguageModel.default.isAvailable はテキスト生成モデルの準備状態しか確認しないため、このチェックをパスしていてもVision機能では発生しうる。
現行ベータ版では、画像解析を含むVision機能はシミュレータで動作しない。実機で試すことで解消する。
まとめ
Foundation Modelsのマルチモーダル機能を使うことで、オンデバイスでの画像解析をシンプルなAPIで実装できた。サーバーへのアップロードが不要なため、プライバシーに配慮したアプリ開発に活用できると感じている。
一方で、Apple Intelligenceに対応したデバイス・Xcodeのベータ版が必要という制約があり、現時点では開発環境の準備に手間がかかる。正式リリース後は対象デバイスも広がっていくため、今後に期待したい。
マルチモーダルAPIを試してみたい方の参考になれば幸いだ。








