AI 应用的追加功能:使用 Ably AI Transport 将流合并为单条消息
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (or the portion you want translated) here? Once I have it, I’ll provide a Simplified Chinese version while preserving the original formatting, markdown, and code blocks.
Introduction

流式传输 token 很容易,干净地恢复却不容易。用户在响应中途刷新,另一个客户端迟到加入,移动网络掉线 10 秒,结果你的“一次回答”变成了 600 条小消息,UI 必须把它们重新拼接。消息历史变成了碎片。于是你开始构建一个旁路存储,仅仅为了重建“目前的响应”。
这 不是 模型本身的问题,而是交付的问题。
这就是我们为 Ably AI Transport 开发 message appends 的原因。Appends 让你在生成时把 AI 输出的 token 流式写入单条消息,从而为实时订阅者提供渐进式渲染,并在历史记录中保持整洁、紧凑的响应。
我们正在修复的故障模式
常规实现会将每个 token 作为单独的消息进行流式传输。这在连接稳定时运行完美,但在生产环境中,客户端会在流式传输中途断开并恢复:页面刷新、移动端掉线、后台标签页以及后加入的情况。
当真实的重连和刷新发生时,你会继承一些原本没有计划的工作:
- 排序
- 去重
- 缓冲
- “最新优先”逻辑
- 使历史记录与实时数据保持一致的回放规则
你可以自行实现,但这会悄悄消耗数周的工程时间。

通过追加(append)方式,你可以通过改变数据形状来避免上述问题。你不再需要数百条 token 消息,而是拥有 一条响应消息,其内容会随时间增长。
模式:一次创建,多次追加
在 Ably AI Transport 中,您发布一个初始响应消息并捕获其服务器分配的序列号。后续追加的就是该序列号。
// 创建空的响应消息
const result = await channel.publish({ name: 'response', data: '' });
const { serials: [msgSerial] } = result;
现在,当您的模型产生 token 时,您将每个片段追加到同一条消息中:
if (event.type === 'token') {
channel.appendMessage({ serial: msgSerial, data: event.text });
}
对客户端有什么变化
订阅者仍然会看到渐进式输出,但他们会把它视为对同一条消息序列的操作。一次响应以 create 开始,令牌以 append 形式到达,偶尔客户端会收到一次完整状态更新以重新同步(例如,重新连接后)。
大多数 UI 已经实现了这种结构;有了 append 后,它变得可预测且一致:
switch (message.action) {
case 'message.append':
renderAppend(message.serial, message.data);
break;
case 'message.update':
renderReplace(message.serial, message.data);
break;
}
重要的区别在于历史记录和实时数据不再不一致,且无需额外的客户端代码。你可以为实时用户逐步渲染,同时仍然把响应视为一条消息来进行存储、检索和回放。
重连和刷新不再是特例
短暂的断开算是一回事。刷新很痛苦,因为本地状态丢失,并且把每个 token 作为单独的消息进行流式传输会迫使你重新播放片段,并希望客户端能够重建相同的响应。
采用 每条消息对应一次响应 的方式,状态恢复变得直接,因为始终有一个当前累计的响应消息版本。后加入或重新加载的客户端可以获取最新的状态作为单条消息并继续。
const channel = realtime.channels.get('ai:chat', {
params: { rewind: '2m' } // Rewind 2 minutes
});
现在,回溯和历史再次变得有用,因为你回溯的是有意义的消息,而不是 token 零散。
无需令牌速率痛点的令牌速率
模型可以以远高于大多数实时设置所需的速度输出令牌。每个令牌发布一条消息会导致速率限制问题,并迫使你在代码中进行批处理。
Append 设计用于高频工作负载,并且包含自动合并功能。订阅者仍然会收到渐进式更新,但 Ably 可以在内部对快速的 append 进行合并,这样你就不必自己实现限流层。
如果需要在平滑度和消息速率之间进行权衡,可调整 appendRollupWindow:
- 窗口更小 → 响应更快,但使用的消息速率更高。
- 窗口更大 → 更积极的批处理,消息数量更少。
启用追加
追加需要您使用的命名空间的 “Message annotations, updates, appends, and deletes” 通道规则。启用它还意味着消息会被持久化,这会影响使用量和计费。
为什么这是 AI 输出的更好默认
如果你在发布具备自主性的 AI 应用,最终你需要三件事:
- 渐进式渲染(progressive rendering),以便实时用户使用。
- 单一、紧凑的完整响应表示,便于存储和检索。
- 对重新连接、刷新和后加入的稳健处理,无需自定义管道。
消息追加(message appends)天然提供这三点。 🎉
at the same time:
- streaming UX
- history that's usable
- recovery that does not depend on luck
Appends are how you get there without building your own "message reconstruction" subsystem. If you want the deeper mechanics (including the *message‑per‑response* pattern and rollup tuning), the [AI Transport docs](https://ably.com/docs/ai-transport) are the best place to start. 