西安智唐科技后端面经:SingleFlight Key 设计、ASR 拼接与部署实践
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
技术栈与项目背景
- 请介绍一下你熟练掌握的技术栈,包括编程语言和常用中间件?
- 讲一下你最熟悉的 AI 相关项目,整体架构和业务逻辑是什么?
- 这个平台的用户群体是谁?核心业务流程是怎样的?
- 项目中用的 Spring Boot 和 Spring AI 分别是什么版本?你个人负责哪些模块?
- 团队规模多大?项目周期多长?前后端是怎么分工的?
后端架构与中间件
- 你在项目中具体做了哪些后端优化工作?
- 为什么引入 SingleFlight 机制?请求 Key 是怎么构造的?
- 去重机制的作用范围是什么?能不能支持跨用户、跨会话去重?
- 为什么同时用 Redis 和 MongoDB?MongoDB 在这个项目里解决什么问题?
- WebSocket 通信是你负责的吗?主要对接了什么功能?
AI 接口与语音转写
- AI 接口调用成本高,你是怎么避免重复扣费的?
- 对接讯飞 ASR 语音转写时,遇到了哪些数据处理上的难点?
- 讯飞返回的数据结构比较特殊,你是怎么做排序和拼接的?
- 前端发送数据和讯飞消费数据的节奏不一致,你是怎么解决的?
部署与全栈能力
- 你平时是怎么做项目部署的?用过哪些工具?
- 你掌握哪些编程语言?有没有前端开发经验?
个人特质与团队协作
- 你觉得自己的最大优势是什么?
- 团队里任务一般怎么分配?你平时扮演什么角色?
- 你对自己未来的技术发展方向有什么规划?
- 刚才提到的去重方案是你独立设计的吗?
《参考解析》
项目架构怎么讲:用一张分层图讲清:接入层(Web/WebSocket、鉴权、限流)→ 应用层(会话编排、答题流程、评分)→ AI 能力层(模型网关、ASR、RAG、工具)→ 数据层(MySQL/Redis/MongoDB/向量库)。业务逻辑落到「用户创建面试 → 选择岗位与简历 → 实时对话/答题 → 转写与评分 → 生成报告」。版本号这类细节如实说,不记得就说不记得,别编。
SingleFlight 的 Key 构造与范围:key 要能唯一标识「一次可复用的执行」,通常由「用户 ID + 会话 ID + 操作类型 + 输入内容哈希」组成;如果希望跨用户复用,就去掉用户 ID,只保留「模型 + 提示词版本 + 输入哈希」。范围要明确:按用户去重能避免同一用户重复提交,但不同用户问同样的问题仍会各调一次;跨用户去重能省钱,但要注意权限与数据隔离(不能把 A 的简历内容返回给 B),所以只对「输入完全相同且不含私有数据」的请求做跨用户复用。回答时把「省钱」和「隔离」的边界讲清,比一味说能跨用户复用更加分。
Redis 与 MongoDB 的分工:Redis 存热状态、锁、去重 key、限流计数、会话最近消息,特点是读写快、可设 TTL;MongoDB 存会话快照、完整消息、工具调用记录,特点是文档结构灵活、可持久化、按会话查询方便。MongoDB 解决的是「长会话的状态持久化与恢复」:进程重启或断线后能按 sessionId 把上下文捞回来。两者不是替代关系,Redis 是加速层,MongoDB 是事实层。
WebSocket 对接:负责的话要讲清「连接建立 → 鉴权(token 放 query 或首帧)→ 会话绑定 → 消息收发 → 心跳保活 → 断线重连 → 关闭清理」。主要功能是实时面试的语音/文本流、评分进度、状态同步。要注意多实例下的连接路由(网关按 userId 粘性、或用 Redis Pub/Sub 广播)、消息顺序、以及背压。
避免 AI 重复扣费:三层。① 请求去重:SingleFlight + 幂等键,重复请求复用结果;② 结果缓存:相同输入(模型 + 提示词版本 + 内容哈希)命中缓存直接返回,设合理 TTL;③ 计费对账:每次调用记录 requestId、token 用量、渠道,和上游账单对账,发现重复调用能定位。还要防「重试导致重复计费」:写操作带幂等键,重试前先查状态。
讯飞 ASR 的数据处理难点:流式返回是分片、带序号、可能乱序或重复;中间结果会不断修正;连接可能中断;标点与断句由服务端追加。难点在「把分片还原成正确的文本」以及「把文本和说话人/时间对齐」。
排序与拼接:按 sn(序号)排序,用 map 暂存已到达的分片,维护 expectedSn 依次取;缺失时等待补包,超时则标记缺口并继续,不能阻塞整个会话。同一句的中间结果只保留最新版本,最终结果(ls=true)才落库。拼接时注意中英文空格、标点重复、以及跨分片的词被切断。
前后端节奏不一致:前端按 VAD 切段发送,ASR 消费是流式的,可能出现「前端已经发完、ASR 还没返回最终结果」。解决是解耦:音频帧进队列,ASR 结果按会话 ID 聚合,前端用「临时文本 + 最终文本」两种状态渲染;服务端维护「已确认序号」,前端拿到最终结果后替换临时文本;如果用户提前结束,服务端等待 ASR 的最终结果或超时后用已有文本兜底,并标记「可能不完整」。
部署:讲一条完整链路:本地构建(Maven/Gradle 或 npm)→ 打镜像(多阶段构建)→ 推镜像仓库 → 服务器拉取 → docker compose 或 K8s 启动 → Nginx 反向代理与 TLS → 健康检查与日志 → 回滚(保留上一个镜像 tag)。常用工具:Docker、Docker Compose、Nginx、Jenkins/GitHub Actions、云服务器与对象存储。要能说出「配置与密钥走环境变量、数据卷持久化、日志落盘并轮转」。
优势与协作:优势用证据说,比如「能把一个模糊需求拆成可交付的模块,并自己补监控和回滚」;团队协作讲清需求评审、任务拆分、接口约定、联调与验收的流程,自己通常承担「后端主程 + 对接」的角色。职业规划可以分短期(把 AI 应用的工程化做扎实:可观测、可评测、成本可控)和长期(往架构或 AI 平台方向走),不要空泛。
去重方案是否独立设计:如实回答。如果是自己设计的,讲清动机(发现重复调用浪费 token)、方案对比(本地锁 vs Redis vs 幂等表)、以及上线后的效果(调用量下降多少);如果是团队一起做的,说清自己负责哪部分。面试官在意的是你能否对方案负责,而不是独占功劳。