it0/packages/services/voice-agent/SPEECHMATICS_POSTMORTEM.md

68 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Speechmatics STT 集成失败记录 (2026-03-03)
## 结论
**Speechmatics 的 livekit-plugins-speechmatics 插件完全不可用。**
经过一整天的深度集成和调试,四种 Turn Detection 模式全部失败,没有任何一种能在
LiveKit agents 框架 v1.4.4 下正常工作。该方案已被彻底移除STT 回退至 OpenAI。
## 测试的四种 Turn Detection 模式及失败原因
### 1. EXTERNAL 模式
- **现象**: 只有 INTERIM_TRANSCRIPT永远没有 FINAL_TRANSCRIPT
- **原因**: EXTERNAL 模式需要客户端手动调用 `client.finalize()` 才会产生 FINAL。
但 LiveKit agents 框架在 VAD 检测到说话结束后**不调用** `stream.flush()`
(不发 FlushSentinel而是推送静音帧 + 等待 FINAL 事件。
结果: 2 秒超时 → "final transcript not received" → 用户无回复。
- **尝试的修复**: monkey-patch `_process_audio` 在 FlushSentinel 时调用 finalize()
→ 但 FlushSentinel 根本不会到达(框架不发 flush
- **尝试的修复 2**: debounce timerpartial 停止 400ms 后自动 promote 为 FINAL
→ 能工作但产生重复 FINAL每个 FINAL 触发 LLM 请求导致前一个被 abort
### 2. ADAPTIVE 模式
- **现象**: 零转写输出,完全静默
- **原因**: ADAPTIVE 使用 Speechmatics SDK 内置的 Silero VAD 做客户端转弯检测,
但 LiveKit 自己也有 Silero VAD 在运行,两个 VAD 冲突导致音频流被截断
### 3. SMART_TURN 模式
- **现象**: 连续语音被切成碎片("有好结果。"、"收?的知识。"、"就。"
- **原因**: 服务器端智能转弯检测过于激进,把中文连续语音切成小段,
每段各自产生一个 FINAL_TRANSCRIPT每个 FINAL 触发一次 LLM 请求,
前一个请求被 abort实测完全不可用
### 4. FIXED 模式(最后尝试)
- **配置**: `end_of_utterance_silence_trigger=1.0`1秒静音后 finalize
- **现象**: 仍然不工作
- **原因**: VoiceAgentClient 内置的 END_OF_UTTERANCE handler 调用 finalize()
但 finalize() 是异步链create_task → emit() → _stt_message_queue → _emit_segments
经常输掉与 session teardown 的竞争
## 额外发现的问题
### 语言码兼容性
- Speechmatics 使用 ISO 639-3中文为 "cmn"LiveKit 的 `LanguageCode("cmn")`
会自动归一化为 "zh",而 Speechmatics API 不接受 "zh"
- 需要手动 `stt._stt_options.language = "cmn"` 绕过
### 延迟
- 即使在能产生转写的情况下Speechmatics 的延迟也明显高于 OpenAI
- OpenAI Realtime API (gpt-4o-transcribe) 约 10 秒端到端Speechmatics 超过 35 秒
## 时间线
- 09:00 开始集成 livekit-plugins-speechmatics
- 10:00 解决语言码映射问题
- 11:00 发现 EXTERNAL 模式无 FINAL开始 monkey-patch
- 13:00 发现 FlushSentinel 永远不到达,理解框架架构
- 14:00 实现 debounce timer能转写但有重复问题
- 15:00 搜索官方文档,切换到 SMART_TURN → 语音碎片化
- 16:00 切换到 FIXED 模式 → 仍然不工作
- 17:00 放弃,彻底移除所有 Speechmatics 代码,回退至 OpenAI
## 删除的文件
- `src/plugins/speechmatics_stt.py` — 整个 Speechmatics STT 工厂
- `requirements.txt` 中的 `livekit-plugins-speechmatics>=1.0.0`
- `agent.py` 中的 speechmatics 分支
- `docker-compose.yml` 中的 `SPEECHMATICS_API_KEY`
- `voice-config.entity.ts``voice-config.controller.ts` 中默认值改为 'openai'
- web-admin 设置页中的 Speechmatics 选项和 i18n 翻译