AI Agent开发工具AI 产品与平台

iOS 27 开发者指南:把 App 接进 Siri,在 App 里调用模型

在 iOS 27 里把 AI 能力接进应用,摆在面前的是两条方向相反的路。如果想让 Siri 在系统层面调用应用里的功能,走 App Intents;如果想在应用内部调模型做长文总结、票据提取或者视觉看图,走 Foundation Models。如果之前写过 function calling 或者接过 MCP,这两套接口的角色并不陌生:一套把应用做成工具供外部模型调用,另一套让应用充当调用方去向模型发请求。

这两条路在系统里各有各的跑道。开发者无法把 Siri 的推理引擎替换成自建模型,应用之间也无法跨沙盒直接读取对方的数据。系统架构把这些边界钉得很严,两套接口分别解决各自方向上的工程需求。

两套接口方向相反:App Intents 里你的 App 是供模型调用的工具,Foundation Models 里你的 App 是调用模型的一方

把你的 App 做成 Siri 能调用的工具

用户对着手机说「嘿 Siri,把购物清单里的牛奶删掉」,这句话最终会在应用里触发一个具体函数,参数精准对应到牛奶这条记录。中间的语音识别、意图推断、实体抽取和参数组装都由系统处理。开发者只需要提前声明清楚两件事:应用支持执行什么动作,动作需要操作什么数据(App Intents 文档)。

应用能执行的动作映射为 AppIntent。比如删除清单项就是一个 AppIntent,代码里明确写出它接收哪些输入、触发时运行哪段逻辑。拿 MCP 来对照,这就像 MCP server 里定义的 tool,只是写成了 Swift 原生代码,在编译期就已经确定下来。

动作所操作的数据则映射为 AppEntity。工具参数往往指向特定对象,比如删除具体的哪一条待办、播放哪一首歌曲。AppEntity 会给应用内的数据模型加上系统能认出的唯一标识和若干属性,让用户嘴里说的牛奶能准确对上数据库里的主键。这不需要推翻现有的数据表重新设计,只要给系统补齐一套描述协议。

每个应用都有自己的一套命名习惯,系统不可能去死记硬背每个团队自造的词汇。Apple 的解法是划出 12 个通用领域,涵盖音频、日历、邮件、信息、地图、照片、提醒事项等(完整列表),并为每个领域提前定好了标准动作与数据模板。开发音乐应用时,只要套上音频领域的模板,Siri 自然知道播放、暂停和歌单是什么意思。这相当于官方按分类预置好了工具命名空间,省去了各家自行定义 schema 的成本。

接入这些领域时规则很明确。邮件、信息、时钟这三个领域必须整套接入,不支持挑选个别动作(官方规则)。如果业务场景落在这 12 个领域之外,应用就拿不到 Siri 的自然语言理解能力,只能退回到固定短语唤醒,要求用户念出字字相符的指令口令。动手写代码前,先对照自己的核心场景落不落在这些模板里。

除了把动作注册给系统,还得让 Siri 随时搜得到应用里的数据,这依赖 Spotlight 索引。用户让 Siri 调出上个月的某份会议纪要,Siri 会去查 Spotlight 索引;应用如果没有把这条记录写进去,Siri 就找不到内容。系统还有两条补充通道:一条会在后台自动记录用户在界面里的高频操作习惯,另一条允许应用在特定时机主动通知系统当前某条内容处于活跃状态,详细运行机制可以参考 session 345

写代码时还会碰到几个运行时规则。用户看着屏幕说「打开第三个」,Siri 要看懂屏幕上的所指对象,前提是开发者在界面元素上标注了对应的实体属性(session 343)。Intent 的同步执行时间默认卡在 30 秒以内,视频导出或者大文件转码这类长耗时任务,必须接入专门的长任务接口,并持续向系统推送进度,否则遇到超时或系统资源吃紧,系统会叫停任务(LongRunningIntent)。过去沿用多年的 SiriKit 在 iOS 27 里已经废弃,App Intents 成了系统唯一的接入通道(SiriKit)。

邮件、日历这类热门领域,往往有好几个应用同时注册了相同的操作模板,同一个动作背后站着好几个竞争者。用户下达模糊指令时,调度权在系统编排层,由 Siri 与 Shortcuts 统一分发,第三方应用之间没有互相调用的通道。WWDC26 lab session 8011 原话提到,“There’s no API for a third-party app to invoke another app’s intents directly”,Siri 与 Shortcuts 就是编排者。系统判断拿不准时,会弹出列表让用户手动选;应用自身解析参数遇到歧义,也可以主动抛出 needsDisambiguationError,列出候选结果让用户点击确认。

官方没有公开平局仲裁的具体算分机制,唯一明确提到的加分项是交互捐赠。用户平时在应用里点得越频繁,Siri 做出推断时就越偏向这个应用,session 343 原话提到:“Siri might infer the right app to use for that contact”。用 MCP 的视角来看,多个 server 注册了相同名字的 tool,中间网关如何做意图路由在 iOS 上是个黑盒。光把动作注册进系统只是完成声明,并不保证 Siri 每次都会调用;开发者唯一的抓手,就是让用户在真实生活里高频用起来,靠真实交互记录建立调度优势。

你的应用调用模型

另一类需求的方向正好反过来:这次由应用自己主动调用模型。例如长篇文档摘要、从票据照片中识别金额和日期、或者在应用内通过自然语言检索内容,这类需求对应的是 Foundation Models(框架文档)。

这套框架的核心交互围绕会话 LanguageModelSession 展开。代码里初始化一个会话,递入提示词和可选的图片附件,就能异步取回推理结果。底层模型支持三种来源,对外暴露出统一的调用协议,换模型只需要改动一行配置:

来源 特点 成本
Apple 端侧模型 跑在手机上,离线可用,iOS 27 里重建过,支持图片输入 免费,无限制
Apple 云端 (PCC) 上下文 32K,能力更强 每天有额度;要申请权限,只对首年下载低于 200 万的开发者免费(说明
你自己的模型 实现同一个协议打包进来,Anthropic 和 Google 都发了官方包(session 339 按各家的 API 计费

端侧模型不需要申请任何开发者权限,导入模块就能直接调用(entitlement 列表)。在 macOS 27 上,Apple 还附带了命令行工具 fm,不用编译整个项目,就能在终端里直接向模型发请求调试提示词。

初始化 LanguageModelSession 时如果不显式指定模型参数,系统默认加载的就是端侧模型 SystemLanguageModel.default。多份开发者社区的实测记录都验证了这一默认行为(参见 Create with SwiftArtem Novichkov 的记录)。三种模型来源遵循同一套会话协议,后续想要切换模型,只需要调整构造函数的参数。

在会话里选什么模型,只影响应用自己的内部逻辑,影响不到系统的 Siri。这也是区分两套体系的关键:在 Foundation Models 里,应用充当调用方,可以自行挑选合适的模型提供方;而在 App Intents 那一侧,应用退回到工具位置,静待系统发起调用。

处理具体业务数据时,结构化输出能省去很多麻烦。以往让模型提取字段,往往需要写复杂的正则表达式去解析非结构化文本,现在给 Swift 结构体加上 @Generable 属性宏,模型就会直接生成符合这个类型定义的数据结构,字段类型一旦对不上,在生成环节就会直接报错阻断。

遇到需要动态查询数据的场景,应用可以向会话注册函数,让模型在推理过程中发起工具调用。比如本地存着私有数据库,注册一个查询函数后,模型发现当前上下文缺少必要信息,就会暂停输出并调用这个函数,拿到返回结果后再继续向下推导。这样就省去了把全量数据预先塞进提示词的开销,系统甚至直接内置了文字识别和条形码识别两个现成的 Tool(session 241)。

做不到的:agent 这个角色不在你手上

有些设想从技术上看很自然,但翻遍公开文档也找不到入口。在 iOS 的架构设计里,应用可以充当供系统调用的工具,也可以做调用模型的客户端,但系统级 agent 这个全局协调者的角色始终留在 Apple 自己手里。

能力边界:公开可用的能力、架构上没有接口的能力、官方规则明确禁止的能力

许多人首先会想能不能让 Siri 换用自己的模型。公开 SDK 没有任何注册接口允许开发者把外部模型挂载成 Siri 的推理引擎,替换模型的自由度只存在于应用自身的局部会话里。这容易让人产生误解:在日本市场,系统确实支持把 iPhone 侧边按键设置成启动第三方语音应用,但这只是系统级的快速启动快捷方式,和 Siri 的推理层没有任何关系(说明)。

另一个常见的念头是让应用跨界去读其他应用的数据,比如记账软件直接向银行软件读取近期流水。在 iOS 上,应用之间没有互相调用的通道,所有跨应用的动作都必须由 Siri 居中编排,各个应用的本地数据处于相互隔离的沙盒里(session 8011)。记账软件想越过系统拿到外部数据,在底层走不通。

即便通过 App Intents 接收到了系统分发过来的用户数据,开发者协议也明令禁止将这些信息上传或转存到设备之外(DPLA)。与此配合的还有两条审核红线:应用在运行时不能动态下载并执行改变自身功能特性的代码(审核指南 2.5.2);如果确实要把用户数据发送给第三方 AI 接口,必须在事前明确向用户提示并获得同意。

Apple 把 agent 调度权锁在自己手里,在面向欧盟的公开声明里说明了缘由:如果向外界开放全局控制接口,就相当于允许任意虚拟助手获取用户的私有数据,并能操控其他应用(原声明)。在开放的 MCP 生态里,无论是工具端 server 还是编排端 client 都向开发者敞开;但在 iOS 的世界里,编排者的位置只有 Apple 自己能坐。

时间会花在哪

把基础接口写通其实花不了多少时间。官方日历演示项目用三个 Swift 结构体就能在真机上跑通全套流程(session 344);在调用模型那一侧,几行代码就能完成会话声明并拿到返回。真正消耗工程时间的地方,集中在排查运行时静默失败和应对模型的不稳定性上。

接入 Siri 最大的时间黑洞是排查静默失败。这套系统有大量运行时隐性规则,Swift 编译器只检查语法类型,到了运行时如果违反了这些规则,控制台既不崩溃也不报错,表现出来的现象只是 Siri 对应用没有任何反应。一位反复踩过这类坑的开发者把它压缩成一句话:「Pass the compiler and fail one of those, and you get silence.」(来源)。

排查这类问题之所以费劲,是因为踩坑场景几乎全在控制台视野之外。比如在 Intent 里声明必须前台执行,用户却在锁屏界面唤起语音;触发短语定义得过窄,稍微换个说法就无法匹配;业务数据更新之后,忘记同步通知 Spotlight 刷新索引;或者在更新接口里没有区分字段是传了空值还是原本就没有传参,导致已有数据意外丢失。由于控制台看不到任何堆栈线索,每次排查都只能拿着检查清单一项项比对。

在 Foundation Models 这一侧,时间主要花在与模型的不确定性磨合。端侧模型的上下文窗口只有 4096 token,系统提示词、工具函数定义、历史对话以及生成的输出必须在这个小空间里共享额度,Apple 官方建议单次请求挂载的工具函数不要超过 5 个(管理窗口)。端侧小模型偶尔会出现漏调用工具或凭空编造数值的情况,这类故障在代码层面同样不抛出异常:前几次测试好好的,下一次就因为走偏了分支而给出错误结果,排查时很容易让人误以为是本地数据出了差错。Apple 为此专门提供了评测框架,日常开发必须依赖标注数据集做系统性的质量回归,单靠人工随机提问很难守住稳定性底线(session 241)。

排期推进时,可以按照场景把工作拆开。如果重点是获取 Siri 的语音入口分发,先确认核心功能能不能对应上 12 个领域模板;能套进去就尽早补齐动作和实体声明,把数据写入 Spotlight,并预留充足的精力重点测试锁屏状态和索引同步。如果目的是在应用内部增强业务处理能力,优先从离线免费的端侧模型切入,将单次调用的工具数量控制在 3 个以内,用 @Generable 守住输入输出契约。两套路径彼此独立,可以分头演进。至于替换系统语音助手或跨应用拉取数据,目前并没有公开接口,留待后续版本观察即可。

鸭哥每日手记

日更的深度AI新闻和分析