AnyLanguageModel 对话管理指南:Transcript 与多轮会话实现
【免费下载链接】AnyLanguageModelAn API-compatible, drop-in replacement for Apple's Foundation Models framework with support for custom language model providers.项目地址: https://gitcode.com/gh_mirrors/an/AnyLanguageModel
AnyLanguageModel 是一个 API 兼容、可直接替换 Apple Foundation Models 框架的 Swift 开源库,支持 OpenAI、Anthropic、Gemini、Ollama 等十余种自定义语言模型提供商。很多新手在接入 AI 后遇到的第一个坎就是:模型总是"失忆",答完上一句就忘了下一句。本文将手把手讲解它的对话管理机制——Transcript对话记录与多轮会话实现,帮你用最少的代码构建出真正"有记忆"的 AI 聊天应用。
什么是 Transcript?AI 对话的"记忆档案" 📝
Transcript是 AnyLanguageModel 中专门用来表示用户与模型之间完整对话历史的类型。它定义在 Transcript.swift,本质上是一个有序的对话条目数组,同时满足Sendable、Equatable、Codable三个协议。
这意味着它有三个杀手级特性:
- Sendable:可以安全地在并发任务之间传递;
- Equatable:方便做状态对比与测试断言;
- Codable:可以直接序列化为 JSON,用于保存、恢复、传输整段对话。
更贴心的是,Transcript还实现了RandomAccessCollection协议,你可以像操作数组一样对它进行下标访问和遍历,例如session.transcript[0]、session.transcript.count。
一次对话的 5 种条目类型 🧩
Transcript.Entry用枚举把一次对话拆成了 5 种角色,覆盖了从"设定角色"到"工具调用"的完整生命周期:
| 条目类型 | 含义 | 典型来源 |
|---|---|---|
.instructions | 开发者设定的系统指令 | 初始化会话时自动写入 |
.prompt | 用户发送的提示词 | 每次respond自动写入 |
.toolCalls | 模型发起的工具调用 | 工具调用场景自动写入 |
.toolOutput | 工具执行后的返回结果 | 工具执行完成后自动写入 |
.response | 模型生成的回答 | 每次respond自动写入 |
每种条目都带有稳定的id(默认是 UUID),方便你追踪、回放或定位某一条具体消息。测试代码 TranscriptTests.swift 中详细验证了每种条目的 ID 路由逻辑。
多轮会话的核心机制:LanguageModelSession 自动记录 ⚙️
多轮会话的秘密藏在LanguageModelSession里,它定义在 LanguageModelSession.swift,是一个@Observable的会话对象,负责协调模型、工具、指令与对话记录。
关键点在于:你不需要手动维护对话历史。每次调用session.respond(...)时,框架会自动完成两件事:
- 把用户的
Prompt追加进Transcript; - 把模型的
Response追加进Transcript。
所以在 MockLanguageModelTests.swift 中你能看到这样的测试结论:连续发起三轮对话后,session.transcript.count从 0 依次变为 2、4、6——每一次问答都会让"记忆档案"多两条记录。
这些记录可不是摆设。以 OpenAI 提供商为例,其实现会直接调用session.transcript.toOpenAIMessages()把整段对话历史转换成 API 请求消息(见 OpenAILanguageModel.swift),从而让云端模型"看到"完整上下文。其他提供商也遵循同样的模式。
三步实现多轮会话:最快配置方法 🚀
理解了机制,实现就非常简单了。核心思路是:复用同一个 Session 对象。下面是一个完整示例:
let model = OpenAILanguageModel( apiKey: ProcessInfo.processInfo.environment["OPENAI_API_KEY"]!, model: "gpt-4o-mini" ) // 第一步:创建会话(复用同一个 session 即可) let session = LanguageModelSession(model: model) // 第二步:第一轮对话 let first = try await session.respond(to: "你好,我叫小明,是一名 iOS 开发者") // 第三步:第二轮对话——模型已经记得你是谁 let second = try await session.respond(to: "我叫什么名字?我做什么工作?") print(second.content) // 输出会包含"小明"和"iOS 开发者"整个多轮会话实现只需要三步:建会话、发消息、复用会话继续发。Transcript的自动记录让上下文无缝衔接,你甚至可以在 UI 上直接绑定session.transcript来渲染聊天界面——由于它支持@Observable响应式更新,新消息出现时界面会自动刷新。
流式输出也能自动记录对话 🔄
如果你想要打字机式的流式输出,streamResponse同样会自动维护对话记录:Prompt 在流开始时就写入,Response 在流结束后自动追加。用法与非流式几乎一致:
let stream = session.streamResponse(to: "用一句话解释什么是大语言模型") for try await snapshot in stream { print(snapshot.content) // 边生成边显示 }流式期间你可以通过session.isResponding判断模型是否正在响应,用于显示加载动画,防止用户重复提交。
多模态对话:图片也能写进 Transcript 🖼️
Transcript.Segment支持三种内容段:.text(文本)、.structure(结构化内容)、.image(图片)。图片段ImageSegment既可以用二进制数据(data:mimeType:)构造,也可以用 URL 构造,还支持直接从UIImage、NSImage、CGImage编码转换。
多轮对话中加入图片非常直观:
let response = try await session.respond( to: "这张图里有什么?", images: [ .init(url: URL(fileURLWithPath: "/path/to/photo.jpg")) ] )图片会被作为 prompt 的一部分写入Transcript,也就是说——多轮对话里发过的图片,后续轮次中模型依然"看得到"。这在构建"看图连续追问"的场景(如识别发票后追问金额)时非常实用。
恢复历史会话:用已有 Transcript 初始化 💾
得益于Codable,你可以把Transcript序列化保存,下次启动应用时再恢复。LanguageModelSession提供了接受Transcript的初始化方法:
// 保存:把对话记录转成 JSON 数据 let data = try JSONEncoder().encode(session.transcript) // 恢复:用历史对话创建全新会话 let restored = try JSONDecoder().decode(Transcript.self, from: data) let newSession = LanguageModelSession(model: model, transcript: restored) // 直接接着聊,模型记得之前所有内容 let response = try await newSession.respond(to: "我们刚才聊到哪了?")这是实现"历史聊天记录"、"会话断点续聊"等功能的官方推荐路径。另外,如果初始化时传入了instructions,框架会自动将其作为第一条instructions条目写入对话记录,并且不会重复插入——即使你同时传入了已包含指令的 Transcript(该逻辑同样位于 LanguageModelSession.swift)。
多轮会话最佳实践与避坑指南 ✅
| 实践建议 | 说明 |
|---|---|
| 复用 Session 而非重建 | 多轮会话实现的核心就是保持同一会话对象,避免上下文丢失 |
| 指令只传一次 | 系统指令通过instructions:参数传入,框架会保证唯一 |
| 注意上下文长度 | 对话越久记录越长,注意各提供商的上下文窗口限制,超长时需自行裁剪 |
| 展示层直接绑定 transcript | 用它渲染聊天 UI,天然与响应式框架(SwiftUI + Observation)契合 |
| 工具调用无需手动记录 | toolCalls与toolOutput条目由框架自动写入,你只需专注工具本身的实现 |
总结 🎯
AnyLanguageModel 把"记忆"这件事彻底封装好了:Transcript负责记录,LanguageModelSession负责自动维护。你只需要复用同一个会话对象连续发起请求,就能获得稳定可靠的多轮对话体验;再配合 Codable 序列化和多模态图片支持,无论是聊天应用、客服机器人还是 AI 助手,都能快速落地。如果想要完整运行示例,可以克隆仓库https://gitcode.com/gh_mirrors/an/AnyLanguageModel查看源码与测试用例,从 LanguageModelSession.swift 和 Transcript.swift 开始阅读是最佳入口。
【免费下载链接】AnyLanguageModelAn API-compatible, drop-in replacement for Apple's Foundation Models framework with support for custom language model providers.项目地址: https://gitcode.com/gh_mirrors/an/AnyLanguageModel
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考