整体对话稳定性专题总览
AI Chat 的稳定性问题,通常不是“模型会不会回答”这么简单。
真实用户使用时,会遇到网络抖动、流式输出中断、接口超时、重复点击发送、用户中途停止、浏览器刷新、服务端重试、消息顺序错乱、工具调用失败、模型供应商不可用等问题。每一种失败都可能让对话状态变得不可信:前端显示了一半答案,后端却写入完整答案;用户点了重试,系统生成了两条回复;模型已经调用工具,页面却还停在 loading。
整体对话稳定性的目标,不是让系统永远不失败,而是让失败可见、可恢复、可降级、可复盘。
场景
先看一个具体场景。
在一个面向企业用户的 AI 客服助手里,用户输入:
帮我查一下上周企业版发票为什么还没开,并给客户写一段解释。
系统需要完成几件事:
- 前端立即显示用户消息,并展示模型正在流式生成。
- 后端调用模型理解问题,必要时查询订单、发票和客户信息。
- 模型边生成边返回,让用户不用等完整答案。
- 如果工具或模型超时,系统要说明失败原因,并给出重试或转人工入口。
- 如果用户点击停止,系统要保留已生成内容,但不能把未完成答案当成成功结果。
- 如果用户刷新页面,历史消息和生成状态要能恢复到一致状态。
这个场景里,稳定性问题来自多层链路。
如果没有稳定性设计,用户看到的可能是:
- 助手一直转圈,不知道是模型慢还是系统坏了。
- 答案输出到一半停住,没有失败提示。
- 点击重试后出现两条内容相近但互相矛盾的回答。
- 用户点了停止,后台仍然继续扣费生成。
- 页面刷新后,前端显示失败,历史记录里却出现成功回答。
- fallback 模型给出降级答案,但没有标记能力边界。
这些问题不是 prompt 能解决的。它们属于产品状态、接口协议、后端任务、持久化和观测体系共同承担的工程问题。
问题类型
整体对话稳定性可以拆成五类常见问题。
这些问题和 AI 任务类型也有关。
- 生成任务最容易受流式中断影响,因为输出是逐步出现的。
- 工具调用任务最容易受超时和幂等影响,因为工具可能有副作用。
- 多轮对话最容易状态错乱,因为每条消息都依赖前文顺序。
- 高风险业务最需要 fallback,因为不能让失败变成静默错误。
- 需要引用、结构化输出或写库的场景,重试必须更谨慎。
模型适合处理的部分是:在可用上下文内生成回答、解释降级原因、根据已知信息给出下一步建议。
程序应该处理的部分是:请求 ID、消息状态机、超时、取消、重试、幂等、持久化、fallback 路由、日志和告警。
必须保留人工确认的部分是:高风险工具调用、不可逆操作、对外承诺、涉及权益的降级处理,以及多次失败后的人工接管。
收益和成本判断
对话稳定性的收益,不只是“少报错”。
- 用户知道系统正在做什么,等待焦虑下降。
- 失败后可以继续,而不是整轮对话报废。
- 后端可以避免重复生成、重复扣费和重复执行工具。
- 产品可以定位问题是模型、工具、网络、前端还是存储。
- 运营和客服能接住失败会话,而不是让用户自己猜。
- 团队能通过日志回放复盘线上事故。
但稳定性也有成本:
- 前端需要更细的消息状态和交互设计。
- 后端需要任务状态、取消、重试、幂等和持久化。
- fallback 会增加模型路由、质量控制和产品文案成本。
- 观测系统需要记录 trace、错误类型、耗时和供应商状态。
- 过度重试会增加成本和延迟,甚至放大故障。
低风险场景不需要一开始就做完整可靠性平台。例如内部写作助手,输出只给员工编辑,失败后重新生成即可。这时简单的 loading、失败提示和手动重试就够了。
一旦对话进入客户服务、订单处理、工作流自动化、知识库问答、代码修改或数据分析,稳定性就不能只靠“刷新页面再试”。系统必须明确:这条消息现在是什么状态,失败在哪里,能不能重试,重试会不会重复执行副作用,降级后用户看到的内容是否可信。
方案阶梯
对话稳定性可以从轻到重逐级建设。
第一层是基础 UI 状态。至少让用户知道正在生成、失败了、可以重试或停止。
第二层是消息状态机。不要只有 loading: true。一条 assistant 消息可能处于 queued、streaming、completed、failed、stopped、retrying、fallback 等状态。
第三层是请求和消息 ID。每次发送、重试、停止都要能关联到同一条用户消息和同一轮 assistant 响应,避免重复插入和顺序错乱。
第四层是超时和取消。前端停止不等于后端停止,后端超时也不等于模型供应商已经取消。需要明确取消信号和最终状态。
第五层是有限重试。只有可重试错误才重试,例如网络抖动、429、5xx、临时超时。业务校验失败、权限失败、用户输入不足,不应该盲目重试。
第六层是幂等和持久化。对话消息、工具调用和扣费记录都要能防重复。工具有副作用时,必须用 idempotency key 或事务边界保护。
第七层是 fallback 路由。主模型失败时可以换轻量模型、关闭工具、返回部分结果、进入人工队列或提示用户稍后再试。
第八层是观测和回放。记录每轮对话的状态流转、模型、耗时、错误、重试次数、fallback 路径和用户操作,才能持续改进。
什么时候简单策略足够
以下情况通常可以先用简单策略:
- 输出只是草稿,用户会编辑。
- 没有工具调用、写库或外部副作用。
- 对话轮次短,刷新后丢失也能接受。
- 用户量小,失败可以人工反馈。
- 重试只会重新生成文本,不会改变业务状态。
- 失败代价是体验下降,而不是权益损失。
这时可以做到:前端显示 streaming、failed、retry;后端设置合理超时;失败时保留用户输入;重试生成一条新回答或覆盖原失败回答;记录基础错误日志。
什么时候需要工程方案
以下情况应该升级到完整工程方案:
- 回复会进入客户沟通、工单、审批或业务记录。
- 对话中会调用工具、查询私有数据或执行动作。
- 用户会多次重试、停止、刷新或跨设备继续会话。
- 需要区分“用户取消”“模型失败”“工具失败”“系统超时”。
- 主模型不可用时必须提供降级服务。
- 需要统计成功率、失败率、超时率、重试率和 fallback 质量。
- 失败可能导致重复扣费、重复发消息、重复创建工单或错误承诺。
这时要把 AI Chat 当成一个有状态的分布式流程,而不是一个单次 HTTP 请求。
方案选型表
反模式
第一种反模式:把流式输出当成普通字符串追加。
流式输出不是“多次 setState”这么简单。每个 chunk 都应该属于某一条 assistant 消息、某一次响应、某个状态。否则重试或并发时,chunk 可能追加到错误消息上。
第二种反模式:只有 loading 和 error 两种状态。
AI Chat 至少要区分 streaming、failed、stopped、retrying、completed。否则用户取消、模型失败和网络断开都会变成同一种“失败”,后续无法恢复。
第三种反模式:失败后直接重新发送整段历史。
如果上一轮已经调用工具或写入状态,整段重试可能重复执行副作用。重试应该基于明确的响应 ID、失败阶段和幂等策略。
第四种反模式:前端停止按钮只停止 UI。
如果后端仍继续生成,用户以为已经取消,系统却继续消耗 token,甚至把结果写入历史。停止需要有取消信号和最终状态。
第五种反模式:fallback 不告诉用户。
降级模型、关闭工具或返回部分结果时,如果仍用正常成功口吻,用户会误以为答案具备同等可信度。fallback 应该明确能力边界。
第六种反模式:没有 trace,只看错误率。
对话失败常常跨越前端、网关、模型、工具和数据库。只有错误率无法定位问题,必须记录状态流转和关键耗时。
工程清单
- 场景边界:对话是草稿生成、知识问答、客户服务,还是工具执行。
- 状态模型:用户消息和 assistant 消息有哪些状态,状态如何流转。
- 流式协议:chunk、完成、错误、取消、fallback 是否有明确事件类型。
- 超时策略:前端、网关、后端、模型和工具各自的超时预算是否一致。
- 重试策略:哪些错误可重试,最大次数、退避和总时长是多少。
- 幂等设计:发送、重试、工具调用、写库和扣费是否有 idempotency key。
- 持久化:partial、failed、stopped、completed 是否都能被恢复和审计。
- fallback:主模型、工具、上下文、供应商失败时分别如何降级。
- 用户体验:失败原因、重试入口、停止入口和人工接管是否清晰。
- 可观测性:是否记录 traceId、messageId、requestId、模型、耗时、错误类型。
- 成本控制:重试和 fallback 是否有成本上限和限流策略。
- 回放复盘:线上失败能否按一次对话完整重建状态流转。
小结
整体对话稳定性不是某一个 SDK 参数,而是一套围绕“消息状态”的产品和工程设计。
低风险草稿类功能,可以先用基础状态、手动重试和简单失败提示。只要涉及流式输出、工具调用、业务记录、多轮恢复或 fallback,就需要把消息、请求、工具和模型调用都纳入可追踪的状态流转。
这个专题的后两篇会继续展开:
- 前端如何设计 AI Chat 的 retry、stop、failed、streaming 状态。
- 后端如何做 timeout、retry、fallback、幂等和降级。