news 2026/8/18 14:50:05

AnyLanguageModel 对话管理指南:Transcript 与多轮会话实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AnyLanguageModel 对话管理指南:Transcript 与多轮会话实现

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,本质上是一个有序的对话条目数组,同时满足SendableEquatableCodable三个协议。

这意味着它有三个杀手级特性:

  • 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(...)时,框架会自动完成两件事:

  1. 把用户的Prompt追加进Transcript
  2. 把模型的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 构造,还支持直接从UIImageNSImageCGImage编码转换。

多轮对话中加入图片非常直观:

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)契合
工具调用无需手动记录toolCallstoolOutput条目由框架自动写入,你只需专注工具本身的实现

总结 🎯

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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/18 14:48:13

xpack基础用法详解:XPACK宏与encode/decode手把手教学

xpack基础用法详解:XPACK宏与encode/decode手把手教学 【免费下载链接】xpack convert json/xml/bson to c struct 项目地址: https://gitcode.com/gh_mirrors/xp/xpack 一句话认识 xpack:它是一个纯头文件的 C 库,帮你轻松实现 JSON/X…

作者头像 李华
网站建设 2026/8/18 14:40:56

Rust 语言特性:共享指针 Rc<T>

在日常编程中,我们经常会遇到“一份数据会被多个“所有者”共享的情形”,比如 Cache / Config / Session 中的数据基本都是此类情形。从所有权的视角来看:这些类型的数据并不具有唯一的、明确的所有者,而更倾向于是多个所有者共同拥有,当所有的持有者都不再使用时,再销毁…

作者头像 李华