用 App Intents 适配 Shortcuts 与 Spotlight:Use Model 是今年的重头戏
Develop for Shortcuts and Spotlight with App Intents
2025年6月9日
一句话判断
Shortcuts 今年最大的变化是 Use Model action——用户可以在快捷指令中直接调用 Apple Intelligence 模型,而你的 App Entity 会被序列化成 JSON 传给模型推理。这意味着你的实体定义不仅决定了 UI 展示,还决定了模型能”看到”什么信息。
这场 Session 讲了什么
三个板块:Use Model action、Spotlight on Mac、Automations on Mac。
Use Model action:用户可以选择 Private Cloud Compute 服务器模型、设备端模型或 ChatGPT。模型输出可自动推断类型(比如 If action 需要 Boolean,模型会自动返回 yes/no)。支持三种输出类型——Text(支持富文本 Attributed String)、Dictionary(结构化数据提取)、App Entity(过滤/转换实体列表)。支持 Follow Up 功能,用户可以在初始请求后与模型来回对话调整输出。
App Entity 与模型的交互:传入实体列表给模型时,实体会被序列化为 JSON。序列化包含三部分:所有 Shortcuts 暴露的属性(转为字符串)、Type Display Representation 的名称、Display Representation 的 title 和 subtitle。这意味着实体暴露的信息量直接决定了模型推理的质量。
Spotlight on Mac:App Intents 现在可以直接在 Spotlight 中运行。要求:参数摘要必须包含所有无默认值的 required 参数、intent 不能被标记为隐藏。支持建议填充(Suggested Entities / All Entities)、搜索查询(Entity String Query / Indexed Entity)、前台/后台执行模式分离(通过 Opens Intent 关联)。
Automations on Mac:个人自动化带到 Mac,新增文件夹和外置硬盘自动化类型。只要 intent 在 macOS 可用,就能用于自动化。
值得深挖的点
Entity 序列化策略需要重新审视。以前设计 Entity 时,重点是 UI 展示和 Shortcuts 参数。现在 Use Model action 会把你的实体属性全部序列化给模型——这意味着属性名、属性值的可读性、title/subtitle 的信息密度都直接影响模型推理效果。你需要同时为”人看”和”模型看”两个受众设计实体。
Indexed Entity 协议是连接 Spotlight 和 Shortcuts 的桥梁。以前需要分别实现 Entity Query 和 Core Spotlight 索引。现在通过 indexingKey 参数将实体属性关联到 Spotlight attribute key,系统会自动生成 Find action。对于没有对应 attribute key 的属性,用 customIndexingKey 指定自定义 key。
富文本输出的无损传递。如果你的 app 支持富文本(比如 Bear 笔记 app),intent 的文本参数应该使用 AttributedString 类型。模型输出的富文本(加粗、斜体、列表、表格)可以无损地传入你的 app。这是一个容易被忽略但对用户体验影响很大的细节。
前台/后台 intent 分离是 Spotlight 体验的关键。后台 intent 在 Spotlight 中执行完就结束(比如”创建事件”),前台 intent 会打开 app 到特定页面(比如”打开事件”)。通过让后台 intent 返回前台 intent 作为 OpensIntent,用户可以选择”创建后打开”或”静默创建”。
代码片段
// 1. 让 Entity 属性对模型可见
struct EventEntity: AppEntity {
static let typeDisplayRepresentation = TypeDisplayRepresentation(name: "Calendar Event")
@Property(title: "Event Title")
var title: String
@Property(title: "Start Date")
var startDate: Date
// Entity 的 display representation 也会被序列化
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "\(title)")
}
}
// 2. Indexed Entity:关联 Spotlight 属性
struct EventEntity: IndexedEntity {
// title, subtitle, image 自动关联 Spotlight attribute
@Property(title: "Event Title")
var title: String // 自动映射
@Property(title: "Notes")
var notes: String // 无对应 attribute key
// 用 indexingKey 关联已有的 attribute key
// 用 customIndexingKey 关联自定义 key
}
// 3. Spotlight 中的后台/前台 intent 分离
struct CreateEventIntent: AppIntent {
static var openAppWhenRun: false // 后台执行
func perform() async throws -> some IntentResult {
let event = createEvent()
// 返回前台 intent,用户可选择打开
return .result(opensIntent: OpenEventIntent(event: event))
}
}
最佳实践
-
重新审视你的 Entity 属性。从”模型能理解什么”的角度审查每个属性——属性名应该自解释,属性值应该是人类可读的字符串。模型看到的是 JSON 序列化结果,不是你的代码。
-
富文本参数用 AttributedString。如果 app 支持富文本编辑,intent 的文本参数必须用 AttributedString 类型,否则模型输出的格式会丢失。
-
参数摘要包含所有必要信息。Spotlight 依赖参数摘要展示 intent——所有无默认值的 required 参数都必须出现在摘要中,否则 intent 不会在 Spotlight 中显示。
-
为每个参数提供 Suggestions。大列表用
suggestedEntities(比如未来一天的日历事件),有限集合用allEntities(比如时区列表)。没有建议的参数字段在 Spotlight 中体验很差。 -
考虑 Follow Up 对 workflow 的影响。Use Model action 的 Follow Up 功能让用户可以在模型输出后继续对话——这意味着你的 intent 需要能处理比预期更丰富或格式不同的输入。
还什么值得关注
- Use Model action 支持 ChatGPT,用户可以利用其广泛的世界知识
- 模型输出 Dictionary 类型适合从非结构化数据(PDF、网页)提取结构化信息
- App Intents Travel Tracking App 示例代码在 developer.apple.com 上提供了完整实现参考
isDiscoverable设为 false 或assistantOnly设为 true 的 intent 不会出现在 Spotlight 中- 没有 perform 方法的 widget 配置 intent 也不会显示在 Spotlight