Skip to content

fix(interview): stabilize VAD orchestration and structured LLM output - #95

Merged
yydounai1234 merged 4 commits into
1024XEngineer:mainfrom
pionxe:main
Aug 14, 2026
Merged

fix(interview): stabilize VAD orchestration and structured LLM output#95
yydounai1234 merged 4 commits into
1024XEngineer:mainfrom
pionxe:main

Conversation

@pionxe

@pionxe pionxe commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • 为面试材料整理和修复请求增加 JSON_OBJECT 响应格式支持
  • 将面试链路 VAD 调整为 3 秒静音窗口,并统一响应编排
  • 支持面试过程中的自动 VAD 与用户打断
  • 确保结束语音频播放完成后再结束会话
  • 支持通过环境变量配置本地后端端口

Root Cause

面试链路此前同时存在自动响应和状态机响应两套触发路径,可能导致响应重复、过早结束或用户语音被截断。同时,结束流程仅依赖模型响应完成事件,未等待客户端音频播放缓冲完全排空。

材料整理请求没有显式声明 JSON_OBJECT 格式,也增加了模型返回非结构化内容、解析失败和修复请求失败的概率。

Changes

  • 新增 LlmResponseFormat
  • LlmProviderAiProviderRegistry 增加格式参数重载
  • 仅在 Qwen 请求 JSON_OBJECT 时发送 response_format
  • 面试材料整理与 repair 请求统一使用 JSON_OBJECT
  • 面试报告提示词要求 evaluationadvicesummary 使用简体中文
  • 面试 VAD 使用 3 秒静音时长、自动检测和可打断响应
  • 由面试状态机统一决定下一题和结束语响应
  • 结束语播放完成后增加音频 drain 等待
  • 支持 BACKEND_HOST_PORT 配置本地后端映射端口

Validation

  • Backend:
    ./mvnw -q -DskipITs -Dtest=InterviewReportCoordinatorTest,InterviewSceneServiceTest,QwenRealtimeProviderTest test
  • Web:
    npm run check:realtime-events
  • git diff --check

Notes

移动端 Jest 检查未执行,原因是当前环境缺少 jest 可执行文件。

pionxe added 4 commits August 14, 2026 15:05
将PaddleOCR改为后端启动时同步加载的常驻Worker,通过JSON Lines协议复用已加载模型,避免每次请求重复启动Python进程。\n\n同步更新Web端OCR可用性探测、Docker与本地启动配置、接口文档及OCR测试,支持本地实际上传JD截图进行识别。

@yydounai1234 yydounai1234 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@yydounai1234
yydounai1234 merged commit 3258897 into 1024XEngineer:main Aug 14, 2026
11 checks passed

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论

后端结构化输出、Web 端状态机响应编排和音频 drain 的主路径整体一致;但移动端仍存在供应商自动响应绕过状态机的竞态,OCR Worker 的启动失败恢复路径也被可用性门控阻断。已运行后端定向测试与 npm run check:realtime-events,均通过;移动端依赖未安装,因此未执行 Jest。

View job run

// open through natural pauses and never let a new user turn cancel an
// interviewer response while the candidate is still speaking.
turn_detection: { type: 'semantic_vad', threshold: 0.8, prefix_padding_ms: 1_000, silence_duration_ms: 3_000, create_response: false, interrupt_response: true },
turn_detection: { type: 'semantic_vad', threshold: 0.8, prefix_padding_ms: 1_000, silence_duration_ms: 3_000, create_response: true, interrupt_response: true },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 禁止移动端 VAD 自动创建面试响应

这里把 create_response 打开后,供应商可在 speech_stopped 后立即开始回答,而 responseAwaitingInterviewState 直到转写完成事件才会设为 true,后端 submitTurn 的状态结果则更晚。因此自动响应可能在取消逻辑生效前已经播放,甚至在接口较慢时完整结束,随后 sendInterviewResponse 又基于状态机创建第二个响应,重新引入重复提问或跳题。Web 端同一面试契约明确使用 create_response: false;移动端也应只保留自动 VAD 检测和打断,把响应创建交给状态机结果。

Comment on lines +113 to +114
return baseAvailable() && workerReady && workerProcess != null
&& workerProcess.isAlive();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 让 OCR 可用性探测能够重启 Worker

启动时的 Worker 初始化失败会把 workerReady 留为 false,此处之后只返回不可用而不调用 ensureWorkerStarted()。这使注释所述的“首次 OCR 请求重试”实际无法发生:Web 端先用可用性接口禁用图片入口,服务端 MaterialTextExtraction 也会在调用 recognizeText 前检查 available() 并直接抛错。一次瞬时启动超时或资源问题因此会让 OCR 在整个进程生命周期内保持关闭,必须重启应用才能恢复;可用性探测或调用门控应触发受锁保护的重启尝试。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants