问题描述
Copilot 实时面试辅助功能中,麦克风采集的所有语音都被硬编码为 HR 角色,系统无法区分 HR 和候选人的声音。这导致在真实远程面试场景下,候选人自己的发言也会被当成 HR 提问,触发完整的分析流水线(Intent Router → Strategy Tree → Answer Coach → MCTS),产生错误的建议。
当前行为
音频流路径
浏览器麦克风 (16kHz PCM) → WebSocket binary → CopilotASR → NLS on_sentence_end
↓
_process_hr_utterance() ← 永远当作 HR
各输入通道的角色绑定
| 输入方式 |
角色 |
代码位置 |
麦克风 ASR on_sentence_end |
固定 HR |
main.py _init_copilot_session → on_sentence_end 回调直接调用 _process_hr_utterance() |
手动输入 type: "manual" |
HR |
main.py WebSocket handler |
手动输入 type: "candidate_response" |
候选人 |
main.py WebSocket handler |
| 麦克风二进制帧 |
全部路由到 ASR → 当作 HR |
main.py session["asr"].send_audio(data["bytes"]) |
关键代码
main.py — ASR 回调注册(硬编码为 HR):
async def on_sentence_end(text):
try:
await ws.send_json({"type": "asr_final", "text": text})
await _process_hr_utterance(ws, _copilot_sessions.get(session_id, {}), text)
except Exception as e:
logger.error(f"ASR sentence processing failed: {e}")
前端 Copilot.jsx — asr_final 消息也固定标记为 HR:
// asr_final 消息固定创建 role: "hr" 的对话条目
手动输入有角色切换,ASR 没有:
前端提供了 HR / You 角色切换按钮,但仅用于手动文本输入。麦克风录音无法标记角色。
影响
- 候选人发言被误判为 HR 提问:触发 Answer Coach 生成错误的回答建议
- 对话历史被污染:MCTS 引擎、Interview Monitor、HR Profiler 收到的对话角色全部错误
- 策略树定位偏移:Intent Classifier 在候选人发言上做 HR 意图匹配,定位到错误节点
建议方案
方案 A:系统音频捕获
前端用 getDisplayMedia({ audio: true }) 采集系统音频(HR 在腾讯会议 / Zoom 等工具中的声音),与麦克风音频分为两路:
- 系统音频 → 发送为 HR 语音,走 ASR →
_process_hr_utterance
- 麦克风音频 → 发送为候选人语音,走 ASR → 仅记录到对话历史
WebSocket 协议扩展:在二进制帧前加 1 byte role header(0x00 = HR, 0x01 = candidate)。
方案 B:说话人分离(Speaker Diarization)
使用阿里云 NLS 实时会议转写 NlsRealtimeMeeting(SDK 中已有),支持多人角色识别自动区分说话人。复杂度较高,依赖云端能力。
方案 C:手动 Push-to-Talk
前端增加按住说话按钮,按住时麦克风音频标记为 candidate role,松开后恢复 HR 监听。实现简单但用户体验较差。
环境
- 阿里云 NLS SDK
nls==1.1.0
- 前端使用
getUserMedia + ScriptProcessor 采集 PCM 16kHz
问题描述
Copilot 实时面试辅助功能中,麦克风采集的所有语音都被硬编码为 HR 角色,系统无法区分 HR 和候选人的声音。这导致在真实远程面试场景下,候选人自己的发言也会被当成 HR 提问,触发完整的分析流水线(Intent Router → Strategy Tree → Answer Coach → MCTS),产生错误的建议。
当前行为
音频流路径
各输入通道的角色绑定
on_sentence_endmain.py_init_copilot_session→on_sentence_end回调直接调用_process_hr_utterance()type: "manual"main.pyWebSocket handlertype: "candidate_response"main.pyWebSocket handlermain.pysession["asr"].send_audio(data["bytes"])关键代码
main.py— ASR 回调注册(硬编码为 HR):前端
Copilot.jsx—asr_final消息也固定标记为 HR:// asr_final 消息固定创建 role: "hr" 的对话条目手动输入有角色切换,ASR 没有:
前端提供了 HR / You 角色切换按钮,但仅用于手动文本输入。麦克风录音无法标记角色。
影响
建议方案
方案 A:系统音频捕获
前端用
getDisplayMedia({ audio: true })采集系统音频(HR 在腾讯会议 / Zoom 等工具中的声音),与麦克风音频分为两路:_process_hr_utteranceWebSocket 协议扩展:在二进制帧前加 1 byte role header(
0x00= HR,0x01= candidate)。方案 B:说话人分离(Speaker Diarization)
使用阿里云 NLS 实时会议转写
NlsRealtimeMeeting(SDK 中已有),支持多人角色识别自动区分说话人。复杂度较高,依赖云端能力。方案 C:手动 Push-to-Talk
前端增加按住说话按钮,按住时麦克风音频标记为 candidate role,松开后恢复 HR 监听。实现简单但用户体验较差。
环境
nls==1.1.0getUserMedia+ ScriptProcessor 采集 PCM 16kHz