3.9 KiB
3.9 KiB
问题定位总结
🎯 核心问题
卡在 ASR(语音识别)环节,导致后续 LLM 和 TTS 都没有被触发。
🔍 详细分析
问题流程
客户端 → 一次性发送 260KB PCM 文件
↓
服务器 → 接收到大块数据
↓
ASR → 无法处理(期望流式小块数据)❌
↓
没有识别结果
↓
LLM 不被触发 ❌
↓
TTS 不被触发 ❌
↓
60秒后 idle timeout
根本原因
架构不匹配:
-
服务器设计:
- 使用
paraformer-realtime-v2(实时 ASR) - 期望流式接收音频数据
- 设计用于边说边识别
- 使用
-
客户端实现:
- 录音完成后一次性发送整个文件
- 不是流式传输
- 类似"批处理"模式
这就像:
- 服务器是一个"实时翻译员",期望你一句一句说
- 但客户端把整篇文章一次性扔给他
- 翻译员不知道怎么处理
📊 各环节状态
| 环节 | 状态 | 说明 |
|---|---|---|
| 客户端录音 | ✅ 正常 | PCM 格式,16kHz |
| 文件读取 | ✅ 正常 | 260KB |
| WebSocket 发送 | ✅ 正常 | 发送成功 |
| ASR 识别 | ❌ 卡住 | 无法处理大块数据 |
| LLM 生成 | ⏸️ 未触发 | 因为 ASR 没有结果 |
| TTS 合成 | ⏸️ 未触发 | 因为 LLM 没有结果 |
| 返回音频 | ⏸️ 未触发 | 因为 TTS 没有结果 |
🔧 解决方案
已实现:分片发送
修改客户端,将大文件分成小块发送:
// 每次发送 8KB
const chunkSize = 8192
// 模拟流式传输
for (let offset = 0; offset < totalSize; offset += chunkSize) {
const chunk = audioData.slice(offset, offset + chunkSize)
socketTask.send({ data: chunk })
await sleep(50) // 延迟 50ms
}
// 发送结束标记
socketTask.send({ data: 'end' })
工作原理
客户端 → 发送 8KB 片段 1
↓
服务器 → ASR 开始识别
↓
客户端 → 发送 8KB 片段 2
↓
服务器 → ASR 继续识别
↓
... (重复)
↓
客户端 → 发送 "end" 标记
↓
服务器 → ASR 完成识别
↓
服务器 → 触发 LLM 生成
↓
服务器 → 触发 TTS 合成
↓
服务器 → 返回音频
📈 预期效果
修改前
- ❌ ASR 无法识别
- ❌ 60 秒后超时
- ❌ 没有任何响应
修改后
- ✅ ASR 正常识别
- ✅ LLM 生成回复
- ✅ TTS 合成语音
- ✅ 返回音频播放
🧪 测试步骤
- 重新编译项目
- 进入语音通话页面
- 按住"按住说话"按钮
- 说话 2-3 秒
- 松开按钮
- 观察日志:
- 应该看到 "开始分片发送"
- 应该看到 "第 X 片发送成功"
- 应该看到 "发送结束标记"
- 应该收到服务器的识别结果
- 应该收到 LLM 的回复
- 应该收到 TTS 的音频
🎓 经验总结
教训
-
架构匹配很重要
- 实时 ASR 需要流式输入
- 不能用批处理方式
-
日志很重要
- 通过日志快速定位问题
- 每个环节都要有日志
-
理解服务端设计
- 要了解服务端期望什么
- 不能想当然
最佳实践
-
使用流式传输
- 对于实时 ASR,必须流式发送
- 分片大小:4-8KB
- 发送间隔:50-100ms
-
添加结束标记
- 告诉服务器数据发送完毕
- 触发最终处理
-
完善错误处理
- 每个环节都要有错误处理
- 超时要有提示
🔗 相关文档
✅ 结论
问题已定位并解决:
- 问题:ASR 无法处理大块数据
- 原因:客户端一次性发送,服务器期望流式接收
- 解决:客户端改为分片发送,模拟流式传输
- 状态:已实现,待测试