
网罗开发 (小红书、快手、视频号同名)
大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。
图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG
我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验 。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。
展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索"展菲",即可纵览我在各大平台的知识足迹。
📣 公众号"Swift社区",每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友"fzhanfei",与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!
文章目录
-
- 背景
- [引入 Streaming:实时获取模型输出](#引入 Streaming:实时获取模型输出)
- 结构定义背后的"魔法":PartiallyGenerated
- [完整流式输出 + 最终结果收集](#完整流式输出 + 最终结果收集)
- 实际场景分析
- 总结
背景
在前面我们已经了解过 Foundation Model 的基本用法,比如使用 Generable 注解结构化输出。
通常,我们会写出类似这样的代码:
swift
import FoundationModels
@Generable struct Article {
@Guide(description: "The title of the article")
let title: String
@Guide(description: "The content of the article")
let body: String
@Guide(description: "Useful tips related to the article")
let tips: [String]
}
import Playgrounds
#Playground {
let articleGenerationInstructions = "Write a health related article."
let session = LanguageModelSession(instructions: articleGenerationInstructions)
let response = session.respond(to: "Heart Rate", generating: Article.self)
print(response.content)
}
这段代码中:
- 我们定义了一个
Article结构体,使用@Generable宏标记; - 每个属性(
title、body、tips)都有明确的语义指导(@Guide); - 模型会生成一个符合
Article类型格式的结果; - 我们使用
respond()来等待模型一次性返回完整输出。
这种方式虽然简单,但在用户体验上略显"卡顿"------尤其当生成内容较长时,用户要等全部生成完才能看到结果。
引入 Streaming:实时获取模型输出
为了让生成过程更自然、实时,Apple 在 Foundation Model 框架中引入了 Streaming API。
我们可以通过 streamResponse() 方法来替代 respond(),从而在模型生成过程中不断接收部分结果:
swift
import Playgrounds
#Playground {
let articleGenerationInstructions = "Write a health related article."
let session = LanguageModelSession(instructions: articleGenerationInstructions)
let stream = session.streamResponse(to: "heart rate", generating: Article.self)
for try await article in stream {
print(article)
}
}
在这个例子中:
streamResponse()返回的是一个ResponseStream对象;- 它符合
AsyncSequence协议 ,可以通过for try await来异步遍历; - 每一次迭代,模型都会返回当前生成的部分结果。
这意味着,我们可以在界面上 边生成边展示,比如一篇文章的标题出来后立刻显示,正文陆续追加,最后再呈现小贴士。
结构定义背后的"魔法":PartiallyGenerated
有趣的是,@Generable 宏在编译时会自动为我们的结构体生成一个内部类型,比如 Article.PartiallyGenerated,里面的字段都变成了可选类型(Optional)。
这让流式生成成为可能:
- 当模型只生成了
title时,body和tips仍然是nil; - 模型每生成一个字段,就会触发一次流式输出;
- Swift 的类型系统保证了这种"部分可用"的结构安全。
换句话说,模型生成的顺序会严格按照我们定义的属性顺序执行:
swift
struct Article {
let title: String // 先生成
let body: String // 再生成
let tips: [String] // 最后生成
}
所以当我们渲染前端 UI 时,也建议保持这种顺序输出,提升体验的连贯性。
完整流式输出 + 最终结果收集
如果我们希望在流式展示的同时,最后还能拿到完整的结果,也可以这样写:
swift
import Playgrounds
#Playground {
let articleGenerationInstructions = "Write a health related article."
let session = LanguageModelSession(instructions: articleGenerationInstructions)
let stream = session.streamResponse(to: "heart rate", generating: Article.self)
// 实时流式输出
for try await article in stream {
print(article.content)
}
// 等待最终生成结果
let article = try await stream.collect()
print(article.content)
}
这里的关键在于:
for try await是一个 异步迭代器,逐步输出生成结果;collect()是 聚合函数 ,在流结束后获取完整的Article实例。
这让我们可以既实现「实时更新 UI」,又能在生成完成后「统一保存完整数据」。
实际场景分析
这个机制在工程上非常有用。比如:
- 实时内容生成:写作类 App 可以在用户输入主题后立即显示文章开头;
- 对话系统:用户提问后,AI 回答可以逐句出现,不必等待整段生成;
- 编程助手:代码生成时可逐行输出,方便开发者实时查看。
通过 Foundation Model 的 Streaming API,我们能让生成式 AI 的交互更接近人类思维过程,提升用户参与感和响应速度。
总结
流式生成的本质是:
让模型输出变得可感知、可等待、可预览。
借助 @Generable + streamResponse():
- 结构化类型安全输出;
- 异步流式传递;
- 最终统一收集结果。
这标志着 Foundation Model 在 Swift 生态中不只是一个"生成 API",而是一个具备 类型安全 + 实时反馈 + 异步语义统一 的完整生成体系。