View in English

  • Apple 开发者
    • 入门汇总

    探索“入门汇总”

    • 概览
    • 学习
    • Apple Developer Program

    及时了解最新动态

    • 最新动态
    • 开发者你好
    • 平台

    探索“平台”

    • Apple 平台
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    • App Store

    精选

    • 设计
    • 分发
    • 游戏
    • 配件
    • 网页
    • Home
    • CarPlay 车载
    • 技术

    探索“技术”

    • 概览
    • Xcode
    • Swift
    • SwiftUI

    精选

    • 辅助功能
    • App Intents
    • Apple 智能
    • 游戏
    • 机器学习与 AI
    • 安全性
    • Xcode Cloud
    • 社区

    探索“社区”

    • 概览
    • “与 Apple 会面交流”活动
    • 社区主导的活动
    • 开发者论坛
    • 开源

    精选

    • WWDC
    • Swift Student Challenge
    • 开发者故事
    • App Store 大奖
    • Apple 设计大奖
    • Apple Developer Centers
    • 文档

    探索“文档”

    • 文档库
    • 技术概述
    • 示例代码
    • 《人机界面指南》
    • 视频

    发布说明

    • 精选更新
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • Apple tvOS
    • Xcode
    • 下载

    探索“下载”

    • 所有下载
    • 操作系统
    • 应用程序
    • 设计资源

    精选

    • Xcode
    • TestFlight
    • 字体
    • SF Symbols
    • Icon Composer
    • 支持

    探索“支持”

    • 概览
    • 帮助指南
    • 开发者论坛
    • “反馈助理”
    • 联系我们

    精选

    • 《开发者账户帮助》
    • 《App 审核指南》
    • 《App Store Connect 帮助》
    • 即将实行的要求
    • 协议和准则
    • 系统状态
  • 快速链接

    • 活动
    • 新闻
    • 论坛
    • 示例代码
    • 视频
 

视频

打开菜单 关闭菜单
  • 专题
  • 所有视频
  • 关于

更多视频

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 将 LLM 提供平台引入 Foundation Models 框架

    通过为新模型实现 LanguageModelExecutor,进一步扩展 Foundation Models 框架。探索如何与 LanguageModelSession 的对话记录进行交互、有效管理会话状态,并优化 KV 缓存的利用率。了解如何支持自定分段类型,并为你的生成式 AI 功能解锁高级能力。

    章节

    • 0:00 - Introduction
    • 3:37 - Packaging
    • 4:48 - Protocol
    • 14:50 - Authentication
    • 15:51 - Customization
    • 19:47 - Next steps

    资源

    • Foundation Models
    • Core AI Models
    • MLX Swift LM on GitHub
      • 高清视频
      • 标清视频

    相关视频

    WWDC26

    • 使用 fm CLI 和 Python SDK 构建 AI 驱动的脚本
    • 使用 Foundation Models 框架构建智能体 App 体验
    • 通过专用云计算充分利用 Apple Foundation Model
    • Foundation Models 框架的新功能
  • 搜索此视频…

    你好! 我是Christopher Webb 机器学习研究团队的工程师 我很高兴向你介绍 一种使用Foundation Models框架的新方式 我们之前推出了 Foundation Models框架 让你能够使用 Apple的设备端语言模型 现在 我们正在开放该框架 以支持几乎所有LLM 无论是本地还是基于服务器的 这让所有人 从大型公司 到独立开发者 都能轻松在该框架之上 构建自己的模型集成

    设备端系统语言模型 已从头全面重建 它更智能 更擅长遵循指令 并且可以直接在提示词中 接受图像输入 除了系统模型 我们还新增了三个选项 Private Cloud Compute带来了 Apple 智能许多功能背后的模型 现在支持推理 32K token上下文窗口 以及你所期待的隐私保障 Core AI让你高效运行 本地模型 并充分利用ANE 而MLX则开放了数千个 可用模型 通过Hugging Face上的 MLX-Community

    由于这些都建立在 全新的公共协议之上 开发者可以将前沿AI模型 使用同一框架集成到他们的App中 Anthropic和Google即将扩展 Foundation Models框架 推出各自的Swift包 让最先进的Claude 和Gemini模型 面向所有Swift开发者开放 无论你使用哪种模型 Apple的 你自己的 或社区的 调用方式完全相同 因为每个模型都遵循 Language Model协议 对于App开发者 我将向你展示 如何调用这些模型中的任意一个 通过相同熟悉的API 对于模型提供商 我将引导你创建 自己的Language Model包 但首先 让我向你展示 使用它有多简单 这是我们的设备端Foundation Model 创建它 传入Session 然后调用respond函数 还有更多模型选项 如果你需要更强的算力 试试Private Cloud Compute 只需替换模型即可 如果你想集成自己的模型 只需将CoreAI指向你的资源 如果你想尝试 最新的开源模型 只需传入一个模型ID 让框架处理其余的一切

    使用基于Language Model协议 构建的模型 意味着你可以使用各种出色的 Foundation Models功能 例如Dynamic Profiles 要了解我们新增内容的概览 请观看 《What's new in the Foundation Models framework》

    之所以能如此轻松地 切换模型 是因为每个LanguageModel 都遵循同一协议 System Language Model PCC Core AI MLX 以及社区构建的模型 如果你是模型提供商 欢迎加入! 让我来展示如何操作 将模型接入框架 共分四个步骤 我们从打包开始 一个精心设计的Swift包 能让开发者轻松上手 然后实现协议 通过定义描述模型的类型 以及运行它的Executor 接下来 我们将讨论如何实现 基于服务器的模型的身份验证 以及一些最佳实践 最后是自定义 如果你需要定制 协议的构建模块 以满足你的需求 完全可以 从附加响应元数据 到定义全新的模态 首先是打包 我们建议使用Swift Package Manager 让开发者可以直接 将你的包添加 作为App的依赖项 我们将介绍如何配置Package.swift 以及如何发布版本 一个重要的考量 是你想要支持哪些平台 Foundation Models支持iOS macOS visionOS 和watchOS 让开发者能够创建 多种多样的体验 我们建议你也尝试做到同样的支持 同时由于 Foundation Models框架 正在以开源方式发布 你的包也可以 对那些开发者有用 那些在服务器上部署Swift的开发者 因此也考虑支持Linux 第三 你的依赖项 每个依赖项都转化为字节 随App发送给用户 仔细考虑你的包 链接了哪些依赖项

    发布你的包 就像创建git标签一样简单 Swift Package Manager是去中心化的 因此你的仓库URL 就是你的分发渠道 开发者可以粘贴URL 到Xcode并开始 集成你的模型 到他们的App中 更多信息 请观看 《Creating Swift Packages》 包已就绪 我们继续讲协议 协议是你的模型 与框架之间的桥梁 即Foundation Models框架 协议有两个关键部分 第一个是LanguageModel 它向框架描述模型 它声明模型的能力 通过capabilities 并提供框架所需的配置 来设置模型的Executor

    第二部分是LanguageModelExecutor 实际工作发生的地方 它有一个接受Configuration的初始化器 一个用于在首次请求前 准备资源的prewarm函数 在第一个请求之前 以及一个respond函数 将生成内容 流式传输回Session

    Configuration是连接 两种类型的纽带 Model提供它 框架用它来构建Executor 现在你已经看到了 代码中的协议 让我们建立对 模型配置如何 将其链接到Executor的直觉 每个Session持有 一个Executor存储 当Model1到来时 框架使用模型的配置 检查存储 但没有匹配的Executor 因此 LanguageModelSession 创建一个新的Executor并存储它 Model2产生相同的配置 由于Configuration是Hashable的 框架知道它匹配 并解析到同一个Executor 配置是查找键 而不是模型 Model3产生 不同的配置 因此它有自己的Executor 每个唯一的配置 在存储中对应一个Executor

    那么这在你的代码中是什么样的呢 这是一个LanguageModel实现 它声明了它的capabilities 并返回框架用来 查找其Executor的配置

    Executor是真正工作所在的地方 加载权重 管理资源 并将token流式传回Session 框架从你的模型提供的配置 构建它 然后在每次请求时传入模型 这种分离使你的Model 构建起来非常简单 当Session释放时 存储也随之释放 每个存储的Executor都被释放 你的deinit运行 权重被释放 连接被关闭 全部自动完成 你不需要自己编写 任何清理代码 在该生命周期中 你的Executor还有 一个函数:prewarm 在请求到来之前 开发者可以要求框架进行预热 这是你提前完成 耗时初始化的机会 例如加载权重 建立连接 或任何可能减慢 第一次响应的操作 让我们看看如何使用它 一种方法是将该初始化 放入私有辅助方法 该方法只加载一次权重 并缓存它们 prewarm会主动调用该辅助方法 这样在第一个请求到来前 权重就已就绪 但prewarm不保证一定会运行

    无论如何 权重只加载一次 如果你的Executor 没有耗时的初始化 例如基于服务器的模型 prewarm可以简单地是空操作 一旦你的respond函数被调用 你的Executor就开始工作 它将对话的转录内容 转换为你的模型期望的格式 它应用开发者设置的选项 并将生成事件流式传输到Session

    从开发者的角度来看 Session是整个交互界面 他们初始化模型 创建Session 调用respond并等待 你的Executor以及 你包中的其余部分 这一切都在Session背后 不可见 开发者从不看到这些机制 但这就是幕后发生的事情 框架将transcript条目传递给你 但你的推理引擎 只能处理其原生类型 因此你的Executor处于中间位置 将条目转换为你的推理引擎 能够理解的消息 并传递给推理引擎进行推理 当你的推理引擎响应时 同样的转换反向进行 将消息转回transcript条目 流式传输到Session

    现在 让我们专注于 流入和流出Executor的transcript 流入流出Executor的transcript

    transcript是迄今为止的对话 以一系列条目的形式表示 每个条目扮演一个角色 由开发者设置的instructions 来自用户的prompts 你的模型发出的工具调用 以及它们返回的输出 以及你的模型产生的响应

    拉远来看 你的Executor的工作是 将每个transcript条目 转换为你的推理引擎 能够读取的消息 那么 transcript里有什么 Foundation Models定义了 这六种条目类型

    你的模型定义了自己的角色 你的Executor的工作是 在两者之间映射 无论你的模型是什么形态 在这个例子中 instructions prompt和response 映射到system user和assistant 这里 工具调用 工具输出 和reasoning都映射到assistant 它们是模型在其回合中 所做事情的一部分 由于该模型没有 专用角色来处理这些 我们只是将它们映射到assistant 如果你的模型确实定义了 类似专用工具角色的东西 你可以路由到那里 无论如何 你的Executor始终保持控制 你的Executor读取对话 但每个请求携带的 不仅仅是历史记录 它携带着开发者对模型 如何响应的意图 通过两个额外属性表达

    每个请求对象 都可以包含ContextOptions 和GenerationOptions ContextOptions控制 哪些内容进入提示词 例如你希望模型使用的 推理级别 或响应schema GenerationOptions控制解码循环 采样策略 温度 以及最大响应长度

    这在respond内部 是什么样的呢 两种类型的选项 都通过请求传入 你的Executor提取它们 并在调用模型时传递 这就是所有传入的内容 transcript 选项 全部解析完毕 现在是开发者看到的部分 响应 在响应端 有几件事需要发送 你的推理引擎生成的文本 任何工具调用或推理内容 以及随之传递的元数据 它们都以事件形式 通过channel发出 推理引擎发出的每个块 一个token或工具调用片段 都成为一个事件 textDelta toolCallDelta等等 框架将它们写入transcript Foundation Models同时提供 一次性响应和流式响应 但实现始终是流式的 一次性API只是在内部 收集delta

    目前为止 我们从你模型的 角度来看这个问题 随着模型生成 事件不断发出 但把自己想象成 开发者的角度 他们调用了respond 正在等待 他们最先需要什么

    这是你的Executor 与开发者的握手协议 有一个刻意的顺序 首先是元数据更新 开发者可用于日志记录和调试的 模型和请求ID 然后是用量更新 用于计费的提示词token数量 提前发送这些意味着开发者 不必等到整个流结束 才能知道每次请求的费用 最后 对于模型产生的每个token 在它到达的瞬间发送文本delta 框架将这些delta 在到达时流式传输到Session 这样用户就能看到响应 逐词显示而非一次全部出现 之前我们看到了框架 如何按配置缓存Executor 如果你的集成是有状态的 持有KV缓存或调用间 的持久化Session 这种缓存让你能最小化 网络开销 避免重复工作 现在让我们看看 如何设计你的实现 以及你的Executor 如何跨调用保留工作 你的Executor在每次 respond调用时接收完整的transcript 这是你上次处理的内容 一条instruction 一个prompt 以及你生成的响应 当下一次调用到来时 你将新的transcript 与上次保存的进行比较 在大多数情况下 新条目只是被追加 在上次响应后有一个新的prompt 当这种情况发生时 你可以保留你现有的状态 只处理新的内容 但有时你的比较发现 条目被删除或修改了 例如 当开发者裁剪旧条目 以节省上下文时 当这种情况发生时 你需要回滚到 两个transcript分叉的地方 框架在每次调用时 都给你完整的transcript 你的Executor决定 什么算作匹配 以及如何处理变更 有时你的模型无法完全完成 开发者的请求 当这种情况发生时 你的Executor 有两种选择:近似或抛出异常 尽可能灵活 尊重开发者的意图 但有时没有 诚实的近似方案 如果开发者设置了token限制 但同时指定了一个 带有必填字段的schema 可能无法同时满足两者 所以你抛出异常 Foundation Models为这类情况 专门提供了LanguageModelError 上下文窗口溢出 速率限制 拒绝响应等 抛出其中之一 任何使用过该框架的开发者 都知道如何处理它

    当内置的LanguageModelError 无法覆盖你的情况时 定义你自己的错误类型 某些失败只在你服务的 上下文中有意义 你的订阅等级 你的功能 你的账户状态 一个专为目的设计的 case名称传达了意图 这样开发者捕获它时 就能确切知道发生了什么 自定义错误很强大 有时你需要它们 但每一个都是开发者 必须学习的新case 需要在App中捕获和处理 尽量使用合适的内置 LanguageModelError 将自定义错误留给 只有你的服务才能产生的故障 我们已完成了 协议要求的实现 接下来让我们讨论 如何处理身份验证 作为包作者 你的工作是让 开发者轻松做正确的事 如果你的初始化器 接受字符串形式的API密钥 开发者会被诱惑 走阻力最小的路径 相反 帮助开发者 做正确的事 提供token提供者或 登录流程 如果你的包代表开发者 获取访问token 务必使用Keychain安全地持久化它们 凭据处理只是一半 设备认证是另一半 如果你正在发布 基于云的LanguageModel包 这值得深入研究 这个相关Session将介绍 如何验证设备 检测篡改的构建 对有效载荷签名 以及使用Apple的欺诈信号 防止恶意流量进入你的服务 请查阅 "Secure your apps with App Attest" 你已经打包了你的模型 实现了协议 并处理了身份验证 这意味着你已经为 你的LanguageModel构建了 一个涵盖所有基础的 稳固包 现在是时候进行差异化了 该协议给了你空间来塑造 LanguageModelSession 围绕只有你的模型 才能提供的能力 响应元数据是一个轻量级选项 可以为你的响应 附加额外信息 并为开发者提供 清晰的访问方式

    你可以将自己的 自定义元数据附加到响应 这里 流式传输完成后 我们的Executor发送tokensPerSecond 和timeToFirstToken 通过channel传输 我们建议提供工具或文档 让开发者方便地 使用你的元数据 清晰的键 类型化的访问器 任何有意义的形式 在底层 元数据只是 一个字典 它可以包含字符串 数字 和其他内置类型 但在某些情况下 你可能需要更灵活的东西

    自定义segment就是答案 你将定义一个新的segment类型 在你的Executor中接收它 并通过同一channel 流式传输结果 开发者无需离开 LanguageModelSession即可使用 自定义segment类型 让你能够扩展协议 当新的模态出现时 音频 视频 或任何新出现的 开发者有一种类型化的结构化方式 将数据发送到你的模型 以下是它的工作原理 首先 你将定义一个 遵循custom segment的类型 由于custom segment 需要PromptRepresentable 开发者可以直接 在提示词中传递它 就像文本一样 在你的Executor中 你将 在transcript中接收到customSegment 与你已经处理的 文本条目并排 当你的模型响应时 你通过channel 将结果发回 作为custom segment更新 segment ID控制你是否 在添加新segment 还是更新已经开始 流式传输的segment 这给了你完全的控制 结果如何流式传输到App 有了custom segment 还有一件事值得提及 关于服务器端工具的建议 服务器端工具是你的模型 自主运行的能力 例如网络搜索 代码执行 或图像生成 模型调用它们 服务器运行它们 你的Executor观察 结果流入 我们将介绍三个详细级别 每个级别呈现更多 工具的工作细节 以网络搜索为例 服务器端工具是你模型上 命名的类型化值 开发者使用他们想要的工具 构建模型 你的Executor在每次请求时 通过模型接收它们 与模型声明的其他所有能力 接收方式相同 首先 最简单的模式 私下运行工具 只将答案流式传输回来 该工具为模型的响应 提供基础 但其工作保留在 你的Executor内部

    你追加的每个文本delta 都被框架流式传输到transcript 没有产生它的工具的任何痕迹 除了在工具输出的基础上 提供答案 你还可以将额外的 元数据附加到响应 当文本delta携带元数据时 例如引用 将两者都转发到channel 框架会将元数据附加到 transcript中的文本segment

    最后 你可以选择 呈现工具的工作本身 使用custom segment 将工具的结构化输出 转发到channel 与文本和任何元数据一起 为App提供模型 沿途产生的一切 通过一个channel 你转发的事件 你附加的元数据 以及你设计的custom segment 服务器端工具塑造了 使用你包的App 能够向用户展示什么 还有一件事需要记住 无论你是选择一个包 还是发布一个包 确保链条中的每个人都了解 其背后模型的 隐私影响 设备端和基于云的模型 具有非常不同的隐私特征 你的用户应该知道 他们使用的是哪种 你已经了解了如何将 你的模型接入框架 这些Session展示了 开发者将用它构建什么 观看《Integrate On-Device AI Models into Your App Using Core AI》 了解如何将本地模型 直接打包到App中 《Build with the new Apple Foundation Model on Private Cloud Compute》 深入讲解了基于Apple隐私保障 的服务器规模推理 以及"Build agentic app experiences with the Foundation Models framework" 展示了开发者如何使用dynamic profiles 构建多步骤 使用工具的工作流 在像你的模型之上 我们对未来充满期待 我们希望看到 LanguageModel包的繁荣生态 赋予Swift开发者 自由选择 适合其App的模型 我们迫不及待地想看看 你会构建什么

    • 2:00 - Choose a language model

      import FoundationModels
      import MLXFoundationModels
      
      // On-device Apple Foundation Model
      let model = SystemLanguageModel()
      
      // Private Cloud Compute model
      // let model = PrivateCloudComputeLanguageModel()
      
      // Custom Core AI model
      // let model = try await CoreAILanguageModel(resourcesAt: modelURL)
      
      // Open-source MLX model from HuggingFace
      // let model = MLXLanguageModel(modelID: "mlx-community/my-model")
      
      let session = LanguageModelSession(model: model)
      let response = try await session.respond(to: "...")
      print(response.content)
    • 3:46 - Configure Package.swift for your model package

      // Package.swift
      
      let package = Package(
          name: "MyModel",
          platforms: [
              .macOS(.v27), .iOS(.v27), .visionOS(.v27), .watchOS(.v27)
          ],
          products: [
              .library(name: "MyModel", targets: ["MyModel"])
          ],
          dependencies: [
              .package(url: "...", .upToNextMinor(from: "1.0.0"))
          ],
          targets: [
              .target(name: "MyModelRuntime"),
              // public: LanguageModel conformance
              .target(name: "MyModel", dependencies: ["MyModelRuntime"]),
              .testTarget(name: "MyModelTests", dependencies: ["MyModel"])
          ]
      )
    • 4:56 - LanguageModel and LanguageModelExecutor protocols

      // LanguageModel protocol
      
      public protocol LanguageModel: Sendable {
          var capabilities: LanguageModelCapabilities { get }
          var executorConfiguration: Executor.Configuration { get }
      }
      
      // LanguageModelExecutor protocol
      
      public protocol LanguageModelExecutor: Sendable {
          init(configuration: Configuration) throws
          func prewarm(model: Model, transcript: Transcript)
          func respond(
              to request: LanguageModelExecutorGenerationRequest,
              model: Model,
              streamingInto channel: LanguageModelExecutorGenerationChannel
          ) async throws
      }
    • 6:25 - Implement LanguageModel and Executor conformances

      // LanguageModel conformance
      public struct MyLanguageModel: LanguageModel {
          typealias Executor = MyLanguageModelExecutor
      
          public var capabilities: LanguageModelCapabilities {
              LanguageModelCapabilities(capabilities: [
                  .toolCalling, .guidedGeneration, .reasoning
              ])
          }
      
          public var executorConfiguration: Executor.Configuration {
              Executor.Configuration(/* ... */)
          }
      }
      
      // Executor conformance
      public struct MyLanguageModelExecutor: LanguageModelExecutor {
          public typealias Model = MyLanguageModel
      
          public struct Configuration: Hashable, Sendable { /* ... */ }
      
          public init(configuration: Configuration) throws { /* ... */ }
      
          public func respond(
              to request: LanguageModelExecutorGenerationRequest,
              model: MyLanguageModel,
              streamingInto channel: LanguageModelExecutorGenerationChannel
          ) async throws { /* ... */ }
      }
    • 7:28 - Manage model resources with prewarm and respond

      // One approach to managing resources
      
      struct MyLanguageModelExecutor: LanguageModelExecutor {
      
          private mutating func loadModelIfNeeded() throws -> LoadedWeights {
              let weights = try loadedModel ?? loadWeights()
              loadedModel = weights
              return weights
          }
      
          func prewarm(transcript: Transcript) {
              loadedModel = try? loadModelIfNeeded()
          }
      
          func respond( ... ) async throws {
              let weights = try loadModelIfNeeded()
              // ...generate with 'weights'...
          }
      }
    • 9:00 - Map Transcript entries to model messages

      // Transcript entries
      
      let transcript = Transcript(entries: [
          .instructions( ... ),  // "You are a helpful assistant"
      
          .prompt( ... ),        // "What's the weather in Pittsburgh?"
          .toolCalls( ... ),     // getWeather(location: "Pittsburgh")
          .toolOutput( ... ),    // 65°F, sunny
          .response( ... ),      // "It's 65°F and sunny in Pittsburgh"
      
          .prompt( ... ),        // "What's the address of Apple Park?"
          .response( ... ),      // "One Apple Park Way, Cupertino, CA 95014"
      ])
    • 10:42 - Read generation and context options from the request

      // Parse generation and context options
      
      func respond(
          to request: LanguageModelExecutorGenerationRequest,
          model: MyLanguageModel,
          streamingInto channel: LanguageModelExecutorGenerationChannel
      ) async throws {
          let reasoningLevel = request.contextOptions.reasoningLevel
          let temperature = request.generationOptions.temperature
          let maxTokens = request.generationOptions.maximumResponseTokens
      }
    • 11:47 - Stream tokens and metadata through the channel

      // Streaming text tokens
      
      func respond( ... ) async throws {
          // 1. Report metadata
          await channel.send(.response(action: .updateMetadata([
              "modelID": "my-model-2026-06-08",
              "requestID": request.id.uuidString
          ])))
          // 2. Report prompt token usage before generating
          await channel.send(.response(action: .updateUsage(
              input: .init(totalTokenCount: promptTokens, cachedTokenCount: cachedTokens),
              output: .init(totalTokenCount: 0, reasoningTokenCount: 0)
          )))
          // 3. Stream text deltas as the model generates
          for try await token in tokens {
              await channel.send(.response(action: .appendText(token)))
          }
      }
    • 13:33 - Honor the developer's intent or throw

      // Honor the developer's intention where possible
      
      // The developer set sampling: .greedy, but our service only takes temperature
      if request.generationOptions.sampling?.kind == .greedy {
          serviceRequest.temperature = 0
      }
      
      // Otherwise, throw an error
      
      // The token budget is too small to satisfy the schema
      if let schema = request.schema,
         let budget = request.generationOptions.maximumResponseTokens,
         budget < minimumTokens(for: schema) {
          throw LanguageModelError.unsupportedCapability(
              .init(
                  capability: .guidedGeneration,
                  debugDescription: "Token budget too small to satisfy this schema."
              )
          )
      }
    • 13:57 - Built-in errors that any model can throw

      // Built-in errors that any model can throw
      
      public enum LanguageModelError: LocalizedError, CustomDebugStringConvertible {
          // Transcript grew past the model's context window. Trim entries and retry.
          case contextSizeExceeded(     )
          // Too many requests in a short window. Space them out or reduce load.
          case rateLimited(     )
          // Model declined to answer. Fall back to a message of your choosing.
          case refusal(     )
          // Safety guardrails tripped on the prompt or the response.
          case guardrailViolation(     )
          // Model lacks a feature you used, such as guided generation or tools.
          case unsupportedCapability(     )
          // Prompt contains content the model can't process (bad files, unknown formats).
          case unsupportedTranscriptContent(     )
          // A generation guide (e.g., a regex pattern) isn't supported by this model.
          case unsupportedGenerationGuide(     )
          // Prompt asked for output in a language or locale the model doesn't support.
          case unsupportedLanguageOrLocale(     )
          // Request timed out before the model produced a response.
          case timeout(     )
      }
    • 14:14 - Handle errors from your model executor

      // Custom errors
      
      public enum MyModelError: Error, LocalizedError {
          // User hit monthly token limit. Prompt upgrade or wait for reset.
          case exceededSubscriptionTierLimit
          // Model variant isn't enabled on this account.
          case modelNotProvisioned
          // Billing or policy review locked this account.
          case accountSuspended
      
          public var errorDescription: String? {
              switch self {
              case .exceededSubscriptionTierLimit:
                  String(localized: "Your plan limit has been reached.")
              // ...
              }
          }
      }
    • 16:08 - Attach custom metadata to responses

      // Attach service-specific performance metadata
      
      let elapsed = Date().timeIntervalSince(startTime)
      let tokensPerSecond = Double(tokenCount) / elapsed
      let timeToFirstToken = firstTokenTime?.timeIntervalSince(startTime) ?? 0
      
      await channel.send(.metadataUpdate([
          "tokensPerSecond": tokensPerSecond,
          "timeToFirstToken": timeToFirstToken
      ]))
    • 17:05 - Define and use custom Transcript segments

      // Define a custom segment
      public struct AudioSegment: Transcript.CustomSegment {
          public var id: String
          public var content: URL
      }
      
      // Pass it in a prompt
      let recording = AudioSegment(id: UUID().uuidString, content: URL(filePath: "/path/to/recording.m4a"))
      let response = try await session.respond {
          "Where was Frank Lloyd Wright's original architecture school located?"
          recording
      }
      
      // Emit a custom segment from the executor
      for try await event in stream {
          switch event {
          case .audioFileGenerated(let file):
              await channel.send(.response(action: .updateCustomSegment(
                  AudioSegment(id: file.id, content: file.url)
              )))
          }
      }
    • 18:09 - Implement server-side tools in your model

      // Configure server-side tools
      public struct MyLanguageModel: LanguageModel {
          public struct ServerTool: Sendable {
              public static let webSearch: ServerTool = ...
          }
          public init(serverTools: [ServerTool] = []) { }
      }
      
      // Surface tool results through the channel
      let client = MyServerClient(serverTools: model.serverTools)
      let response = try await client.send(prompt: .init(request))
      for try await chunk in response {
          switch chunk {
          case .webSearch(let webSearch):
              await channel.send(.response(action: .updateCustomSegment(
                  WebSearchSegment(url: webSearch.url, content: webSearch.html)
              )))
          case .textDelta(let textDelta):
              await channel.send(.response(action: .appendText(
                  textDelta.text, tokenCount: textDelta.tokenCount
              )))
          }
      }
    • 0:00 - Introduction
    • Overview of the Foundation Models framework opening to nearly any LLM. Covers improvements to the on-device System Language Model, three new model options (Private Cloud Compute, Core AI, and MLX), upcoming Anthropic and Google partner integrations, and a code preview showing how any model can be swapped into a LanguageModelSession using the same Swift API.

    • 3:37 - Packaging
    • How to package your LLM provider as a Swift package — configuring Package.swift with the right platform targets (iOS, macOS, visionOS, watchOS, and Linux), being deliberate about dependencies to minimize shipped bytes, and publishing a release via a git tag that developers can paste directly into Xcode.

    • 4:48 - Protocol
    • The two core protocol types bridging your model to the framework: LanguageModel (declares capabilities and provides a Configuration) and LanguageModelExecutor (handles prewarm, translates Transcript entries to your inference engine's native format, applies ContextOptions and GenerationOptions, and streams responses with metadata-first ordering). Covers executor caching by configuration and KV cache state reuse across calls, plus how to approximate unsupported options or throw LanguageModelError when needed.

    • 14:50 - Authentication
    • Best practices for credential handling — designing initializers that guide developers toward secure usage rather than plain API key strings, persisting tokens securely via Keychain, and using App Attest for device attestation to verify devices, catch tampered builds, and protect cloud-based language model services.

    • 15:51 - Customization
    • How to differentiate your model package beyond the protocol fundamentals — attaching custom response metadata (e.g., tokensPerSecond, timeToFirstToken), defining custom segment types for new input and output modalities (audio, video, and beyond), and implementing server-side tools (web search, code execution, image generation) at three levels of visibility: privately grounded, metadata-enriched, or fully surfaced through custom segments.

    • 19:47 - Next steps
    • Privacy considerations when choosing or shipping a model package — on-device versus cloud-based models have very different characteristics and users deserve to know which they're getting. Pointers to companion sessions on Core AI model integration, Private Cloud Compute, and building agentic app experiences on top of the new model ecosystem.

Developer Footer

  • 视频
  • WWDC26
  • 将 LLM 提供平台引入 Foundation Models 框架
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • Apple 智能
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习与 AI
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • Mini Apps Partner Program
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    阅读最近新闻。
    获取 Apple Developer App。
    版权所有 © 2026 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则