Skip to content

Proposal_英文模拟面试(Interview)模块详细设计 #33

Description

@pionxe

RFC:英文模拟面试(Interview)模块详细设计

  • 状态:阶段性冻结
  • 冻结日期:2026-08-03
  • 实施状态:待实现
  • 适用范围:Interview 业务模块内部
  • 约束:不得修改或违背现有项目整体架构

本 RFC 冻结截至当前已经确认的设计。文末“待后续设计”内容不属于本次冻结结论。

1. 背景与目标

英文模拟面试需要根据目标岗位和用户材料,完成有结构的英文问答、动态追问、完整录音和面试报告,并沉淀为可复练的学习资产。

本次设计目标:

  • 支持岗位定制和可选简历输入。
  • 提供可控且有难度梯度的英文面试。
  • 保留完整录音、实际问题和五维报告。
  • 不持久化用户逐字稿及原始求职材料。
  • 严格复用项目现有 Provider、评分能力和会话状态体系。
  • 避免为未来需求提前增加状态、表和抽象层。

2. 架构边界

Interview 是待实现的独立业务模块,沿用现有项目约定:

service/interview
domain/dto/interview
controller/InterviewController.java

Interview 模块负责:

  • 岗位信息准备。
  • 面试问题计划。
  • 主问题与追问流程。
  • 面试业务进度。
  • 报告组装和学习资产持久化。
  • 快速复练和历史查询规则。

现有能力继续复用:

  • ASR Provider
  • LLM Provider
  • TTS Provider
  • Scoring Provider
  • EvaluationService
  • SessionStatus
  • 对象存储能力

禁止新增:

  • InterviewLlmService
  • InterviewTtsService
  • Interview 专属评分 Provider
  • 第二套会话状态枚举

评分模块复用的是评分能力,不直接复用旧五维契约、session_evaluation 表或现有固定权重。

3. 面试输入

3.1 简历

简历为可选项。

支持:

  • 粘贴文本
  • 文本型 PDF
  • DOCX

不支持:

  • DOC
  • 图片简历
  • 扫描型 PDF
  • 其他需要 OCR 的简历文件

3.2 岗位信息

  • 岗位名称必填。
  • JD 文字选填。
  • JD 图片选填,使用本地部署的 OCR 识别。
  • OCR结果必须允许用户检查和修改。
  • 不直接以未经用户确认的 OCR结果启动面试。

材料解析或岗位摘要生成失败时,不创建 interview 记录。

3.3 数据保留

原始简历、JD文字、JD图片及 OCR 临时文件只用于本次准备,不进入最终学习资产。

最终只保留岗位名称及“岗位信息摘要”。

4. 面试结构与难度

不提供面试时长选择。每场面试固定规划5个主问题,以问题完成情况结束。

难度 主问题数量 每题追问上限 追问定位
BASIC 5 1 澄清式追问
STANDARD 5 1 深入追问
CHALLENGE 5 2 连续深入追问

用户现有的 A–D 英语水平只影响面试官用词和句式复杂度,不写入 Interview 记录,也不改变问题数量。

5. Interview 内部业务对象

对象 职责 是否持久化
TargetRoleSummary 保存可复用的岗位信息摘要 作为 interview.role_summary 保存
InterviewQuestionPlan 预先确定5个主问题及追问上限
InterviewProgress 管理当前问题、追问次数和业务结束原因
InterviewTurn 表示一次AI提问及用户完整回答
InterviewReport 表示完整或部分面试报告
InterviewSession 管理运行时连接和临时数据

InterviewQuestionPlan 不预生成具体追问,也不承担运行状态。

InterviewTurn 中的回答音频引用和临时转写仅存在于运行时。完成后只持久化实际AI问题。

6. 单轮面试流程

采用受控的 ASR → LLM → TTS 三段式,不使用自主实时语音大模型驱动面试流程。

单轮流程:

  1. AI通过TTS播放问题,同时前端显示AI问题字幕。
  2. 用户进行完整英文回答。
  3. 用户手动点击“回答完成”。
  4. 后端对完整回答执行ASR,产生临时转写。
  5. LLM根据回答和当前进度返回:
    • ASK_FOLLOW_UP
    • MOVE_TO_NEXT_MAIN
  6. InterviewProgress检查难度对应的追问上限。
  7. 生成追问或下一主问题,并通过TTS播放。

VAD只可用于录音辅助,不得自动结束业务轮次。

前端不显示用户逐字稿,只显示AI问题字幕。

临时转写只用于:

  • 动态追问判断
  • 报告生成
  • 必要的评分计算

临时转写不得持久化、进入日志或作为历史资产展示。

7. 结束条件与状态

7.1 业务结束原因

只保留两种业务结束原因:

  • PLAN_COMPLETED:完成问题计划。
  • USER_ENDED:用户主动结束。

不设置时间到期结束,也不设置 SAFETY_LIMIT_REACHED

结束原因由 InterviewProgress 在运行时管理,不写入数据库。持久化后的完整程度由报告类型表达:

  • PLAN_COMPLETEDFULL
  • USER_ENDEDPARTIAL

7.2 Session状态

Interview 完全复用现有 SessionStatus,不新增 FINALIZING 等状态。

InterviewSession 仅保存在进程内存中:

  • 不建立 interview_session 表。
  • 不持久化题号、追问数或运行阶段。
  • 不支持后端进程重启后的会话恢复。
  • 浏览器刷新或短暂断网仅在原进程仍存活时允许恢复。

7.3 断网清理

  • 网络中断后保留10分钟重连窗口。
  • 后端每分钟检查一次中断会话。
  • 10分钟内允许恢复同一运行时会话。
  • 超过10分钟后,物理删除未完成 Interview、临时音频和运行状态。

网络超时不等同于用户主动结束:

  • 不生成 PARTIAL
  • 不进入历史。
  • 不累计训练时长。
  • 不产生趋势贡献。

8. 完成链路

报告与完整录音共同构成面试完成门槛。

完整录音必须包含:

  • AI实际提出的问题
  • 用户对应的完整回答

完成顺序:

  1. InterviewProgress确定 FULLPARTIAL
  2. 停止接受新的回答。
  3. 保留临时转写和分段音频。
  4. 使用临时数据生成面试报告。
  5. 合成并上传完整录音。
  6. 在同一数据库事务中:
    • 写入实际AI问题;
    • 写入面试报告;
    • 更新录音信息和 completed_at
  7. 数据库事务成功后,将 SessionStatus 设为 COMPLETED
  8. 学习资产开始可见。
  9. 删除临时转写、分段音频和运行时会话。

报告或完整录音任意一项最终失败时:

  • SessionStatus = FAILED
  • 不生成学习资产
  • 物理删除已有 Interview 业务记录
  • 不保留半成品报告或录音记录

因此不保存:

  • report_status
  • recording_status

9. 面试报告与评分复用

报告类型:

  • FULL
  • PARTIAL

五个固定评分维度:

  1. 流利度
  2. 逻辑与连贯性
  3. 语法控制
  4. 发音可理解度
  5. 词汇与面试表达

每个维度包含:

  • 0–100分数
  • 中文评价
  • 可执行的行动建议

报告同时包含综合分和整场总结。

评分实现继续复用现有 EvaluationService、Provider Registry、LLM及语音评分能力,但不直接复用现有五维结果模型:

  • 现有 accuracy 不等同于发音可理解度。
  • 现有 naturalness 不等同于逻辑与连贯性。
  • 面试词汇评分需要考虑岗位和面试表达适切性。
  • Interview 不使用现有会持久化逐字稿的评分流程。
  • 不创建 InterviewScoringService

FULL 报告参与最近成绩和能力趋势;PARTIAL 报告不参与趋势。

10. 学习资产与快速复练

一次实际面试对应一条学习资产。

资产保留:

  • 岗位名称
  • 难度
  • 岗位信息摘要
  • 实际AI问题
  • 完整录音
  • 五维报告

资产不保留:

  • 用户逐字稿
  • 分轮回答音频
  • 原始简历
  • 原始JD
  • JD截图
  • 未实际提出的问题

历史与训练时长包含 FULLPARTIAL 记录。

最近成绩和能力趋势:

  • 只使用 FULL 报告。
  • BASICSTANDARDCHALLENGE 分别计算。

快速复练

快速复练创建一个新的 Interview,并带入:

  • 岗位名称
  • 难度
  • 岗位信息摘要

不带入:

  • 原始JD
  • JD截图
  • 原始简历
  • 旧问题作为新问题内容

为避免问题重复:

  1. 快速复练请求明确携带来源 Interview ID。
  2. 只读取该场 Interview 实际提出的问题。
  3. 将旧问题作为排除上下文,要求模型从不同角度生成。
  4. 不检索用户全部历史。
  5. 不做语义相似度检测。
  6. 不因生成结果可能重复而再次重试。
  7. 不持久化 source_interview_id

11. 数据保留与删除

完成后的录音和学习资产不自动过期。

用户删除一条面试记录时,同时删除:

  • 完整录音
  • 面试报告
  • 实际问题
  • Interview主记录
  • 该记录对历史和趋势的贡献

业务表采用物理删除,不增加 deleted_at

趋势基于现有 FULL 报告动态计算,不建立趋势汇总表。因此删除报告后,其趋势贡献自然消失。

12. 数据库设计

数据库遵循项目现有规范:

  • PostgreSQL
  • MyBatis-Plus
  • Repository封装Mapper
  • 不使用数据库外键
  • 关联完整性和删除顺序由Service/Repository保证

本模块只需要三张业务表。

12.1 interview

id                          VARCHAR(64) PRIMARY KEY
user_id                     UUID NOT NULL
session_id                  VARCHAR(64) NULL UNIQUE
job_title                   VARCHAR(128) NOT NULL
difficulty                  VARCHAR(16) NOT NULL
role_summary                JSONB NOT NULL
recording_object_key        TEXT NULL
recording_duration_seconds  INTEGER NULL
completed_at                TIMESTAMPTZ NULL
created_at                  TIMESTAMPTZ NOT NULL
updated_at                  TIMESTAMPTZ NOT NULL

约束:

  • difficulty仅允许 BASIC / STANDARD / CHALLENGE
  • role_summary必须是JSON对象。
  • 完成后必须同时存在 session_id、录音Key、录音时长和 completed_at
  • 录音时长必须大于0。
  • 历史查询使用完成记录索引:
    (user_id, completed_at DESC) WHERE completed_at IS NOT NULL

不保存:

  • status
  • completion_reason
  • report_status
  • recording_status
  • job_title_normalized
  • cefr_level
  • source_interview_id
  • 运行时进度字段
  • deleted_at

12.2 interview_question

interview_id   VARCHAR(64) NOT NULL
question_no    INTEGER NOT NULL
question_type  VARCHAR(16) NOT NULL
question_text  TEXT NOT NULL
created_at     TIMESTAMPTZ NOT NULL
updated_at     TIMESTAMPTZ NOT NULL

约束:

  • 复合主键:(interview_id, question_no)
  • question_type仅允许 MAIN / FOLLOW_UP
  • 只保存实际提出的问题。
  • 不保存 main_question_nofollow_up_no,通过问题顺序和类型推导。
  • 不保存用户回答、转写或分轮音频。

12.3 interview_report

interview_id     VARCHAR(64) PRIMARY KEY
report_type      VARCHAR(16) NOT NULL
overall_score    NUMERIC(5,2)
overall_summary  TEXT NOT NULL
created_at       TIMESTAMPTZ NOT NULL
updated_at       TIMESTAMPTZ NOT NULL

五个维度分别展开为:

{dimension}_score
{dimension}_evaluation
{dimension}_action_suggestion

维度前缀:

fluency
logic_coherence
grammar_control
pronunciation_intelligibility
vocabulary_expression

不增加:

  • 独立报告ID
  • session_id
  • user_id
  • difficulty
  • trend_contribution
  • generated_at
  • JSONB维度字段
  • 维度子表

difficultyinterview 组合返回;created_at同时作为报告生成时间。

12.4 明确不建立的表

interview_session
interview_turn
interview_progress
interview_question_plan
interview_asset
interview_trend
interview_material
interview_transcript
interview_audio_segment

13. 初始接口边界

现有架构已经预留以下路由方向:

POST /api/interviews
POST /api/interviews/{interviewId}/sessions
GET  /api/interview-sessions/{sessionId}
GET  /api/interview-sessions/{sessionId}/evaluation

回答提交、主动结束、重连、历史、播放、删除、快速复练和趋势接口尚未形成最终契约,本 RFC 不预设具体路径或通信方式。

14. 关键决策与代价

决策 原因 代价
使用ASR–LLM–TTS三段式 能控制长回答、动态追问和报告生成 交互自然度低于实时语音模型
用户手动结束回答 避免停顿和语气词导致错误切轮 用户每轮需要一次操作
Session只保存在内存 符合现有架构并减少持久化状态 不支持进程重启恢复
报告与录音共同完成 避免向用户暴露半成品资产 用户结束后等待时间更长
不保存用户逐字稿 降低隐私和存储风险 无法提供历史逐句回看
只保存三张业务表 当前所有持久化需求均可覆盖 将来新增业务需求时再迁移
复用评分能力但独立报告契约 避免错误映射旧五维语义 需要新增面试评分入口和解析规则
简化问题去重 首版实现和成本可控 不能绝对保证模型不产生相似问题

15. 非目标

本阶段不实现:

  • 自主实时语音大模型面试流程
  • 用户逐字稿展示或历史存储
  • DOC、图片简历及扫描简历识别
  • 后端重启后的会话恢复
  • 分布式会话状态同步
  • 全历史问题语义去重
  • 生成问题后的重复检测与自动重试
  • 学习资产自动过期
  • 额外的学习资产或趋势汇总表

16. 待后续设计

以下内容尚未裁决,不得在实现中自行假设:

  1. PARTIAL报告的最低有效回答门槛。
  2. 零回答或回答过少时是否生成报告。
  3. PARTIAL是否始终包含综合分和完整五维分数,以及数据库字段是否允许为空。
  4. 五维权重和综合分计算公式。
  5. 发音评分使用临时ASR文本作为参考文本的准确性及替代方案。
  6. role_summary的具体JSON Schema。
  7. PDF、DOCX和JD图片的大小、页数限制及OCR引擎选型。
  8. 浏览器录音格式、采样率、声道、单轮大小和上传方式。
  9. 单轮接口采用阻塞HTTP、轮询、SSE或WebSocket。
  10. 回答提交的幂等、重复点击和超时重传规则。
  11. 录音中或上传中断网后的当前回答恢复规则。
  12. ASR、LLM、TTS、评分、合成及上传的重试次数和最终失败标准。
  13. 对象存储上传成功但数据库提交失败时的补偿机制。
  14. 多实例部署时的会话粘性方案。
  15. 历史、播放、删除、复练和趋势接口的最终契约。
  16. 完整DDL、约束命名、Entity、Repository及迁移脚本。
  17. 当前开发规范与实际Flyway迁移目录不一致的问题。

17. 实现验收要点

  • 输入格式、JD OCR及用户校正规则符合本 RFC。
  • 面试固定5个主问题,并严格执行难度对应的追问上限。
  • 用户手动结束回答,VAD不触发业务切轮。
  • 用户转写不展示、不持久化、不写入日志。
  • 报告和完整录音全部成功后,资产才可见。
  • 报告或录音最终失败时不产生半成品资产。
  • 断网超过10分钟后清理未完成 Interview。
  • 完整与部分记录均计入历史和训练时长。
  • 只有 FULL 报告参与分难度成绩与趋势。
  • 快速复练不携带原始材料,并只读取指定上一场的实际问题。
  • 数据库只新增本 RFC 规定的三张业务表。
  • 所有实现严格遵守现有项目模块边界和无外键规范。

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions