登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

AI 流式响应断线重连 怎样处理

来源:17golang原创

时间:2026-10-22 07:06:36 470浏览 收藏

AI 流式响应断线后,先判断原生成任务是否还在,再决定恢复订阅还是重新生成。可靠续传需要同一任务的事件记录、客户端游标和去重规则共同配合;单独重发 HTTP 请求,不能保证接着原来的文字输出。

网络连接恢复不等于历史内容恢复,重新生成也不等于续写原流。服务端没有保留可重放事件时,前端无法只靠重连补出丢失内容。

本文讨论自建转发层的设计,不承诺任一模型供应商自带断点恢复。SSE 标准入口:https://html.spec.whatwg.org/multipage/server-sent-events.html。Fetch 标准入口:https://fetch.spec.whatwg.org/。以下任务与序号均为原创示例,不是线上日志。

先确认断的是连接还是生成任务

页面已经显示半段回答,网络短暂中断,再次连接后从头出现一份新回答。这时不能先归因于模型“忘记上下文”:更直接的可能是,重连请求又创建了一次生成,或前端把重放片段重复追加。

先在应用记录里区分生成任务、上游请求和浏览器连接。一条浏览器连接断开后,上游可能继续、可能被转发层取消,也可能已完成但完成通知没送到。具体行为取决于实现,不能从浏览器报错单独推断。

排查时至少确认原任务状态、最后保存事件位置、客户端最后应用事件位置,以及新连接对应的任务标识。日志使用脱敏标识,不记录令牌、完整提示词和敏感回答。

查清客户端有没有重连语义

浏览器原生 EventSource 有标准规定的重连与最后事件 ID 机制。但使用 fetch 发起 POST 并读取响应体的 AI 客户端,并不因为响应采用 SSE 文本格式,就自动变成 EventSource;重连、游标保存和解析仍需应用或 SDK 负责。

实际接入方式应先确认的能力不能默认获得
原生 EventSource事件ID与重连请求的处理服务端历史存储和重放
fetch 读取响应流应用的重试、解析与游标约定EventSource 自动续订行为
供应商或框架SDK文档说明重试的是连接还是生成业务层幂等和原回答不变

SSE 的 id 和 Last-Event-ID 提供传递游标的机制,不替服务器实现事件仓库。手动新建连接或页面刷新时,也要考虑应用如何恢复游标,不能假定新对象知道旧页面进度。游标代表接收到的事件位置,也不天然代表业务数据已持久化成功。

为一次生成和一条事件分别编号

建议给每次生成一个稳定任务标识,比如 demo-r17;该任务内的已提交事件再分配可排序位置,如17、18、19。这里的连续数字是应用自定契约,SSE 标准本身不要求 id 一定为整数。

任务标识回答“是哪份回答”,事件位置回答“收到哪一段”。若用户点击重新生成,应新建任务;若只是恢复订阅,应指向原任务。不要用“用户最近一次任务”这种全局查找方式串接多标签页或并发对话。

生成任务事件记录与客户端游标的静态关系说明图
图1:任务与事件归属的原创结构说明图,非流式运行截图。

每个事件还应有明确类型,例如内容增量、完成或失败。网络字节块不等于完整 SSE 事件,更不一定等于一个模型 token;如果按每次读取到的字节块直接拼接和保存游标,断线可能留下一条未完成事件。应在解析出完整协议事件并按应用规则应用后更新进度。

让服务端重放与前端去重配套

以 demo-r17 为例:客户端已应用到17,服务端保存到20。恢复请求携带原任务和游标17,服务器应按本应用约定重放18至20,再衔接该任务的新事件。这个能力需要转发层自行实现,不是给响应头加上 SSE 类型就会出现。

为防止“读取历史结束”与“订阅实时事件开始”之间漏一条事件,服务器需要统一有序事件源或相应同步机制。建议先把事件写入可恢复记录,再允许发布给订阅者;写入失败时明确终止或降级,不先发出无法重放的片段再宣称支持续传。

事件存储重放窗口与前端去重的静态边界说明图
图2:恢复契约的原创静态结构说明图;连线不是实测执行顺序。

前端按“任务标识加事件位置”去重,而不是按文字内容去重。模型合法输出可能包含连续相同的字,不能把重复文本当成重复事件。对于本例的单调序号,可忽略已应用的位置;若出现间隙则暂停追加并请求恢复,不默默跳过。

连接恢复后也要重新鉴权,检查用户是否有权读取该任务。任务标识和事件游标不是访问凭据,不应为了方便续传就把敏感回答暴露为可猜测的公开地址。

重放失效时明确结束或重新生成

服务端需定义重放保留窗口。若游标太旧、记录已过期,应该明确返回“无法恢复原流”的应用状态,并提供已有完整结果或重新生成选项,不悄悄从当前最新片段开始。重新生成的内容可能不同,应作为新回答展示。

如果原任务已经完成,恢复时应能取得剩余事件与完成状态;收到完成事件后,客户端结束订阅,避免再次接收相同尾部。若只看到连接关闭却没有完成状态,不要把截断的回答标成成功。

对于仍在生成的任务,应有最长保留时间、无人订阅后的处理规则和取消入口。是否允许断线后继续消耗模型资源是产品决策;浏览器取消接收也不自动证明上游计算已停止。重试采用有上限的退避,鉴权失败或明确不可恢复时停止循环。

按断点场景核对恢复结果

读者落地时,可在受控测试环境分别模拟:完整事件之后断线、事件中间断线、完成通知前断线、页面刷新,以及重放窗口过期。检查的不是“重新连上了”这一个现象,而是原任务有没有被重复创建、已显示片段有没有重复、缺失事件有没有补齐、最终状态是否一致。

可以记录恢复成功率、游标过期次数、重复事件数与重复生成数。本文没有执行这些实验,也没有提供实测指标;这些是应用实现后的核对项目,而不是协议自动保证。

没有事件存储,还能续传吗?

若供应方提供恢复接口,可按其明确契约接入;否则自建层没有保存的片段通常无从重放。产品应展示“响应中断”,让用户选择重试,不能把另一次生成伪装成原流接续。

心跳可以解决丢字吗?

心跳有助于维持或发现连接状态,但不会补齐历史事件。保活、事件持久化、去重和最终状态是不同职责,不应只增加心跳就宣称支持恢复。

能按已经显示的字符数跳过新回答开头吗?

不可靠。新生成可能改变措辞,字符位置和原事件位置也不是同一概念。要恢复原流,就使用原任务的事件游标;没有这个条件,则明确创建新回答。

参考:WHATWG SSE 规范、WHATWG Fetch 规范。任务持久化、重放窗口、鉴权和去重属于本文建议的应用层契约,应由项目实现并测试。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>