Build agentic app experiences with the Foundation Models framework
AI & Machine Learning 高级 21m

使用 Foundation Models 框架构建智能体 App 体验

Build agentic app experiences with the Foundation Models framework

2026年6月10日

在 Apple 官方观看视频

一句话判断

Foundation Models 终于从“套壳对话框”进化到了“真正的多 Agent 编排框架”,DynamicProfile 是今年做 AI App 必须拿下的 API。

这场 Session 讲了什么

以前用 LanguageModelSession 搞复杂任务极其痛苦。要么一个模型硬扛导致 Token 爆炸和幻觉,要么开多个 Session 导致上下文割裂,手动拼 Prompt 和摘要写到吐血。Apple 这次直接给出了官方解法:DynamicProfile(动态配置文件)和 DynamicInstructions(动态指令)。

现在你可以在同一个 Session 里,根据 App 的不同阶段动态切换底层模型。比如头脑风暴时用高温度(temperature)的 Private Cloud Compute(私有云计算)模型,审查阶段切到低温度的端侧 SystemLanguageModel(系统语言模型)。配合 historyTransform(历史转换),你还能自动裁剪历史对话,把那些又长又没用的 Tool Call(工具调用)记录丢掉。

这对做复杂 AI 工作流的开发者影响最大。你不再需要自己手写一堆状态机来管理 Prompt 和上下文窗口,Apple 把“上下文工程”做成了声明式的 SwiftUI 风格 API。

值得深挖的点

端云混合调度的官方范式

做 AI App 最大的成本痛点就是模型调度。端侧模型便宜快但笨,云端模型聪明但贵且慢。真实场景必须混合使用,但以前在多个 Session 间传递上下文简直是灾难。DynamicProfile 漂亮地解决了这个问题。它允许你在同一个 LanguageModelSession 中,通过类似 SwiftUI 的 body 声明式地切换模型、温度甚至推理级别(reasoningLevel)。

Apple 在这里的设计取舍很明确:他们选择了让开发者通过 Profile 显式声明边界,而不是在底层做黑盒魔法。当你切换模型或大幅修改历史时,底层的 KV Cache(键值缓存)会失效,导致首字延迟飙升。Apple 没有帮你自动抹平这个差异,而是提供了全新的 Xcode Instrument 让你自己去测。说白了,Apple 给你提供了最灵活的换挡杆,但踩离合的时机得你自己把握。

上下文工程与无状态历史裁剪

长对话必然超出 Context Window(上下文窗口),或者塞满无关的 Tool Call 导致模型变笨。historyTransform 是这次最实用的 API。它的设计非常克制:它是无状态的(stateless),每次请求前跑一遍,只改变发给模型的快照,绝不修改 Session 本身的真实历史。这比直接 mutate 历史安全得多,避免了状态同步的噩梦。

如果你不想自己写裁剪逻辑,Apple 顺手开源了 Foundation Models framework utilities(基础模型框架工具包)。直接用里面的 .rollingWindow(滚动窗口)和 .droppingCompletedToolCalls(丢弃已完成的工具调用)修饰符就行。这里有个大坑:如果你把 transcriptErrorHandlingPolicy(转录错误处理策略)设为 .preserveTranscript 并在 Tool 报错时手动改历史,一定要确保 isResponding == false,否则直接崩溃。

代码片段

1. 声明式切换模型与 Agent 配置

场景:根据 App 当前所处的阶段(头脑风暴或审查),动态切换底层模型和温度。

struct CraftProfile: LanguageModelSession.DynamicProfile {
    var orchestrator: CraftOrchestrator
    
    var body: some DynamicProfile {
        switch orchestrator.mode {
        case .brainstorming:
            // 头脑风暴需要创造力,使用云端模型并调高温度
            Profile { BrainstormFacilitator(orchestrator: orchestrator) }
                .model(orchestrator.pccLanguageModel)
                .temperature(1)
        case .reviewing:
            // 审查阶段需要严谨,使用端侧模型并降低温度
            Profile { CraftCoach() }
                .model(orchestrator.systemLanguageModel)
                .temperature(0.2)
        }
    }
}

坑:body 会在每次 prompt 时重新计算,确保 orchestrator 的状态变化能正确触发 UI 和 Profile 更新,别在 body 里写耗时逻辑。

2. 使用官方工具包裁剪上下文

场景:对话太长时,自动丢弃已经执行完的 Tool Call,并只保留最近 10 条记录,防止 Token 超限。

import FoundationModelsUtilities

struct CraftProfile: LanguageModelSession.DynamicProfile {
    var orchestrator: CraftOrchestrator
    
    var body: some DynamicProfile {
        switch orchestrator.mode {
        case .reviewing:
            Profile { CraftCoach() }
                // 丢弃已完成的工具调用记录,减少噪音
                .droppingCompletedToolCalls()
                // 只保留最近的 10 条历史记录
                .rollingWindow(size: .entries(10))
        }
    }
}

坑:频繁改变历史窗口大小或裁剪逻辑会导致 KV Cache 失效。尽量保持裁剪规则稳定,并用 Xcode 的 Foundation Models Instrument 监控延迟。

最佳实践

已有项目如果还在用单个大 Prompt 塞所有逻辑,或者手动维护多个 Session 传递摘要,建议立刻重构。新项目直接上 DynamicProfile,把不同的业务阶段拆分成独立的 Profile

在多 Agent 协作时,优先使用 baton-pass(接力)模式:多个 Profile 共享完整的 transcript(对话历史),通过一个 Tool 来切换当前激活的 Profile,由接手的 Profile 输出最终结果。如果是需要隔离上下文的子任务,再用 phone-a-friend(求助)模式,派生一个短生命周期的子 Session。

实战中极容易踩的一个坑是 Tool calling mode(工具调用模式)。当你把模式设为 required(必须调用)时,模型会陷入无限循环调用 Tool 的死胡同。一定要给个退出条件,比如条件化这个模式,或者提供一个 final-answer tool(最终答案工具),让它抛出异常来打破循环。

还有什么值得关注

  • SessionProperty 跨 Profile 共享状态:通过 @SessionPropertyEntry 声明自定义属性(比如对话摘要),可以在不同的 Profile 和 Tool 之间无缝共享状态,不用再搞全局单例了。
  • transcriptErrorHandlingPolicy 新选项:现在 Tool 报错时,你可以选择 .preserveTranscript 保留错误现场,自己手动修复转录历史,而不是像以前那样只能默认回滚。
  • DynamicInstructions 组合能力:可以像 SwiftUI 视图一样嵌套组合指令,比如把 OrigamiExpert 嵌套在 BrainstormFacilitator 里,自动拼接 Prompt 和 Tools,代码复用率极高。
Foundation Models DynamicProfile Agentic AI LanguageModelSession Private Cloud Compute