Skip to content

Latest commit

 

History

History
571 lines (435 loc) · 25.9 KB

File metadata and controls

571 lines (435 loc) · 25.9 KB

AI Interview Agent — 项目规格说明书

用 AI 复现 AI 面试官。项目代号:Interview Agent


实现状态(Implementation Status)

以下记录 P1 / P2 中已落地功能,与上方规格描述对照阅读。

✅ P1 文字面试(已完成)

  • 状态机 21 个状态,30+ 转移规则完整实现
  • PDF 简历解析 → 背景画像 → 规划问题 → 技术问答 → 人格评估 → Fuku 式报告
  • 动态人格问题personality_dynamic_questions=true(默认)时 LLM 根据 JD + 画像生成问题,而非静态列表
  • 动态追问决策dynamic_follow_up_decision=true 时每题由 LLM 自主判断追问/下一题/收尾
  • 画像合并(简历初稿 + 引导增量),冲突处理与来源标记
  • 多段经历逐个深挖,经历级综合评估
  • 会话状态落盘(JSON + JSONL 事件流)

✅ P2 语音输入(已完成)

  • 实时听写:录音开始 2s 后开始每 5s 上传累积完整 webm 块,输入框实时显示转写结果(不等停止)
  • 停止后补发:停止录音时若有未转写分块,立即补发最终段
  • TTS 朗读:点击 🔊 按钮,window.speechSynthesis 朗读当前题目(zh-CN
  • STT 三选一:通过 STT_BACKEND 切换 sensevoice_http(默认,最快)/ xfyun / local_whisper
  • SenseVoice 本机服务SenseVoice/ 目录已纳入主仓库(做法 A),uvicorn SenseVoice.api:app 启动
  • VAD 切段(webrtcvad,无则固定 55s 窗口兜底),避免讯飞 60s 上限
  • 文字输入全程保留,可随时切换说/打字
  • GET /api/config 返回 transcribe_auto_submit / tts_enabled / stt_backend

🗂️ 项目结构

ai-interview-agent/
├── app/
│   ├── config.py          # 所有配置(STT/LLM/Guards/人格开关)
│   ├── main.py            # FastAPI 入口 + 所有 HTTP 端点
│   ├── schemas/           # Pydantic 模型(Context/Plan/Scores)
│   ├── services/
│   │   ├── session_runner.py   # 业务编排层
│   │   └── stt/                # STT 提供者工厂
│   │       ├── factory.py       # STT_BACKEND → 提供者路由
│   │       ├── sensevoice_http.py
│   │       ├── xfyun_iat.py
│   │       ├── local_whisper.py
│   │       ├── audio_pcm.py     # webm → PCM 16k 单声道
│   │       └── vad_segment.py   # VAD 静音检测切段
│   └── state_machine/     # 状态机引擎
├── static/
│   ├── app.js             # 前端(含录音/TTS/实时听写/轮询)
│   └── index.html         # 面试主界面
├── SenseVoice/            # FunAudioLLM/SenseVoice 裁剪版(已纳入 Git)
├── docs/SENSEVOICE.md     # SenseVoice 子模块说明
└── run.py                 # 启动脚本

1. 项目概述

目标: 构建一个开源的 AI 驱动的面试系统,能够自主引导面试全流程(从候选人背景收集到问题生成到评分),生成结构化评估报告。

定位: 对标 Fuku AI Interview Agent,但完全透明、开源可审计、支持本地部署。

核心价值:

  • 全流程可复现、可审计(不是 black box)
  • AI 主动引导,非填表式——更像真人面试
  • 支持本地部署(隐私敏感场景)
  • 多语言、多面试场景适配

2. 核心链路(Phase 1 MVP)

流程执行以状态机为准,详见:STATE_MACHINE.md(本目录)。

候选人 ────────────────────────────────────────────────►

  ┌─────────────────────────────────────────────────────┐
  │ 【阶段 0】面试规划(AI 内部分析)                    │
  │  AI 读取候选人背景 + JD                            │
  │  → 分析每段经历的关键问题点                        │
  │  → 规划本次面试的问题列表                          │
  │  → 确定每个问题考察什么能力                        │
  └────────────────────────┬──────────────────────────┘
                           ▼
  ┌─────────────────────────────────────────────────────┐
  │ 【阶段 1】AI 引导自我介绍 & 背景收集               │
  │  AI 主动提问,候选人文字回复                       │
  │  → 收集:学历、实习经历、技术栈、求职目标、薪资期望 │
  │  → 输出:候选人背景画像(JSON)                    │
  └────────────────────────┬──────────────────────────┘
                           ▼
  ┌─────────────────────────────────────────────────────┐
  │ 【阶段 2】AI 根据背景 + 规划提问列表逐题提问        │
  │  LLM(MiniMax M2.7)按规划的问题顺序提问           │
  │  候选人文字回复                                   │
  │  → 每回答后 AI 决定:追问 / 换下一题 / 结束        │
  └────────────────────────┬──────────────────────────┘
                           ▼
  ┌─────────────────────────────────────────────────────┐
  │ 【阶段 3】AI 逐题评分(实时)                      │
  │  LLM(MiniMax M2.7)逐题评分                      │
  │  → 三维度打分 + 理由 + 改进建议                   │
  └────────────────────────┬──────────────────────────┘
                           ▼
  ┌─────────────────────────────────────────────────────┐
  │ 【阶段 4】生成最终评估报告                          │
  │  → JSON 文件存储(可导出 HTML 报告)               │
  │  → 包含:背景画像 + 面试规划 + 每题评分 + 总体建议│
  └─────────────────────────────────────────────────────┘

◄──────────────────────────────────────────────────────

3. 评分体系(核心!)

参考 Fuku AI,每道题从 3 个维度打分:

维度 分制 含义
Expertise(专业度) 1-5 技术深度、准确性、是否到 senior 水平
Clarity(表达清晰度) 1-5 逻辑结构、术语准确性、是否有重复/模糊表述
Detailedness(详细程度) 1-5 是否有具体数据/实例/实现细节/量化结果

每个维度的评分标准:

分数 标签 含义
1 Below average 明显缺失或错误
2-3 Average 基本到位但不深入
3-4 Good 不错,有亮点
4-5 Excellent 非常出色,超越预期

每题 AI 输出格式(固定结构):

## 题目 X:[问题原文]

### 评分
- Expertise:3/5(Good)
  理由:候选人展示了XXX的正确理解,正确识别了关键组件和挑战。然而,缺乏数学层面的清晰度和更广泛的设计考量,表明他还未达到 senior 水平。
  
- Clarity:2/5(Average)
  理由:回答有些口语化、表达不精确,有用词重复和不清晰的表述,影响了整体的连贯性。

- Detailedness:2/5(Average)
  理由:虽然覆盖了主要模块,但缺少实现细节、替代方案和量化证据。损失函数类型、噪声处理、评估指标等关键方面均未涉及。

### 改进建议
1. **结构化回答**:先用简要概述,再用具体过程,最后说挑战和结果。
   示例:"The RERAW model focuses on reconstructing RAW images from RGB inputs. My approach involved designing modules for color reconstruction..."
   
2. **使用精确术语**:避免口语化表达,用准确的技术术语描述。
   示例:"The multi-head gamma predictor allows us to estimate the RAW image before applying gamma transformation..."
   
3. **突出具体挑战**:说清楚遇到了什么问题、如何解决的、结果如何。
   示例:"One challenge was balancing the gradients from different gamma heads. I adjusted the loss function to improve the model's accuracy..."
   
4. **用数据量化结果**:尽可能给出具体指标。
   示例:"As a result, the model's PSNR improved by 2dB, leading to more accurate RAW image reconstructions."

4. 面试规划阶段(Phase 0)— 核心差异点

这是我们 vs Fuku AI 最重要的区别!

Fuku AI 是"一题一评"模式,随机抽题。我们要有面试规划——像真人面试官一样,面试前就想好要问什么。

4.1 规划 Prompt 模板

PLANNING_PROMPT = """
你是一个资深面试官。面试开始前,请根据候选人背景和目标岗位,做面试规划。

【候选人背景】
{candidate_background}

【目标岗位 JD】
{job_description}

【规划任务】
1. 分析候选人每段实习/工作经历,找出 2-3 个最值得深挖的点
2. 针对每个深挖点,规划 1 个核心问题 + 可能的追问方向
3. 确定本次面试的问题列表(建议 3-5 题,覆盖不同能力维度)
4. 说明每道题考察什么能力

【输出格式】
```json
{
  "interview_plan": [
    {
      "question_id": "Q1",
      "target_experience": "华为实习 - RERAW 轻量化模型",
      "ability_dimension": "计算机视觉 / 模型设计能力",
      "main_question": "请介绍一下你在华为做的 RERAW 轻量化模型的设计思路和遇到的挑战...",
      "follow_up_directions": [
        "如果回答模糊,追问具体模块设计",
        "如果只说结果,追问训练过程和 loss 设计",
        "如果缺乏量化,追问具体提升了多少 PSNR"
      ],
      "expected_depth": "能说清楚模型架构、设计取舍、实验结果"
    },
    {
      "question_id": "Q2",
      "target_experience": "Infineon - TCL 自动化脚本",
      "ability_dimension": "工程能力 / 脚本自动化",
      "main_question": "在 Infineon 做芯片验证时,你如何用 TCL 脚本优化测试流程...",
      "follow_up_directions": [
        "如果只说做了什么,追问具体减少了多少 runtime",
        "如果缺乏具体技术,追问脚本的核心逻辑"
      ],
      "expected_depth": "能说清脚本逻辑、优化效果、可量化的结果"
    }
  ],
  "question_order": ["Q1", "Q2", ...],
  "estimated_duration": "10-15 分钟"
}

4.2 追问决策逻辑(AI 自主判断)

每道题回答后,AI 自主决定是否追问:

FOLLOW_UP_DECISION_PROMPT = """
候选人回答了问题:"{question}"
回答内容:"{answer}"

【追问决策】
请判断是否需要追问。规则:
- 如果回答已经足够具体(包含具体数字、步骤、结果)→ 不追问
- 如果回答模糊、有明显漏洞、可以深挖 → 追问
- 如果候选人说"不知道"或明显跑题 → 追问(换一种问法)

【输出格式】
```json
{
  "decision": "follow_up" | "next_question" | "wrap_up",
  "reason": "判断理由(1-2句)",
  "follow_up_question": "(如果决定追问)追问内容",
  "new_direction": "(如果换方向)新的追问方向"
}

4.3 面试结束判断

所有规划问题问完后,AI 判断是否结束:

WRAP_UP_PROMPT = """
面试已完成 {n} 道题。

【各题评分概览】
{scores_summary}

【最后一道题的回答】
{last_answer}

判断:
- 如果某维度普遍低于 2 分,考虑追加补充问题
- 如果整体不错,主动告知面试结束
- 任何时候不超过 12 道题(避免候选人疲劳)

【输出格式】
```json
{
  "continue": true | false,
  "reason": "判断理由",
  "additional_questions": ["如果继续,追加的问题(最多1-2道)"]
}

5. AI 引导背景收集(Part 1)

不是填表,是 AI 主动提问! 模仿真人面试官的开场:

引导问题序列(LLM 自动生成):

1. "请简单介绍一下你的学历背景,包括学校、专业和毕业时间。"
2. "请介绍一下你最近的实习或工作经历,重点说清楚你负责的项目和使用的技术。"
3. "在这些经历中,你最擅长的技术领域是什么?"
4. "你为什么想要离开目前的岗位/寻找新机会?"
5. "你希望下一份工作是什么样的?(公司类型、团队氛围、技术方向等)"
6. "你的期望薪资范围是多少?"

AI 根据候选人回答动态追问,最后生成背景画像 JSON:

{
  "name": "候选人姓名",
  "education": "NTU CS Master 2026",
  "experience": [
    {
      "company": "华为新加坡研究院",
      "role": "Video/Audio Research Engineer Intern",
      "skills": ["CV", "RAW重建", "KVCACHE优化"],
      "projects": ["RERAW轻量化模型", "VLM KVCACHE"]
    }
  ],
  "strongest_skills": ["计算机视觉", "算法优化", "系统调优"],
  "reason_to_move": "作为应届生,希望获得全面成长...",
  "career_goals": "AI方向entry-level,挑战性项目,协作团队...",
  "salary_expectation": "10,000 SGD/月"
}

6. 个性评估(可选,Phase 2)

该模块在状态机中由 PERSONALITY_ASK -> PERSONALITY_EVAL 承载,详见 STATE_MACHINE.md

参考 Fuku AI 的 5 维度滑动条,AI 根据回答内容推断

维度 A 端 B 端
稳定性(Stability) Conservative Innovative
思维(Thinking) Logical Compassionate
社交(Social) Introvert Extrovert
角色(Role) Individual Contributor Team Manager
创新方式(Innovation style) Incremental Transformative

说明:稳定性创新方式是两轴:前者偏整体是否守成/拥抱变化;后者偏创新路径是渐进迭代还是颠覆式/范式级,英文极名 deliberately 不同,避免报告页两栏文案看起来「一模一样」。

6.1 人格与个人补充访谈(技术面结束后)

在技术问答结束后,进入 PERSONALITY_ASK:题量由配置 personality_questions_count 控制(默认约 6 题)。题目需兼顾

  1. 行为证据(供五维人格量表):如需求不明时的推进、分歧处理、协作偏好、高压取舍等。
  2. 与 Fuku 式报告叙事对齐:在画像/技术面材料仍不足时,通过口语题补采 候选人概览与亮点、核心专长与岗位匹配、看机会动机、职业目标、薪资期望 等(薪资提问宜委婉,允许不透露具体数字)。

动态出题由 personality_questions_plan_user 提示词约束;关闭 personality_dynamic_questions 时使用 prompts.PERSONALITY_QUESTIONS 静态回退列表。

说明:本阶段以短问短答为主,一般不再多轮深挖;若回答过于抽象,可在后续版本中考虑单题一次追问。

6.2 人格评估输出(与技术评分并列)

  • 输出 5 维度倾向(滑动条两端)
  • 每个维度必须包含:倾向 + 证据 + 置信度
  • 证据来源优先级:人格问题回答 > 技术问答中的行为片段 > 背景引导内容

输出格式:

{
  "personality": {
    "innovation": {
      "pole_a": "Incremental",
      "pole_b": "Transformative",
      "leaning": "Transformative",
      "rationale": ""
    }
  }
}

7. 技术架构

分阶段交付,与 RESEARCH.md 中的选型建议一致;P1 明确不做 RAG,先跑通状态机与核心链路。

P1 — 极简 MVP(不做 RAG)

目标: 文本面试全流程可跑通、可审计、本地可部署。

前端:        纯 HTML + Vanilla JS(单文件,零框架成本;后续 P3 再工程化)
后端:        Python FastAPI(状态机驱动,见 STATE_MACHINE.md)
LLM:         MiniMax M2.7(CodePlan 覆盖时零额外模型成本)
JD / 题库:   硬编码或配置文件,不接入向量检索 —— 不做 RAG
存储:        本地 JSON + 事件 JSONL(无数据库)
部署:        pip install + python run.py

P2 — 接入语音(单段录制 → 转写 → 分析)

目标: 在 P1 文本主链路稳定的前提下,增加「语音输入」路径。每题录制一段音频,录音停止后自动转写并注入评分流程。

P2 第一步(已定案):语音子状态仅前端。 录音、上传、等 STT 等 UI 阶段写入服务端 State 枚举;服务端在作答环节与 P1 一样保持「等待本题答案」,直至收到 POST .../answer 的文本。转写由 POST /api/audio/upload 完成,返回文本后由前端填入输入框(可编辑)再发送,或产品确认后自动提交——服务端路径与纯打字一致。详见 STATE_MACHINE.md §11.0。

用户交互流程:

AI 提问
  -> 候选人点击 🎤 开始录音
  -> 候选人点击 ⏹ 停止录音
  -> 前端上传音频到后端
  -> 后端 STT 转写
  -> 转写文本进入现有评分流程(状态机不变)
  -> AI 追问 / 下一题 / 收尾

技术方案:

环节 选型 说明
录音 浏览器 MediaRecorder API 单段 .webm 文件,每题一段
后端接收 FastAPI POST /api/audio/upload UploadFile 接收 .webm
STT 转写 Faster-Whisper(本地 CPU/GPU) 零云成本,隐私友好,支持中文
降噪处理 音频预处理(可选) 去除静音片段,降低 STT 错误率
分析注入 转写文本经 POST /answer 进入与 P1 相同的后续状态 服务端状态机不增录音态

STT 备选方案(按接入难度排序):

方案 优势 劣势
Faster-Whisper(本地) 零成本,隐私,不依赖网络 首次需下载模型(~1GB)
MiniMax STT API 接入简单,中文效果好 走云端,有成本
Groq Whisper 速度快,$0.004/分钟,极便宜 走云端,需 API Key
讯飞语音听写(流式版 WebAPI) 中文/方言能力强,控制台有免费额度;流式可边传边收 走云端与商务套餐;WebSocket + 服务端鉴权;单路约 60s,长回答需 VAD 多段串行文件转写(见下文)

讯飞听写(与现有 P2 架构的接法):

  • 官方文档:语音听写(流式版)WebAPI — 端点示例 wss://iat-api.xfyun.cn/v2/iat,握手带 authorization / date / host(HMAC-SHA256 + Base64),需 AppID、APIKey、APISecret(仅放服务端环境变量)。
  • 与本项目 POST /api/audio/upload 对齐:浏览器仍上传 单段录音(如 .webm);FastAPI 将音频转为接口要求的格式(常见为 16 kHz、16 bit、单声道 PCM,或文档支持的 speex/mp3 等),再在服务端建立 WebSocket、按文档分帧发送(注意单帧 base64 长度等限制),聚合返回 JSON 中的文本后作为 text 返回给前端。不要在浏览器直连讯飞 WebSocket(会泄露密钥且跨域/鉴权不便)。
  • 流式听写单路会话上限约 60s(以 官方说明 为准)。面试单题口述往往更长,必须在实现层应对,不能只「卡用户 1 分钟」。

长回答应对策略(与 60s 限制自适应,可组合):

  1. 服务端 VAD 自适应切分 + 多路串行听写(推荐,仍用流式听写 API)

    • 整段音频解码为 16 kHz 单声道 PCM 后,用 VAD(如 Silero-VAD、WebRTC VAD)静音/停顿处切分为多个片段;每片段目标时长 ≤ 55s(留余量,避免单路触顶),尽量避免在说话中间硬切。
    • 找不到足够长静音(连续长篇大论)时,再对 PCM 按时长兜底切分(例如每 50~55s 一刀),作为次要策略。
    • 每个片段 独立一次 WebSocket 听写会话,按时间顺序执行,将各段识别结果 顺序拼接(段间可用空格或换行)。
    • 边界减损:相邻片段可保留 约 0.3~0.5s 重叠 再分别送识别,合并文本时对重叠区做简单去重(可选,避免重复词)。
  2. 整段 HTTP 转写(同平台备选或自动降级)

    • 评估讯飞 录音文件转写、极速转写等 整文件上传 能力:若支持 数分钟级 单文件,则 POST /api/audio/upload 内可对「超过某阈值时长」的音频 自动走文件转写,避免自研多段 WS 拼接。
    • 与方案 1 可并存:短音频单路 WS长音频文件接口VAD 多段 WS,由服务端策略选择。
  3. 前端分段录制(补充)

    • 引导用户 停顿后再续录(多段 blob 或多请求),服务端仍按「多段转写 + 拼接」处理;体验弱于「一次长录、服务端自适应切」,可作为无 VAD 时的兜底。
  4. 产品兜底

    • 保留 文字输入;极端失败时提示重录或改打字。

降噪/预处理(与长音频一致): VAD 既可用于去静音提升准确率,也是 自适应切分 的核心信号,建议放在同一套音频管线中实现。

新增 API 端点:

POST /api/sessions/{session_id}/transcribe  (推荐:路径即校验会话存在)
  Body: multipart/form-data
    - audio: 单段录音(常用 webm;服务端 ffmpeg 解码为 16k PCM)
  Response: { "text": "…", "confidence": null | number }
  说明:只转写,不推进会话状态;前端拿到 text 后再 POST /answer。

POST /api/audio/upload  (与历史 SPEC 字段兼容)
  Body: multipart/form-data
    - session_id: 字符串(必填)
    - audio: 同上
  Response: 同上

另:GET /api/config 返回 transcribe_auto_submittts_enabledstt_backend 供前端行为开关(可选)。

降噪/预处理(可选 Phase 2.1):

  • 使用 silero-vad(等)检测语音边界:既可裁掉首尾静音、也可驱动上文「长回答切分」
  • 减少无意义音频输入,提升 STT 准确率并降低幻觉

文字输入保留(Fallback):

  • Phase 2 同时保留文字输入路径
  • 候选人可自由切换"说"或"打字",体验一致
  • 架构:输入层抽象,AnswerInput = TextInput | AudioInput

TTS 播报题目(可选 Phase 2.2):

  • AI 提问后可选 TTS 朗读题目(提升真实感)
  • 方案:Web Speech API(浏览器原生,无需后端)或 MiniMax TTS API

P3 — 优化前端

目标: 提升可用性、可读性与可维护性,不等于必须上云。

前端:        Next.js + TailwindCSS(或 React + Vite 工程化后再迁)
体验:        会话状态展示、报告可视化、加载与错误态
可选:        Docker Compose 打包、多会话/多候选人管理界面

后续可选(不绑定 P1–P3)

  • RAG:JD/题库/公司知识库向量检索(如 Chroma / Qdrant)
  • 存储升级:PostgreSQL + 对象存储
  • 产品化:账号体系、与招聘系统集成等

8. 评分 Prompt 模板

SCORING_PROMPT = """
你是一个资深面试评分官。请根据候选人的回答,从以下三个维度评分。

【评分维度】
- Expertise(专业度):技术深度、准确性、是否达到 senior 水平
- Clarity(表达清晰度):逻辑结构、术语准确性、表达连贯性
- Detailedness(详细程度):具体数据/实例/量化结果/实现细节

【输出格式】
对每个维度,输出:
- 分数(1-5)和等级标签(Below average / Average / Good / Excellent)
- 2-3 句话的理由
- 4 条改进建议,每条带一句话示例

【评分标准】
1 = 明显缺失或错误
2-3 = 基本到位但不深入  
3-4 = 不错,有亮点
4-5 = 非常出色

【问题】
{question}

【候选人回答】
{answer}

请开始评分:
"""

9. 开发阶段

§7 技术架构 的 P1 / P2 / P3 对齐。

P1:极简 MVP(不做 RAG)

  • 流程编排采用状态机驱动(STATE_MACHINE.md
  • PDF 简历提取 → 初稿画像 → 引导补全 → 按经历技术问答 → 收尾与人格(若开启)→ 报告
  • 文字对话为主;JD 硬编码或配置文件,不接入 RAG
  • 单页 HTML + Vanilla JS 或最小前端;存储为本地 JSON / JSONL

P2:接入语音(单段录制 → 转写 → 分析)

  • 每题一段 .webm 录音(MediaRecorder API)
  • 后端 POST /api/audio/upload 仅 STT 转写;服务端状态机不增加录音相关状态
  • 转写文本经与 P1 相同的 /answer 提交后进入评分等后续逻辑
  • 保留文字输入作为 Fallback,支持混合使用
  • 可选:TTS 播报题目(Web Speech API 或 MiniMax TTS)

P3:优化前端

  • Next.js + Tailwind(或 React 工程化方案)重写/增强 UI
  • 报告与会话体验优化 多会话列表等

后续可选(不列入 P1–P3 必做)

  • RAG(题库 / JD / 知识库)、PostgreSQL、账号与产品化集成等 —— 见 §7「后续可选」

10. 命名

  • 项目名:ai-interview-agent
  • License:Apache 2.0

11. 参考