-
使用 App Schemas 打造智能 Siri 体验
利用 App Intents,将你 App 的内容和操作带到 Siri。通过 App Entities 对数据进行建模,使用 App Schemas 实现强大的系统操作,并为依托 Apple 智能的自然语言交互提供支持。探索如何启用语义搜索、跨 App 执行操作,以及利用屏幕感知和内容传输功能打造贴合情境的用户体验。了解一些最佳做法和测试工具,助你构建快速、可靠的 Siri 体验。
章节
- 0:00 - Introduction
- 1:06 - What's new in Siri
- 4:06 - Contributing content with App Entities
- 6:21 - Entity resolution and IndexedEntity
- 9:49 - Making actions available
- 12:03 - Adopting a schema domain in UnicornChat
- 15:39 - Moving content across apps
- 16:00 - Working across apps: onscreen awareness
- 21:09 - Best practices
- 24:18 - Testing your integration
- 26:21 - Next steps
资源
- Integrating your messaging app with Apple Intelligence
- Donating your app’s data and actions to the system
- Making app entities available in Spotlight
- Making actions and content discoverable by Apple Intelligence
- Providing contextual cues to Apple Intelligence and Siri
- Apple Intelligence and Siri AI
- Messages
- App schema domains
相关视频
WWDC26
-
搜索此视频…
你好 我是Dan Niemeyer Swift Intelligence Frameworks团队的软件工程师 今天 我将向你展示 如何将你的App接入Siri 利用由Apple Intelligence 驱动的全新功能 在27版本中 Siri变得更强大 更懂上下文 也更个人化 App Intents是实现这一切的基础
今天我将介绍以下内容 首先介绍Siri和App Intents的新功能 Siri如何理解你App中的内容 以及当Siri理解你的内容后 如何让它采取相应操作
在演讲最后 我将介绍一些使用场景 用于跨App协作 比如让Siri给我妻子 发送她的机票信息 或为这张照片 添加电影效果滤镜 并分享一些最佳实践 教你如何将App接入Siri 通过扩展系统对 你App功能的理解
好了 内容很多 让我们开始吧
在27版本中 Siri迈出了重要一步 由Apple Intelligence驱动 这是我们的个人智能平台 帮助人们更具创造力 在工作中更高效 作为开发者 你参与 Apple Intelligence的方式 是通过App Intents框架 App Intents是将你的App 整合到Siri的基础 以及Apple Intelligence 并提供了一种结构化方式 来描述你的App能做什么 以及它所管理的内容 今天我讲的所有内容 都建立在App Intents之上
如果你对App Intents不熟悉 强烈建议从这些视频开始 这些视频更深入地 介绍了基础知识
今年 Siri在三个 关键方面变得更强大 Siri现在可以访问 你App中的实体 即App内部真正有意义的内容 这意味着人们可以这样提问: "我的下次会议是何时何地?" Siri可以通过理解直接回答 你App中"会议"的含义 哪个会议最相关 以及应返回哪些属性 比如时间和地点
Siri可以使用你App的Intent 执行操作 例如 有人可以说: "把我的最新报告发给Mary" 这样 用户只需开口 就能发送邮件 Intent描述了你App支持的操作 它们所需的参数 以及何时可以安全运行 Siri负责处理语言理解 你的App专注于执行操作
Siri还可以理解 屏幕上的内容 例如 用户可以这样说: "解释这段文字" 或者:"获取这个产品的评价" 当你用描述屏幕内容的实体 标注视图时 Siri就能理解 哪些内容是有意义的 它代表哪些实体 以及适用哪些操作 这为用户提供了 更具上下文感知的对话体验 感觉自然 且功能强大
这就是Siri的新功能预览 包括如何查找内容 执行操作 以及理解屏幕上的内容 现在是时候将这些内容 在实际App中落地了
在视频的剩余部分 我将在 名为UnicornChat的示例App中演示
UnicornChat是一款消息App 用户可以在其中 与虚构的独角兽角色聊天 比如Bubbles、Flare和Glow 它具备足够的功能来演示 我今天要介绍的概念 虽然它是一款消息App 但同样的思路适用于 许多其他领域的App 你可以从Apple Developer网站 下载示例App 并跟着学习 了解了新功能和演示用的App后 让我们来谈谈如何将 这些功能引入你的App 所有这些App Intents驱动 体验的核心 是一个单一概念——App实体 AppEntity是一种结构化表示 用于描述App内部的内容 为了让这更具体 想想你的App每天处理的数据
如果你有一个日历App 每个日程就是一个实体 如果你有一个邮件App 每条消息就是一个实体 如果你有一个照片App 每张照片和相册都是实体
App实体描述了三个重要方面 它是什么 如何识别它 以及哪些属性重要 比如标题 日期或某些文本
它们不是新的数据模型 而是描述现有内容的方式 让系统能够理解它
建模实体是第一步 但仅凭这一点 还不足以让Siri 找到或谈论它 为了让Siri理解实体是什么 它代表哪类事物 你的实体需要遵循AppSchema
App Schema为Siri提供了 对常见概念的预定义理解 比如消息 联系人或文档 当你的实体遵循某个Schema时 Siri就已经知道如何对它们进行推理
与其将你的App视为黑盒 Siri可以推理用户在谈论什么 在UnicornChat中 App中的名词 是Contact、Conversation和Message 三者都被建模为 符合App Schema的App实体 这使得Siri能够理解以下问题: "显示Flare发来的最后一条消息" Flare是我们的联系人之一 或者"打开UnicornChat与Glow聊天" Glow是另一个独角兽好友
一旦你将内容建模为App实体 下一个问题就是 Siri如何找到正确的那个?
实体解析是Siri将用户语言 解析为App内真实实体的方式
例如 当用户说: "打开UnicornChat与Glow聊天" Siri会解析Glow 指的是某个特定的独角兽 找到匹配的联系人 并填入该实体 以及其属性的值 比如名称和标识符 以便系统可以使用它 但人们并不总是用 精确的名称来提问 他们用概念和描述来表达 当有人这样说: "Carmel最棒的风帆冲浪" 他们并不是在寻找 精确的文本匹配 他们在表达含义 为了支持这种体验 Siri需要的不只是字符串匹配 它需要语义搜索 这正是IndexedEntity所实现的
支持实体解析的主要方式 是通过采用IndexedEntity 这样 你App的实体将被 索引到系统语义索引中 这让Siri能够基于含义 而非仅仅文本进行匹配 理解实体之间的关系 甚至回答关于你内容的问题 例如:"显示我与Flare 关于电影的消息" 这不是字符串匹配 Siri可以找到 提及电影名称的消息 因为它正对UnicornChat的 索引消息执行语义查询 实现这种行为的方式 是让已应用Schema的实体 遵循IndexedEntity协议
indexingKey告诉Spotlight 哪些属性(比如消息正文) 应该是可搜索的
一旦建立索引 Siri就能 搜索你的内容并进行推理 并用它来回答问题 而不仅仅是检索条目
IndexedEntity通过语义匹配 提供最佳Siri体验 减少追问 提升自然语言理解能力 但并非所有内容都能被索引 你的数据集可能很大 存储在服务器上 或者变化太频繁 无法提前建立索引 在这些情况下 可以使用EntityStringQuery 使用字符串查询时 Siri会将用户输入传给你 你的App负责查找 匹配实体并返回结果
你无法获得语义理解 但可以完全掌控 如何搜索和匹配 你App的实体
综合以上内容 首先将你App的内容 建模为App实体 让每个实体遵循AppSchema 这样Siri就能理解 它是哪类事物 当你的数据可以建立索引时 采用IndexedEntity 或者当索引不可行时 使用EntityStringQuery 这将解锁强大的体验 例如回答问题 以及即时查找内容 但实体本身只是信息 真正有趣的地方 是将实体与操作结合时
App Intents是你的App 向系统公开操作的方式 但重要的是要知道 并非所有操作都以相同方式处理 因此我们将分两部分来讲
当你定义App Intent时 该操作可在整个系统中显示 比如Shortcuts、Spotlight Widgets等地方 这意味着用户可以发现 并触发你App的操作 在许多地方 甚至无需Siri
你描述操作的功能 定义其参数 并实现相应行为 系统会负责呈现它 建议它 并将其 整合到系统体验中 这极其强大 为你的App提供了极大价值 以及为使用它的用户 但通过额外几个步骤 你可以提供更多价值 将你的操作接入Siri
就像实体通过App Schema 被理解一样 操作通过Schema 成为Siri可执行的 可以把Schema理解为 App Intents的专门化 它们仍然是App Intents 但以Siri能处理的方式塑造
Schema定义了Siri理解的操作类型 它所期望的结构 以及这些操作 如何映射到自然语言 这让Siri能够自信地处理 以下命令: "发消息给Mary" 或"播放我的专注播放列表" 单个Schema定义单个操作 但App通常需要完整的一组 这就是为什么Schema 被分组为AppSchema域 每个域代表一类任务 例如邮件 照片 消息等 当你集成某个域时 你需要实现 一组预定义的App Schema 你将它们映射到App的功能 Siri立即就知道 如何在该域中谈论你的App 可以将域视为你的App 与Siri之间的合约类别 它们告诉Siri你的App能做什么 有哪些可用操作 以及系统应如何响应
有关App Schema工作方式的更多详情 请查看我在WWDC24的视频
现在我们了解了 通用App Intents与 Siri专属App Schema之间的区别 让我们通过采用其中一个域 将其付诸实践 在UnicornChat中 进行端到端的实现
和之前一样 一切都从实体开始 在UnicornChat中 我们已经建模了 发送消息所需的两个实体
Contact代表收件人 并公开名称和标识符等属性
还有Message 它包含 消息正文和作者等信息
这些是App实体 告诉Siri消息发给谁 以及发送什么内容 现在 让我展示如何 将这些实体连接到操作 通过采用App Schema
在Xcode中 我们首先输入Schema名称 Xcode已经知道 所有可用的App Schema 按域分组 自动补全让我们 精确选择所需的Schema
由于我们正在构建消息功能 我们从消息域中 选择sendMessage Schema
我们不需要发明 自定义Intent结构 而是采用Siri已经理解的Schema 并将其映射到 UnicornChat的现有逻辑 这告诉Siri该操作的功能 以及它期望的参数 比如收件人和消息内容 以及在缺少信息时 如何引导用户
我们的工作是将这些Schema参数 映射到UnicornChat的现有消息流程 首先 我们处理参数
然后将它们传入 UnicornChat的界面 使消息得以实际发送
最后 我们将新发送的消息 作为App实体返回给系统
就这样
由于这个操作是 作为App Intent实现的 它在整个系统中都可用 由于它遵循消息域中的App Schema Siri可以直接执行它 而无需你自己 处理自然语言 让我们看看实际效果
我说:在UnicornChat中 发消息给Glow 内容是“你推荐什么电影?"
Siri通过我们的AppEntity查询 解析出Glow 调用我们的Intent并发送
无需打开App
这就是App Schema的强大之处 一旦实体就位 你将它们连接到 定义明确的操作 Siri负责处理其余事项
总结一下 App Intents向系统公开操作 App Schema使这些操作 能够被Siri理解 像消息这样的App Schema域 将Schema打包成 强大的端到端体验 一旦你采用某个域 Siri就能流畅地理解你的App
目前我们专注于 Siri如何理解你的内容 以及在你的App内执行操作 但许多真实场景下的请求 会涉及多个App
它们从一个App开始 在另一个App中继续 并在其他地方完成 例如:"嘿Siri 把Bubbles的这条回复 发邮件给我妻子" 这些体验结合了两项能力 理解用户正在查看的内容 以及将该内容移至另一个App
让我们将其分为两部分来讲 首先 Siri需要理解 Bubbles的这条回复指的是什么 这就是屏幕感知 然后 Siri需要将该内容 传入另一个App 以便执行某个操作 这就是内容传递 我们逐一来看 为了启用屏幕感知 你的App将屏幕上可见的内容 与系统能理解的 结构化信息连接 其核心是App实体 当视图与实体关联时 Siri可以解析 "这条消息"等引用 或"那段对话" 而无需用户明确说出名称 有两个API用于 标注屏幕上的内容 它们用途不同 当屏幕上有一个主要内容时 使用UserActivity 比如查看文档或撰写消息
当多个有意义的条目 同时可见时 使用视图标注 比如对话中的消息 或列表中的条目
以下是实现方式 列表中的每一行 都代表App中的真实数据 在UnicornChat中 那就是一条消息 每条消息行都标注了 对应的消息实体 这明确地将屏幕内容 与相同的实体连接起来 即我们已用于Intent的实体 这让用户可以这样说: "编辑这条消息" 或"转发最后一条" Siri直接从视图解析实体 实现强大的App内体验 但真正的强大之处是 将标注与内容传递结合时
内容传递让其他App 能够对你的实体执行操作 你通过使用Transferable 导出实体来实现这一点 这告诉系统 如何表示你的内容 以其他App能理解的形式 例如:"把这段对话 发短信给我妻子" 或"总结这条消息"
你通过采用Transferable 并提供IntentValueRepresentation来实现 在UnicornChat中 我们将 ContactEntity导出为IntentPerson 导出后 系统可以将该内容 传入其他App的操作中 这实现了"拨打这个联系人" 等使用场景 你的App不需要知道 接下来会发生什么 它只需要准确描述 自己的内容
当内容进入你的App时 通常有两种情况 要么该内容指向 已经存在的某样东西 要么它代表全新的内容 你决定App采用哪种方式 如果要匹配已有内容 使用IntentValueQuery 如果要创建新内容 使用transferRepresentation 上的importing
当传入内容应解析为现有App实体时 使用IntentValueQuery 即你App中已有的实体 从概念上讲 这与实体查询非常相似 但范围限定于Intent参数 而非独立的实体解析
在此示例中 UnicornChat从 另一个App接收到IntentPerson 并尝试将其匹配到 现有的ContactEntity 当内容已存在于你的App中时 这是理想选择 或者你想从现有数据中进行选择 你本质上是在说: 给定这个传入的值 它指向我的哪个实体?
当传入内容应创建新内容时 使用IntentValueRepresentation的importing 在你的App中 与其解析为现有实体 不如将传入的值 转换为全新的App实体 在UnicornChat中 这让我们 能够创建新的独角兽 在需要时从IntentPerson创建 从用户角度来看 内容就是能用 但你的App始终掌控 该内容如何存储和管理
因此在导入内容时 如果内容已存在于你的App中 就解析它 如果不存在 就导入它 许多App会根据Intent 和工作流程两者兼用
总结一下 屏幕感知让Siri 理解用户正在查看的内容 内容传递让该内容 在App之间流转 两者结合 解锁了 强大的多步骤体验 所有这些都建立在App实体上 App Intents和Schema之上 现在我们已介绍了实体 操作 以及跨App协作 让我们来谈谈最佳实践 除了让功能正常运行外 还有一些实践 能让Siri与你的App 配合得更好 并随时间推移更加稳健 因为虽然你可以独立采用 各个Schema和API 出色的Siri体验通常取决于 这些部分如何协同工作 好消息是你不必独自摸索 工具的设计是为了 在这一过程中帮助你 让我通过演示来说明
让我们回到Xcode 从上次中断的地方继续 在上一个演示中 我们在 UnicornChat中采用了sendMessage Schema 效果很好 用户可以通过Siri发送消息 但现在 让我们尝试构建
我们遇到了构建错误 Xcode告诉我们 虽然采用了sendMessage 但我们尚未采用 相关的draftMessage Schema 这很重要 因为某些Siri场景 需要多个Schema 才能提供完整的体验 这不仅仅是编译器错误 而是一个设计提示 Xcode知道 如果你的App 可以通过Siri发送消息 它还需要一种起草消息的方式 尤其是在需要确认时 因此构建系统会提前显示这个问题 而不是在运行时静默失败
如果我们点击错误 Xcode会提供修复建议
Xcode生成draftMessage Schema 的示例采用代码 这提供了一个Intent定义
所需的参数 以及一个存根实现 全部正确连接 接下来只需填入 App特有的部分 首先 我们将Intent连接到实体
然后 注入依赖项
接下来 处理输入
最后 打开消息创建视图
由于此操作会改变UI状态 需要在主Actor上运行
现在 当我们重新构建时 构建成功了
我们完成了Schema的采用 Siri现在拥有所需的一切 来引导用户完成 完整的消息流程
要记住的重要一点是 如果Siri体验 依赖于多个Schema Xcode会告诉你 缺少什么 并帮你生成 正确的剩余步骤 这使得构建完整 高质量的集成变得更加容易 一旦你采用了Schema 测试就变得至关重要 最佳起点是AppIntentsTesting 这是一个新的测试框架 让你可以测试Intent 完全隔离地运行 无需涉及Siri 你可以调用Intent 传入参数 并验证结果 就像其他集成测试一样 这是验证业务逻辑 最快且最可靠的方式 在开发早期
请观看讲座 《Validate your App Intents adoption with AppIntentsTesting》 以了解更多
一旦你的逻辑稳固 下一步是Shortcuts App Shortcuts为你的Intent 提供了结构化UI 让你检查参数 调整输入 并了解你的操作 如何呈现给用户 这是你验证Intent形态的地方 不仅是它的功能 还有它的配置和公开方式 接下来 转到Spotlight Spotlight是你 验证内容集成的地方 确保你的实体被正确索引 可被发现 且可链接 这帮助你确认 Siri能找到正确的数据 在Siri尝试对其执行操作之前
最后 使用Siri测试完整体验 这是一切汇聚之处 自然语言 实体解析 屏幕上下文 以及跨App工作流程 端到端测试确保 所有内容协同工作 符合用户的预期
此时 你已了解如何 用App实体建模内容 使用App Intents和App Schema 公开操作 启用跨App工作流程 以及使用工具 放心地构建和测试 让我们用几个 具体的后续步骤来总结
以下是入门方法 将实体建模并索引到Spotlight 让Siri能找到你的内容 采用与你App核心体验 相匹配的App Schema域 采用Transferable 启用内容导入和导出 并使用AppIntentsTesting 尽早且频繁地测试 然后是Shortcuts、Spotlight和Siri 所有这些API今天都可用 它们的设计是为了随之扩展 随着你的App一起 随着Siri持续发展
Siri变得越来越强大 越来越懂上下文 功能也越来越丰富 App Intents是 实现这一切的基础 将你的App接入Siri 不只是添加语音支持 你让你的App更快 更易访问 在整个系统中 更易使用 感谢观看 我们迫不及待地 想看看你会构建什么
-
-
7:59 - Contributing message content to Apple Intelligence
// Contributing message content to Apple Intelligence @AppEntity(schema: .messages.message) struct MessageEntity: IndexedEntity { // The text content of the message @Property(indexingKey: \.textContent) var body: AttributedString? } -
8:36 - An interface that locates entities using arbitrary string input
// An interface that locates entities using arbitrary string input struct ContactQuery: EntityStringQuery { func entities(matching string: String) async throws -> [ContactEntity] { let predicate = #Predicate<Person> { person in person.name.localizedStandardContains(string) } let descriptor = FetchDescriptor<Person>(predicate: predicate) let matches = try modelContext.fetch(descriptor) return matches.map(\.entity) } } -
17:19 - Working across apps - View annotations
// Working across apps - View annotations List { ForEach(messages) { message in MessageRow(message: message) .appEntityIdentifier( EntityIdentifier( for: MessageEntity.self, identifier: message.id ) ) } } -
18:18 - Working across apps - Exporting content to another app
// Working across apps - Exporting content to another app extension ContactEntity: Transferable { static var transferRepresentation: some TransferRepresentation { IntentValueRepresentation( exporting: \.person ) } } -
19:21 - Working across apps - IntentValueQuery
// Working across apps - IntentValueQuery struct ContactEntityQuery: IntentValueQuery { func values(for input: [IntentPerson]) async throws -> [ContactEntity] { let names = input.map(\.displayName) let descriptor = FetchDescriptor<Contact>() let contacts = try model.mainContext.fetch(descriptor) let matches = contacts.filter { contact in names.contains(where: { name in contact.name.localizedStandardContains(name) }) } return matches.map(\.entity) } } -
20:00 - Working across apps - IntentValueRepresentation
// Working across apps - IntentValueRepresentation extension ContactEntity: Transferable { static var transferRepresentation: some TransferRepresentation { IntentValueRepresentation(exporting: \.person, importing: { intentPerson in let contact = Contact(importing: intentPerson) ContactManager.shared.contacts.append(contact) return contact.entity }) } }
-
-
- 0:00 - Introduction
How App Intents bring your app to Siri, made more capable, contextual, and personal by Apple Intelligence in the 27 releases. Previews the agenda: what's new, contributing content, making actions available, working across apps, and best practices.
- 1:06 - What's new in Siri
Siri gains three capabilities built on App Intents: accessing your app's entities, taking action through your intents, and understanding onscreen context. Introduces the UnicornChat sample app used throughout the session.
- 4:06 - Contributing content with App Entities
Model your app's content as App Entities (what a thing is, how it's identified, and which properties matter), then conform them to an App Schema so Siri understands the category of content.
- 6:21 - Entity resolution and IndexedEntity
How Siri resolves spoken references to real entities. Adopt IndexedEntity for semantic search and content Q&A over indexed content, using indexingKey to mark searchable properties, or EntityStringQuery when data can't be indexed ahead of time.
- 9:49 - Making actions available
App Intents expose actions across Shortcuts, Spotlight, and Widgets. Conforming intents to App Schemas, and grouping them into App Schema domains, makes those actions executable by Siri through natural language.
- 12:03 - Adopting a schema domain in UnicornChat
End-to-end walkthrough of adopting the Messages domain's sendMessage schema: mapping schema parameters onto UnicornChat's messaging flow and returning the sent message as an entity, so Siri can send messages without opening the app.
- 15:39 - Moving content across apps
Export entities with Transferable and IntentValueRepresentation so other apps can act on them. On import, use IntentValueQuery to match existing content or IntentValueRepresentation(importing:) to create something new.
- 16:00 - Working across apps: onscreen awareness
Requests that span apps rely on onscreen awareness. Connect views to App Entities, via NSUserActivity for a single primary item or view annotations for multiple visible items, so Siri can resolve references like "this" and "that."
- 21:09 - Best practices
Design for complete Siri conversations by adopting full schema sets. Xcode surfaces missing related schemas (for example draftMessage alongside sendMessage) at build time with Fix-Its.
- 24:18 - Testing your integration
Validate progressively: App Intents Testing for business logic in isolation, then the Shortcuts app for intent shape, Spotlight for content indexing, and finally Siri for the full end-to-end experience.
- 26:21 - Next steps
Model and index entities, adopt the App Schema domains matching your app, enable content transfer with Transferable, and test early with Shortcuts, Spotlight, and Siri.