← 所有文章

Apple Foundation Models:端侧LLM框架详解

Foundation Models 框架让应用得以直接、免费、离线地访问驱动 Apple Intelligence 的同一个端侧大语言模型1。无需 API 密钥,没有按 token 计费,没有网络往返,也没有任何数据离开设备。对于过去意味着一次云端LLM调用加一轮隐私审查的那一类功能而言,如今的成本几乎归零。代价在于能力:端侧模型很小,上下文窗口有限,框架也对自己愿意做与不愿做的事划下了清晰的边界。摸清这些边界,就是全部的关键。

本文是这套框架本身的参考:您真正会调用的类型、让它值得一用的那一个特性,以及您应当就此打住、转而求助于更大模型的那个临界点。

太长不看

  • LanguageModelSession 是入口。创建一个,调用 respond(to:),拿回文本。多轮上下文保存在会话之中;单轮任务则每次新建一个会话2
  • 引导式生成才是使用这套框架的理由。 给某个 Swift 类型标注 @Generable,模型便会返回这个类型——已填充、且经过类型检查,而不是一段还得您自己解析的字符串3
  • Tool 协议让模型能在生成途中调用您的代码,去获取数据或执行操作,再把结果融回它的答案里4
  • 动手之前,先检查 SystemLanguageModel.default.availability。在不符合条件的设备上、Apple Intelligence 处于关闭状态时、或模型正在下载期间,模型都不存在5
  • 上下文窗口是真实存在且很小的。SystemLanguageModel.default.contextSize 报告的是提示词与响应共享的 token 预算6。要为此做好规划,否则会话就会抛出错误。
  • 需要 iOS 26 以及一台支持 Apple Intelligence 的设备。低于这个门槛,框架根本不存在。

这套框架是什么,又不是什么

Foundation Models 并不是对某个云端接口的封装。模型驻留在设备上,随操作系统一同发布,运行在神经网络引擎之上。这一个事实,驱动着 API 中的每一项设计决策,也驱动着您使用它时做出的每一个决定。

您能得到的:文本生成、摘要、分类、抽取、短文本改写,以及结构化输出,全部在端侧完成,全部免费。您得不到的:一个前沿模型。Apple 把端侧模型构建为应用内部专注的语言任务工具,而非开放式推理、长文档分析,或可供您随意盘问的世界知识。Apple 自己也是这么讲的,而这套定位之所以重要,是因为它界定了一种期望——否则 API 会任由您去触犯它1

能让您远离麻烦的心智模型是这样的:把端侧模型当成一位快速、私密、免费的实习生,他极擅长打磨文本,却极不擅长掌握事实。把素材和一项明确的任务交给他。不要问他根本无从回答的问题。

LanguageModelSession:入口

每一次交互都从一个会话开始。

import FoundationModels

let session = LanguageModelSession()
let response = try await session.respond(to: "Summarize this review in one sentence: \(reviewText)")
print(response.content)

会话保存着对话状态。每次调用 respond(to:) 都会追加到正在进行的记录中,因此一个一直保留的会话会记得此前发生过什么。对于聊天类功能,这正是您想要的。而对于彼此独立的一次性任务(摘要这个、分类那个),请为每次调用新建一个会话,免得陈旧的上下文渗进来、吃掉您的 token 预算2

respond(to:)async throws 的。它在模型工作时挂起,并在请求超出上下文窗口、模型不可用或防护栏拒绝内容时抛出错误。这其中每一种,都是您要处理的真实分支,而非可以无视的边角情形。

要让界面有响应感,就用流式输出而非干等。streamResponse(to:) 会随着模型产出而逐步交付部分内容,把一段三秒的卡顿,变成随成形而显现的文字7

引导式生成:让这套框架物有所值的特性

下面这部分,才是入场费所换来的东西。多数LLM集成会把三分之一的代码花在哄模型吐出合法的 JSON 上,另外三分之二则用来防备它终究还是失败的那些时刻。Foundation Models 把这些活儿一笔勾销。

给某个 Swift 类型标注 @Generable,让会话去生成它,模型便会返回该类型的一个实例——已填充、且类型安全3

@Generable
struct Recipe {
    @Guide(description: "The dish name")
    let title: String

    @Guide(description: "Ingredients, each as 'quantity item'")
    let ingredients: [String]

    @Guide(description: "Total minutes, start to finish", .range(5...240))
    let minutes: Int
}

let session = LanguageModelSession()
let response = try await session.respond(
    to: "A weeknight pasta for two.",
    generating: Recipe.self
)
let recipe = response.content   // a Recipe, not a String

无需解析。没有 JSONDecoder。没有为畸形输出而设的重试循环。@Guide 宏约束着各个字段:一段模型会当作指令来读的描述,以及可选的限制——比如一个数值范围,或一个输出必须匹配的正则表达式8。框架并不是客客气气地请求模型给出一个介于 5 到 240 之间的数字;它约束的是解码过程,让这个字段不可能以别的形态返回。

这一约束所带来的纪律,才是真正的价值所在。您先用 Swift 设计好输出类型,由编译器替您把关。模型填写的是一份您所定义的契约,而不是返回一段还要您逆向破解的散文。对于抽取、表单填充,以及任何把语言变成数据的功能,引导式生成正是 demo 与可交付代码之间的那道分水岭。

有一个控制项值得了解:respond(to:generating:) 默认把 includeSchemaInPrompt 设为 true,会把您类型的结构注入提示词,使模型偏向于它。除非模型已经从训练中、或从会话此前几轮中知道了这个格式,否则就让它保持开启;为了在一个模型从未见过的格式上省下 token 而关掉它,正是您会拿回一堆垃圾的原因9

工具调用:让模型够得着您的代码

引导式生成塑造的是输出的样子。工具调用改变的是输入的内容。所谓工具,是一段您的代码,模型可以在生成途中调用它,去取得它没有的信息或执行某个操作,再用结果继续它的答案4

一个工具需遵循 Tool 协议:一个 name、一段供模型据以决定何时调用的 description、一个 @GenerableArguments 类型,以及一个负责干活的 call(arguments:) 方法4

struct FindContacts: Tool {
    let name = "findContacts"
    let description = "Find a specific number of contacts from the address book"

    @Generable
    struct Arguments {
        @Guide(description: "How many contacts to return", .range(1...10))
        let count: Int
    }

    func call(arguments: Arguments) async throws -> [String] {
        // Fetch contacts, return formatted names.
    }
}

let session = LanguageModelSession(tools: [FindContacts()])
let response = try await session.respond(to: "Draft a dinner invite to three of my contacts.")

整个流程是:模型判断自己需要联系人,便带着一个已校验的 count 调用您的工具,您返回数据,模型再用真实的姓名写出邀请。参数经由同一套引导式生成机制传入,已经类型检查过,因此您从不必从自由文本中去解析模型的意图。工具描述是您唯一能左右模型何时去取用它的杠杆,所以写它时要像写一份函数文档——交给另一位毫无背景信息的工程师,他也得照着把它用对。

这里也正是 Foundation Models 与整个智能体故事接合的那道缝。端侧模型调用的工具,与 Apple Intelligence 调用的 App Intent,是形态相同的两个不同界面:一项具名、有描述、有类型的能力。能力只设计一次,便可经由两者同时暴露出去。

可用性:不能跳过的检查

模型并非总在那里。在不支持 Apple Intelligence 的设备上、用户把它关掉时、以及操作系统仍在下载模型资源的那段窗口期内,它都不存在。如果您的代码假定模型一定存在,它就会崩溃、悄无声息地降级,或对一群您从未测试过的用户挂起。

请检查 SystemLanguageModel.default.availability,并依据原因分支处理5

switch SystemLanguageModel.default.availability {
case .available:
    // Show the intelligence feature.
case .unavailable(.deviceNotEligible):
    // Hide it. This device will never have the model.
case .unavailable(.appleIntelligenceNotEnabled):
    // Prompt the user to turn on Apple Intelligence.
case .unavailable(.modelNotReady):
    // Downloading or otherwise not ready yet. Try again later.
case .unavailable(let other):
    // Unknown reason. Fail closed.
}

这三种原因要求三种不同的产品回应,而把它们混为一谈,正是让这类功能显得”坏掉了”的最常见方式。deviceNotEligible 是永久性的:隐藏功能,别去纠缠。appleIntelligenceNotEnabled 是用户掌控的一项设置:弹一次提示是合理的。modelNotReady 是暂时的:重试即可,别报错。请用对待正常路径的同等用心去构建不可用路径,因为对于相当一部分设备而言,它就是唯一的路径。

当模型可用、而您又知道有一次请求即将到来时,对会话调用 prewarm() 可以把模型预热,让第一次真正的响应来得更快10。在用户即将操作的页面上,这值得;若是凭空臆测地调用,则是浪费。

上下文窗口,以及它何时不再够用

SystemLanguageModel.default.contextSize 报告的是模型所处其中的 token 预算,而这份预算是共享的:提示词加响应,两者合起来必须装得下6。相对于云端模型,这个数字很小,面对真实输入时您很快就会感受到它。一份长文档、一段完整的聊天记录、一个臃肿的工具返回结果:其中任何一个,都可能撑爆预算,让 respond 抛出错误。

由此引出两种失败模式,而两者都得靠您去防范。其一是缓慢的累积:一个多轮会话不断堆积记录,直到再多一轮就溢出。对策是为不相关的工作另起新会话,并让每一轮的输入保持精简。其二是单次过大的请求:一份 20 页的 PDF 装不下,没有余地。把它切块、对各块做摘要,再在摘要之上进行推理(这正是LLM工程师所熟知的 map-reduce),或者干脆接受这项任务在形态上就不适合端侧模型。

上下文窗口,是这套框架真正要紧的那个决定——何时留在端侧、何时离开——最干净的信号。

何时不该用 Foundation Models

这套框架免费、私密又离线,叫人忍不住处处都想用它。请克制。在以下情形,要越过它去寻求别的方案:

  • 您需要真正的推理,或宽广的世界知识。 端侧模型在设计上就很小。开放式推理、代码生成与深度分析,属于前沿云端模型。向端侧模型索要这些,得到的是自信却错误的答案。
  • 输入装不进上下文窗口,而切块又会摧毁其含义。有些任务需要一次性看到全部。
  • 您需要一个由自己掌控的模型: 某个特定检查点、一次微调、自定义权重、跨系统更新的确定性版本控制。Apple 按它自己的节奏发布并更新模型,不按您的。
  • 您所在的环境低于 iOS 26,或设备不符合条件。 框架就是不在那里,而可用性检查会在每一次运行时如实告诉您。

对于这套框架未覆盖的那些端侧场景(自定义模型、您自己的权重、在设备上训练),更下一层是 Core ML 与 Apple 的 MLX。对于那些确实需要规模的场景,把一个云端LLM放在隐私边界之后,仍然是诚实的答案。Foundation Models 不是两者中任何一个的替代品。对于您手头已有的文本上专注的语言工作,它是恰当的第一选择;对于其余一切,它都是错的选择。

这套框架所奖赏的本领,不是提示词的雕琢功夫。而是对范围的品味:喂给模型它擅长的任务,设计出恰好捕捉您所需之物的 @Generable 类型,并在工作超出设备承载力的那一刻认出它来。带着这些直觉去构建,端侧模型就能免费完成出人意料的大量实活。无视它们,您交付的就是一个——对每一位输入恰好多出一个 token 的用户都会崩溃的——功能。

常见问题

Apple 的 Foundation Models 框架是免费使用的吗?

是的。这套框架让应用得以直接、免费、离线地访问驱动 Apple Intelligence 的同一个端侧模型。没有 API 密钥,没有按 token 计费,也没有网络往返1

Foundation Models 需要什么设备和 iOS 版本?

它需要 iOS 26 以及一台支持 Apple Intelligence 的设备。低于这个门槛,框架不存在;而即便在受支持的系统上,模型在不符合条件的设备上、Apple Intelligence 关闭时、或模型下载期间也都不存在。使用之前,务必先检查 SystemLanguageModel.default.availability5

我该如何获得结构化、类型安全的输出,而不是一段字符串?

给某个 Swift 类型标注 @Generable,模型便会返回这个类型——已填充、且经过类型检查,而不是一段还得您解析的字符串。这种引导式生成,正是让这套框架值得一用的那一个特性3

Apple 端侧模型的上下文窗口有多大?

SystemLanguageModel.default.contextSize 报告的是 token 预算,它由提示词与生成的响应共享6。它在设计上就很小,因此长文档与长的多轮记录都会超出它。要为这个上限做好规划,否则会话就会抛出错误。

Foundation Models 能离线工作吗?它会把数据发给 Apple 吗?

它完全在端侧、运行于神经网络引擎之上。没有任何数据离开设备,也不需要网络往返——这正是它适合那类过去需要云端LLM加隐私审查的功能的原因1

端侧模型能在生成途中调用我自己的代码吗?

可以。Tool 协议让模型能在生成过程中调用您的代码,去获取数据或执行操作,再把结果融回它的答案里4

我什么时候不该用 Foundation Models?

当您需要一个前沿模型时,就越过它:开放式推理、代码生成、长文档分析,或世界知识。Apple 把端侧模型构建为应用内部专注的语言任务工具,因此向它索要通用智能,得到的是自信却错误的答案1



  1. Apple Developer, “Foundation Models” framework overview. Apple describes the framework as access to the on-device model that powers Apple Intelligence, suited to focused language tasks such as text generation, summarization, classification, and structured output rather than open-ended reasoning or world knowledge. 

  2. Apple Developer, “LanguageModelSession” and “Generating content and performing tasks with Foundation Models”. A session holds multi-turn context; Apple’s guidance is to create a new session for each distinct single-turn interaction. 

  3. Apple Developer, “Generable” and “Prompting an on-device foundation model”. The @Generable macro lets the framework return a populated, type-checked Swift value rather than a string. 

  4. Apple Developer, “Tool” protocol. Defines protocol Tool<Arguments, Output>: Sendable with required name, description, and parameters: GenerationSchema, plus call(arguments:) async throws -> Output. The Arguments type conforms to ConvertibleFromGeneratedContent and is typically declared @Generable

  5. Apple Developer, “SystemLanguageModel.Availability” and its UnavailableReason. Cases: .available and .unavailable(...) with reasons deviceNotEligible, appleIntelligenceNotEnabled, and modelNotReady. SystemLanguageModel.default.isAvailable is the convenience boolean. 

  6. Apple Developer, “SystemLanguageModel.contextSize”. An instance property (reached through SystemLanguageModel.default) documented as the maximum context size, representing the total tokens across input prompt and generated response. 

  7. Apple Developer, “LanguageModelSession.streamResponse(to:)”. Streams partial generated output as the model produces it, for incremental UI updates. 

  8. Apple Developer, “Guide(description:_:)”. A peer macro that attaches a natural-language description and optional constraints (numeric ranges, regular-expression guides) to a @Generable property. Requires iOS 26.0+. 

  9. Apple Developer, “respond(to:schema:includeSchemaInPrompt:options:)”. includeSchemaInPrompt defaults to true; Apple’s discussion recommends keeping the default unless the model already knows the expected format. 

  10. Apple Developer, “LanguageModelSession.prewarm()”. Asks the framework to load model resources ahead of a known upcoming request to reduce first-response latency. 

  11. Author’s related analysis: On-Device LLMs with Apple’s Foundation Models, Custom Adapters for Foundation Models, Foundation Models Use Cases, and Agentic Workflows on Foundation Models. The App Intents and tool-surface argument is developed in App Intents Are Apple’s New API to Your App

相关文章

Foundation Models 使用场景:通用与内容标记

iOS 26 Foundation Models 提供了 .general 和 .contentTagging 两种使用场景。运用 Apple 的规则来决定何时提示词优于专门化方案。

3 分钟阅读

Foundation Models 自定义适配器:何时需要训练

iOS 26 Foundation Models 自定义适配器训练 LoRA 权重,导出 .fmadapter 包,通过 Background Assets 交付,并需要 Apple 的授权。

3 分钟阅读

The Robots Are Taking Exams in My Search Console

First-party GSC data: 91% of 3.8M impressions fail a human-query filter. Exam questions, pasted errors, and agent sweeps…

10 分钟阅读