面试复盘功能设计

AI Agent 工程实践教程 · 第 12 章

把模拟面试后的问题、回答、评分和建议沉淀成可复盘的产品功能。

返回系列目录

第十二天:面试复盘功能设计

前面我们已经完成了学生端、后台管理、文件上传、知识库问答、Text-to-SQL 等能力。

今天要设计一个更贴近真实业务的 AI 功能:面试复盘

这个功能不是简单地上传一个音频文件,也不是单纯做语音转文字。它的目标是把学生真实面试后的录音,结合学生简历,整理成一份可读、可追踪、可复盘的面试报告。

整体链路如下:

学生简历
  ↓
学生上传面试录音
  ↓
录音文件转文字
  ↓
ASR 分句整理成对话
  ↓
结合简历生成面试复盘
  ↓
学生和老师查看复盘结果

从系统视角看,它不是一个单点接口,而是一条完整的异步处理链路:

面试复盘总链路


1. 为什么要做面试复盘

学生出去面试以后,常见问题是:

面试问了什么?
学生当时怎么回答的?
哪些地方回答得不好?
哪些问题和简历内容有关?
下次怎么优化?
老师怎么快速了解学生这次面试表现?

如果只靠学生口头描述,信息很容易丢失:

问题 影响
学生记不全问题 老师无法判断真实表现
学生复述不准确 容易漏掉关键追问
没有原始材料 无法对照分析
老师逐个听录音成本高 复盘效率低
学生不知道怎么改 下次面试仍然重复犯错

所以面试复盘功能要解决的核心问题是:

把一次真实面试沉淀成结构化资料,并自动给出可执行的优化方案。

2. 功能边界

面试复盘功能由学生自助上传触发。

这里的录音来源不是平台内模拟面试,而是学生出去真实面试时录下来的音频,所以不设计面试官模块,也不设计后台老师代上传录音。

功能范围如下:

模块 是否需要
学生简历上传 需要
学生面试录音上传 需要
录音转文字 需要
ASR 分句整理为对话 需要
AI 生成面试复盘 需要
后台查看学生复盘 需要
面试官管理 不包含
后台代上传录音 不包含

一句话概括:

学生上传自己的面试录音,系统自动转写、整理、分析,后台负责查看结果。

3. 用户角色和使用场景

3.1 学生端

学生端主要做三件事:

上传简历
上传面试录音
查看复盘结果

学生完整使用流程:

进入学生首页
  ↓
上传或更新简历
  ↓
点击“面试复盘”
  ↓
上传面试录音
  ↓
填写面试时间和备注
  ↓
等待系统转写和分析
  ↓
查看对话稿和复盘报告

学生上传录音时填写辅助信息:

字段 说明
面试时间 这场面试发生的时间
录音文件 mp3、m4a、wav 等音频文件
复盘备注 学生自己补充的信息,比如公司、岗位、感觉不好的地方

3.2 后台老师端

后台老师主要做三件事:

查看学生简历
查看学生上传的面试录音
查看面试对话和 AI 复盘报告

后台不需要复杂操作,重点是信息清晰:

后台内容 作用
学生姓名、手机号 定位学生
简历 了解学生背景
面试录音 必要时回听原始材料
对话稿 快速看面试问答内容
说话人 区分不同发言人
复盘报告 快速知道问题和优化方案

4. 总体业务流程

面试复盘拆成五个阶段:

阶段一:学生资料准备
  ↓
阶段二:学生上传录音
  ↓
阶段三:语音识别转文字
  ↓
阶段四:对话结构化
  ↓
阶段五:生成复盘报告

用流程图表示:

按钮提交和定时轮询流程

这里采用“按钮提交 + 定时轮询”:

这张图里最重要的是两个边界:

边界 说明
上传录音 只保存文件和业务记录,不在上传接口里同步识别
开始转写 由页面按钮触发 ASR 任务,后端通过定时任务查询结果

5. 学生简历在复盘中的作用

面试复盘不能只看录音文本。

因为很多面试问题其实是围绕简历展开的,例如:

你简历上写了 RAG 项目,具体是怎么做的?
你说自己熟悉 Spring Boot,说一下你们项目里的权限怎么设计?
你这个项目里用到了 Milvus,它的作用是什么?

如果系统不知道学生简历内容,就很难判断回答是否充分。

所以简历在面试复盘中有三个作用:

作用 说明
背景补充 让 AI 知道学生写了哪些项目和技能
问题归因 判断面试官的问题是否来自简历
回答评估 判断学生回答是否和简历匹配

举例:

简历写了:熟悉 LangChain、RAG、向量数据库。

面试官问:你们知识库问答怎么做的?

学生回答:就是把文件传上去,然后 AI 回答。

AI 复盘结论:
这个回答过于表层,没有讲清楚文档解析、切分、向量化、召回、Prompt 拼接和模型生成流程。
复盘报告会要求学生补充 RAG 的完整链路。

6. 录音上传设计

学生端上传录音时,前端不直接把文件传给 AI 服务。

正确做法是:

前端获取上传凭证
  ↓
前端上传到对象存储
  ↓
前端把 objectKey 提交给后端
  ↓
后端保存面试复盘记录

这样做有几个好处:

好处 说明
文件存储统一 简历、作业、SOP、面试录音都走同一套上传逻辑
后端可控 后端校验 objectKey 是否属于当前学生
密钥安全 前端不接触 AI 服务密钥
可回听 后台生成临时下载地址播放录音

录音文件支持常见音频格式:

mp3
m4a
wav
aac
ogg
flac
webm
amr

录音文件统一存入学生面试复盘目录,后端负责校验文件归属:

只能访问当前学生自己的录音
只能上传允许的音频格式
不能访问非法文件路径

7. 语音转文字设计

学生上传录音以后,下一步就是 ASR,也就是 Automatic Speech Recognition,自动语音识别。

这里使用语音识别专用模型,而不是直接用多模态大模型。

原因是:

方案 作用
ASR 专用模型 稳定完成长音频转写,生成带说话人的对话稿
大模型 在对话稿基础上做角色判断、问题分析和复盘报告

转写流程:

录音文件
  ↓
ASR 语音识别模型
  ↓
带说话人的分句结果
  ↓
保存 speaker + text 对话JSON

录音识别采用异步流程:

submit 提交识别任务
  ↓
query 查询识别结果
  ↓
保存识别结果

提交识别任务时,后端会把对象存储里的录音转换成临时可访问地址:

audio_object_key
  ↓
后端生成 presigned download url
  ↓
传给 ASR 服务

识别任务需要包含三类信息:

信息 说明
用户标识 用来标记是哪名学生的识别任务
录音地址 后端生成的临时下载地址
识别配置 开启标点、文本规整、分句和说话人识别

识别任务设计如下:

豆包 ASR 请求结构

识别完成后,系统只提取复盘需要的内容:说话人和发言文本。


8. 从 ASR 分句到对话

语音识别模型返回的结果通常是一整段文本,或者一组带时间戳的分句。

但面试复盘需要的是更清晰的结构:

面试官:请你介绍一下你的项目。
学生:我做的是一个 AI 课程系统,里面有知识库问答和 Text-to-SQL。

面试官:你们知识库问答是怎么实现的?
学生:主要是文档上传以后切分,然后向量化,查询的时候做相似度召回。

所以要增加一个“对话整理”步骤。

系统不会把原始识别结果直接展示给学生。

面试复盘真正需要的是结构化对话:

谁在说
说了什么
这句话属于面试问题还是学生回答

输入:

ASR 分句结果
说话人聚类 speaker
学生简历
学生备注

输出:

[
  {
    "speaker": "1",
    "text": "请你介绍一下你的项目。"
  },
  {
    "speaker": "2",
    "text": "我做的是一个 AI 课程系统,里面有知识库问答和 Text-to-SQL。"
  }
]

这里要注意:speaker=1 不一定天然等于“面试官”,speaker=2 也不一定天然等于“学生”。

ASR 做的是说话人聚类,含义是:

字段 说明
speaker=1 第一类声音
speaker=2 第二类声音
speaker=3 第三类声音,可能是环境声、其他人、误分离

页面展示:

说话人 1:你现在还在这家公司吗?
说话人 2:离职了。

生成复盘报告时,系统会根据对话内容识别说话人角色:

说话人聚类和角色识别


9. 面试复盘报告设计

有了简历和带说话人的对话稿以后,才能生成真正有价值的复盘报告。

复盘报告包含以下部分:

模块 内容
面试概要 这场面试主要聊了什么
问题清单 面试官问了哪些问题
回答评价 学生回答得怎么样
简历关联 哪些问题来自简历
风险点 哪些回答暴露出知识短板
优化方案 下次怎么回答
推荐话术 给学生一版更好的回答

报告结构:

# 面试复盘报告

## 1. 面试概要

本次面试主要围绕 AI 课程系统、RAG 知识库问答、Text-to-SQL 和项目权限设计展开。

## 2. 高频问题

1. 请介绍一下你的项目
2. RAG 知识库问答怎么实现
3. 向量数据库在项目里起什么作用
4. Text-to-SQL 如何保证 SQL 安全

## 3. 回答表现

整体能讲出项目方向,但细节不足。尤其在 RAG 和 Text-to-SQL 部分,回答偏概念,没有结合项目里的真实流程。

## 4. 主要问题

- 回答缺少完整链路
- 技术细节不够具体
- 没有主动讲业务价值
- 对异常场景和安全控制说明不足

## 5. 优化方案

按照“业务背景 -> 技术方案 -> 关键难点 -> 结果价值”的结构回答项目问题。

## 6. 推荐回答

如果面试官问“你们知识库问答怎么做的”,推荐回答如下:

我们先把用户上传的文档做解析和切分,然后对文本块生成向量并存入 Milvus。
用户提问时,系统会先做向量召回,找到相关片段,再把问题和召回内容拼成 Prompt 发给大模型。
为了提升回答质量,我们还做了上下文压缩和来源保留,避免模型凭空编造。

10. 数据库表设计

面试复盘记录放在一张主表中。

这张表承载一条面试复盘从上传到生成报告的完整状态。

核心数据分为五组:

数据组 内容
学生信息 学生 ID、学生姓名、手机号
面试信息 面试时间、学生备注
录音信息 录音文件、文件大小、上传时间
转写信息 转写状态、对话稿、失败原因、完成时间
报告信息 报告状态、复盘报告、失败原因、完成时间

状态字段:

状态 说明
PENDING 等待处理
PROCESSING 处理中
SUCCESS 处理成功
FAILED 处理失败

转写结果:

内容 说明
对话稿 保存说话人和发言内容
转写状态 标记是否未开始、处理中、成功或失败
失败原因 转写失败时用于页面提示和后台排查
完成时间 记录转写任务完成时间

对话稿结构:

[
  {
    "speaker": "1",
    "text": "你现在还在这家公司吗?"
  },
  {
    "speaker": "2",
    "text": "离职了。"
  }
]

转写状态流转图:

转写状态和数据库保存字段


11. 后端接口设计

11.1 学生端接口

学生端接口放在 studentFront 下。

接口:

接口 方法 说明
/student/interview-reviews GET 查询我的面试复盘列表
/student/interview-reviews POST 上传一条面试复盘录音
/student/interview-reviews/{id}/transcribe POST 点击开始转写或重新转写

11.2 后台管理接口

后台先以查看为主。

接口:

接口 方法 说明
/api/interview-reviews GET 分页查询学生面试复盘
/api/interview-reviews/{id}/transcribe POST 后台提交转写或重新转写

后台列表展示:

字段 说明
学生姓名 来自学生表
手机号 来自学生表
面试时间 学生填写
录音文件 可播放
转写状态 是否转写完成
报告状态 是否生成报告
上传时间 记录创建时间

接口调用关系:

接口调用关系分为三段:

阶段 接口 结果
上传记录 POST /student/interview-reviews 保存 PENDING 记录
发起转写 POST /student/interview-reviews/{id}/transcribe 保存 taskId,状态变成 PROCESSING
查看结果 GET /student/interview-reviews / GET /api/interviewReviews 学生和后台查看录音、状态和对话稿

12. 异步任务设计

语音转文字和复盘报告生成都不适合放在上传接口里同步执行。

原因:

音频文件可能很大
ASR 识别需要时间
大模型生成报告也需要时间
接口同步等待容易超时
用户体验不好

语音转写采用异步任务,不在上传接口里同步执行:

学生上传录音
  ↓
接口快速返回:PENDING
  ↓
学生或老师点击“开始转写”
  ↓
后端 submit ASR,状态改为 PROCESSING
  ↓
Spring Boot 定时任务轮询 query
  ↓
转写完成后保存对话 JSON
  ↓
前端轮询状态或刷新列表

系统使用 Spring Boot 定时任务查询转写结果:

每隔 1 分钟扫描 transcript_status = PROCESSING 的记录
  ↓
查询 ASR 结果
  ↓
识别完成,保存 transcript_dialogue_json,状态改为 SUCCESS
  ↓
识别失败,保存 transcript_error_message,状态改为 FAILED

定时任务核心规则:

开关未启用:直接跳过
没有 PROCESSING 记录:直接结束
ASR 还在处理:保持 PROCESSING
ASR 成功:保存 speaker/text JSON
ASR 失败:保存失败原因,状态改为 FAILED

13. AI 复盘 Prompt 设计

生成复盘报告时,输入不是一整段纯文本,而是结构化材料。

模型输入包含三部分:

输入材料 作用
学生简历 提供项目、技能和经历背景
面试对话稿 还原面试问题和学生回答
学生备注 补充公司、岗位、面试反馈等信息

复盘报告输出结构:

面试复盘报告

一、面试概要

二、面试问题清单

三、回答表现分析

四、简历相关问题分析

五、主要短板

六、下次优化方案

七、推荐回答话术

报告生成时必须遵守两个原则:

原则 说明
不编造 录音里没有出现的问题不能写进报告
改法具体 每条优化方案都要指向具体回答和改法

14. 前端页面设计

14.1 学生端页面

学生端顶部入口:

面试复盘

页面结构:

顶部:返回首页 / 页面标题

左侧:上传面试录音
  - 面试时间
  - 选择录音文件
  - 复盘备注
  - 上传按钮

右侧:我的复盘记录
  - 面试时间
  - 录音文件
  - 转写状态
  - 开始转写 / 重新转写
  - 查看对话

详情页展示:

录音播放器
对话稿
AI复盘报告

学生端页面结构:

学生端页面拆成两块:

区域 内容
上传表单 面试时间、录音文件、复盘备注、上传按钮
录音列表 文件名、上传时间、转写状态、开始/重新转写、查看对话

14.2 后台页面

后台页面以管理和查看为主:

筛选区:
  - 学生姓名
  - 手机号
  - 转写状态
  - 报告状态

列表区:
  - 学生信息
  - 面试时间
  - 录音播放
  - 转写状态
  - 开始转写 / 重新转写
  - 查看对话

后台详情页分 Tab:

基础信息
录音播放
对话稿
复盘报告

15. 关键异常处理

这个功能涉及文件、第三方接口和大模型,异常处理必须提前设计。

异常 处理方式
音频格式不支持 上传时提示用户
文件过大 上传前限制大小
ASR 提交失败 保存失败原因,允许重试
ASR 长时间无结果 设置超时时间,转为失败
对话内容为空 不生成报告,提示录音质量可能有问题
大模型生成失败 保存失败原因,允许重试
简历不存在 仍可复盘,但报告提示缺少简历背景
无法区分说话人 对话稿中标记 UNKNOWN

用户看到的提示要简单:

录音转写中,请稍后查看
录音识别失败,请重新上传或联系老师
复盘报告生成中,请稍后刷新

后台看到的信息要更详细:

ASR错误码
ASR错误信息
任务ID
失败时间
重试次数

16. 落地流程

功能按下面的顺序落地:

第一步:学生上传简历
第二步:学生上传面试录音
第三步:后台能播放录音
第四步:页面增加“开始转写”按钮
第五步:后端接入豆包 submit/query
第六步:Spring Boot 定时任务轮询 PROCESSING 记录
第七步:保存 speaker/text 对话 JSON
第八步:学生端和后台展示对话
第九步:生成 Markdown 复盘报告

本次不做:

逐字时间轴
点击文字跳转录音
复杂统计报表
多版本复盘报告
自动判断面试官/学生角色

主链路:

录音上传成功
  ↓
录音能播放
  ↓
录音能提交转写
  ↓
定时任务能拿到 speaker/text 对话
  ↓
学生和老师能看到对话

后端代码模块:

后端模块拆分


17. 最终效果

功能完成后,一条面试复盘记录包含:

学生是谁
学生简历是什么
什么时候面试
录音文件在哪里
面试录音转写状态是什么
speaker/text 对话是什么
AI 复盘报告是什么
老师和学生怎么改进

这时,面试复盘就不再是一个简单文件上传功能,而是一个完整的 AI 辅导流程。

它把原本散落的信息:

简历
录音
学生记忆
老师经验

整理成了结构化、可追踪、可复用的学习资料:

对话稿
问题清单
短板分析
优化方案
推荐回答

这就是面试复盘功能真正的价值。

最终数据从“录音”变成“可复盘资料”的过程如下:

复盘报告生成材料