3つのサーフェス:人間、Apple Intelligence、エージェント
iOS 26以降のiOSアプリにおいて、意味のあるすべての機能は、最大3つのサーフェスから呼び出される可能性があります。コップ1杯の水を記録する同じSwift関数が、ボタンをタップする人間によって、Siriリクエストをルーティングする Apple Intelligence によって、あるいはMCPツールを呼び出す外部エージェント(Claude Code、Cursor、ChatGPT)によってトリガーされ得ます。3つの異なる呼び出し元、3つの異なる責務、3つの異なるレンダリングサーフェス。機能は同じでも、サーフェスは違うのです。
iOSアーキテクチャの間違いの多くは、1つのサーフェス向けに設計したものを他のサーフェスへ無理やり押し込もうとすることから生まれます。UIフローがSiriのレスポンスに漏れ出したり、開発者にとって正しいエージェントツールがエンドユーザーにとっては危険になったり、オンデバイスのLLM機能がクラウドレベルのコンテキストを前提としたり。このクラスターでは、これらのサーフェスを個別の記事で整理してきました。本稿はその統合です。3つのサーフェス、その違い、ルーティングの原則、そしてどれも妥協させずに3つすべてに応えるためにアプリのドメイン層がどう見えるべきか。
メンタルモデルはこうです。あるドメイン機能を選びます。3つのサーフェスのうち、どれが呼び出せるべきかを問います。どれが実際に呼び出せるのかを問います。各サーフェスがその機能から何を必要とし、その機能がサーフェスに何を返さねばならないのかを問います。その答えがアーキテクチャを形作ります。
TL;DR
- 3つのサーフェス:人間(SwiftUIビュー、タップ、ジェスチャ、画面)、Apple Intelligence(App Intents、Siri、ショートカット、Spotlight)、エージェント(MCPサーバー、外部のLLMホスト)。
- 各サーフェスには異なる責務があります。信頼姿勢、レイテンシ予算、レンダリング場所、永続化のセマンティクス、エラーハンドリング、アクセシビリティ要件。
- 正しいアーキテクチャは、サーフェスの下に置かれたドメイン層です。各サーフェスは同じSwift関数の薄いアダプターであり、関数は型付きの
Caller引数を受け取って、サーフェスごとのプロトコル詳細を知らずにクロスサーフェスのルール(レート制限、監査、確認)で分岐できます。 - すべての機能が3つのサーフェスすべてに対応するわけではありません。どのサーフェスに載せるかの判断こそが設計判断です。持つべきでないサーフェスから機能を隠すことは、持つべきサーフェスに公開することと同じくらい重要なプロダクトの決断です。
サーフェス1:人間
人間サーフェスは画面です。ユーザーはアプリを見て、タップし、スクロールし、ドラッグし、スワイプし、入力します。フレームワークはSwiftUI(あるいはUIKit、visionOS上の一部ワークロードではRealityKit)です。レンダリングはユーザーのデバイス上、アプリプロセス内で、ユーザーの選んだカラースキーム、Dynamic Typeサイズ、アクセシビリティ設定に対して行われます。1
人間サーフェスが機能から必要とするもの:
- 視覚的なアフォーダンス。 ボタン、リスト行、スワイプジェスチャ、コンテキストメニュー。機能はアプリのナビゲーションを通じて発見可能で、UIの他の部分と一貫したスタイルでなければなりません。
- リアルタイムなフィードバック。 すべてのインタラクションには即座の視覚的レスポンスが必要です。長時間処理を発火するボタンは、進捗インジケーター、有効/無効状態、アニメーションを示さなければなりません。
- アクセシビリティ。 VoiceOverラベル、Dynamic Typeのサポート、コントラスト、運動制御の代替手段。人間サーフェスは、ユーザーがレンダリングと直接やり取りするため、最も厳しいアクセシビリティ要件を持ちます。
- エラーの可視性。 エラーはユーザーの視界に届きます。保存失敗はアラートを表示し、ネットワークタイムアウトは再試行を提示し、権限拒否は設定リンクを示します。
人間サーフェスが機能に返すもの:
- 曖昧さのないユーザー意図。 ユーザーは特定のボタンをタップしました。機能は何が要求されたかを正確に知っています。推論層はありません。
- タイトなレイテンシ予算。 タップから数百ミリ秒以上経っても可視のレスポンスが返らないと壊れているように感じられます。機能は速いか、すぐに進捗を示すように設計されているかのどちらかでなければなりません。
- 外部権威の不在。 ユーザーはアプリ内におり、ユーザーが(緩い意味での)エージェントです(人間がアクションを駆動する側)。サードパーティのLLMもシステムエージェントもなく、ユーザーの手だけがあります。
人間サーフェスは3つのうち最も歴史が長いものです。iOS 7以降にプラットフォームが蓄積してきたあらゆるiOSフレームワーク、デザインパターン、アクセシビリティルールは、このサーフェスのためにあります。他の2つのサーフェスは比較的新しく、パターンはまだ落ち着き切っていません。
サーフェス2:Apple Intelligence
Apple Intelligenceサーフェスはシステムエージェントです。Siri、ショートカット、Spotlight、システムサジェストのスタック。ユーザーが話しかけたり、Spotlightに入力したり、ショートカットでアクションを連結したりすると、システムはApp Intentsフレームワークを通じてリクエストをルーティングし、マッチするAppIntentを見つけ、パラメータを解決し、インテントのperform()本体を実行します。フレームワークはApp Intentsです。2
Apple Intelligenceサーフェスが機能から必要とするもの:
- 型付きのスキーマ。
AppIntent型は@Parameterプロパティを宣言し、AppEntity型はシステムが言及できるオブジェクトに永続的なアイデンティティを与え、AppEnum型は閉じた選択肢の集合に名前を付けます。システムはインストール時にスキーマを読み取ります。 - アプリプロセスを超えて存続するアイデンティティ。 ユーザーが昨日Siri経由で記録した水分エントリは、今日もSiriから参照できるべきです。
AppEntityモデルは、システムがセッションをまたいでオブジェクトを語る安定した方法を提供します。 - 静かなエラーハンドリング。 エラーはユーザーのビューには届きません。Siriのレスポンス、ショートカットの出力、Spotlightの結果に届きます。システムが期待するエラー形式は、ビジュアルではなく構造化されたもの(Appleの
AppIntentErrorプラスLocalizedErrorに準拠したthrow)です。 - 再試行下での冪等性。 システムはショートカットチェーンの最中や部分的失敗の後に、インテントを再度呼び出すことがあります。状態を変更する機能は、繰り返しの呼び出しに対して安全であるか、明確な「すでに完了済み」というセマンティクスを表面化する必要があります。
Apple Intelligenceサーフェスが機能に返すもの:
- ユーザーの実在のアイデンティティ。 システムはユーザーが誰かを把握し、OS経由で認証を行い、そのコンテキストでインテントを実行します。機能はOSが提供する以上のアイデンティティ検証を行う必要はありません。
- システムレベルのレンダリング。 インテントが返す結果はシステムによって適切なクロムにフォーマットされます(Lock Screenバナー、Siriレスポンスカード、ショートカットの出力)。アプリはレスポンスがどう提示されるかを制御しません。
- コードを実行せずに行われる発見可能性。 App Intentsはアプリが実行されていなくても呼び出されます。システムはスキーマを読み取り、機能を能動的に表面化します。
信頼姿勢:Apple IntelligenceはAppleのファーストパーティエージェントです。ユーザーが設定したのではなく、システムが設定しました。ユーザーはOSを信頼し、OSはアプリがレビューを通じて出荷したApp Intentsスキーマを信頼します。信頼の連鎖はOS → アプリです。App IntentsはrequestConfirmation(...)とフォアグラウンドモード確認をサポートしているため、「本当によろしいですか?」を必要とする機能も技術的にはそこに置けます。高リスクの確認をSiriのターン内に置くか、それともアプリ自身の画面に置くかは、プラットフォーム制約ではなくプロダクトの判断です。元に戻せないもの(アカウント削除、破壊的な一括編集、決済)は、App Intentsが確認を要求できるとしても、通常は人間サーフェスの方が安全です。3
サーフェス3:エージェント
エージェントサーフェスはアプリのドメインを操作したい、それ以外のすべてのLLM駆動システムです。Claude Desktop、Claude Code、Cursor、ChatGPTデスクトップアプリ、Codex CLI、カスタムのエージェントハーネス。フレームワークはModel Context Protocolです。MCPサーバーはアプリのドメインをJSON-RPCのtools/callメソッドで公開し、ホストのLLMはセッション開始時にツールを発見し、名前とJSONペイロードで呼び出します。4
エージェントサーフェスが機能から必要とするもの:
- JSON-RPCの契約。 ツール名、説明、
inputSchema、オプションのoutputSchema。エージェントは説明を読んで呼び出すかを判断し、スキーマに従って引数を整形します。 - 役立つ説明。 モデルはツールの説明を頼りに使用判断を下します。説明は、別の開発者(モデル)が読むことを期待するdocstringのように扱ってください。曖昧な説明は誤ったツール選択を生みます。
- 2つの形を持つエラー。 ツール実行エラーは、モデルが読むツール結果に
isError: trueを付したコンテンツブロックとして返されます。プロトコルレベルのエラー(不正なリクエスト、欠落したツール、トランスポート障害)は、ホストが処理する標準的なJSON-RPCのerrorレスポンスとして返されます。前者はツール作者の責務、後者はプロトコルの責務です。 - ステートレスまたは明示的にステートフルなセマンティクス。 MCPはプロトコル層ではステートフル(セッションのライフサイクル、Streamable HTTPでのセッションID)ですが、永続的なドメインアイデンティティはサーバー側の責任であり、プロトコルレベルの保証ではありません。同じ識別子がセッションをまたいで同じ意味を持つべきなら、サーバーが強制しなければなりません。
エージェントサーフェスが機能に返すもの:
- ホストの認証であって、ユーザーの認証ではない。 信頼はMCPサーバーをデプロイした主体から来ます。開発者のローカルstdio:開発者自身のファイルシステム権限。インターネット到達可能なHTTP:サーバーが強制する認証は何であれ。機能は、アイデンティティの主張が「サーバーが与えたもの」であると想定する必要があります。
- 可変なレイテンシ許容度。 ホストは人間サーフェスやApple Intelligenceサーフェスより長く待てます。30秒かかるツール呼び出しはエージェントサーフェスでは許容されますが、他では許容されません。
- レンダリングサーフェスの不在。 結果はモデルが解釈するテキストか構造化データです。クロムなし、UIなし、システムフォーマットなし。
信頼姿勢:MCPサーバーは誰が呼び出してよいかに関する開発者の契約です。同じサーバーの2つのデプロイ(開発用のローカルstdio、エンドユーザー向けのインターネットHTTP)は、まったく異なる信頼姿勢を持ち、まったく異なるガードレールを必要とします。プロトコルは同じでも、デプロイがアーキテクチャです。詳細はApp Intents vs MCP:ルーティングの問題とLLMがアプリの中に住むとき vs ツーリングの中に住むときで扱っています。5
サーフェスたちが意見を異にする6つの軸
3つのサーフェスを比較表にまとめると、アーキテクチャの判断が具体的になります。
| 軸 | 人間 | Apple Intelligence | エージェント |
|---|---|---|---|
| 呼び出し元のアイデンティティ | ユーザー(アプリ内、OS認証) | ユーザー(OS経由でシステムが解決) | ホストのアイデンティティ主張(サーバーが強制) |
| レイテンシ予算 | 数百ミリ秒 | 数秒(Siriのターンテイク) | 数秒から数十秒 |
| レンダリング | アプリのSwiftUIビュー | システムクロム(バナー、Siriカード、ショートカット) | モデルが解釈するコンテンツブロック |
| 発見 | アプリのナビゲーション | インストール時に読み取られるApp Intentスキーマ | セッション開始時に返されるツールリスト |
| 永続化のセマンティクス | アプリ管理の状態 | セッションをまたぐAppEntityアイデンティティ |
サーバー管理。プロトコルレベルではない |
| エラー形式 | アラート、バナー、ビュー状態 | AppIntentError + LocalizedErrorのthrow |
ツール実行:コンテンツ + isError、プロトコル:JSON-RPC error |
これらの不一致は重なり合います。人間サーフェス向けに設計された機能は、タイトなレイテンシ、リッチなレンダリング、アプリ管理のエラーを前提とします。それをApple Intelligenceに無理やり通すとレンダリング制御を失い、OS仲介のアイデンティティが加わります。エージェントサーフェスに無理やり通すとレンダリングを完全に失い、信頼境界はサーバーをデプロイした主体に移ります。機能は再ラップではなく、再形成されなければなりません。
アーキテクチャの原則:サーフェスの下のドメイン層
3つのサーフェスを通じて生き残るパターンは、その下に置かれたドメイン層です。ドメイン層はプレーンなSwift関数で、型付きの入力、型付きの出力、プロトコルの前提なしです。各サーフェスはドメインの薄いアダプターになります。同じlogWater(amount:caller:)関数が、SwiftUIボタン、App Intentのperform()、MCPツールのハンドラを支えます。
スケッチ(実プロダクションでは、App Intentの戻り値としてWaterEntryをAppEntityに準拠させ、domainをトップレベル参照ではなく依存として注入し、インテントに必要なstatic var titleを追加します):
// Domain layer (the actual capability)
func logWater(amount: Measurement<UnitVolume>, at: Date, caller: Caller) throws -> WaterEntry {
try guards.requireWritePermission(caller)
let entry = WaterEntry(amount: amount, timestamp: at)
try store.insert(entry)
return entry
}
// Adapter A: human surface (SwiftUI button)
Button("Log 250ml") {
Task {
let entry = try await domain.logWater(
amount: .init(value: 250, unit: .milliliters),
at: .now,
caller: .human
)
// Update view state, show confirmation animation, etc.
}
}
// Adapter B: Apple Intelligence surface (AppIntent)
struct LogWaterIntent: AppIntent {
static var title: LocalizedStringResource = "Log Water"
@Parameter(title: "Amount") var amount: Measurement<UnitVolume>
func perform() async throws -> some IntentResult & ReturnsValue<WaterEntry> {
let entry = try domain.logWater(amount: amount, at: .now, caller: .siri)
return .result(value: entry) // WaterEntry conforms to AppEntity
}
}
// Adapter C: agent surface (MCP tool handler)
let entry = try domain.logWater(
amount: .init(value: ml, unit: .milliliters),
at: .now,
caller: .mcp(host: hostName)
)
return .text("Logged \(entry.amount) at \(entry.timestamp)")
3つの呼び出し元、1つのドメイン関数。ドメイン関数はCallerパラメータを受け取り、サーフェスごとに異なるルール(レート制限、監査ロギング、確認要件)を、各サーフェスが再実装することなく強制できます。アダプターは賢くなく、ドメインが賢いのです。
この形はApp Intents vs MCPで示したデュアルアダプターパターンを一般化したもので、人間サーフェスを3つ目の呼び出し元クラスとして加えるのは自然な拡張です。アプリ内で使われるFoundation ModelsのオンデバイスLLMは、人間サーフェス上に位置します(ユーザーがモデルを呼び出すアプリ内機能を起動した形)。ランタイムLLMは4つ目のサーフェスではなく、すでに人間サーフェスに属する機能を実行する1つの方法です。6
すべての機能が3つのサーフェスすべてに対応するわけではない
均等な公開がゴールではありません。機能ごとに、属するサーフェスは違います。
通常はフォアグラウンドの人間の存在を必要とすべき機能。 写真撮影、生体認証、機微なPII入力、決済確認、アカウント削除。人間が画面を見ていて、同意し、認証する必要があります。Apple Intelligenceは技術的にはアプリをフォアグラウンドにして確認を要求できますが、エージェントサーフェスにはそれに相当する存在保証がありません。プロダクト判断としては、これらの機能は静かなSiriやバックグラウンドのツール呼び出しではなく、明示的かつ意図的なアクションを伴うフォアグラウンドUIとして実行されるべきです。
人間 + Apple Intelligenceサーフェスに属すべき機能。 ほとんどのユーザー向けアクション。水を記録する、瞑想を開始する、リストに項目を追加する、火曜日のエントリを見せて。ユーザーはボタンをタップするかもしれませんし、「Hey Siri」と言うかもしれません。両方のサーフェスが妥当で、両方が同じドメイン関数に到達するべきです。
3つのサーフェスすべてに属すべき機能。 プロセスをまたぐ統合。ユーザーのiPhoneと、レシピをインポートするClaude Codeセッションで共有される買い物リスト。人間サーフェスが日常使いを担い、Apple IntelligenceサーフェスがSiri/Spotlightのリーチを担い、エージェントサーフェスが開発者またはユーザー駆動の外部ワークフローを担います。
エージェントサーフェスにのみ属すべき機能。 エンドユーザーのレビューフローを伴わない開発者または管理者の一括インポート、外部システムとの統合、Siriやアプリ内表現を持たないエージェントオーケストレートワークフロー。1回限りのバックフィル中に、開発者のCSVから歴史エントリを500件一括インポートする。 エンドユーザーのファイルインポートはしばしば人間サーフェスのフローを持ちます(ショートカットがファイルを渡せますし、アプリ内インポーターが進捗をチャンク表示できます)。エージェント専用となるのは、他の2つのサーフェスに本当に居場所がないワークフローです。
決断こそ設計です。機能が対応しないサーフェスを列挙することは、対応するサーフェスを列挙することと同じくらい重要です。
自分なら違う形で作るところ
このクラスターのアプリで実際に出荷したか、出荷したかったと思う2つのパターンです。
ドメイン層でCallerを第一級の型にする。 すべての公開ドメイン関数はCaller引数を取ります。型はどのサーフェスが呼び出したかをエンコードします(.human、.siri、.mcp(host:))。ドメインロジックはそれに基づいて、確認プロンプト、レート制限、監査ロギング、機微アクションのゲートを分岐させます。代替案(各サーフェスがルールを再実装する)はドリフトしますが、中央集約版は一貫性を保ちます。
サーフェスカバレッジを明示的なチェックリストとして扱う。 機能を追加するとき、設計ドキュメントは3つのサーフェスのうちどれが公開し、どれが拒否するかをリスト化します。拒否リストはデフォルトではなく、意図的な選択です。拒否:Apple Intelligenceサーフェス。なぜならこの機能はSiriが提供できないユーザーのアテンション証明を必要とするから。 推論が記録され、後の監査でドリフトを捕まえられます。
このパターンがiOS 26+で出荷されるアプリにとって意味するもの
3つのテイクアウェイ。
-
3つのサーフェス、3つの信頼姿勢。 人間、Apple Intelligence、エージェント。それぞれが他にはない責務を持ちます。1つに向けて設計し他に無理やり押し込むと、すべてのサーフェスで悪いアーキテクチャになります。
-
下にドメイン、上にアダプター。 機能ごとに1つのSwift関数、サーフェスごとの薄いアダプター。関数は
Callerパラメータを取り、サーフェス固有のルールを1か所で強制します。 -
すべての機能が3つすべてに対応するわけではない。 持つべきでないサーフェスから機能を隠すことは、公開することと同じくらい設計判断です。拒否リストは存在意義を持ちます。
Apple Ecosystemクラスターの全体像:Apple Intelligenceサーフェス向けの型付きApp Intents、エージェントサーフェス向けのMCPサーバー、両者の間のルーティングの問題、人間サーフェス内のオンデバイスLLM機能向けのFoundation Models、ランタイム vs ツーリングLLMの区別、iOS Lock Screenステートマシン向けのLive Activities、Apple Watch上のwatchOSランタイム契約、人間サーフェスの基盤となるSwiftUIの内部、visionOSシーン向けのRealityKitの空間メンタルモデル、サーフェスをまたぐ永続化のためのSwiftDataのスキーマ規律、人間ビジュアル層向けのLiquid Glassパターン、デバイスをまたぐリーチのためのマルチプラットフォーム出荷。ハブはApple Ecosystem シリーズにあります。AIエージェントを伴うiOSのより広い文脈については、iOS Agent Development guideをご覧ください。
FAQ
iOSアプリの3つのサーフェスとは?
人間サーフェス(SwiftUIビュー、タップ、ジェスチャ、画面)、Apple Intelligenceサーフェス(App Intents、Siri、ショートカット、Spotlight)、エージェントサーフェス(Claude Code、Cursor、ChatGPTのような外部のLLMホストに公開されたMCPサーバー)です。それぞれが固有の呼び出し元アイデンティティ、レイテンシ予算、レンダリング場所、永続化のセマンティクス、信頼姿勢を持ちます。複数のサーフェスに対応したい機能は、サーフェスごとの薄いアダプターの下にあるドメイン層に置くべきです。
すべての機能を3つのサーフェスすべてに公開すべきですか?
いいえ。一部の機能は1つか2つのサーフェスに正しく限定されます。写真撮影、生体認証、機微アクションの確認は、信頼シグナル(ユーザーのアテンション、意図的なアクション)が最も確実に存在するため、通常はフォアグラウンドの人間サーフェスフローとして最も適しています。エンドユーザーのレビューフローが存在しない開発者駆動の一括操作は、エージェントサーフェス単独に属します。設計判断は、機能がどのサーフェスに対応し、どのサーフェスを拒否するかです。
Apple Intelligenceサーフェスとエージェントサーフェスの違いは?
Apple IntelligenceはAppleのファーストパーティエージェントです。ユーザーがSiri、ショートカット、Spotlightを呼び出すと、システムはApp Intentsを通じてルーティングします。信頼はOSから来ます。エージェントサーフェスは、それ以外のすべてのLLMホストです。開発者はClaude CodeやCursorを動かし、エンドユーザーはClaude DesktopやChatGPTを動かします。信頼はMCPサーバーをデプロイした主体から来ます。前者のプロトコルサーフェスがApp Intentsで、後者のプロトコルサーフェスがMCPです。
オンデバイスのFoundation Models LLMはどこに位置しますか?
人間サーフェスの内側です。ユーザーがFoundation Modelsを呼び出すアプリ内機能を起動するとき、ランタイムLLMは人間サーフェス機能の実装であり、4つ目のサーフェスではありません。ランタイムLLMはそれ自身のSiri呼び出しや外部ホスト呼び出しを持ちません。Foundation Modelsツールは、オンデバイスモデルがアプリのドメイン状態を読み書きする方法であり、呼び出しを駆動するのはユーザーです。
ドメイン層のパターンは、マルチサーフェスのコードをどう簡素化しますか?
ルールを中央集約することによってです。1つのSwift関数がCaller引数を取り、サーフェス固有の振る舞い(確認プロンプト、レート制限、監査ロギング)を1か所で強制します。各サーフェスは、サーフェスのプロトコルをドメイン関数に翻訳する薄いアダプター(SwiftUIバインディング、AppIntent.perform、MCPハンドラ)です。真実の源が1つになるため、サーフェス間のドリフトは不可能になります。
参考文献
-
著者の分析、What SwiftUI Is Made Of、2026年4月30日。値型のビューツリー、result-builderのDSL、人間サーフェスを支える基盤を扱っています。 ↩
-
著者の分析、App Intents Are Apple’s New API to Your App、2026年4月28日。
AppIntent、AppEntity、AppEnum、Apple Intelligenceがアプリを操作することを可能にする型付きスキーマモデルを扱っています。 ↩ -
Apple Developer、“App Intents framework”。Apple Intelligence、Siri、ショートカット、Spotlightがルーティングできるインテント、エンティティ、パラメータ、クエリを宣言するためのサーフェス。発見はインストール時とアップデート時に加え、寄贈とインデックスがインテントをSpotlight検索やSiriサジェストに表面化します。 ↩
-
Anthropic、“Model Context Protocol”および“MCP Specification: Tools (2025-06-18)”。JSON-RPCのツール公開、ホスト/サーバーアーキテクチャ、stdio + Streamable HTTPのトランスポート、
inputSchema/ オプションのoutputSchema。 ↩ -
著者の分析、App Intents vs MCP:ルーティングの問題、2026年4月30日、およびLLMがアプリの中に住むとき vs ツーリングの中に住むとき、2026年5月1日。信頼姿勢に関するデプロイ-ノット-プロトコルのフレーミングと、ランタイム/ツーリングLLMの区別。 ↩
-
著者の分析、Foundation Models On-Device LLM: The Tool Protocol、2026年4月30日。人間サーフェス機能を支えるランタイム機能としてのオンデバイスLLM、アプリ内モデルとアプリのドメインを橋渡しする
Toolプロトコル。 ↩