Skip to content

React + AI 应用开发

AI 生成如何实现停止、取消、重试和断线恢复?

停止按钮只是前端动作,真正可靠的实现还要处理服务端任务、已产生内容和重复提交。

适合阶段:资深前端 / 稳定性面试核心能力:请求生命周期 · 幂等 · 恢复

面试官想考什么

  • 点击停止后模型真的停止了吗? 考察客户端与服务端边界。
  • 网络重试会不会产生两条答案? 考察幂等设计。
  • 断线恢复从哪里继续? 考察 cursor、重放和最终一致。
  • 哪些错误应该自动重试? 考察错误分类和成本控制。

一句话回答

text
取消要同时 abort 客户端读取和取消服务端任务,重试必须携带幂等键,断线恢复依赖服务端持久化的事件游标或最终消息;只对瞬时错误做有限退避,不能把业务拒绝和模型超时无限重试。

面试回答详解

1. 生命周期状态机

text
idle -> queued -> running -> completed
                         |-> cancelled
                         |-> failed
                         |-> reconnecting -> running

前端保存 requestIdconversationIdmessageIdlastCursorabortController。这些字段不能只存在组件局部变量里,否则路由切换或恢复时丢失上下文。

2. 取消链路

  1. 用户点击停止,立即停止继续渲染并调用 controller.abort()
  2. 若服务端任务仍在运行,发送带 requestId 的 cancel 命令。
  3. 服务端把上游模型请求绑定到取消信号,尽力释放连接和计费资源。
  4. 已收到的内容保留为 cancelled 消息,不把它伪装成 completed。

取消是尽力而为,不应向用户承诺已经撤回模型侧所有计算。

3. 重试策略

  • DNS、网络断开、网关 502/503、明确的速率限制通常可有限重试。
  • 参数错误、权限拒绝、内容安全拒绝不应自动重试。
  • 超时重试前先查询 requestId 的服务端状态,避免原任务其实已经完成。
  • 指数退避加随机抖动,并设置总预算、最大次数和用户可见反馈。

4. 断线恢复

服务端应保存事件或可查询的消息快照。客户端重连时带上 Last-Event-ID 或业务 cursor,服务端重放缺失事件;若不支持重放,则查询最终消息并用 revision 覆盖本地 draft。恢复期间禁止用户再次提交同一个请求。

5. 验证与观测

测试断网、切后台、浏览器刷新、重复点击、服务端完成后客户端断线、取消竞态和 token 超时。记录 cancel_requested、cancel_confirmed、reconnect_count、resume_gap、retry_reason 和最终状态。

可直接背诵的 30 秒回答

text
我会把生成任务建模成有 requestId 的状态机。停止时前端立即 abort reader,同时向服务端发送取消,让服务端继续取消上游模型;重试必须先查询原任务状态并使用幂等键。断线恢复用事件 id 或 cursor 重放,不能简单重新调用模型。错误要分类,只对瞬时错误做有限退避,并记录取消、重连和恢复缺口。

扩展知识

客户端取消和服务端取消的差异

  • 客户端取消:停止等待和 UI 更新。
  • 服务端取消:停止上游调用、释放资源、写入审计状态。
  • 两者之间存在网络延迟,所以状态必须允许 cancelling

面试官追问链

追问一:AbortController 能取消服务端模型调用吗?

  • 考察点:边界意识。
  • 回答方向:它只能取消浏览器侧 fetch;服务端必须接收取消意图并把 signal 传给上游,且要处理取消竞态。

追问二:重试是否应该复用 messageId?

  • 考察点:数据建模。
  • 回答方向:用户语义相同但每次执行应有新的 attemptId;原 messageId 可关联多个尝试,最终只选择一个有效版本。

追问三:流已经完成但 done 事件没到怎么办?

  • 考察点:异常结束处理。
  • 回答方向:服务端落库是权威状态,客户端可查询任务或消息快照,用 revision 和 checksum 判断是否完整。

推荐阅读

基于 MIT 协议开源