三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

流式回答中途断连:生成任务与断点续传机制如何设计

流式回答中途断连:生成任务与断点续传机制如何设计

一位用户在手机上通过企业内部的合同审查智能体查询一份供应商合同的违约条款。智能体开始逐字输出分析结论,用户看着文字一段段浮现,读到"该条款在以下情形下可能构成违约"时,页面突然加载中断——地铁信号波动导致长连接断开。用户切回网络重新打开对话,界面上只显示到"该条款在以下情形下可能构成违约"就戛然而止,后面的分析内容全部消失了。用户等了一会儿,界面没有任何变化。重新提问,智能体从头开始生成,但上一次生成的内容——不管后端是否已完成——彻底看不到了。

遇到这类问题,不少团队的反应是把流式输出当作普通请求中断处理:连接断了就算了,用户重新提问即可。这种处理方式的问题在于,它假设生成内容是随连接一起消失的。实际上流式输出的架构里,生成过程在后端进行,前端通过长连接逐段接收。连接断开不等于生成停止——后端可能已经完成了完整生成,只是结果没有推送到前端;也可能后端按照任务策略中止了生成。两种情况下用户看到的都是半截回答,但后端状态完全不同。也有团队给前端加了自动重连机制,但重连后请求的是新的生成任务,不是重新挂接上一次未完成的生成,用户得到的是两段从头开始的不同回答。

问题可以从三个方面拆解。

一类是生成任务与推送通道的耦合。流式输出通常由两个部分组成:后端的生成任务和前端的推送通道。如果生成任务的生命周期绑定在推送通道上——通道断开,生成任务立即终止——那么连接断开时生成确实停了,用户看到的就是生成中断点。但如果生成任务独立于推送通道运行——通道断了,生成继续——那么后端可能有完整结果,只是用户拿不到。两种架构下中断后的正确处理方式完全不同,但不少系统没有显式区分,导致中断后的行为不可预测。

另一类是把网络断连当作生成任务状态。不少系统在连接断开时直接把生成任务标记为"已中断",仿佛断连本身就改变了生成任务的执行状态。但网络断连是传输层事件,不是生成任务的执行状态。生成任务在后端是否继续运行,取决于任务策略:策略可能规定连接断开后继续生成并把结果留存待续传,也可能规定超时未重连则取消生成以释放资源。把传输层事件和任务执行状态混为一谈,导致系统无法区分"生成还在跑"和"生成已经停了"两种情况,后续的恢复逻辑无从正确分支。

还有一类是重连恢复机制缺失。用户重新打开对话后,理想情况是系统能重新挂接到上一次的生成任务,先补发断连后已经生成但用户还没看到的内容,再继续实时接收新生成的内容。但大多数系统没有这个机制——重连等于新会话,上次的上下文和生成状态全部丢失。用户只能重新提问,承受重复生成的等待时间和token消耗。如果问题本身涉及长文本分析或多次工具调用,重新生成的成本更高,而且两次生成结果可能不完全一致——模型温度参数即使设为零,检索结果的变化也可能导致差异。

针对流式回答中途断连后用户无法获取已生成内容的问题,青山不语AI工作室在部分项目实践中将这套处理框架归入"异步任务执行与结果回传保障",通过生成任务与推送通道分离、事件序列化标记、断点续传和完整性校验控制流式输出中断后的用户体验。

起始环节是生成任务与推送通道分离。生成任务在后端独立运行,生命周期由生成任务管理器控制,不随推送通道的断开而终止。每个生成任务分配一个独立的任务ID,生成过程中产生的每一段输出作为一个事件,事件携带单调递增的序列号。推送通道只负责将事件推送到前端,通道断开时生成任务是否继续由任务策略决定——合同分析这类需要完整结果的任务,策略可以规定连接断开后继续生成并留存结果;闲聊类任务,策略可以规定超时未重连即取消生成以释放资源。任务策略的判断依据是业务场景,不是网络状态。

第二环节是任务状态与事件序列化管理。生成任务的状态统一为四种:生成中,后端仍在产出事件;已完成待续传,后端已生成完毕但客户端尚未确认接收全部事件;已取消,任务策略判定中止或用户主动取消;失败,生成过程中发生异常。网络断连不改变任务状态——断连时任务仍在生成中,是否转为已取消由任务策略的超时规则决定。每个事件携带任务ID和序列号,生成事件按任务ID和序列号写入短期可重放的事件缓冲,至少保留到客户端确认收齐或达到TTL过期,不只存在原生成进程的内存中——进程重启后缓冲仍然可读,断连后补发才能从缓冲中取到已生成的事件。客户端每收到一个事件向服务端返回确认,服务端记录客户端最后确认的序列号。这套任务ID加事件序列号加客户端确认序列号的三元组,是断点续传的定位依据,不依赖字符数或段落数这种粗粒度位置。

第三环节是断点续传与重连挂接。用户重新打开对话时,系统通过对话ID查找关联的生成任务。如果任务状态是已完成待续传,系统从客户端最后确认的序列号之后开始补发已生成但未推送的事件,补发完毕后告知客户端后续内容已全部送达。客户端按任务ID和事件序列号做幂等去重——ACK丢失导致服务端重复补发同一序列号的事件时,客户端识别到已接收过的序列号直接丢弃,不重复渲染。如果任务状态是生成中,系统将客户端重新挂接到该任务的事件流上,先补发确认位置之后已生成的事件,再继续实时接收新生成的事件——不是只告诉用户还在生成中就结束,而是让用户实际拿到断连期间错过的内容。如果任务状态是已取消或失败,系统告知用户上次回答未能完成,提供重新生成的选项。

第四个环节是最终完成事件与完整性校验。生成任务结束时产出一条最终完成事件,携带任务的总事件数和完成标记。客户端收到最终完成事件后,校验本地已接收事件的序列号是否连续无缺口——从起始序列到最终序列,中间不能有缺失。只有序列无缺口且收到完成标记,客户端才判定回答完整,可以正常渲染并标记为已送达。如果校验发现序列缺口,客户端向服务端请求补发缺失序列对应的事件,补齐后再判定完整。已确认完整的生成结果关联对话ID写入持久化存储,超过保留期限后由清理任务回收。如果用户在续传过程中再次断连,系统按同样的逻辑处理——以最新的客户端确认序列号为起点重新挂接,不重复推送已确认的事件。

流式输出断连恢复的核心矛盾是生成连续性和连接不可靠之间的冲突。移动网络环境下连接波动是常态,但用户期望的回答是完整的。生成与推送分离让生成不受连接影响,任务状态与传输事件解耦让恢复逻辑有明确分支,事件序列化让断点续传有精确定位,完整性校验让回答的完整性可判定。在我看来,这套机制是否值得投入,取决于智能体的使用场景:轻量问答场景——用户问一句答一句,回答短——断连后重新提问的代价不大,简单的重试就够了。但涉及长文本分析、多步骤推理或工具调用的场景——回答本身就需要较长时间生成——用户经历了长时间等待却因为网络波动只拿到半截回答,重新提问意味着再次等待,体验会很差。是否需要断连恢复机制,不取决于连接多不可靠,而取决于重新生成一次的代价用户能不能接受。

← 返回列表