数字人到了客户现场就"不灵":四类故障的分诊表与实测判据

2026-10-24 · AI智工坊 · 数字人交付实录

实验室里跑通的数字人,搬到客户现场经常变成四种"不灵":嘴动了但慢半拍、说着说着嘴不动了、画面正常但叫它不理、欢迎词死活不响。这四种现象在客户眼里都是"你这东西坏的",但在工程上是四条完全不同的链路。

我们在展厅、门店、政务大厅这类无人值守、长期开机、网络不由我们控制的现场反复踩过这四类问题。下面这张分诊表和后面的判据,是每一次都把"猜"换成"量"之后才定下来的。每条判据都能远程执行,不需要人在机器前面点鼠标。

一、先记住一个反直觉事实:画面能显示 ≠ 网络是通的

这是现场排查最容易走错的一步。数字人页面里的 idle、talk 两段视频是浏览器缓存过的,网络断了它照样播。而每句回复的 TTS 音频是每次新生成的 URL,必然要现拉。

所以"人像在动、就是不说话"这件事,恰恰证明不了网络好。必须在设备本机实测下载速度:

curl -sk -o NUL --max-time 30 -r 0-2097151 -w "%{speed_download}" \
  https://<你的入口>/assets/fenshen_v1_talk_1080x1920.mp4

判据很简单:低于 50 KB/s 基本不可用。我们的一版素材是待机 4.3 MB、口播 3.7 MB、每句 mp3 约 100 KB,全都要现拉——这是 1080×1920 的代价(待机 4.7 Mbps、口播 2.3 Mbps,对现场宽带偏高)。

二、四类"不灵"的分诊表

现场描述一行判据(远程可跑)根因修法方向
嘴在动,但比声音慢约两秒 日志里的口型时序:出画面 是否 > 2.5s、primed 是否 False 口型管线粒度(batch_size)+回声式 TTS 二次排队 调管线粒度,不调音画补偿
说一段之后,后半段嘴定格 可见视频元素 currentTime 是否贴住 duration 口播素材不循环,本次累计朗读超过素材时长 素材循环 + 页面侧自愈看门狗
画面正常,叫它不理 micStream 是否 false、麦克风 rms 是否长期 <0.01、ASR 是否输出空文本 弱网 / 麦克风没起来 / 上传全是噪声 先量网络,再看起麦,最后看识别
欢迎词不响,但聊天正常 /motion 的 ok 与 frames 是否递增 摄像头黑帧(物理侧),或播报地址被写死 先分清黑帧/地址,别改 ASR

为什么强调"先量三个数":这四类的修法互不通用。把"网络不行"当"模型坏了"去重装环境,是现场最常见的浪费;反过来把"素材不循环"当"音画不同步"去调补偿,嘴会越调越乱。

三、第一类:嘴动了,但慢半拍

先拿三个数,别动手。口型准备阶段已经埋了计时,一次播报就够:

journalctl --user -u <口型服务> --no-pager | grep -a '口型时序' | tail -3
# 口型时序:等空闲 0.00s / 喂音频 0.54s / 出画面 1.59s(primed=True)
量含义健康值故障值
等空闲等上一轮口型落地才喂新音频0~2.5s(首句 0)—
喂音频上传 + 入队耗时0.02~0.6s—
出画面喂完到"嘴开始动"1.5~1.7s3.06s
primed是否真的等到口型起来TrueFalse

primed=False 必须当故障看:它意味着等超时了就放声——客户先听到声音,画面三秒后才到,主观感受就是"延迟两秒"。

三个互相独立的真因,按贡献排序

  1. batch_size 就是"图像延迟"的量纲(主因)。管线粒度 = batch_size × 40ms。推理要凑满两轮才推画面,batch_size=16 时每轮 0.64s,两轮 1.28s 起。16 → 8 后粒度降到 0.32s。

    但"越小越好"是错觉:batch_size=4 时推理帧率掉到 21.7~22.7 fps,低于 25 的输出帧率,画面会越播越落后,比延迟更糟。同一台机器上 8 是下限(26.5~26.8 fps,余量只有 5~6%)。判据是两端都看——延迟降了、帧率还得 > 25。

  2. 渲染主循环的积压刹车。发送队列积压 ≥5 帧时每轮 sleep(0.04×qsize×0.8),就是 0.16~0.26s,还把同一循环里的语音处理一起拖慢。阈值 5 → 60 后只在真积压时刹一次。

    注意:单改这一条实测没有效果(仍是 3.08s,积压告警 0 条)。它不是主力,别在这儿死磕。

  3. 回声式 TTS 让同一条音频被合成两遍。走"文本 + type=echo"的路径每次 1.4~2.4s/句,且串行排队——说一句欠一秒,越说越欠。正解不是提速,是音频同源:把刚合成的那份 mp3 原样喂给渲染端,页面播的和驱动口型的是同一份文件,时长必然一致。

    同源最硬的自证是逐句对齐到小数点后两位:24000: (110592,) = 4.608s 对 mp3 的 4.61s,(45504,) = 1.896s 对 1.90s。

改完怎么验收

修复前修复后
出画面3.06s1.52~1.69s
primedFalseTrue
音画差(页面侧实测)约 2000ms+227ms
推理帧率26.926.1~26.6

量"音画差"必须用头部 ROI,不能用全画帧间差分。全身数字人的待机素材本身一直在微动,全画差分会把"说话"和"待机"切得乱七八糟——我们实测过把偏移算成 +2794ms 和 +11643ms 两回,纯粹是配对错了。正确做法:只取头部区域,只统计变化超过 24 色阶的像素占比,能干净切出说话窗口。

还有一条现场纪律:验证时一个声音都不能出。展示机在客户面前,任何"为了量一下"而让它出声都是事故。做法是在页面侧勾住 HTMLMediaElement.prototype.play,真正播放前强制 muted=true; volume=0,全链路照常跑完再复位——字幕、口型都在动,但没有声音。

判读口径:+1500ms 以上 = 管线级故障;±150ms 内 = 同步良好;负值大 = 补偿调过头了(画面跑到了声音前面)。

四、第二类:说着说着,嘴不动了

这一类的关键差别在于哪种"不动",三种现象的修法完全不同:

现象判据(在页面里量)根因
画面完全定格,时间轴在走currentTime 在涨,但 totalVideoFrames 不涨解码/渲染停摆、页面被遮挡节流
人在动,只有嘴不动可见层播的是待机素材(待机本身有轻微晃动,嘴是闭的)状态机没切到口播层
讲一段后后半段嘴不动可见层是口播但 currentTime 贴住 duration口播素材不循环 + 累计朗读超过素材时长

第三种我们遇到过最典型的一例:为了让音尾对齐,口播素材被改成了不循环(时长 12.84s),而一次会话只在开场复位一次播放头,多句回答连续播同一条。于是单次累计朗读一旦超过 12.84s,视频必然播到末帧——这就是客户说的"回答完问题、重播欢迎语那一段嘴不动"。

修法不是"把素材做长",而是结果校验 + 自愈 + 上报。页面里挂 250ms 巡检,只要在讲话就校验四件事:可见层是口播素材、没有暂停、totalVideoFrames 在增长、没有贴住末帧。

为避免误报,巡检要设三个闸门:冷却 1800ms、起播后 1400ms 内不判、淡化动画期间不判(交叉淡化时两层透明度都不是 0/1,此时判"哪一层在播"必然误判)。这三条落下后,正常朗读实测 0 误报,正常播放时帧增长约 25 帧/秒。

验证要能复现,别只说"好了":①正常朗读一次,帧率对、看门狗命中 0;②人为把 currentTime 设到末帧前 0.05s,应在一个巡检周期内被检出并回卷;③人为把状态改成"讲话中"但可见层停在待机素材,应被检出并重挂。

五、第三类:画面正常,叫它不理

按顺序量三件事,每件 1 分钟内出数,不要跳步:

  1. 媒体下载速度(第一条已给命令)。<50 KB/s 就别往下查了,是网络。
  2. 麦克风电平:页面里读分析器的 rms。人正常说话应在 0.05 以上;长期只有 0.005~0.01,说明是环境噪声在误触发语音检测,上传的全是噪声片段,看起来"在听",其实一句也没听清。
  3. 语音识别有没有出非空文本:日志里只有"识别耗时"、没有"[听] 文字"、也没有合成,就是识别结果为空。这条链路里唯一静默退出的分支就是"文本为空",其它分支(回声窗口、噪声、低置信、过期轮次)都会留日志。

搬家/换网后必查"幽灵网卡抢默认路由"

这是我们吃过最大的一次亏:设备搬到楼下换了网络,公网吞吐只有 391 B/s,页面几乎打不开。查下来不是宽带问题,是一块已经拔掉网线、留着静态 IP 的网卡仍然保留默认路由,而且度量值比无线还优——流量全被丢进黑洞,TCP 反复重传。

Get-NetRoute -DestinationPrefix 0.0.0.0/0 | Select InterfaceAlias,RouteMetric,InterfaceMetric
# 实测:以太网(Disconnected,169.254 地址) 1+5=6  <  WLAN 0+55=55  → 有线赢了
Set-NetIPInterface -InterfaceAlias 以太网,WLAN -AddressFamily IPv4 -AutomaticMetric Enabled
# 立刻从 391 B/s → 30 KB/s(约 77 倍)
Disable-NetAdapter -Name 以太网 -Confirm:$false     # 当下不用有线就直接停用

顺带一个判据:ping -l 1400 -n 15 <网关> 如果一跳就丢包 13%、平均 152ms、抖动 19~419ms,是射频/链路质量问题,与"网卡速率 72Mbps、信号 100%"并不矛盾。这种现场不要在软件侧补救,直接给三条路:插网线、换信号好的 AP、手机热点临时验证。

还有一种"聋":页面重载之后麦克风不会自己起来

起麦通常只有三条触发路径:点麦克风按钮、手机接管释放、页面重新可见(且此前起过麦)。页面一 reload,那个"起过麦"的标志就复位了——页面看着完全正常,麦克风流却是 null,客户怎么喊都没反应。

一行判据:{micStream:!!d.micStream, vad:!!d.vad, status:document.getElementById('status').textContent}

micStream:false 配上 status:'online' 就是聋了(正常应该是 listening)。修法是加自动起麦:15s 节流,失败后 2.5s / 8s 各补一次,挂在连接建立、15s 保活、页面可见性变化、任意点击/触摸上。验收标准是——重载页面后什么都不做,20s 内自己恢复成 micStream=true / vad=true / status=listening。

六、第四类:欢迎词不响,但聊天正常

先分清是"没检测到人"还是"检测到了却播不出来",这两条路的日志特征完全不同:

铁律:任何"写死服务端地址"的参数都是搬家即哑。正确顺序是:显式参数 → 局域网兜底 → 从页面同源地址推断。后者让终端自己找到入口,换网不用改配置。

摄像头黑帧:软件救不了,别在软件里绕

如果 /motion 拿不到画面,按代价从低到高排:

  1. 看日志是"能打开但是黑帧"还是"打不开";
  2. 查设备管理器:设备状态正常、问题码 0,说明不是没插上或驱动坏;
  3. 查系统摄像头隐私开关是否 Allow;
  4. 停掉占用服务,用独立进程直开一次(避免"被别的程序占用"的误判),分别试不同后端接口;
  5. 抓一帧存盘拉回来看——最直接。

黑帧的判据很干脆:像素均值 ≈0.01、标准差 ≈1、最大值 255 只有几颗噪点。这时候软件侧已经到头了:

我们后来找到一条容易被忽略、但决定"能不能一次治好"的物理根因:摄像头和 USB 无线网卡挂在同一个根集线器上,而机器另有空闲的一组。二者抢供电与带宽;而且不少 USB 摄像头在 USB3 控制器上"能枚举、不给流",插 USB2 反而稳。把摄像头挪到另一个根集线器、换一根短线,与"昨天换口即恢复"的现象互相印证。

防复发可以远程做:关闭 USB 选择性暂停(电源计划里那一项),防止设备被系统断电后醒不来。

七、现场巡检清单

无人值守的机器,交付时把下面六条做成定时巡检,任何一条不满足就报警——它们覆盖了上面四类故障的早期信号:

#检查项通过判据
1人像页可达HTTP 200,且页面里的 status 是 listening
2麦克风活着micStream=true、vad=true
3人体感应活着/motion 的 ok=true 且 frames 递增
4口型链路活着一次播报的"出画面"<2.5s、primed=true
5音画同步无声音测量,偏移在 ±150ms 内
6网络余量媒体下载 >50 KB/s

还有一个必须提前处理的连带风险:页面上的"退出"如果只有一个按钮、且直接杀掉浏览器,那一声被误识别的"关闭/退出"就能让大屏永久黑掉。交付前给它加二次确认,或者加自动回归——这是"看起来能用"和"能无人值守"的分界线。

八、一句话总结

数字人现场故障几乎都能归到四句话:声音是节拍器(画面跟声音走,宁晚不早);检测要自己找到服务端;麦克风要自己起来;黑帧永远在物理侧。

凡是靠"人在现场点一下"才能恢复的环节,客户现场就一定会出哑场。

要一份可打印的现场巡检表?我们把上面六条巡检项和四类故障的分诊步骤整理成一页检查表,免费下载:数字人现场故障分诊与巡检清单。需要按你的现场做一次远程体检或部署一套无人值守数字人,走服务页的"数字人部署 / 素材体检"档。