ハイライト
3 つのトピック: Use Model action、Spotlight on Mac、Automations on Mac。
主要内容
Shortcut を書いていて一番煩わしいのは、フォーマットが噛み合わずに次の action に繋がらないことです。モデルが文章を返してきても、次の action は Boolean を要求するので、結局パース用のステップを挟むことになります。PDF から金額や日付を抽出するには正規表現を書く必要がありますし、ChatGPT が出力したリッチテキストを Bear のようなノートアプリに貼り付けると、太字や表組みは丸ごと失われてしまいます。こうした「のりしろのステップ」が Shortcut の大半を占めており、ユーザーが途中で諦めてしまう典型的な原因にもなっています。
WWDC25 における解決策が、新しい Use Model action (01:20) です。この action を使うと、Shortcut から Apple Intelligence のモデルを呼び出せます。選択肢は Private Cloud Compute のサーバーモデル、オンデバイスモデル、または ChatGPT です。開発者体験を本当に左右するのは、後続の action との繋ぎ込み方です。次の action が Boolean を要求していれば、ランタイムが自動的にモデルの出力を yes/no に変換します。構造化されたフィールドが必要なら Dictionary を、App Entity が必要なら渡された entity リストの中からモデルが該当するものを選び、App Entity として返してくれます。開発者側でコードを書き換える必要はありませんが、entity が十分な情報を露出していることは前提になります。なぜなら、モデルが見ているのは entity の JSON 表現だからです。
モデル系の action 以外に、このセッションでは Mac 専用の話題も 2 つ取り上げられています。Spotlight から App Intent を直接実行できるようになった (10:43) こと、これまでの「検索だけ」の枠を超えた点。そして Personal Automations が Mac に上陸 (17:18) し、フォルダや外付けドライブといった新しいトリガータイプが加わったことです。この 2 つに共通する前提条件は同じで、App Intent が十分整っていること、つまりパラメータサマリーが完備されていて、entity が find action を露出しており、リッチテキスト系のパラメータには AttributedString が使われていることです。
詳細
モデルから App Entity がどう見えるか (06:51)。entity リストをモデルに渡すと、システムは各 entity を JSON にシリアライズしてモデルに食わせます。JSON には次の 3 つが含まれます。
- Shortcuts に露出しているすべての entity プロパティ (すべて文字列に変換されます)。
- Type Display Representation の name。これはどの種類のものなのかをモデルに伝えます (たとえば “Calendar Event”)。
- Display Representation の title と subtitle。
つまり、Shortcuts 上で表示されるものが、そのままモデルから見えるものです。id と title しか露出していなければ、モデルは「開始時間」を基準に予定をフィルタすることはできません。
Find action の 2 通りの実装方法 (08:06)。モデルに entity を渡すには、まず Find action が必要です。アプローチは 2 つあります。
- 手書きの query:
EnumerableEntityQueryとEntityPropertyQueryを実装する。 - Spotlight インデックス経由: entity に
IndexedEntityを実装し、新しい API で entity のプロパティを Spotlight の attribute key に紐付けると、Find action がシステムによって自動生成されます。
後者のアプローチには今回新しい API が追加されました。indexingKey と customIndexingKey (09:05) です。前者は既存の Spotlight 属性キー (たとえば予定タイトルなら eventTitle) にプロパティをマッピングし、後者は既存のキーが存在しないプロパティ (たとえば独自の notes) のために使います。
struct EventEntity: IndexedEntity {
@Property(indexingKey: \.title)
var eventTitle: String
@Property(customIndexingKey: "notes")
var notes: String
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Event")
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "\(eventTitle)", subtitle: "\(notes)")
}
}
ポイント:
IndexedEntityプロトコルにより、entity は Core Spotlight インデックスと Shortcuts の Find action の両方に同時に乗ります。indexingKey: \.titleはeventTitleを Spotlight 既存のタイトル属性キーに関連付け、システムはこれを元に「タイトルで検索する」Find action を生成します。customIndexingKey: "notes"は文字列でカスタムキーを定義します。Spotlight の組み込み属性キーが存在しないフィールド向けです。typeDisplayRepresentationの name (“Event”) は、モデルに渡される JSON にタイプヒントとして書き込まれます。displayRepresentationの title と subtitle も JSON に入ります。モデルが読み取れる詳細情報は、まさにここで表示しているフィールドです。
Intent を Spotlight に表示させるための 2 つの必須条件 (12:34):
- パラメータサマリー (parameter summary) は「デフォルト値のない required パラメータ」をすべて含んでいる必要があります。1 つでも欠けると、その intent は Spotlight から消えます。
- Intent が非表示にされていないこと。
isDiscoverable = false、assistantOnly = true、または widget の構成専用 (perform メソッドのない) intent は、Spotlight に出てきません。
たとえば新たに required な notes パラメータを追加したものの、サマリーに書き忘れた場合、その intent は消えてしまいます。修正方法は 3 通りで、サマリーに書き加える、optional に変更する、デフォルト値 (空文字列など) を与える、のいずれかです。
バックグラウンドとフォアグラウンドの分離実行 (16:20)。Spotlight ユーザーには「サクッと済ませたい」場合 (バックグラウンドで予定を作るだけ) もあれば、「結果を見たい」場合 (アプリにジャンプして作成された予定を確認する) もあります。Apple は intent を 2 つに分けることを推奨しています。バックグラウンド intent (たとえば CreateEventIntent) を実行し、その後 Opens Intent でフォアグラウンド intent (たとえば OpenEventIntent) を関連付ける、という形です。こうすれば同じ動作をバックグラウンドでも走らせられますし、必要なときにはアプリを前面に持ってくることもできます。
Follow Up (09:50)。Use Model action には Follow Up トグルがあります。これを有効にすると、最初の結果が返ってきた後にユーザーが追加で一言入力して出力を調整できます (デモでは「double the recipe」と入力していました)。開発者への影響としては、intent が受け取る入力が一回限りのリクエストよりも豊富かつ整っていない可能性があるという点です。
Automations on Mac (17:18)。Mac 専用のトリガーとしてフォルダ (folder) と外付けドライブ (external drive) の 2 種類が追加されました。これに加えて、iOS から引き継がれた Time of Day や Bluetooth などのトリガーも使えます。ルールはシンプルで、intent が macOS で利用可能でありさえすれば、Mac 自動化に組み込めます。Mac にインストールできる iOS アプリの intent も対象です。
重要ポイント
-
「モデルに何が読めるか」から逆算して entity を設計する: 各
@Propertyで露出するプロパティ、displayRepresentationの title/subtitle、typeDisplayRepresentationの name、これらすべてが JSON にシリアライズされてモデルに渡されます。なぜ取り組む価値があるか: モデルは JSON を元に推論するため、露出されていないフィールドはほぼ存在しないも同然です。どこから始めるか: コアな entity を 1 つ取り上げ、現状の JSON 表現を出力してみて、「この JSON だけを見て、フィルタやソートができるか」を自問し、不足を補っていきましょう。 -
リッチテキスト系のパラメータはすべて AttributedString に置き換える: モデルは太字、リスト、表組みをよく出力します。なぜ取り組む価値があるか: String で受け取ってしまうと、モデルが生成したフォーマットがそのまま静かに失われ、ユーザー体験が突然劣化します。どこから始めるか: コードベース内のすべての intent のテキストパラメータを洗い出し、アプリ内部で元々リッチテキストをサポートしているもの (ノート、メール、ドキュメント) については、型を
StringからAttributedStringに変更し、What’s New in Foundation で紹介された新しい API と組み合わせて使います。 -
パラメータサマリーを監査して intent を Spotlight に乗せる: Spotlight on Mac は無料の流入口ですが、intent が整っていないと載りません。なぜ取り組む価値があるか: Mac ユーザーは毎日 Cmd+Space を何十回と叩きます。そこから直接 action を実行できるというのは、相当な流量になります。どこから始めるか: すべての intent をリストアップし、パラメータサマリーがデフォルト値のない required パラメータをカバーしているかを 1 つずつ確認しましょう。漏れているものは、サマリーに書き加えるか、optional に変更するか、デフォルト値を補ってください。
-
バックグラウンド/フォアグラウンドの 2 つの intent に分け、
Opens Intentで繋ぐ: 単一の intent では、毎回アプリを開く (うっとうしい) か、決して開かない (結果が見えない) かのどちらかになりがちです。どこから始めるか: 「作成系」の action を 1 つ選び (予定を作る、タスクを追加する、家計簿に記入する、など)、新たにOpenXxxIntentを作って、元の intent の perform でOpensIntentを返してそこに関連付け、ユーザーの入口に応じてどちらの経路を取るか決めるようにします。 -
すべてのパラメータに Suggestions を補完する: Spotlight でパラメータフィールドを開いたのに何の候補も表示されない、というのはユーザーをその場で離脱させる典型例です。どこから始めるか: 大きなリスト (予定、メール、ドキュメント) には
EntityQueryのsuggestedEntitiesを実装します (たとえば「これから 24 時間以内のカレンダーイベント」)。有限集合 (タイムゾーン、通貨、言語) にはEnumerableEntityQueryのallEntitiesを実装します。動的検索が必要ならEntityStringQueryを補うか、IndexedEntityを採用してシステムに任せましょう。
関連セッション
- Code-along: Bring on-device AI to your app using the Foundation Models framework — Foundation Models を使い、SwiftUI アプリにオンデバイス AI 機能を組み込みます。
- Deep dive into the Foundation Models framework — Guided generation、tools、安全性ポリシーまで踏み込んで解説しています。
- Design interactive snippets — App Intent から呼び出されるコンパクトなビュー。entity の情報をシステム各所で再利用できます。
- Bring advanced speech-to-text to your app with SpeechAnalyzer — SpeechAnalyzer の新しい API。音声書き起こしを intent フレンドリーな入力ソースに変えます。
コメント
GitHub Issues · utterances