第11章 实时数字人故障排除指南
完整文档索引见 llms.txt。本页面也提供 Markdown 版本。
Troubleshooting
构建实时数字人时的常见问题,以及对应的原因与解决方法。
🟢 SDK 已处理:Python SDK 和 Pipecat 已自动处理此类问题;只有直接使用 WebSocket API(或手动关闭了某项功能)才会遇到。最简单的解决方式通常是"直接用 SDK"。
🟠 你的环境问题:无论用哪种集成方式都归你负责,比如部署、网络、凭证、容量或裸 API 调优。
跳转到具体问题
嘴部几乎不动、只有待机动画,或数字人在语句之间跳变 唇形与音频不同步 播放卡顿或有爆音 完全没有视频帧 延迟随时间不断增长 裸 API 下说话时帧滞后 没有可用的后端服务器 连接或鉴权失败 打断效果生硬,或 barge-in 后数字人还在继续说话 Direct WebRTC:数字人加入后视频是黑屏 Direct WebRTC:数字人无法加入房间 Direct WebRTC:会话在就绪前超时 Direct WebRTC:会话中途掉线 Direct WebRTC:WEBRTC_NOT_SUPPORTED Direct WebRTC:我的 bot 听到了数字人的声音
嘴部几乎不动、只有待机动画,或数字人在语句之间跳变
🟢 SDK 已处理
原因:音频到得太少,或传输停滞。Presence 的最小初始音频为 320 ms,Portrait 为 200 ms。TTS 或网络上的停顿仍可能中断播放。
解决方法:每轮开头按推荐值提供音频(Presence 500 ms,Portrait 400 ms),然后以尽可能大的 chunk(约 400 ms)实时流式喂入。参见 Optimizing Performance → Feed audio。使用 OjinSTVClient 时,在 TTS 产出的同时喂入音频,让 SDK 处理分批。
唇形与音频不同步
🟢 SDK 已处理
原因:走 SDK 路径时,你在本已同步好的流之上又自己做了一次 A/V 重同步。走裸 API 时,你按自己的时钟播放自己那份 TTS 音频副本,而不是随每帧一起到达的音频,或者帧在异步解码时被乱序了。
解决方法:用 SDK 或 Pipecat 时,output_stream() 已经对齐到 25 fps,不要再自己重同步。帧到了就展示,或把每帧的 pts 传给你的媒体传输层(如 WebRTC),由它负责同步。如果你在裸 API 上自建循环,播放随每帧到达的音频负载,并同时渲染该帧的画面。服务端已帮你对齐,无需音频主时钟。保持解码顺序稳定。如果播放中有空隙,检查 TTS 和网络是否在持续供音频。参见 API Reference 中的 Audio and Video Synchronization。
播放卡顿或有爆音
🟢 SDK 已处理
原因:音频播放速率不稳定,或事件循环被阻塞。
解决方法:SDK 每 40 ms tick 恰好输出一帧音频(真实音频或静音),因此它的输出自身不会断供。保持帧处理器轻量:繁重的同步工作会拖慢调度这些帧的 tick。裸 API 上,以稳定速率无缝播放音频,不要因为某个视频帧迟到就停音频。参见 Optimizing Performance → Play back at realtime。
完全没有视频帧
🟢 SDK 已处理
原因:你还没收到 SESSION_READY / SessionReady,或者(SDK 场景)你用了 PassthroughDecoder,它会完全抑制视频帧。
解决方法:发送音频前先等会话就绪信号。用 SDK 时保留默认解码器:它会填充 frame.rgb,同时在 frame.source_bytes 中携带原始 JPEG,可以直接转发而无需重新编码。PassthroughDecoder 会导致客户端完全不输出视频帧,不要使用。参见 Optimizing Performance → Relay frames。
延迟随时间不断增长
🟢 SDK 已处理 · 🟠 你的环境(部署)
原因:缓冲区过大,或网络停顿后帧积压。模型以实时 25 fps 输出,缓冲区不应自行增长,只需保留一个小的 jitter buffer。
解决方法:SDK 会保持小缓冲并帮你裁剪积压的空闲帧(idle_buffer_target_frames,默认 6),所以不要自己按 frame_type 过滤 output_stream(),那会和客户端自身的追赶机制冲突。裸 API 上,把缓冲控制在几帧以内;如果弱网下帧积压,裁剪空闲帧(frame_type == 0),但绝不要丢语音、语音起始或淡出帧。无论哪种方式,都在 US East 的后端上用稳定连接运行客户端。参见 Optimizing Performance → Where to run。
裸 API 下说话时帧滞后
🟠 你的环境(裸 API 调优)
原因:播放缓冲区偏大,每一帧都要排在前面帧之后等待。
解决方法:把 jitter buffer 缩小到网络能容忍的最小值。输出平滑本身不可由调用方调节:线协议上没有改变它的参数。如果小缓冲下仍滞后,带着 session id 联系支持,而不是继续从客户端调参。
没有可用的后端服务器
🟠 你的环境
原因:推理容量暂时耗尽。
解决方法:稍后带退避重试。SDK 上表现为一个 code 为 NO_BACKEND_SERVER_AVAILABLE 的 ERROR 事件。裸 API 上可能是带 BACKEND_UNAVAILABLE 的 ErrorResponse,也可能是完全没有 code 的纯文本帧("No backend servers available. Please try again later.")。记得也处理非 JSON 的文本帧。
连接或鉴权失败
🟠 你的环境
解决方法:
✓ 检查你的 API key 和 config_id,并确认该 config 存在于你的 dashboard 中
✓ Authorization 头必须使用原始 API key(不要加 Bearer 前缀)
✓ 确认你的网络允许 443 端口上的 WebSocket 连接
打断效果生硬,或 barge-in 后数字人还在继续说话
🟢 SDK 已处理
原因:旧的 TTS 音频还在发送,或已缓冲的帧在你取消后继续播放。
解决方法:停掉旧的 TTS 生产者,并调用 SDK 的 interrupt()。在喂入下一轮回复前先调用 start_turn()。裸 API 上,按延迟/流畅度的取舍选择打断策略:清空缓冲实现瞬时切断,或保留视频播放、只停音频以获得更平滑的效果。参见 API Reference 中的 Interruption Handling。
Direct WebRTC:数字人加入后视频是黑屏
🟠 你的环境(观看端 UI)
原因:数字人在加入房间时就会发布视频轨道,此时模型还没有渲染任何内容。在第一帧产生之前该轨道不会发送任何数据,因此在这个窗口内订阅的观看者会拿到一个没有视频的轨道。等待的是模型的启动:暖启动的 persona 不到一秒,冷启动要几秒。
解决方法:
✓ 在第一帧解码完成或收到 FIRST_FRAME 时再显示数字人,而不是在订阅轨道时
✓ 在此之前显示你自己的占位内容,比如 persona 的静态图
✓ 如果等待时间超出预期,那是冷启动。参见"会话在就绪前超时"
这里的黑屏元素表示数字人尚未启动,而不是连接断开。参见 Direct WebRTC → Events。
Direct WebRTC:数字人无法加入房间
🟠 你的环境(凭证)
原因:房间拒绝了数字人。你会收到一个致命 ERROR,其 code 指明原因:WEBRTC_AUTH_FAILED(token 与房间不匹配)、WEBRTC_NETWORK_FAILED(Ojin 无法连上房间)或 WEBRTC_INVALID_SETTINGS(房间 URL 或 provider 不可用)。
解决方法:
✓ LiveKit:room_url 是你的服务器 URL(wss://…),token 需允许对应房间的加入和发布,且 identity 为 ojin-avatar
✓ Daily:room_url 是房间 URL,token 是该房间的 meeting token
✓ token 未过期
✓ WEBRTC_NETWORK_FAILED:检查你的 LiveKit 或 Daily 服务是否可达,然后重试
参见 Direct WebRTC → Prerequisites。
Direct WebRTC:会话在就绪前超时
🟠 你的环境
原因:会话未在 webrtc_join_timeout_s(默认 10 s)内就绪。该超时同时覆盖房间加入和模型冷启动,因此仅冷启动就可能超时。你会收到致命的 WEBRTC_JOIN_TIMEOUT。
解决方法:生产环境把 webrtc_join_timeout_s 调到约 90 s。仅冷启动就可能超过 30 s。重试通常也能解决,因为客户端放弃后服务端仍在继续启动。
Direct WebRTC:会话中途掉线
🟠 你的环境
原因:数字人在加入后失去了房间连接,你会收到致命的 WEBRTC_ROOM_LOST。客户端不会自动重连。
解决方法:开启新会话。如果反复出现,对照你的会话时长检查房间的生命周期和 token 有效期。
Direct WebRTC:WEBRTC_NOT_SUPPORTED
🟠 你的环境
原因:服务端没有返回房间结果,因此该会话无法发布到房间。客户端不会回退到 WebSocket,而是发出致命 ERROR 并关闭会话。
解决方法:去掉 webrtc= 参数改用 WebSocket 模式,或带上 config_id 联系支持。
Direct WebRTC:我的 bot 听到了数字人的声音
🟠 你的环境
原因:你自己的语音 agent 在同一个房间里,订阅了数字人的麦克风,于是它把数字人的声音当成用户语音转写并自问自答。
解决方法:让 bot 取消订阅数字人的音频。用 ojin 提供的 is_avatar_participant()(Daily)或 is_avatar_identity()(LiveKit)识别数字人。参见 Direct WebRTC (LiveKit & Daily)。
仍然解决不了?联系支持。
上一页:Optimizing Performance
最后更新于 11 天前
这有帮助吗?