PaiSmart面试题预测:WebSocket、客户端掉线重连、Elasticsearch、并发上传分片、Kafka、context、LLM切换
1. WebSocket 流式对话与主动中断
简历描述
基于 WebSocket 实现全双工流式对话,后端通过 WebFlux 的 Stream 接入 DeepSeek 等 LLM 的 SSE 流,实现逐字输出;支持用户主动中断,后端同步取消 LLM 侧的流式连接,避免错误提示词下的 Token 消耗;整体首字响应延迟控制在 500ms 以内。
面试提问
Q1: 为什么选择 WebSocket 而不是 SSE 来实现流式对话?
考察点:WebSocket vs SSE 的技术选型
参考答案:SSE 是单向通道(服务端→客户端),无法在流式输出过程中接收客户端的中断指令;WebSocket 是全双工通信,客户端可以在接收流式输出的同时发送 stop 命令。此外 WebSocket 支持心跳保活(ping/pong),更适合长连接场景。
Q2: 用户点击"停止生成"后,后端做了哪些事情确保 LLM 也停下来?
考察点:流式中断的完整链路
参考答案:分三步
(1) 在 stopFlags 中标记该 generationId 为已取消;
(2) 从 activeStreams 中取出 StreamHandle,调用 cancel() 方法,内部调用 Reactor Disposable.dispose() 断开与 LLM API 的 HTTP 流连接;
(3) 对关联的 CompletableFuture 调用 completeExceptionally(CancellationException) 唤醒完成监控线程,向客户端推送 {type:"stop"}。
源码位置:ChatHandler.java:520-558
关键代码:
public void stopResponse(String userId, String generationId) {
cancelledGenerations.add(generationId);
stopFlags.put(generationId, true);
StreamHandle handle = activeStreams.remove(generationId);
if (handle != null) {
handle.cancel(); // Disposable.dispose() → 断开 HTTP 流
}
CompletableFuture future = responseFutures.remove(generationId);
if (future != null) {
future.completeExceptionally(new CancellationException("User stopped"));
}
}
Q3: stop 指令中为什么要加一个 token 校验?去掉会有什么风险?
考察点:安全性设计
参考答案:WSS_STOP_CMD_ + 时间戳片段构成的 token 用于验证 stop 指令来自合法客户端,而非通过 XSS 或 CSRF 注入的恶意消息。去掉后攻击者可以构造 {type:"stop"} 消息中断其他用户的对话。
源码位置:ChatWebSocketHandler.java:28, 99-113
延伸问题
- 后端用了 5 个
ConcurrentHashMap存储流式状态,如果服务重启全部丢失怎么办? - 如果用户快速连续发送多条消息,如何防止并发冲突?
2. 对话内容持久化与断线续传
简历描述
实现对话内容的持久化和断线续传,每个流式内容原子写入 Redis,并通过状态机维持状态;用户断线重连后自动恢复上一次输出进度,不丢失已生成文本,保障弱网环境下的用户体验。
面试提...
企业级Agent工作流编排项目PaiFlow
Vibe Coding版本的PaiAgent
派聪明RAG AI知识库Java版本+Go版本
微服务 PmHub、技术派、MYDB
求职派JobClaw(OpenClaw/Hermes架构
PaiCLI(类似Claude Code的Agent
派简历(代码已完成)
等实战项目。
1. 微信扫右侧的优惠券加入知识星球
2. 解锁星球的实战项目教程和源码: 项目源码+教程获取
3 条评论
回复