🎯 第一部分:开场和Foundation Models简介
1.1 为什么需要Foundation Models?
业务痛点 vs 解决方案
在相册业务中,我们经常遇到以下问题:
难以用关键词找到照片] P2[分类工作繁琐
手动整理耗时耗力] P3[内容理解不足
无法自动理解照片] P4[个性化推荐缺失
难以推荐相关照片] end subgraph "Foundation Models解决方案" S1[自然语言搜索
去年夏天在海边的照片] S2[智能分类
自动组织照片] S3[内容理解
自动分析照片内容] S4[智能推荐
相似照片推荐] end P1 --> S1 P2 --> S2 P3 --> S3 P4 --> S4 style P1 fill:#FF3B30,color:#fff style P2 fill:#FF3B30,color:#fff style P3 fill:#FF3B30,color:#fff style P4 fill:#FF3B30,color:#fff style S1 fill:#34C759,color:#fff style S2 fill:#34C759,color:#fff style S3 fill:#34C759,color:#fff style S4 fill:#34C759,color:#fff
1.2 什么是Foundation Models Framework
核心定义
- 官方定义: Apple在iOS 18/macOS 15中引入的原生AI框架,是Apple Intelligence的核心组件
- 技术定位: 让开发者轻松集成Apple Intelligence的大语言模型能力到应用中
- 设计理念 :
- 隐私优先:所有处理都在设备本地完成
- 开发者友好:简洁的API,易于集成
- 系统集成:与iOS/macOS深度集成
Foundation Models vs 传统AI模型
需要网络连接] T2[数据上传
需要上传到服务器] T3[高延迟
网络往返延迟] T4[成本计费
按使用量付费] T5[API密钥
需要密钥管理] T6[隐私风险
数据可能泄露] end subgraph "Foundation Models方案" F1[设备端运行
无需网络] F2[数据本地化
不出设备] F3[低延迟
本地处理] F4[零成本
Apple提供] F5[无需密钥
系统集成] F6[隐私保护
完全本地处理] end T1 -.对比.-> F1 T2 -.对比.-> F2 T3 -.对比.-> F3 T4 -.对比.-> F4 T5 -.对比.-> F5 T6 -.对比.-> F6 style T1 fill:#FF3B30,color:#fff style T2 fill:#FF3B30,color:#fff style T3 fill:#FF3B30,color:#fff style T4 fill:#FF3B30,color:#fff style T5 fill:#FF3B30,color:#fff style T6 fill:#FF3B30,color:#fff style F1 fill:#34C759,color:#fff style F2 fill:#34C759,color:#fff style F3 fill:#34C759,color:#fff style F4 fill:#34C759,color:#fff style F5 fill:#34C759,color:#fff style F6 fill:#34C759,color:#fff
对比表格:
| 特性 | 传统AI模型 | Foundation Models |
|---|---|---|
| 部署方式 | 云端服务 | 设备端运行 |
| 网络要求 | 需要网络连接 | 无需网络 |
| 数据处理 | 数据上传到服务器 | 数据完全本地化 |
| 延迟 | 较高(网络往返) | 低(本地处理) |
| 成本 | 按使用量计费 | 零成本(Apple提供) |
| API密钥 | 需要管理 | 无需API密钥 |
| 隐私 | 数据可能泄露 | 完全隐私保护 |
Apple Intelligence 架构概览
会话管理] FM2[Tool Protocol
工具协议] FM3[Structured Generation
结构化生成] FM4[SystemLanguageModel
系统语言模型] end subgraph "底层执行层" CoreML[Core ML
模型推理] NeuralEngine[Neural Engine
硬件加速] end subgraph "隐私和安全层" Privacy[隐私保护
设备端处理] Security[数据加密
安全存储] end App1 --> FM1 App2 --> FM1 App3 --> FM1 FM1 --> FM2 FM1 --> FM3 FM1 --> FM4 FM4 --> CoreML CoreML --> NeuralEngine NeuralEngine --> Privacy Privacy --> Security style FM1 fill:#007AFF,color:#fff style FM2 fill:#007AFF,color:#fff style FM3 fill:#007AFF,color:#fff style FM4 fill:#007AFF,color:#fff style CoreML fill:#34C759,color:#fff style NeuralEngine fill:#34C759,color:#fff style Privacy fill:#FF9500,color:#fff style Security fill:#FF9500,color:#fff
关键组件说明:
- LanguageModelSession: 会话管理,维护对话上下文
- SystemLanguageModel: 系统提供的语言模型
- Tool Protocol: 扩展模型能力,连接系统功能
- Structured Generation: 类型安全的数据生成
核心能力概览
核心能力)) 自然语言理解 理解用户查询 生成流畅响应 多轮对话 上下文维护 结构化数据生成 @Generable标记 类型安全 自动解析 易于集成 工具调用 Tool协议 系统功能连接 AI自动判断 多工具协调 流式响应 实时生成 提升体验 长文本支持 多语言支持 10种语言 自动检测 代码切换
1.3 系统要求与兼容性
设备要求详解
⚠️ 重要澄清:关于设备要求的常见混淆
- 正确理解 :需要 A17 Pro 芯片及以上
- 对应设备:iPhone 15 Pro 及以上(因为 iPhone 15 Pro 搭载 A17 Pro 芯片)
- 常见误解 :有人误以为需要 "iPhone 17 Pro",但实际上:
- iPhone 15 Pro 使用的是 A17 Pro 芯片
- iPhone 17 Pro 目前还不存在(截至 2024 年,最新是 iPhone 16 系列)
- 要求是 A17 Pro 芯片,不是 iPhone 17 Pro
完整设备要求列表:
| 设备类型 | 具体要求 | 示例设备 |
|---|---|---|
| iPhone | A17 Pro 芯片及以上 | iPhone 15 Pro、iPhone 15 Pro Max、iPhone 16 系列 |
| iPad | A17 Pro 芯片或 M1 芯片及以上 | iPad Pro (M1/M2/M3)、iPad Air (M1/M2) |
| Mac | Apple Silicon (M 系列) | MacBook Air/Pro (M1/M2/M3)、iMac (M1/M2/M3) |
| Apple Vision Pro | 支持 | Apple Vision Pro |
系统要求:
- 操作系统: iOS 18.0+ / macOS 15.0+ / iPadOS 18.0+
- 开发工具: Xcode 16.0+
- 功能要求: Apple Intelligence 已启用(在系统设置中)
系统要求检查流程
iOS 18+/macOS 15+?} CheckOS -->|否| Error1[系统版本过低
提示升级] CheckOS -->|是| CheckDevice{检查设备
A17 Pro+/M系列?} CheckDevice -->|否| Error2[设备不支持
Apple Intelligence] CheckDevice -->|是| CheckSetting{检查设置
Apple Intelligence已启用?} CheckSetting -->|否| Error3[功能未启用
引导用户开启] CheckSetting -->|是| CheckModel{检查模型可用性
SystemLanguageModel.default} CheckModel -->|可用| Success[可以使用
Foundation Models] CheckModel -->|不可用| Error4[模型不可用
显示原因] Error1 --> End([结束]) Error2 --> End Error3 --> End Error4 --> End Success --> Prewarm[预热模型
可选但推荐] Prewarm --> End style Start fill:#007AFF,color:#fff style CheckOS fill:#5AC8FA,color:#000 style CheckDevice fill:#5AC8FA,color:#000 style CheckSetting fill:#5AC8FA,color:#000 style CheckModel fill:#5AC8FA,color:#000 style Success fill:#34C759,color:#fff style Error1 fill:#FF3B30,color:#fff style Error2 fill:#FF3B30,color:#fff style Error3 fill:#FF3B30,color:#fff style Error4 fill:#FF3B30,color:#fff style Prewarm fill:#FF9500,color:#fff
兼容性检查代码:
swift
import FoundationModels
// 检查模型可用性
let model = SystemLanguageModel.default
switch model.availability {
case .available:
// 可以使用Foundation Models
print("✅ Foundation Models可用")
case .unavailable(let reason):
// 处理不可用情况
print("❌ 模型不可用: \(reason.localizedDescription)")
}
开发注意事项
必须真机测试] L2[地区限制
部分功能不可用] L3[用户设置
需启用AI功能] end subgraph "解决方案" S1[使用真机测试
iPhone 15 Pro及以上] S2[提供降级方案
功能不可用时] S3[引导用户设置
提示开启步骤] end L1 --> S1 L2 --> S2 L3 --> S3 style L1 fill:#FF3B30,color:#fff style L2 fill:#FF3B30,color:#fff style L3 fill:#FF3B30,color:#fff style S1 fill:#34C759,color:#fff style S2 fill:#34C759,color:#fff style S3 fill:#34C759,color:#fff
1.4 应用场景概览
在相册业务中的应用场景
去年夏天] B2[地点搜索
在海边] B3[人物搜索
包含女朋友] end subgraph "智能分类" C1[时间分类] C2[地点分类] C3[主题分类] C4[人物分类] end subgraph "视频理解" D1[视频摘要] D2[关键时刻] D3[封面生成] end subgraph "智能推荐" E1[相似照片] E2[相关回忆] E3[个性化推荐] end subgraph "相册管理" F1[清理建议] F2[存储优化] F3[相册整理] end style A1 fill:#007AFF,color:#fff style A2 fill:#007AFF,color:#fff style A3 fill:#007AFF,color:#fff style B1 fill:#34C759,color:#fff style B2 fill:#34C759,color:#fff style B3 fill:#34C759,color:#fff style C1 fill:#FF9500,color:#fff style C2 fill:#FF9500,color:#fff style C3 fill:#FF9500,color:#fff style C4 fill:#FF9500,color:#fff style D1 fill:#5AC8FA,color:#000 style D2 fill:#5AC8FA,color:#000 style D3 fill:#5AC8FA,color:#000 style E1 fill:#AF52DE,color:#fff style E2 fill:#AF52DE,color:#fff style E3 fill:#AF52DE,color:#fff style F1 fill:#FF2D55,color:#fff style F2 fill:#FF2D55,color:#fff style F3 fill:#FF2D55,color:#fff
1.5 与其他AI框架的对比
Foundation Models vs Core ML vs OpenAI API
对比表格:
| 特性 | Core ML | Foundation Models | OpenAI API |
|---|---|---|---|
| 定位 | 通用ML框架 | 专用语言模型 | 云端AI服务 |
| 模型来源 | 需要自己训练/转换 | Apple预训练 | OpenAI提供 |
| API级别 | 底层 | 高级 | 高级 |
| 适用任务 | 各种ML任务 | NLP任务 | NLP任务 |
| 部署方式 | 设备端 | 设备端 | 云端 |
| 网络需求 | 无需 | 无需 | 需要 |
| 成本 | 免费 | 免费 | 付费 |
1.6 设计哲学与最佳实践
Apple的设计哲学
设备端处理] P2[开发者友好
简洁API] P3[系统集成
深度集成] P4[性能优化
Neural Engine] end subgraph "最佳实践" B1[检查可用性] B2[错误处理] B3[降级方案] B4[上下文管理] B5[流式响应] end P1 --> B1 P2 --> B2 P3 --> B3 P4 --> B4 P4 --> B5 style P1 fill:#007AFF,color:#fff style P2 fill:#34C759,color:#fff style P3 fill:#FF9500,color:#fff style P4 fill:#5AC8FA,color:#000 style B1 fill:#AF52DE,color:#fff style B2 fill:#AF52DE,color:#fff style B3 fill:#AF52DE,color:#fff style B4 fill:#AF52DE,color:#fff style B5 fill:#AF52DE,color:#fff
🔧 第二部分:核心API快速上手
2.1 LanguageModelSession - 会话管理
基础使用流程
代码示例:
swift
import FoundationModels
// 创建会话
let session = LanguageModelSession()
// 单轮对话
let response = try await session.respond(
to: "生成一个旅行博客的标题"
)
print(response.content)
// 多轮对话 - 会话自动维护上下文
let response1 = try await session.respond(to: "我喜欢摄影")
let response2 = try await session.respond(to: "推荐一些拍摄技巧")
// AI会记住之前说喜欢摄影
自定义指令(Instructions)
swift
let session = LanguageModelSession(
instructions: Instructions("""
你是一个专业的摄影助手,擅长:
1. 分析照片和提供拍摄建议
2. 识别照片内容和场景
3. 提供构图和光线建议
""")
)
2.2 流式响应
流式响应工作流程
代码示例:
swift
let stream = session.streamResponse(to: "分析照片")
for try await partialText in stream {
updateUI(with: partialText) // 实时更新UI
}
应用场景: 聊天界面、长文本生成
2.3 结构化数据生成(@Generable)
结构化生成流程
@Generable] --> B[生成Prompt
包含字段描述] B --> C[AI理解需求
基于@Guide] C --> D[生成结构化数据
类型安全] D --> E[自动解析
返回结果] style A fill:#007AFF,color:#fff style B fill:#5AC8FA,color:#000 style C fill:#FF9500,color:#fff style D fill:#34C759,color:#fff style E fill:#AF52DE,color:#fff
定义数据模型:
swift
@Generable
struct PhotoAnalysis {
@Guide(description: "照片的主题或主要内容")
let subject: String
@Guide(description: "照片的情感色彩:positive, neutral, negative")
let mood: PhotoMood
@Guide(description: "照片的拍摄场景:indoor, outdoor, portrait, landscape等")
let scene: String
@Guide(description: "照片质量评分,1-10分")
let qualityScore: Int
@Guide(description: "照片的关键词标签")
let tags: [String]
@Guide(description: "改进建议")
let suggestions: [String]
}
enum PhotoMood: String, Codable {
case positive, neutral, negative
}
使用结构化生成:
swift
let session = LanguageModelSession()
let analysis = try await session.respond(
to: "分析这张照片:\(photoDescription)",
generating: PhotoAnalysis.self
)
print("主题: \(analysis.content.subject)")
print("质量评分: \(analysis.content.qualityScore)")
print("标签: \(analysis.content.tags.joined(separator: ", "))")
优势:
- ✅ 类型安全
- ✅ 自动解析
- ✅ 易于集成到现有代码
⚠️ Schema 开销注意 : 使用 @Generable 时,每个属性约增加 30 tokens 的开销。在设计复杂的数据结构时,需要考虑这个开销对上下文窗口的影响。
2.4 工具调用(Tool Calling)- 核心概念
Tool协议结构
Tool协议定义:
swift
protocol Tool<Arguments, Output> : Sendable {
var name: String { get }
var description: String { get }
var parameters: GenerationSchema { get }
func call(arguments: Arguments) async throws -> Output
}
基础Tool实现示例
swift
struct PhotoSearchTool: Tool {
let name = "searchPhotos"
let description = "根据关键词搜索相册中的照片"
@Generable
struct Arguments {
@Guide(description: "搜索关键词")
var keyword: String
}
func call(arguments: Arguments) async throws -> some PromptRepresentable {
let photos = await searchPhotos(keyword: arguments.keyword)
return GeneratedContent(properties: [
"count": photos.count,
"photos": photos.map { $0.toDict() }
])
}
}
工具调用工作机制
找一下去年夏天在海边的照片]) --> Step1[1. AI理解用户意图
分析查询内容] Step1 --> Step2[2. 匹配工具描述
PhotoSearchTool description] Step2 --> Step3[3. 生成参数
keyword: 海边
timeRange: 去年夏天] Step3 --> Step4[4. 执行工具
PhotoSearchTool.call] Step4 --> Step5[5. 获取结果
返回照片列表] Step5 --> Step6[6. 生成最终响应
我找到了5张照片...] Step6 --> End([返回给用户]) style Start fill:#007AFF,color:#fff style Step1 fill:#5AC8FA,color:#000 style Step2 fill:#5AC8FA,color:#000 style Step3 fill:#FF9500,color:#fff style Step4 fill:#FF9500,color:#fff style Step5 fill:#34C759,color:#fff style Step6 fill:#34C759,color:#fff style End fill:#007AFF,color:#fff
示例流程:
ini
用户: "找一下去年夏天在海边的照片"
→ AI识别: 搜索照片
→ 匹配工具: PhotoSearchTool
→ 提取参数: keyword="海边", timeRange="去年夏天"
→ 调用工具 → 返回结果
多工具协调
找照片+分析+创建相册]) --> AI[AI分析请求] AI --> Tool1[PhotoSearchTool
搜索照片] Tool1 --> Result1[照片列表] Result1 --> Tool2[PhotoAnalysisTool
分析内容] Tool2 --> Result2[分析结果] Result2 --> Tool3[AlbumCreationTool
创建相册] Tool3 --> Result3[相册创建成功] Result3 --> Response[AI生成最终响应] style User fill:#007AFF,color:#fff style AI fill:#5AC8FA,color:#000 style Tool1 fill:#FF9500,color:#fff style Tool2 fill:#FF9500,color:#fff style Tool3 fill:#FF9500,color:#fff style Response fill:#34C759,color:#fff
使用示例:
swift
let session = LanguageModelSession(
tools: [PhotoSearchTool(), PhotoAnalysisTool(), AlbumCreationTool()],
instructions: Instructions("你是智能相册助手")
)
// AI自动判断何时调用工具
let response = try await session.respond(
to: "找去年夏天在海边的照片,分析内容,创建相册"
)
Tool Calling最佳实践
最佳实践)) 清晰的工具描述 AI判断依据 描述要准确 包含使用场景 详细的参数Guide 帮助AI理解 明确参数含义 提供示例 结构化的返回结果 便于AI处理 统一的格式 包含必要信息 完善的错误处理 友好的错误信息 异常情况处理 降级方案 单一职责原则 一个工具一件事 避免功能耦合 易于维护
📸 第三部分:相册业务应用场景
3.1 智能照片分析
场景1: 自动生成照片描述
数据模型定义:
swift
@Generable
struct PhotoDescription {
@Guide(description: "照片的简短描述,50字以内")
let shortDescription: String
@Guide(description: "详细描述,包含人物、场景、活动等")
let detailedDescription: String
@Guide(description: "建议的相册分类")
let suggestedAlbum: String
@Guide(description: "照片的情感价值:high, medium, low")
let emotionalValue: String
}
实现流程:
ViewModel实现:
swift
@Observable
class PhotoAnalysisViewModel {
private let session = LanguageModelSession(
instructions: Instructions(
"你是一个专业的照片分析助手,擅长分析照片内容并生成有意义的描述。"
)
)
func analyzePhoto(_ photo: Photo) async throws -> PhotoDescription {
let metadata = photo.metadata
let prompt = """
分析这张照片:
- 拍摄时间: \(metadata.date)
- 拍摄地点: \(metadata.location ?? "未知")
- EXIF信息: \(metadata.exifInfo)
请生成详细的照片描述和分类建议。
"""
let response = try await session.respond(
to: Prompt(prompt),
generating: PhotoDescription.self
)
return response.content
}
}
场景2: 智能相册分类
分类流程图:
时间、地点、描述等] Extract --> Build[构建Prompt
包含所有照片信息] Build --> AI[AI分析
识别共同特征] AI --> Classify{分类标准} Classify --> Time[时间相关性] Classify --> Location[地点相关性] Classify --> Theme[主题相关性] Classify --> People[人物相关性] Time --> Result[生成相册建议] Location --> Result Theme --> Result People --> Result Result --> End([返回AlbumSuggestion列表]) style Start fill:#007AFF,color:#fff style Extract fill:#5AC8FA,color:#000 style Build fill:#5AC8FA,color:#000 style AI fill:#FF9500,color:#fff style Result fill:#34C759,color:#fff style End fill:#007AFF,color:#fff
代码实现:
swift
@Generable
struct AlbumSuggestion {
@Guide(description: "建议的相册名称")
let albumName: String
@Guide(description: "相册描述")
let description: String
@Guide(description: "应该包含的照片ID列表")
let photoIds: [String]
@Guide(description: "分类理由")
let reasoning: String
}
func suggestAlbums(for photos: [Photo]) async throws -> [AlbumSuggestion] {
let session = LanguageModelSession()
let photoDescriptions = photos.map { photo in
"照片\(photo.id): \(photo.description ?? "无描述") - \(photo.date)"
}.joined(separator: "\n")
let prompt = """
分析以下照片,建议如何将它们组织成相册:
\(photoDescriptions)
请考虑:
1. 时间相关性
2. 地点相关性
3. 主题相关性
4. 人物相关性
"""
let response = try await session.respond(
to: Prompt(prompt),
generating: [AlbumSuggestion].self
)
return response.content
}
3.2 智能搜索和推荐
场景3: 自然语言搜索
搜索工作流程:
去年夏天在海边拍的照片]) --> Parse[AI解析查询
提取关键词] Parse --> Extract[提取信息
时间: 去年夏天
地点: 海边
人物: 可选] Extract --> Tool[调用PhotoSearchTool
searchPhotos] Tool --> Search[执行搜索
匹配条件] Search --> Filter[筛选结果
按相似度排序] Filter --> Result[返回照片列表] Result --> Display[展示给用户] style User fill:#007AFF,color:#fff style Parse fill:#5AC8FA,color:#000 style Extract fill:#5AC8FA,color:#000 style Tool fill:#FF9500,color:#fff style Search fill:#FF9500,color:#fff style Filter fill:#34C759,color:#fff style Result fill:#34C759,color:#fff style Display fill:#007AFF,color:#fff
Tool实现:
swift
struct PhotoSearchTool: Tool {
let name = "searchPhotos"
let description = "在相册中搜索照片,支持自然语言查询"
@Generable
struct Arguments {
@Guide(description: "搜索查询,如'去年夏天在海边的照片'、'包含我妈妈的照片'")
var query: String
}
func call(arguments: Arguments) async throws -> some PromptRepresentable {
// 解析自然语言查询
let searchCriteria = parseNaturalLanguageQuery(arguments.query)
// 执行搜索
let results = await performPhotoSearch(criteria: searchCriteria)
return GeneratedContent(properties: [
"count": results.count,
"photos": results.map { $0.toDictionary() }
])
}
private func parseNaturalLanguageQuery(_ query: String) -> SearchCriteria {
// 使用Foundation Models解析查询
// 提取:时间、地点、人物、关键词等
}
}
// 使用示例
let session = LanguageModelSession(tools: [PhotoSearchTool()])
let response = try await session.respond(
to: "帮我找一下去年夏天在海边拍的照片,要包含我女朋友的"
)
场景4: 智能推荐相似照片
推荐算法流程:
描述、地点、时间、人物、标签] Extract --> Compare[与相册中其他照片
进行特征比较] Compare --> Score[计算相似度评分
多维度加权] Score --> Sort[按相似度排序] Sort --> Filter[筛选Top 5] Filter --> Result[生成推荐结果
包含相似原因] style Target fill:#007AFF,color:#fff style Extract fill:#5AC8FA,color:#000 style Compare fill:#FF9500,color:#fff style Score fill:#FF9500,color:#fff style Sort fill:#34C759,color:#fff style Filter fill:#34C759,color:#fff style Result fill:#007AFF,color:#fff
代码实现:
swift
@Generable
struct SimilarPhotoRecommendation {
@Guide(description: "推荐的照片ID")
let photoId: String
@Guide(description: "相似度评分,1-10分")
let similarityScore: Int
@Guide(description: "相似的原因")
let reason: String
}
func findSimilarPhotos(to targetPhoto: Photo) async throws -> [SimilarPhotoRecommendation] {
let session = LanguageModelSession()
let prompt = """
基于以下照片特征,推荐相似的照片:
目标照片:
- 描述: \(targetPhoto.description ?? "无")
- 地点: \(targetPhoto.location ?? "未知")
- 时间: \(targetPhoto.date)
- 人物: \(targetPhoto.people.joined(separator: ", "))
- 标签: \(targetPhoto.tags.joined(separator: ", "))
请从用户相册中推荐5张最相似的照片。
"""
let response = try await session.respond(
to: Prompt(prompt),
generating: [SimilarPhotoRecommendation].self
)
return response.content
}
3.3 视频内容理解
场景5: 视频摘要生成
视频分析流程:
时长、时间、地点] Metadata --> KeyFrames[提取关键帧
描述关键画面] KeyFrames --> Build[构建Prompt
包含所有信息] Build --> AI[AI分析
理解视频内容] AI --> Summary[生成摘要
简短描述] AI --> Moments[提取关键时刻
时间戳+描述] AI --> Theme[识别主题] AI --> Thumbnail[建议封面时间] Summary --> Result[返回VideoSummary] Moments --> Result Theme --> Result Thumbnail --> Result style Video fill:#007AFF,color:#fff style Metadata fill:#5AC8FA,color:#000 style KeyFrames fill:#5AC8FA,color:#000 style Build fill:#5AC8FA,color:#000 style AI fill:#FF9500,color:#fff style Result fill:#34C759,color:#fff
数据模型:
swift
@Generable
struct VideoSummary {
@Guide(description: "视频的简短摘要,100字以内")
let summary: String
@Guide(description: "视频的关键时刻时间戳列表")
let keyMoments: [KeyMoment]
@Guide(description: "视频的主题")
let theme: String
@Guide(description: "建议的封面帧时间")
let suggestedThumbnailTime: Double
}
@Generable
struct KeyMoment {
@Guide(description: "时刻的时间戳(秒)")
let timestamp: Double
@Guide(description: "时刻的描述")
let description: String
@Guide(description: "重要性评分,1-10")
let importance: Int
}
3.4 智能相册管理
场景6: 自动整理和清理建议
清理建议流程:
质量、大小、日期、描述] Analyze --> Criteria[应用清理标准
模糊、重复、低质量、临时] Criteria --> Score[计算清理优先级
综合评分] Score --> Sort[按优先级排序] Sort --> Suggest[生成清理建议
包含原因和空间] Suggest --> Result[返回CleanupSuggestion] style Photos fill:#007AFF,color:#fff style Analyze fill:#5AC8FA,color:#000 style Criteria fill:#FF9500,color:#fff style Score fill:#FF9500,color:#fff style Sort fill:#34C759,color:#fff style Suggest fill:#34C759,color:#fff style Result fill:#007AFF,color:#fff
代码实现:
swift
@Generable
struct CleanupSuggestion {
@Guide(description: "建议删除的照片ID列表")
let photosToDelete: [String]
@Guide(description: "删除原因")
let reason: String
@Guide(description: "预计可释放的存储空间(MB)")
let spaceToFree: Double
}
func suggestCleanup(for photos: [Photo]) async throws -> CleanupSuggestion {
let session = LanguageModelSession(
instructions: Instructions(
"你是一个相册管理助手,帮助用户清理重复、模糊或低质量的照片。"
)
)
let photoList = photos.map { photo in
"""
照片\(photo.id):
- 大小: \(photo.fileSize)MB
- 质量: \(photo.qualityScore)/10
- 日期: \(photo.date)
- 描述: \(photo.description ?? "无")
"""
}.joined(separator: "\n\n")
let prompt = """
分析以下照片,建议哪些可以删除以释放存储空间:
\(photoList)
考虑因素:
1. 照片质量(模糊、过曝、欠曝)
2. 重复照片
3. 截图和临时照片
4. 用户可能不需要的照片
"""
let response = try await session.respond(
to: Prompt(prompt),
generating: CleanupSuggestion.self
)
return response.content
}
💡 第四部分:实际编码实践和最佳实践
4.1 从零开始:实际开发流程
SystemLanguageModel.default] Step1 --> Check{模型可用?} Check -->|否| Error[显示错误提示
提供降级方案] Check -->|是| Step2[步骤2: 创建Session管理器
PhotoAISessionManager] Step2 --> Step3[步骤3: 集成到ViewModel
PhotoAnalysisViewModel] Step3 --> Step4[步骤4: 在SwiftUI中使用
PhotoAnalysisView] Step4 --> Success([完成集成]) Error --> End([结束]) Success --> End style Start fill:#007AFF,color:#fff style Step1 fill:#5AC8FA,color:#000 style Step2 fill:#5AC8FA,color:#000 style Step3 fill:#5AC8FA,color:#000 style Step4 fill:#5AC8FA,color:#000 style Check fill:#FF9500,color:#fff style Error fill:#FF3B30,color:#fff style Success fill:#34C759,color:#fff
步骤1: 检查模型可用性
swift
import FoundationModels
class FoundationModelsManager {
static let shared = FoundationModelsManager()
private init() {}
/// 检查Foundation Models是否可用
func checkAvailability() -> (available: Bool, reason: String?) {
let model = SystemLanguageModel.default
switch model.availability {
case .available:
return (true, nil)
case .unavailable(let reason):
return (false, reason.localizedDescription)
}
}
/// 在应用启动时检查并预热
func setup() async {
let (available, reason) = checkAvailability()
if !available {
print("⚠️ Foundation Models不可用: \(reason ?? "未知原因")")
return
}
// 预热模型(可选,但推荐)
await prewarmModel()
}
private func prewarmModel() async {
let session = LanguageModelSession()
do {
_ = try await session.respond(to: "Hello")
print("✅ Foundation Models预热成功")
} catch {
print("⚠️ 模型预热失败: \(error)")
}
}
}
// 在App启动时调用
@main
struct MyApp: App {
init() {
Task {
await FoundationModelsManager.shared.setup()
}
}
}
步骤2: 创建可复用的Session管理器
完整实现:
swift
import FoundationModels
import Observation
@Observable
class PhotoAISessionManager {
private(set) var session: LanguageModelSession
private let tools: [any Tool]
init() {
self.tools = [
PhotoSearchTool(),
PhotoAnalysisTool(),
AlbumCreationTool()
]
self.session = LanguageModelSession(
tools: tools,
instructions: Instructions("""
你是一个智能相册助手,可以帮助用户:
1. 搜索照片(使用searchPhotos工具)
2. 分析照片内容(使用analyzePhoto工具)
3. 创建相册(使用createAlbum工具)
始终用友好、自然的方式与用户交流。
""")
)
}
func sendMessage(_ message: String) async throws -> String {
let response = try await session.respond(to: Prompt(message))
return response.content
}
func streamMessage(_ message: String) -> AsyncThrowingStream<String, Error> {
AsyncThrowingStream { continuation in
Task {
do {
let stream = session.streamResponse(to: Prompt(message))
for try await partialText in stream {
continuation.yield(partialText)
}
continuation.finish()
} catch {
continuation.finish(throwing: error)
}
}
}
}
func generateStructured<T: Generable>(
prompt: String,
type: T.Type
) async throws -> T {
let response = try await session.respond(
to: Prompt(prompt),
generating: type
)
return response.content
}
func reset() {
self.session = LanguageModelSession(
tools: tools,
instructions: Instructions("你是一个智能相册助手")
)
}
}
步骤3: 集成到ViewModel
SwiftUI View] end subgraph "ViewModel Layer" ViewModel[PhotoAnalysisViewModel
@Observable] SessionManager[PhotoAISessionManager] end subgraph "Model Layer" Model[Photo Model] FoundationModels[Foundation Models] end View -->|@State| ViewModel ViewModel -->|调用| SessionManager SessionManager -->|使用| FoundationModels ViewModel -->|操作| Model Model -->|更新| ViewModel ViewModel -->|通知| View style View fill:#007AFF,color:#fff style ViewModel fill:#5AC8FA,color:#000 style SessionManager fill:#FF9500,color:#fff style Model fill:#34C759,color:#fff style FoundationModels fill:#FF3B30,color:#fff
ViewModel实现:
swift
@Observable
class PhotoAnalysisViewModel {
private let sessionManager = PhotoAISessionManager()
var isLoading = false
var errorMessage: String?
var analysisResult: PhotoDescription?
var streamingText = ""
func analyzePhoto(_ photo: Photo) async {
isLoading = true
errorMessage = nil
do {
let metadata = photo.metadata
let prompt = """
分析这张照片:
- 时间: \(metadata.date)
- 地点: \(metadata.location ?? "未知")
- EXIF: \(metadata.exifInfo)
请生成详细的照片描述和分类建议。
"""
let result = try await sessionManager.generateStructured(
prompt: prompt,
type: PhotoDescription.self
)
await MainActor.run {
self.analysisResult = result
self.isLoading = false
}
} catch {
await MainActor.run {
self.errorMessage = handleError(error)
self.isLoading = false
}
}
}
func analyzePhotoWithStreaming(_ photo: Photo) async {
isLoading = true
streamingText = ""
errorMessage = nil
do {
let metadata = photo.metadata
let prompt = """
分析这张照片:
- 时间: \(metadata.date)
- 地点: \(metadata.location ?? "未知")
请详细分析照片内容。
"""
for try await partialText in sessionManager.streamMessage(prompt) {
await MainActor.run {
self.streamingText += partialText
}
}
await MainActor.run {
self.isLoading = false
}
} catch {
await MainActor.run {
self.errorMessage = handleError(error)
self.isLoading = false
}
}
}
private func handleError(_ error: Error) -> String {
if let generationError = error as? LanguageModelSession.GenerationError {
switch generationError {
case .exceededContextWindowSize:
return "对话内容过长,请清理历史记录"
default:
return "生成失败: \(generationError.localizedDescription)"
}
}
return "错误: \(error.localizedDescription)"
}
}
步骤4: 在SwiftUI中使用
swift
import SwiftUI
struct PhotoAnalysisView: View {
@State private var viewModel = PhotoAnalysisViewModel()
@State private var selectedPhoto: Photo?
var body: some View {
VStack {
if viewModel.isLoading {
ProgressView("分析中...")
.padding()
}
if let error = viewModel.errorMessage {
Text("错误: \(error)")
.foregroundColor(.red)
.padding()
}
if let result = viewModel.analysisResult {
VStack(alignment: .leading, spacing: 12) {
Text("主题: \(result.subject)")
Text("质量评分: \(result.qualityScore)/10")
Text("标签: \(result.tags.joined(separator: ", "))")
}
.padding()
}
if !viewModel.streamingText.isEmpty {
ScrollView {
Text(viewModel.streamingText)
.padding()
}
}
Button("分析照片") {
if let photo = selectedPhoto {
Task {
await viewModel.analyzePhoto(photo)
}
}
}
.disabled(viewModel.isLoading || selectedPhoto == nil)
}
}
}
4.2 性能优化实践
内存消耗与性能特征
实际内存占用:
根据实际测试,Foundation Models 在运行时的内存消耗包括:
| 组件 | 内存占用 | 说明 |
|---|---|---|
| 模型权重 | ~750MB | 3B 参数 × 2-bit 量化 |
| KV Cache | ~300-600MB | 8-bit 量化,37.5% 减少优化 |
| 框架开销 | ~100-200MB | 系统框架和运行时开销 |
| 总计 | ~1.0-1.5GB | 实际运行时内存占用 |
内存管理建议:
- 在内存受限的设备上,需要仔细考虑何时加载和释放 session
- 好消息是苹果做了很多优化,比如 KV cache 的 8-bit 量化和 37.5% 的 block sharing 减少
- base 模型本身似乎在不用时也会自动 unload
性能特征:
| 场景 | iPhone | M2 Pro | 说明 |
|---|---|---|---|
| 单 session | 10-30 tokens/s | ~30 tokens/s | 正常性能 |
| 3 个并发 session | 每个约 1 token/s | 每个约 1 token/s | ⚠️ 严重性能下降 |
⚠️ 并发性能警告: 多 session 并发会严重影响性能,从 10-30 tokens/s 骤降至约 1 token/s。苹果只考虑了单 session 的使用场景。
推荐做法 : 全局管理一个 session,使用队列串行访问,避免任何并发 session。
swift
// ✅ 推荐:使用队列管理请求
actor SessionManager {
private let session = LanguageModelSession()
private var requestQueue: [AIRequest] = []
func processRequest(_ request: AIRequest) async -> AIResponse {
// 串行处理,不要并发
// 使用队列确保同一时间只有一个请求在使用 session
}
}
上下文窗口管理
⚠️ 重要限制 : 虽然苹果提到模型训练时支持最高 65K tokens 的上下文,但实际部署到用户设备上的硬限制是 4096 tokens。这对于一般的对话场景,大约能支持 10-20 轮对话。
检查} Check -->|小于80%| Normal[正常使用] Check -->|达到80%| Clean[清理旧对话] Normal --> Continue[继续对话] Clean --> Keep[保留最近对话
约3000 tokens] Keep --> Continue Continue --> Check style Start fill:#007AFF,color:#fff style Check fill:#FF9500,color:#fff style Normal fill:#34C759,color:#fff style Clean fill:#FF3B30,color:#fff style Keep fill:#5AC8FA,color:#000
实现代码:
swift
class OptimizedChatViewModel: ObservableObject {
// ⚠️ 实际限制是 4096 tokens,不是 65K
private let maxTokens = 4096
private let windowThreshold = 0.8 // 80%时开始清理
private let targetWindowSize = 3000 // 目标窗口大小(保留一些余量)
private(set) var session: LanguageModelSession
init() {
self.session = LanguageModelSession()
}
private func shouldApplySlidingWindow() -> Bool {
let currentTokens = session.transcript.estimatedTokenCount
let ratio = Double(currentTokens) / Double(maxTokens)
return ratio >= windowThreshold
}
@MainActor
private func applySlidingWindow() async {
let recentEntries = session.transcript.entriesWithinTokenBudget(
targetWindowSize: targetWindowSize
)
var finalEntries = recentEntries
if let instructions = session.transcript.first(where: {
if case .instructions = $0 { return true }
return false
}) {
if !finalEntries.contains(where: { $0.id == instructions.id }) {
finalEntries.insert(instructions, at: 0)
}
}
session = LanguageModelSession(
transcript: Transcript(entries: finalEntries)
)
}
@MainActor
func sendMessage(_ message: String) async throws {
if shouldApplySlidingWindow() {
await applySlidingWindow()
}
let stream = session.streamResponse(to: Prompt(message))
for try await _ in stream {
// 流式响应自动更新transcript
}
}
}
预加载和预热(Prewarming)
预热(Prewarming) 是在用户发出请求之前,提前加载和初始化设备上的语言模型,从而减少初始延迟的关键优化技术。
预热的工作原理
预热的核心价值:
- ✅ 减少首次调用延迟: 从 3-6 秒降低到 1-2 秒
- ✅ 提升用户体验: 用户几乎无感知的等待时间
- ✅ 优化资源利用: 在用户空闲时提前准备,避免阻塞主线程
预热的最佳时机
预热时机优先级:
-
应用启动时 (低优先级)
-
优点:最早准备,用户首次使用即可快速响应
-
缺点:可能影响应用启动速度
-
建议:在后台低优先级线程预热,不影响启动
-
-
用户进入AI功能页面时 (中优先级)
-
优点:用户明确意图,预热价值高
-
缺点:如果用户不实际使用,浪费资源
-
建议:在页面出现时立即预热
-
-
用户点击输入框时 (高优先级)
-
优点:用户即将使用,预热最及时
-
缺点:可能来不及完全预热
-
建议:快速预热,至少完成基础初始化
-
基础预热实现
swift
class ModelPrewarmer {
static let shared = ModelPrewarmer()
private var isPrewarmed = false
private var prewarmingTask: Task<Void, Never>?
private let prewarmQueue = DispatchQueue(label: "com.app.prewarm", qos: .utility)
/// 预热模型(基础版本)
func prewarm() {
guard !isPrewarmed else { return }
prewarmQueue.async {
Task {
do {
let session = LanguageModelSession()
// 发送一个简单的请求来预热模型
_ = try await session.respond(to: "Hello")
await MainActor.run {
self.isPrewarmed = true
print("✅ 模型预热成功")
}
} catch {
await MainActor.run {
print("⚠️ 模型预热失败: \(error)")
}
}
}
}
}
/// 检查预热状态
var isReady: Bool {
return isPrewarmed
}
}
智能预热实现(多时机支持)
swift
enum PrewarmPriority {
case low // 应用启动时
case medium // 进入功能页面时
case high // 用户点击输入框时
}
class SmartModelPrewarmer {
static let shared = SmartModelPrewarmer()
private var isPrewarmed = false
private var prewarmingTask: Task<Void, Never>?
private var prewarmStartTime: Date?
/// 智能预热:根据优先级和时机决定是否预热
func prewarm(priority: PrewarmPriority = .medium) {
// 如果已经预热,直接返回
if isPrewarmed {
return
}
// 如果正在预热,检查优先级
if let task = prewarmingTask, !task.isCancelled {
// 高优先级可以取消低优先级预热,重新开始
if priority == .high {
task.cancel()
} else {
return
}
}
// 根据优先级设置 QoS
let qos: TaskPriority = priority == .high ? .userInitiated : .utility
prewarmStartTime = Date()
prewarmingTask = Task(priority: qos) {
do {
let session = LanguageModelSession()
// 根据优先级选择预热策略
switch priority {
case .high:
// 高优先级:快速预热,只做基础初始化
_ = try await session.respond(to: "Hi")
case .medium:
// 中优先级:完整预热
_ = try await session.respond(to: "Hello, how can I help you?")
case .low:
// 低优先级:后台预热,不阻塞
_ = try await session.respond(to: "Hello")
}
let duration = Date().timeIntervalSince(self.prewarmStartTime ?? Date())
await MainActor.run {
self.isPrewarmed = true
print("✅ 模型预热成功(优先级: \(priority), 耗时: \(String(format: "%.2f", duration))秒)")
}
} catch {
await MainActor.run {
print("⚠️ 模型预热失败: \(error)")
}
}
}
}
/// 取消预热(如果用户离开页面)
func cancelPrewarming() {
prewarmingTask?.cancel()
prewarmingTask = nil
}
}
在应用中的集成
场景1: 应用启动时预热
swift
@main
struct MyApp: App {
init() {
// 应用启动时,低优先级预热
Task.detached(priority: .utility) {
await SmartModelPrewarmer.shared.prewarm(priority: .low)
}
}
}
场景2: 进入AI功能页面时预热
swift
struct PhotoAnalysisView: View {
@State private var viewModel = PhotoAnalysisViewModel()
var body: some View {
VStack {
// UI 内容
}
.onAppear {
// 用户进入页面时,立即预热
SmartModelPrewarmer.shared.prewarm(priority: .medium)
}
.onDisappear {
// 用户离开页面时,可以取消预热(可选)
// SmartModelPrewarmer.shared.cancelPrewarming()
}
}
}
场景3: 用户点击输入框时预热
swift
struct ChatInputView: View {
@State private var inputText = ""
@FocusState private var isInputFocused: Bool
var body: some View {
TextField("输入消息...", text: $inputText)
.focused($isInputFocused)
.onChange(of: isInputFocused) { focused in
if focused {
// 用户点击输入框时,高优先级快速预热
SmartModelPrewarmer.shared.prewarm(priority: .high)
}
}
}
}
预热效果对比
性能提升数据(基于 Instruments 分析):
| 场景 | 无预热 | 有预热 | 提升 |
|---|---|---|---|
| 首次调用延迟 | 3-6秒 | 1-2秒 | 50-70% |
| 用户感知等待 | 明显 | 几乎无感知 | 显著改善 |
| 内存占用 | 按需加载 | 提前占用 | 增加约 200-500MB |
预热最佳实践
1. 预热时机选择
2. 预热策略建议
- ✅ 渐进式预热: 先做基础初始化,再逐步完善
- ✅ 优先级管理: 根据用户行为调整预热优先级
- ✅ 资源监控: 使用 Instruments 监控预热对内存和性能的影响
- ✅ 降级处理: 如果预热失败,提供友好的降级方案
3. 预热检查清单
- 是否在合适的时机触发预热?
- 预热是否影响应用启动速度?
- 是否处理了预热失败的情况?
- 是否在用户离开页面时取消不必要的预热?
- 是否使用 Instruments 验证预热效果?
参考资源:
缓存策略
缓存策略是优化 Foundation Models 应用性能的重要手段。合理的缓存可以显著减少重复计算,提升响应速度,降低资源消耗。
缓存策略概述
缓存的核心价值:
- ✅ 减少重复计算: 相同输入直接返回缓存结果
- ✅ 提升响应速度: 缓存命中时几乎零延迟
- ✅ 降低资源消耗: 减少模型调用次数,节省计算资源
- ✅ 改善用户体验: 快速响应,特别是重复查看相同内容时
缓存键设计
缓存键的设计直接影响缓存命中率和有效性。
好的缓存键应该包含:
- 输入数据的唯一标识(如照片ID)
- 可能影响结果的数据版本(如修改时间)
- 生成参数(如不同的Instructions可能产生不同结果)
swift
class CacheKeyBuilder {
/// 为照片分析生成缓存键
static func keyForPhotoAnalysis(
photoId: String,
modificationDate: Date,
instructionsHash: String? = nil
) -> String {
var components = [photoId, String(modificationDate.timeIntervalSince1970)]
if let hash = instructionsHash {
components.append(hash)
}
return components.joined(separator: "|")
}
/// 为自然语言搜索生成缓存键
static func keyForSearch(
query: String,
photoCount: Int
) -> String {
// 使用查询内容和照片数量作为键
// 注意:如果相册内容变化,需要使缓存失效
return "search:\(query.hashValue):\(photoCount)"
}
}
内存缓存实现
基础内存缓存:
swift
class MemoryCache<T: Codable> {
private var cache: [String: CacheEntry<T>] = [:]
private let maxSize: Int
private let accessQueue = DispatchQueue(label: "com.app.cache", attributes: .concurrent)
init(maxSize: Int = 100) {
self.maxSize = maxSize
}
/// 获取缓存
func get(for key: String) -> T? {
return accessQueue.sync {
guard let entry = cache[key] else { return nil }
// 更新访问时间(用于LRU)
entry.lastAccessed = Date()
return entry.value
}
}
/// 设置缓存
func set(_ value: T, for key: String) {
accessQueue.async(flags: .barrier) {
// 如果缓存已满,执行淘汰策略
if self.cache.count >= self.maxSize && self.cache[key] == nil {
self.evictOldest()
}
self.cache[key] = CacheEntry(value: value, lastAccessed: Date())
}
}
/// LRU淘汰:移除最久未访问的条目
private func evictOldest() {
guard let oldest = cache.min(by: { $0.value.lastAccessed < $1.value.lastAccessed }) else {
return
}
cache.removeValue(forKey: oldest.key)
}
/// 清除所有缓存
func clear() {
accessQueue.async(flags: .barrier) {
self.cache.removeAll()
}
}
/// 获取缓存统计
var stats: CacheStats {
return accessQueue.sync {
CacheStats(
size: cache.count,
maxSize: maxSize,
hitRate: 0 // 需要额外实现命中率统计
)
}
}
}
/// 缓存条目
private class CacheEntry<T> {
let value: T
var lastAccessed: Date
var accessCount: Int = 1
init(value: T, lastAccessed: Date) {
self.value = value
self.lastAccessed = lastAccessed
}
}
/// 缓存统计
struct CacheStats {
let size: Int
let maxSize: Int
let hitRate: Double
}
使用内存缓存的完整示例:
swift
class CachedPhotoAnalysisService {
private let cache = MemoryCache<PhotoDescription>(maxSize: 100)
private let sessionManager = PhotoAISessionManager()
func analyzePhoto(_ photo: Photo) async throws -> PhotoDescription {
// 生成缓存键
let cacheKey = CacheKeyBuilder.keyForPhotoAnalysis(
photoId: photo.id,
modificationDate: photo.modificationDate
)
// 检查缓存
if let cached = cache.get(for: cacheKey) {
print("✅ 缓存命中: \(cacheKey)")
return cached
}
print("❌ 缓存未命中,生成新结果: \(cacheKey)")
// 生成新结果
let prompt = generateAnalysisPrompt(for: photo)
let result = try await sessionManager.generateStructured(
prompt: prompt,
type: PhotoDescription.self
)
// 存储到缓存
cache.set(result, for: cacheKey)
return result
}
private func generateAnalysisPrompt(for photo: Photo) -> String {
// 生成分析提示词
return "分析照片..."
}
}
持久化缓存实现
对于需要跨应用启动保持的缓存,可以使用文件系统持久化:
swift
class PersistentCache<T: Codable> {
private let memoryCache = MemoryCache<T>(maxSize: 50)
private let cacheDirectory: URL
private let fileManager = FileManager.default
init(cacheName: String) throws {
let cacheDir = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
cacheDirectory = cacheDir.appendingPathComponent(cacheName)
// 创建缓存目录
try fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
}
/// 获取缓存(先查内存,再查磁盘)
func get(for key: String) -> T? {
// 先查内存缓存
if let memoryValue = memoryCache.get(for: key) {
return memoryValue
}
// 再查磁盘缓存
if let diskValue = loadFromDisk(key: key) {
// 加载到内存缓存
memoryCache.set(diskValue, for: key)
return diskValue
}
return nil
}
/// 设置缓存(同时写入内存和磁盘)
func set(_ value: T, for key: String) {
// 写入内存缓存
memoryCache.set(value, for: key)
// 异步写入磁盘
Task.detached(priority: .utility) {
self.saveToDisk(value: value, key: key)
}
}
/// 从磁盘加载
private func loadFromDisk(key: String) -> T? {
let fileURL = cacheDirectory.appendingPathComponent("\(key.hashValue).json")
guard let data = try? Data(contentsOf: fileURL),
let value = try? JSONDecoder().decode(T.self, from: data) else {
return nil
}
return value
}
/// 保存到磁盘
private func saveToDisk(value: T, key: String) {
let fileURL = cacheDirectory.appendingPathComponent("\(key.hashValue).json")
guard let data = try? JSONEncoder().encode(value) else { return }
try? data.write(to: fileURL)
}
/// 清理过期缓存
func cleanExpired(maxAge: TimeInterval = 7 * 24 * 3600) {
// 清理超过7天的缓存文件
// 实现细节...
}
}
缓存失效策略
缓存失效是缓存策略的重要组成部分,需要根据业务场景选择合适的策略:
实现带失效策略的缓存:
swift
class CacheEntryWithExpiry<T> {
let value: T
let createdAt: Date
let expiresAt: Date?
init(value: T, ttl: TimeInterval? = nil) {
self.value = value
self.createdAt = Date()
self.expiresAt = ttl.map { Date().addingTimeInterval($0) }
}
var isExpired: Bool {
guard let expiresAt = expiresAt else { return false }
return Date() > expiresAt
}
}
class ExpiringCache<T: Codable> {
private var cache: [String: CacheEntryWithExpiry<T>] = [:]
private let maxSize: Int
private let defaultTTL: TimeInterval?
init(maxSize: Int = 100, defaultTTL: TimeInterval? = 7 * 24 * 3600) {
self.maxSize = maxSize
self.defaultTTL = defaultTTL
}
func get(for key: String) -> T? {
guard let entry = cache[key] else { return nil }
// 检查是否过期
if entry.isExpired {
cache.removeValue(forKey: key)
return nil
}
return entry.value
}
func set(_ value: T, for key: String, ttl: TimeInterval? = nil) {
let entry = CacheEntryWithExpiry(value: value, ttl: ttl ?? defaultTTL)
// 如果缓存已满,移除过期或最旧的条目
if cache.count >= maxSize && cache[key] == nil {
evictExpiredOrOldest()
}
cache[key] = entry
}
private func evictExpiredOrOldest() {
// 先移除过期的
let expiredKeys = cache.filter { $0.value.isExpired }.map { $0.key }
expiredKeys.forEach { cache.removeValue(forKey: $0) }
// 如果还有空间,不需要继续
if cache.count < maxSize { return }
// 移除最旧的
if let oldest = cache.min(by: { $0.value.createdAt < $1.value.createdAt }) {
cache.removeValue(forKey: oldest.key)
}
}
/// 手动使缓存失效
func invalidate(for key: String) {
cache.removeValue(forKey: key)
}
/// 使所有缓存失效
func invalidateAll() {
cache.removeAll()
}
}
缓存策略选择指南
不同场景的缓存策略建议:
| 场景 | 缓存类型 | 失效策略 | 淘汰策略 | 容量建议 |
|---|---|---|---|---|
| 照片分析结果 | 内存+持久化 | 照片修改时失效 | LRU | 100-200条 |
| 搜索查询结果 | 仅内存 | 相册内容变化时失效 | LRU | 50-100条 |
| 相册分类建议 | 仅内存 | 照片数量变化时失效 | FIFO | 20-50条 |
| 视频摘要 | 持久化 | 7天过期 | LRU | 50-100条 |
缓存最佳实践
1. 缓存键设计原则
- ✅ 包含所有影响结果的因素
- ✅ 使用稳定的标识符(如照片ID + 修改时间)
- ✅ 避免包含易变数据(如当前时间戳)
- ✅ 考虑哈希冲突,使用足够长的键
2. 缓存容量管理
swift
class CacheManager {
/// 根据设备内存动态调整缓存大小
static func optimalCacheSize() -> Int {
let totalMemory = ProcessInfo.processInfo.physicalMemory
let availableMemory = totalMemory / 4 // 使用1/4可用内存
// 假设每个缓存条目平均占用 10KB
let entrySize = 10 * 1024
let maxEntries = Int(availableMemory) / entrySize
// 限制在合理范围内
return min(maxEntries, 500)
}
}
3. 缓存性能监控
swift
class CacheMetrics {
private var hits: Int = 0
private var misses: Int = 0
func recordHit() { hits += 1 }
func recordMiss() { misses += 1 }
var hitRate: Double {
let total = hits + misses
guard total > 0 else { return 0 }
return Double(hits) / Double(total)
}
func reset() {
hits = 0
misses = 0
}
}
// 在缓存服务中使用
class CachedPhotoAnalysisService {
private let metrics = CacheMetrics()
func analyzePhoto(_ photo: Photo) async throws -> PhotoDescription {
let cacheKey = CacheKeyBuilder.keyForPhotoAnalysis(...)
if let cached = cache.get(for: cacheKey) {
metrics.recordHit()
return cached
}
metrics.recordMiss()
// ... 生成新结果
}
func getCacheStats() -> (hitRate: Double, size: Int) {
return (metrics.hitRate, cache.stats.size)
}
}
4. 缓存检查清单
- 缓存键是否包含所有影响结果的因素?
- 是否实现了合适的失效策略?
- 缓存容量是否合理(不会导致内存压力)?
- 是否监控了缓存命中率?
- 是否处理了缓存失败的情况?
- 是否需要持久化缓存(跨启动保持)?
参考资源:
使用 Instruments 进行性能分析
Instruments 是 Apple 提供的性能分析工具,最新版本已添加 Foundation Models 模块,可以在 iPhone 设备上直接进行性能分析,帮助开发者优化应用性能。
Instruments Foundation Models 模块功能
核心分析指标:
-
模型加载时间(Model Load Time)
-
测量模型从存储加载到内存并准备就绪的时间
-
帮助识别首次调用延迟问题
-
优化建议:预热模型、优化存储位置
-
-
推理时间(Inference Time)
-
测量模型接收输入并生成输出所需的时间
-
识别性能瓶颈和优化点
-
优化建议:精简 Prompt、优化 Instructions
-
-
输入令牌数量(Input Token Count)
-
统计每次请求的输入令牌总数
-
帮助优化输入长度,减少成本
-
优化建议:精简上下文、使用摘要
-
-
内存使用(Memory Usage)
-
监控模型运行时的内存占用
-
识别内存泄漏和峰值使用
-
优化建议:及时释放 Session、管理上下文窗口
-
使用步骤
步骤1: 打开 Instruments
- 在 Xcode 中,选择 Product → Profile (或按
⌘I) - 选择 Foundation Models 模板
- 选择目标设备(必须是支持 Apple Intelligence 的真实设备)
步骤2: 配置分析选项
步骤3: 执行操作并分析
在应用中使用 Foundation Models 功能,Instruments 会自动记录:
- 每次
LanguageModelSession.respond()调用的时间线 - 模型加载事件和耗时
- 输入令牌数量统计
- 内存分配和释放情况
步骤4: 查看分析结果
Instruments 会显示以下视图:
- 时间线视图: 显示模型加载和推理的时间分布
- 统计视图: 显示平均/最大/最小推理时间
- 令牌统计: 显示输入令牌数量分布
- 内存视图: 显示内存使用趋势
性能优化实践示例
场景1: 优化首次调用延迟
swift
// 在 Instruments 中观察模型加载时间
class PhotoAnalysisService {
func analyzePhoto(_ photo: Photo) async throws -> PhotoDescription {
// Instruments 会记录这里的模型加载时间
let session = LanguageModelSession()
// 如果加载时间过长,考虑预热
// 在应用启动时提前加载模型
let response = try await session.respond(
to: Prompt("分析照片"),
generating: PhotoDescription.self
)
return response.content
}
}
优化建议:
- 如果 Instruments 显示首次调用延迟 > 2秒,考虑在应用启动时预热模型
- 使用
ModelPrewarmer在后台预热,避免用户首次使用时等待
场景2: 优化 Prompt 长度
swift
// 在 Instruments 中观察输入令牌数量
func analyzePhotoWithMetadata(_ photo: Photo) async throws -> PhotoDescription {
let session = LanguageModelSession()
// ❌ 不好的做法:包含过多元数据,令牌数量过多
let longPrompt = """
分析照片:
- 拍摄时间: \(photo.date)
- 拍摄地点: \(photo.location ?? "未知")
- EXIF信息: \(photo.exifInfo)
- 文件大小: \(photo.fileSize)MB
- 分辨率: \(photo.resolution)
- 相机型号: \(photo.cameraModel)
- ISO: \(photo.iso)
- 光圈: \(photo.aperture)
- 快门速度: \(photo.shutterSpeed)
... 更多元数据
"""
// ✅ 好的做法:只包含关键信息,减少令牌数量
let optimizedPrompt = """
分析照片:
- 时间: \(photo.date)
- 地点: \(photo.location ?? "未知")
- 关键信息: \(photo.keyMetadata)
"""
let response = try await session.respond(
to: Prompt(optimizedPrompt),
generating: PhotoDescription.self
)
return response.content
}
优化建议:
- 使用 Instruments 监控输入令牌数量
- 如果平均令牌数量 > 1000,考虑精简 Prompt
- 移除不必要的元数据,只保留关键信息
场景3: 识别性能瓶颈
是否过长?} Check1 -->|是| Action1[预热模型
优化加载策略] Check1 -->|否| Check2{推理时间
是否过长?} Check2 -->|是| Action2[精简 Prompt
优化 Instructions] Check2 -->|否| Check3{令牌数量
是否过多?} Check3 -->|是| Action3[减少上下文
使用摘要] Check3 -->|否| Check4{内存使用
是否异常?} Check4 -->|是| Action4[管理上下文窗口
及时释放 Session] Check4 -->|否| Success[性能优化完成] Action1 --> Success Action2 --> Success Action3 --> Success Action4 --> Success style Profile fill:#007AFF,color:#fff style Check1 fill:#FF9500,color:#fff style Check2 fill:#FF9500,color:#fff style Check3 fill:#FF9500,color:#fff style Check4 fill:#FF9500,color:#fff style Action1 fill:#34C759,color:#fff style Action2 fill:#34C759,color:#fff style Action3 fill:#34C759,color:#fff style Action4 fill:#34C759,color:#fff style Success fill:#007AFF,color:#fff
Instruments 分析最佳实践
1. 建立性能基准
在优化前,先建立性能基准:
- 记录首次调用延迟
- 记录平均推理时间
- 记录典型场景的令牌数量
- 记录峰值内存使用
2. 对比优化效果
每次优化后,使用 Instruments 对比:
- 优化前后的时间对比
- 令牌数量变化
- 内存使用改善
3. 关注关键路径
重点关注用户感知明显的路径:
- 首次调用延迟(影响第一印象)
- 常见操作的推理时间(影响日常体验)
- 峰值内存使用(影响稳定性)
4. 真实设备测试
⚠️ 重要: Foundation Models 在模拟器上不可用,必须在真实设备上使用 Instruments 分析。
参考资源:
4.3 Foundation Models 的边界和限制
了解 Foundation Models 的边界和限制,对于在实际项目中使用至关重要。本节基于实际测试数据,帮助你理解框架的能力边界。
核心限制汇总
| 类别 | 限制/特征 | 详细说明 |
|---|---|---|
| 上下文窗口 | 4096 tokens | • 实际限制:4096 tokens(不是训练时的 65K) • 约支持 10-20 轮对话 • 需要设计上下文管理策略 |
| 内存消耗 | 1.0-1.5GB | • 模型权重:~750MB(3B 参数 × 2-bit 量化) • KV Cache:~300-600MB(8-bit 量化,37.5% 减少优化) • 框架开销:~100-200MB |
| 并发性能 | 单 session 正常 | • 单 session:iPhone 10-30 tokens/s,M2 Pro ~30 tokens/s • 多 session:每个 session 降至约 1 token/s • 建议:使用队列串行访问,避免并发 session |
| 结构化生成 | Schema 开销 | • 每个 @Generable 属性约增加 30 tokens • 设计复杂数据结构时需要考虑开销 • 影响上下文窗口使用 |
| 适用场景 | 文本处理为主 | ✅ 适合 :文本摘要、内容分类、结构化提取、自然语言理解 ❌ 不适合:数学计算、代码生成、复杂推理、最新信息(训练数据截止 2023年10月) |
适用场景与不适用场景
✅ 适合的场景:
根据实际测试,Foundation Models 在以下场景表现不错:
- 文本摘要: 生成内容摘要、提取关键信息
- 内容分类: 对文本、照片等内容进行分类
- 结构化数据提取: 从非结构化文本中提取结构化信息
- 自然语言理解: 理解用户意图、解析查询
❌ 不适合的场景:
- 数学计算: 模型不适合进行精确的数学计算
- 代码生成: 代码生成能力有限
- 复杂推理: 复杂逻辑推理能力有限
- 最新信息: 训练数据截止到 2023 年 10 月,世界知识有限
温度参数敏感性
测试发现: 温度参数在 0.0-2.0 范围内表现稳定,意外地不敏感。这意味着你可以在这个范围内调整温度,而不会对输出质量产生显著影响。
swift
// 温度参数设置示例
let session = LanguageModelSession(
// 温度范围 0.0-2.0 表现稳定
// 可以根据需要调整,但影响不会很大
)
安全防护机制
Foundation Models 内置了相当严格的安全防护机制:
- 内容过滤: 会删除违规的 transcript 条目
- 自动清理: 检测到不当内容时会自动清理对话历史
- Guardrail: 内置安全护栏,防止生成不当内容
开发建议:
- 在设计应用时,要考虑安全机制可能删除部分对话内容
- 对于敏感场景,需要额外的输入验证和输出检查
- 不要依赖模型完全阻止不当内容,应用层也需要做防护
Apple Foundation Models 开发流程
Apple Foundation Models 的开发遵循一个完整的机器学习管道,从数据收集到最终部署:
数据收集] --> P[Preprocessing
数据预处理] P --> PT[Pre-Training
预训练] PT --> POST[Post-Training
后训练] end POST --> OPT[Optimization
模型优化] OPT --> ADAPTERS[Adapters
适配器层] ADAPTERS --> FM[Apple Foundation Models
基础模型] style D fill:#4A90E2,color:#fff style P fill:#9B59B6,color:#fff style PT fill:#E91E63,color:#fff style POST fill:#F39C12,color:#fff style OPT fill:#FF9800,color:#fff style ADAPTERS fill:#3498DB,color:#fff style FM fill:#2ECC71,color:#fff
流程阶段详解:
1. Data(数据收集)
- 作用: 收集用于训练模型的数据集
- 特点: 多模态(文本、图像、音频等)和多语言数据
- 重要性: 数据质量直接影响模型性能
2. Preprocessing(数据预处理)
- 作用: 清洗、标准化和准备训练数据
- 任务 :
- 数据清洗(去除噪声、错误数据)
- 数据标注(为监督学习准备标签)
- 数据格式转换(统一数据格式)
- 多语言处理(处理不同语言的数据)
3. Pre-Training(预训练)
- 作用: 在大规模无标注数据上进行自监督学习
- 目标: 让模型学习通用的语言表示和知识
- 特点 :
- 使用大量文本数据
- 学习语言的基本规律和模式
- 建立基础的语义理解能力
4. Post-Training(后训练)
- 作用: 在预训练基础上进行进一步优化
- 任务 :
- 指令微调(Instruction Tuning)
- 对齐训练(Alignment Training)
- 安全训练(Safety Training)
- 评估和验证模型性能
5. Optimization(模型优化)
- 作用: 针对设备端部署进行优化
- 优化技术 (详见下一节):
- 2-bit 量化
- 推测解码和草稿模型
- 约束解码
- KV Cache 优化
- 目标: 在保持模型质量的同时,减少存储和内存需求
6. Adapters(适配器层)
- 作用: 提供特定任务或领域的适配接口
- 特点 :
- 多个适配器可以连接到同一个基础模型
- 每个适配器针对不同的使用场景
- 允许在不修改基础模型的情况下扩展功能
7. Apple Foundation Models(基础模型)
- 作用: 最终部署的设备端模型
- 特点 :
- 通过适配器层访问
- 优化后的模型,适合设备端运行
- 支持多种任务和应用场景
核心原则:
Responsible AI principles inform all steps(负责任 AI 原则贯穿所有步骤)
这意味着在整个开发流程中,Apple 都遵循负责任 AI 的原则:
- 隐私保护: 数据收集和处理过程中保护用户隐私
- 公平性: 确保模型对不同用户群体公平
- 透明度: 公开模型能力和限制
- 安全性: 防止模型生成有害内容
- 可解释性: 提供模型决策的解释
多模态 + 多语言处理:
前四个阶段(Data → Preprocessing → Pre-Training → Post-Training)被标记为"多模态 + 多语言",说明:
- 多模态: 处理文本、图像、音频等多种数据类型
- 多语言: 支持多种语言的训练和推理
- 统一处理: 在同一个流程中处理不同类型的数据
流程关系:
数据收集 → 预处理 → 预训练 → 后训练 → 优化 → 适配器 → 基础模型
↓ ↓ ↓ ↓ ↓ ↓ ↓
多模态 标准化 学习通用 任务对齐 设备优化 任务适配 最终部署
多语言 清洗标注 语言表示 安全训练 量化压缩 功能扩展 用户使用
实际应用:
这个流程确保了:
- 高质量: 通过完整的训练流程保证模型质量
- 设备兼容: 通过优化阶段确保能在设备端运行
- 灵活扩展: 通过适配器层支持不同应用场景
- 负责任: 在整个流程中贯彻 AI 伦理原则
📋 官方来源链接:
该流程图可能来自以下官方资源(建议按顺序查找):
-
WWDC 视频和幻灯片 :
-
🎥 Meet the Foundation Models framework(WWDC 2024)
-
🎥 WWDC 2025 相关 Session(如果有)
-
-
Apple Developer 文档 :
-
Apple 新闻稿和技术报告 :
-
📄 Apple Intelligence 技术报告(如果已发布)
-
Apple Intelligence 相关页面 :
⚠️ 查找建议:
如果无法在上述链接中找到确切的流程图,建议:
- 查看 WWDC 2024/2025 相关 Session 的幻灯片(通常在视频页面可下载)
- 查看 Apple Developer 文档中的图片和图表
- 查看 Apple Intelligence 技术报告(如果已发布)
- 在 Apple Developer Forums 中搜索相关讨论
💡 提示:
- 该流程图可能出现在 WWDC 演示的幻灯片中
- 也可能出现在 Apple Intelligence 的技术报告或白皮书中
- 如果图片来自第三方技术分析文章,建议标注来源
模型优化技术
苹果针对设备端场景做了大量优化:
优化技术详细说明:
1. 2-bit 量化(2-bit Quantization)
技术原理:
- 将模型权重从传统的 32 位浮点数(FP32)压缩到每权重 2 位(2-bit)
- 使用量化感知训练(Quantization-Aware Training, QAT),在训练阶段模拟低精度量化的影响
- 引入可学习的缩放因子(learnable scaling factors),使模型在低精度下仍能保持高质量输出
- 结合可学习的权重裁剪(learnable weight pruning)和权重初始化方法
效果:
- 存储减少 : 模型权重从 ~12GB(FP32)压缩到 ~750MB(2-bit),压缩比约 16:1
- 内存减少: 运行时内存占用大幅降低
- 质量保持: 通过 QAT 训练,模型质量损失最小
数据来源:
- 📰 技术细节 : OSCHINA - Apple Foundation Models 2025 更新
- ⚠️ 注意: Apple 官方文档和 WWDC 视频中未直接提及 2-bit 量化的具体细节,这些信息主要来自第三方技术分析和实际测试
2. 推测解码和草稿模型(Speculative Decoding & Draft Model)
技术原理:
- 主模型: 约 3B 参数的基础语言模型,负责最终输出
- 草稿模型(Draft Model): 约 300M 参数的小型模型,用于快速生成初步预测
- 工作流程 :
- 草稿模型快速生成多个候选 token(推测解码)
- 主模型并行验证这些候选 token
- 接受符合主模型预测的 token,拒绝不符合的并重新生成
- 通过并行验证多个 token,提升整体生成速度
效果:
- 速度提升 : 通过并行验证多个候选 token,推理速度提升约 2-3 倍
- 质量保证: 主模型验证确保输出质量不受影响
- 资源平衡: 300M 草稿模型的内存开销相对较小
数据来源:
- 📰 技术分析 : AIGC.Bar - iOS 26 大模型技术深度解析
- ⚠️ 注意: 3B 和 300M 的具体参数数量来自第三方分析,Apple 官方未明确公布模型参数规模
3. 约束解码(Constrained Decoding)
技术原理:
- 在生成过程中施加特定的结构约束,确保输出符合预期格式
- Apple 通过 引导生成(Guided Generation) 实现约束解码
- 开发者使用
@Generable宏和@Guide注解定义输出结构 - 模型在生成时遵循这些结构约束,生成符合 Swift 数据类型的输出
实现方式:
swift
@Generable
struct PhotoAnalysis {
@Guide(description: "照片的主题")
let subject: String
@Guide(description: "质量评分,1-10分")
let qualityScore: Int
}
效果:
- 可靠性: 确保输出始终符合定义的结构
- 类型安全: 直接生成 Swift 类型,无需手动解析 JSON
- 开发效率: 减少错误处理和类型转换代码
数据来源:
- 📚 官方文档 : Apple Developer - Foundation Models
- 🎥 WWDC 视频 : Meet the Foundation Models framework(WWDC 2024)
- 📰 技术更新 : OSCHINA - Apple Foundation Models 2025 更新
4. KV Cache 优化(KV Cache Optimization)
技术原理:
- KV Cache: 存储注意力机制中的键(Key)和值(Value),避免重复计算
- 8-bit 量化: 将 KV Cache 从 FP32 压缩到 8-bit 整数
- Block Sharing: 通过块共享技术,减少 37.5% 的 KV Cache 存储需求
- 优化效果: 内存占用从理论上的 ~1.2GB 降低到实际的 ~300-600MB
内存占用对比:
| 组件 | 未优化 | 优化后 | 说明 |
|---|---|---|---|
| 模型权重 | ~12GB (FP32) | ~750MB (2-bit) | 2-bit 量化 |
| KV Cache | ~1.2GB (FP32) | ~300-600MB (8-bit + block sharing) | 8-bit 量化 + 37.5% 减少 |
| 总计 | ~13.2GB | ~1.0-1.5GB | 显著降低 |
效果:
- 内存降低 : KV Cache 内存占用减少约 50-75%
- 性能保持: 推理速度不受影响
- 设备兼容: 使得模型能在 iPhone 15 Pro 等设备上运行
数据来源:
- 📊 主要来源 : OneV's Den - Foundation Models 边界探索(基于实际测试和 Instruments 分析)
- ⚠️ 注意: 37.5% block sharing 减少的具体数值来自实际测试分析,Apple 官方未明确公布此优化细节
📋 数据来源总结:
| 优化技术 | 官方来源 | 第三方分析来源 | 可信度 |
|---|---|---|---|
| 2-bit 量化 | ❌ 未明确提及 | OneV's Den、OSCHINA | ⚠️ 需验证 |
| 推测解码 | ❌ 未明确提及 | OneV's Den、AIGC.Bar | ⚠️ 需验证 |
| 约束解码 | ✅ WWDC 2024、官方文档 | - | ✅ 官方确认 |
| KV Cache 优化 | ❌ 未明确提及 | OneV's Den(实际测试) | ⚠️ 需验证 |
⚠️ 重要说明:
- 约束解码是唯一在 Apple 官方文档和 WWDC 视频中明确提及的技术
- 其他三项优化技术(2-bit 量化、推测解码、KV Cache 优化)主要来自第三方技术分析和实际测试
- 建议在实际使用中,以官方文档和 WWDC 视频为准
- 第三方分析数据(如 OneV's Den)基于实际测试,具有较高参考价值,但非官方声明
🔍 验证建议:
- 查看 Apple Developer Documentation - Foundation Models
- 观看 WWDC 2024 相关 Session 视频
- 使用 Instruments 工具在实际设备上验证内存占用
- 参考 OneV's Den 文章 了解实际测试数据
未来展望与注意事项
模型更新:
苹果明确表示模型会随着系统更新持续改进,这意味着:
- ⚠️ Prompt 兼容性: 你针对旧版本模型调好的 prompt 可能会在新版本模型上不太适用
- 📋 测试建议: Apple 建议设定 test set,在每次模型更新时进行确认和调整
- 🔄 更新频率: 模型的更新间隔大概是半年到一年,因此每年可能会有两个新版本模型需要确认
- 🛠️ 维护成本: 如果模型变化很大,可能需要针对不同的系统版本使用不同的提示词
macOS 限制:
macOS 上搭载的本地模型也是这个 3B 的小模型(同时也提供给 macOS 26 上的模拟器使用)。作为性能更加强劲的"生产力级别"设备,却使用了和手持设备一样的方案。
开发建议:
- 现在就可以开始实验: 框架已经相当稳定
- 围绕 4096 token 限制设计应用流程: 不要指望短期内会有大幅提升
- 优先考虑 Tool Calling: 这可能是最有价值的功能
- 准备好上下文管理策略: 如果存在对话式的场景,几乎必须处理上下文溢出
- 在真机上测试性能: 模拟器版本跑的是 macOS 搭载的模型,性能结果可能不准确
📊 数据来源 : OneV's Den - Foundation Models 边界探索
4.4 错误处理和调试
完整的错误处理
错误处理代码:
swift
enum PhotoAnalysisError: LocalizedError {
case modelUnavailable(String)
case contextWindowExceeded
case invalidResponse
case toolCallFailed(String)
var errorDescription: String? {
switch self {
case .modelUnavailable(let reason):
return "AI模型不可用: \(reason)"
case .contextWindowExceeded:
return "对话内容过长,请清理历史记录"
case .invalidResponse:
return "AI响应格式错误"
case .toolCallFailed(let toolName):
return "工具调用失败: \(toolName)"
}
}
}
func analyzePhotoSafely(_ photo: Photo) async throws -> PhotoDescription {
let model = SystemLanguageModel.default
guard case .available = model.availability else {
if case .unavailable(let reason) = model.availability {
throw PhotoAnalysisError.modelUnavailable(reason.localizedDescription)
}
throw PhotoAnalysisError.modelUnavailable("未知原因")
}
do {
let session = LanguageModelSession()
let prompt = generateAnalysisPrompt(for: photo)
let response = try await session.respond(
to: Prompt(prompt),
generating: PhotoDescription.self
)
return response.content
} catch let error as LanguageModelSession.GenerationError {
switch error {
case .exceededContextWindowSize:
throw PhotoAnalysisError.contextWindowExceeded
default:
throw PhotoAnalysisError.invalidResponse
}
} catch let error as LanguageModelSession.ToolCallError {
throw PhotoAnalysisError.toolCallFailed(error.localizedDescription)
} catch {
throw PhotoAnalysisError.invalidResponse
}
}
4.4 提示设计和安全实践
提示设计最佳实践
最佳实践)) 清晰明确 角色定义 职责说明 格式要求 提供上下文 用户信息 当前状态 历史记录 示例引导 输入示例 输出示例 格式示例 结构化 分层次 标记重点 易于理解
Instructions设计示例:
swift
// ✅ 好的Instructions
let instructions = Instructions("""
你是一个专业的照片分析助手,擅长:
1. 分析照片内容(人物、场景、物体)
2. 评估照片质量(构图、光线、清晰度)
3. 提供拍摄改进建议
4. 生成准确的照片标签和描述
请保持回答简洁专业,使用中文回复。
""")
安全实践
内容过滤] S2[输入验证
长度检查] S3[隐私保护
本地处理] end subgraph "实践要点" P1[处理安全错误] P2[验证用户输入] P3[避免敏感信息] end S1 --> P1 S2 --> P2 S3 --> P3 style S1 fill:#FF3B30,color:#fff style S2 fill:#FF3B30,color:#fff style S3 fill:#FF3B30,color:#fff style P1 fill:#34C759,color:#fff style P2 fill:#34C759,color:#fff style P3 fill:#34C759,color:#fff
🎬 第五部分:Demo视频展示
Demo 1: 智能照片分析
演示流程:
讲解要点:
- 展示结构化数据生成的实际效果
- 说明流式响应如何提升用户体验
- 强调本地处理的隐私优势
Demo 2: 自然语言搜索
演示流程:
讲解要点:
- 展示工具调用的工作机制
- 说明自然语言理解的优势
- 强调无需精确关键词的便利性
Demo 3: 完整工作流
演示流程:
讲解要点:
- 展示多工具协调的能力
- 说明AI如何自动判断工具调用顺序
- 强调复杂任务的一站式解决
📚 第六部分:学习资源和总结
官方资源
资源列表:
- Apple Developer Documentation - Foundation Models
- WWDC 2024相关Session
- 示例项目:Foundation Lab
推荐视频:
- Foundation Models Framework 介绍
- 深入了解 Foundation Models 框架
- 实际编码实践
- 探索设备端基础模型的提示设计和安全
- YouTube 分享视频 - 可作为补充参考,结合本文档内容观看,更好理解实际演示细节
深度技术分析:
- OneV's Den - Foundation Models:苹果设备端模型的边界探索 - 基于实际测试的性能数据、边界限制和最佳实践,包含内存消耗、并发性能、上下文窗口等关键指标的详细分析
实践建议
🤔 第七部分:Q&A
常见问题对比
无需网络
数据不出设备] Q2[Q: 可用于生产?] --> A2[需要iOS 18+
设备需支持AI] Q3[Q: 性能如何?] --> A3[性能良好
首次调用有延迟] Q4[Q: 如何测试?] --> A4[必须真机测试
模拟器不支持] Q5[Q: 成本如何?] --> A5[完全免费
无API费用] style Q1 fill:#5AC8FA,color:#000 style Q2 fill:#5AC8FA,color:#000 style Q3 fill:#5AC8FA,color:#000 style Q4 fill:#5AC8FA,color:#000 style Q5 fill:#5AC8FA,color:#000 style A1 fill:#34C759,color:#fff style A2 fill:#34C759,color:#fff style A3 fill:#34C759,color:#fff style A4 fill:#34C759,color:#fff style A5 fill:#34C759,color:#fff
讨论话题
- 在相册业务中,哪些场景最适合使用Foundation Models?
- 如何平衡AI能力和用户体验?
- 如何处理模型不可用的情况?
📝 总结
关键要点总结
关键要点)) 原生AI能力 Apple提供 iOS 18+ Apple Intelligence 隐私保护 设备端处理 数据不出设备 完全本地化 易于集成 简洁API 开发者友好 系统集成 应用场景 照片分析 自然语言搜索 智能分类 视频理解
下一步行动
相册业务应用优先级
优先级详情:
- 高优先级: 智能照片描述生成、自然语言搜索、智能相册分类
- 中优先级: 相似照片推荐、视频摘要生成、清理建议
- 低优先级: 照片质量评分、自动标签生成
📎 附录:代码模板
基础会话模板
swift
import FoundationModels
class BasicSessionManager {
private let session = LanguageModelSession()
func chat(_ message: String) async throws -> String {
let response = try await session.respond(to: message)
return response.content
}
}
Tool实现模板
swift
struct MyTool: Tool {
let name = "toolName"
let description = "工具描述"
@Generable
struct Arguments {
@Guide(description: "参数描述")
var param: String
}
func call(arguments: Arguments) async throws -> some PromptRepresentable {
// 实现工具逻辑
return "工具返回结果"
}
}
结构化数据生成模板
swift
@Generable
struct MyDataModel {
@Guide(description: "字段描述")
let field: String
}
func generateData() async throws -> MyDataModel {
let session = LanguageModelSession()
let response = try await session.respond(
to: "生成数据的提示词",
generating: MyDataModel.self
)
return response.content
}