先摆那个被埋掉的数。
Jhin Lee 十月中在 dev.to 发的那篇(Llama Village 系列第三篇,给角色加本地语音),组件测试表里有一行:1.7B TTS 中位合成 1.78 秒,0.6B TTS 中位合成 1.78 秒。参数量差将近三倍,中位耗时一模一样。
这一行在原文里就是个附注,风头全被后面“整轮 4.27 秒对 5.83 秒”那组对比盖过去了。我觉得整篇文章里唯一一个能往外推广的结论就在这一行,其余的都是他那台开发机上的一次试点。
测试范围先划一下:下面所有数字都是他那台 M4 Max 上的,Dart 3.13.5、llamadart 0.11.0,对话权重 Q4_K_M、音频投影器 Q8_0,温度 0、种子 42、100 token 上限、thinking 关闭、4096 上下文、4 线程。我没有他的脚本,也没重跑,所以这篇做的是拿他的口径去审他的数字,不是一次复现。这点得先说清楚,不然下面的话容易被当成实测结论引用出去。
那 1.56 秒,不是模型大小欠的
| 配置 | 模型文件 | 整轮中位 | 峰值 RSS |
|---|---|---|---|
| Omni 3B + TTS 1.7B | 4.61 GB | 4.27 s | 3.86 GiB |
| Qwen3.5 0.8B + TTS 0.6B | 2.31 GB | 5.83 s | 2.51 GiB |
小模型那套:下载量砍一半,峰值内存低 35%,然后整轮慢了 1.56 秒。
他的口径交代得算清楚——首轮丢掉,两种设置交替跑,各测三个新进程轮次;计时从装载到释放全算进去,不含进程启动、下载、录音和播放;RSS 每 100ms 采样一次,三次取最大观测值,而且是进程内存,不是 GPU 显存也不是整机内存。多数测评连“跑了几次”都不写,这份写了,加分。
但“装载到释放全算”这条恰好让结论更有意思。整轮里包含三个引擎的 load 和 release,小模型组合在装载这一段应该是占便宜的——2.31 GB 对 4.61 GB,磁盘到内存这一趟差着一个量级。占了便宜还慢 1.56 秒,那这个亏空只可能出在别处。
亏在它话多
组件数据摊开:
| 组件 | 中位耗时 | 峰值 RSS |
|---|---|---|
| Omni 3B 对话生成 | 171 ms | 2.57 GiB |
| 0.8B 对话生成 | 96 ms | 1.08 GiB |
| 1.7B TTS 合成 | 1.78 s | 3.85 GiB |
| 0.6B TTS 合成 | 1.78 s | 2.48 GiB |
对话这一环小模型快 75 毫秒,它该有的表现。TTS 两边打平。1.56 秒从哪来?
从产出的音频长度来。1.7B 生成的片段 4.16 到 4.56 秒,0.6B 生成的 4.80 到 6.48 秒。0.6B 合成时间 1.78 到 2.53 秒,中位和 1.7B 一样,但它做出来的东西多了一秒多。
我自己拿他表里的数字除了一下合成耗时和音频时长的比值——不是他给的指标,是我事后算的——1.7B 大约 0.4 比 1,0.6B 在 0.30 到 0.42 之间。两个模型摊到“每秒钟音频花多少算力”上基本一个水平,甚至 0.6B 略好。真正的差额全在“生成了多少秒音频”。
为什么多?原文说得很直白:较小的对话模型给出了更长的回答,并且无视了只回答一句话的指令。
省下 75 毫秒的对话时间,多说了大概一个半句子,倒欠 1.5 秒。你在模型选择上省下的钱和内存,被模型的不听话连本带利吃了回去。
这一条对我比那 1.56 秒本身重要。它说明端到端延迟在这个量级上是个输出长度问题,不是参数规模问题。任何一份不给输出长度、不给音频时长的 TTS 延迟对比表,测的其实是那个模型的啰嗦程度,不是它的速度。这话我说得挺满,但我认为站得住——你没法用一份没锁死输出长度的表去比推理性能,压测里的常识,换到语音栈上就集体失忆。
原文作者自己也把这条接上了:他建议把游戏知识规则放到提示词之外。他给这个建议的出发点是知识注入的可靠性,但这条同时是个延迟修复。提示词里那句“只回答一句话”既然能被无视,就别指望它约束输出长度;把长度约束做进解码参数或者后处理,比写在提示里更省事。他没这么推,我替他推一步。
n=3,但两组区间不重叠
四个字:样本很小。
基线三个轮次 3.76 到 4.41 秒,小模型三个轮次 5.82 到 5.91 秒。⚠️ 每组只有三次,计时的时候机器上还跑着别的开发负载,村庄渲染器根本没开。
但这两个区间不重叠,中间空了一秒四。n=3 的测试里区间不重叠,比 n=30 的测试里中位数差 5% 要有说服力得多。我不会因为样本量小就把“小模型这套整轮更慢”记成运气——方向我认为是稳的。
不稳的是幅度。1.56 秒这个数,下次他开着渲染器、换台机器、或者把那个不听话的输出长度压下去,会变成多少,现在没人知道。这是两件事:“更慢”可以信,“慢 1.56 秒”不能拿去写进任何决策文档。
还有个更麻烦的:这 4.27 秒不含播放。音频合成完了才开始响,Mo 从被问到发出第一个音节,中间大约四秒沉默。游戏里对话四秒不出声,玩家会以为卡了。
1.78 秒那段沉默,才是真过不去的
原文里有一句技术细节,我读的时候停了很久:这个 TTS 的接口返回完整音频之后才能播,进度事件不是可播放的音频块。
意思是你不是“边合成边播”,你是“等 1.78 秒,然后一次性播”。他给的缓解办法是先显示文字回复,等合成完成再播音频。办法本身没错,但它等于承认这条链路做不了实时。
我 care 的不是 1.78 秒这个中位数。是 0.6B 那个合成时间范围:1.78 到 2.53 秒。中位数底下藏着 2.53,而 2.53 对应的音频片段是 6.48 秒。倒霉的那一轮,玩家等两秒半,然后听六秒半的话。这个尾巴在游戏场景里比中位数重要得多,而原文里没有 P95,也没有最差轮次的完整数据——这不能怪他,三次跑测算不出有意义的 P95。
但这是结构性问题,不是调参问题。要真可用,得有流式返回可播放的音频块,让首字延迟和总时长解耦。他这条链路上的引擎是一次性吐完的,改提示词、换小模型、降量化位宽,都动不了这一层。
围巾那段,我比他更在意
两个对话模型被问围巾在哪、什么颜色,都答对了。被问“谁把围巾放进池塘的”,两个都说是 Pip 干的。
这件事从来没在提示里出现过。
0.8B 那个还多加了一句“我看到了它”。
我承认这是 n=1,单次观察,连有统计意义的负面都算不上。但这正是语音链路里最难测的失败模式:ASR 回转只能查可懂度——他把六个片段转回去,全都回到了目标句子,这个检查干净也诚实,他自己也强调了这不是自然度、不是情感、不是音色相似度的评分。
可懂度查不出“Mo 声称自己目击了一件不存在的事”。ASR 只关心波形对不对得上字,不管字对不对得上世界。
一条语音回答在这条链路上要过三道关:ASR 有没有听错、对话模型有没有编、TTS 有没有念糊。现在只有第一道和第三道有检查手段,中间那道全靠人耳听一遍然后皱眉。评论区 Alex Shev 提的那个办法——把音频片段、转写词元、下游动作做一份轻量对齐记录——方向是对的,但那是给人排查用的工具,不是自动化指标。要真做成指标,得先定义什么叫“模型说了提示词里没有的事实”,这件事本身不好办。
所以作者那句“把游戏知识规则放到提示词之外”,我读第二遍的时候觉得比第一遍重得多。它不只是延迟修复,也不只是知识注入,它是在把“哪些事实允许出现在回答里”从模型的自觉变成外部系统的一道闸。
我现在会怎么用它
他倾向在原型存储预算下用小模型组合,我同意这个取舍,但不同意理由只写“下载量减半、内存低 35%”。真正的理由是 2.31 GB 对 4.61 GB 这个差距会跟着你走到每一个平台,而 1.56 秒那个差距,只要把输出长度管住,很可能缩进噪声里。一个差距是结构性的,一个是行为性的。行为性的那个能修。
按键说话这一条我完全赞成,而且应该写进第一版就定死,别等测完渲染再补。Mo 开口时停录音、玩家开新回合就丢掉旧回复、语音挂了留住文字——这些不是体验优化,是在四秒沉默和两秒半不可预测的合成尾巴还没解决之前的兜底。
至于语音和村庄渲染同时跑会怎样,他没测,我也没法替他说。这是他现在唯一还缺的那个数,也是唯一能决定这功能能不能进游戏的那个数。
置信标签:方向大致对。“端到端延迟由输出长度主导,不由模型参数量主导”这个判断在这组数据里成立——两个 TTS 同中位数、片段长度差一秒多、整轮反倒慢 1.56 秒,三条对得上;幅度上我不敢背书,n=3、开发机、带其他负载、没开渲染,1.56 秒先当方向看,别拿去写进排期。至于“小模型更容易编造信息来源”那条,证据不够,先别信,但值得单独设计一次跑测。
他要是把输出长度锁死重跑一遍,数字大概率不会是这个样子。谁手上有类似的两段式语音链路,按他这个口径重测一版,数字要是和我上面这几句推的对不上,告诉我。
