我们如何实现文本转语音 API 免费:S2.1 Pro 背后的推理工程
摘要
- Fish Audio S2.1 Pro 现已作为免费文本转语音 API 开放:支持 83 种语言,无硬性使用限制,模型标识符为
s2.1-pro-free。免费访问在初始阶段提供;如有变动我们将提前通知。欲了解更多信息,请查看此处。- 端到端推理优化将单 GPU 请求容量提升了 4 倍:以往需要四张 H200 的工作负载,现在单张即可运行
- 关键手段:自定义 CUDA 算子(在解码形状下比 cuBLAS 快 2.1–4.3 倍)、连续批处理(吞吐量随 c=1→64 扩展 52 倍)、GPU 利用率从约 50% 提升至 90% 以上
- 相同的技术栈驱动我们的语音克隆 API —— 相同的模型权重,相同的基础设施,包含免费额度。S2.1 Pro 基于我们的开源权重基座模型 Fish Speech。
- 核心算子库 fish-scales-ops 已开源
了解开发者为何从其他平台转向我们 → 开始免费构建
2026 年 7 月 | Fish Audio 重构了推理栈,并为每位开发者免费提供 S2.1 Pro
语音 AI 昂贵的真实原因
语音 AI 推理存在一个定价页面上不会解释的结构性问题:自回归解码在默认情况下对 GPU 利用率极不友好。
每一次 TTS API 调用都会触发一个解码循环,逐个步骤生成音频 token。每个步骤都是一个小型矩阵乘法(实际中 M ≤ 128),随后是对该序列 KV 缓存的内存读取。在内存子系统追赶进度时,CUDA 核心大多处于闲置状态。在一张价值 30,000 美元的 H200 上,你付出了计算成本,却因内存延迟而白白浪费了性能。
在低并发情况下,情况会变得更糟。单请求解码循环以 10–20μs 的脉冲占用 GPU,中间隔着调度开销。在 c=1 时,天生服务于 TTS 的端点,其 GPU 利用率可能低于 10%。硬件就在那里,但工作负载并没有填满它。
行业的对策是通过按字符计费将成本转嫁给开发者。我们的对策是在基础设施层解决利用率问题。当单张 GPU 可以完成以前需要四张 GPU 才能完成的工作时,免费额度的经济可行性就显现了。
以下是实现这一目标所需的条件。
端到端优化:全栈视角
没有任何单一的改变能让你获得 4 倍的效率提升。这些收益来自于同时优化每一层并让它们产生复合效应:
- 自定义 CUDA 算子 —— 消除每个 token 的计算浪费
- FP8 量化 —— 将内存带宽压力减半
- 连续批处理 —— 在并发请求中填满 GPU
- GPU 调度 —— 消除工作负载之间的闲置容量
- 自有网络和存储 —— 移除云基础设施的溢价
下面将详细描述每一层。最后的吞吐量和成本数据是所有这些优化共同作用的结果。
自定义 CUDA 算子:fish-scales-ops
为什么 cuBLAS 不够用
TTS 服务中的解码形状(M ≤ 128)并不是 cuBLAS、PyTorch 的 GEMM 算子,甚至是 torch.compile 所优化的目标形状。这些库针对的是训练和大批量预填充 —— M 在数千级别。在小 M 情况下,它们浪费了内存带宽,并错过了仅在解码批处理大小下才存在的融合机会。
具体差距在于:对于 M=1(单请求解码)的 SwiGLU MLP 前向传播,cuBLAS scaled_mm 会发出三个独立的内核启动 —— 激活、门控乘法、下投影 —— 中间结果在每个算子之间都需要写入 HBM 并重新读回。在 M=1 时,往返过程是瓶颈,而不是计算。
我们构建了 fish-scales-ops 来弥补这一差距:这是一个针对 NVIDIA Hopper (H200, sm_90a) 和 Blackwell (sm_120a) 架构的生产级 FP8 GEMM 和 FlashAttention 库,已开源。
FP8 量化策略
我们针对不同代际的硬件实现了两种量化方案:
bsgemm (128×128 块缩放 FP8) 针对 H200/Hopper。128×128 粒度的块缩放在没有每张量量化准确性风险的情况下,提供了良好的数值稳定性。
mxfp8 (1×32, OCP UE8M0 格式) 针对 Blackwell (RTX 5090, RTX 6000 PRO)。采用 32 元素共享指数的微缩放(OCP MX 标准)在音频 token 生成的关键尺度上提供了更精细的数值忠实度。
在 mxfp8 路径中,一个隐蔽的 bug 耗费了大量调试时间:quantize_blockscale.py 为了 safetensors 兼容性使用 .contiguous() 实例化了 weight_scale 张量,但 linear_mxfp8_raw 以 K-major 步幅 (1, N) 读取缩放系数。加载一个行主序连续的 [N, K/128] 导致每个 GEMM 在全速运行时产生错误的 logit —— 下游采样模式坍缩为单个重复的语义 token,这看起来像模型质量问题,但实际上是内存布局 bug。修复方法是在 MXFP8LinearMethod.process_weights_after_loading 中重新调整步幅。修复后,贪婪解码在首五个音频帧上与 bf16 实现了 Token 级精确匹配。
算子基准测试结果
在解码形状(M ≤ 128)下,同等硬件上的内部基准测试(完整方法论见 fish-scales-ops 仓库):
- MXFP8 路径在从 1024³ 到 16384³ 的 10 个正方形形状中的 8 个击败了
torch.nn.functional.scaled_mm,最高提升 +21% - 端到端 Qwen3-4B SwiGLU MLP 前向传播:在从 1 到 4096 的每个 M 值上,比原始 cuBLAS
scaled_mm快 1.7–6.2 倍 - 与解码形状下的
torch.compile融合 cuBLAS 相比:快 2.1–4.3 倍 - sm_120a 上的 MXFP8 FlashAttention:比 PyTorch SDPA 解码快 7–19 倍,比 FlashInfer BF16 快 1.2–2.7 倍
带动大部分增益的两个融合算子:一个将激活量化 + UE8M0 缩放打包融合为单个启动;另一个将 SwiGLU 前序直接融合到下采样 GEMM 激活量化中,消除了 PyTorch 在两个操作之间必须实例化的完整 BF16 中间写入 + 读取。
批处理推理架构:延迟与吞吐量的权衡
针对自回归 TTS 的连续批处理
算子效率降低了每个 token 的成本。而批处理则是将单 token 效率转化为整个请求流中的 GPU 利用率的关键。
静态批处理 —— 将所有序列填充到相同长度并作为固定批次运行 —— 会在填充上浪费计算资源,并阻塞新请求,直到批次中最慢的序列完成。对于输出长度多变的 TTS,尾部延迟惩罚非常显著。
我们采用了改编自 sglang 的连续批处理:新请求随着槽位释放加入活动的解码批次,无需等待批次边界。GPU 解码循环永远不会因某个慢速离群请求而停滞。
DualAR:S2 特有的批处理约束
S2.1 Pro 的 DualAR 架构分两个阶段生成音频 token —— 粗糙码本后跟精细码本 —— 并带有一个调节每一步的滑动 previous_tokens 窗口。这产生了一个标准 LLM 批处理所没有的正确性约束:prev_tokens_shift_inplace 算子需要严格的形状/数据类型契约(prev int32 [bs, W, cw], next_tokens int32 [bs, cw])。调用者中的任何形状调整(如 .unsqueeze() 或隐式数据类型提升)都会破坏窗口并产生退化的音频,这很难与模型质量退化区分开来。
对于语音克隆工作负载,此约束尤为重要:说话人条件通过相同的解码路径流动,窗口损坏在长输出中表现为说话人身份漂移,而不是明显的音频伪影。
吞吐量结果
H200, bsgemm FP8, 并发扫描:
| 并发数 | 总吞吐量 | TTFB p50 |
|---|---|---|
| 1 | 154 tok/s | 73.2 ms |
| 4 | 595 tok/s | 75.5 ms |
| 8 | 1,206 tok/s | 81.2 ms |
| 16 | 2,373 tok/s | 79.6 ms |
| 32 | 4,099 tok/s | 96.9 ms |
| 64 | 8,006 tok/s | 109.8 ms |
吞吐量在 c=1 到 c=64 之间扩展了约 52 倍,而 TTFB 仅增加了 36.6ms(从 73ms 到 110ms)。GPU 完成了 52 倍的工作,延迟惩罚在大多数生产工作负载中几乎无法察觉。
在 c=64 时,单张 H200 维持 8,006 tok/s。这个数字是免费额度背后的直接机制:单 GPU 吞吐量越高,意味着单个请求的成本越低。
这些是每次免费 API 调用背后的数据。开始构建 →
实时模式:针对低延迟工作负载的架构方案
对于语音智能体和轮替对话应用,我们提供了一个单独的实时端点,该端点针对首个音频生成时间 (TTFA) 而非总吞吐量进行了优化。
核心架构决策:预填充在连接建立时完成,完全脱离延迟敏感路径。流式延迟的时钟从发送第一个音频块开始计算,而不是从连接建立开始。这意味着随提示词长度增加的预填充成本根本不会出现在 TTFA 数据中。
在调度层面,乒乓设计在不同线程上运行解码和预填充,没有每循环的主机屏障。消除屏障是 c≥4 时 TTFA 的主要改进点:在原生实现中,每一步解码后的主机端同步会串行化本应并发的工作。流水线解码循环和固定 H2D 内存传输解决了高并发下的 TTFB 和抖动问题。
完整设计和延迟细分见 arXiv:2603.08823。
质量验证:我们如何验证优化没有降低音质
量化和批处理可能会引入仅靠吞吐量基准测试难以检测的质量退化 —— GPU 全速运行却产生错误的输出。
我们在 mxfp8 开发过程中捕获了这样一个实例:上述权重布局 bug 产生了约 53% 的相对 logit 误差,而算子延迟完全正常。这种退化只出现在输出 token 分析中,而没有出现在任何性能指标中。
我们的验证管线有两个关口:
正确性关口:对于固定参考输入,量化后的贪婪解码必须在首五个音频帧上与 bf16 实现 Token 级精确匹配。首帧的 Token 级匹配能捕获系统性的 logit 损坏 —— 如果量化模型产生了不同的概率分布,它会在确定性输入上立即偏离 bf16。
性能退化关口:单请求 decode_tps 在每个并发点必须保持在基准数据的 5% 以内。任何在任何并发(c=1, c=16, c=64)下导致吞吐量退化超过 5% 的更改,在合并前都需要明确的理由。这个关口防止了那些会悄悄向解码循环添加同步操作的正确性修复。
推理栈的每一项更改都会经过这两个关口。结果是:S2.1 Pro 免费版的模型权重与付费版完全一致,且量化服务路径在每次部署时都会对照非量化基准进行验证。
大规模语音克隆:为什么推理效率至关重要
Fish Audio 的语音克隆一直是免费的 —— 根据我们自己的评估和开发者的反馈,它仍然是同类产品中最强的。83 种语言的说话人一致性、自然的韵律以及在各种口音下的稳定表现,并不是我们添加到付费版的功能。它们是底线。S2.1 Pro 基于我们今年早些时候发布的开源权重基座模型 Fish Speech S2 Pro。
推理优化改变的是在大规模情况下维持这一承诺的经济性。语音克隆工作负载比标准 TTS 具有更高的单请求成本:每次调用都必须根据参考说话人嵌入进行调节,在不同长度的输出中保持说话人身份,并在不同语言中保持一致。如果没有本文描述的效率增益,在大规模生产中提供免费语音克隆将需要对这种结构性昂贵的工作负载进行补贴。有了这些增益,就不需要了。
三项优化对语音克隆尤为重要:
FP8 保留了说话人调节信息。 Token 级精确性验证(捕获 logit 级的损坏)直接验证了量化不会降低说话人嵌入信号。克隆输出中的说话人一致性与 bf16 基准相当。
连续批处理处理混合请求类型。 生产语音克隆流量混合了带参考调节和不带调节的请求、多样的输出长度、多样的语言。连续批处理无论请求类型如何都能填满解码批次 —— 工作负载异质性不会带来任何惩罚。
52 倍吞吐量扩展使批量生成变得可行。 在单张 H200 上达到 8,006 tok/s,生成大型克隆语音音频库(有声书、游戏对话、大规模本地化内容)在免费额度内变得具有经济可行性。
免费层包含语音克隆并不是因为我们通过优化“买得起”它。我们包含它是因为这原本就是产品的核心 —— 而这里描述的工程工作是让我们能够随着使用规模扩大而坚守这一承诺。关于将语音克隆集成到智能体工作流中,请参阅我们的 MCP 和智能体技能支持。
60 秒内克隆语音 → 免费试用
GPU 基础设施:掌握全栈
硬件与采购策略
我们的 GPU 集群在多个数据中心运行约 500 张显卡。多数据中心拓扑在成为可靠性决策之前首先是一个采购决策:GPU 供应和价格是波动的,绑定单一供应商意味着直接吸收这种波动。多供应商、多数据中心采购在增加运营复杂性的同时,也对冲了价格风险和供应限制。
在推理方面,我们运行混合机群。H200 SXM5 处理高并发生产服务,其中 bsgemm FP8 的总吞吐量占据主导。RTX 5090 和 RTX 6000 PRO (sm_120a) 服务于边缘端点 —— 在 c=64 时,5090 mxfp8 达到 5,869 tok/s,在硬件成本大幅降低的情况下,约为 H200 bsgemm 吞吐量的 71%。
sm_120a 的部署需要一个隐蔽的修复:最初针对 32GB GPU 的 cuda_graph_max_bs = 24 限制在高并发下导致了严重的吞吐量跌落 —— c=32 时降至约 31 tok/s/req,c=64 降至约 35 tok/s/req。将限制提升至 min(max_running_requests, 64) 后,吞吐量曲线完全恢复。底层问题是:在 bs=24 时的 CUDA 图捕获使 GPU 在 c=32+ 实际出现的解码批处理大小下利用率不足。
GPU 调度:消除闲置容量
纯推理集群的基准 GPU 利用率约为 50%。推理流量天生具有爆发性;GPU 在非高峰时段、训练任务之间以及数据集加载阶段处于闲置状态。
我们运行两个并行的调度系统 —— 用于推理的 Kubernetes 和用于训练的 Slurm —— 遵循一个共同原则:数据清洗和预处理任务在两个集群中都作为最低优先级的弹性填充任务运行。 只要推理或训练没有占用,清洗任务就会填补闲置的 GPU 容量。它们是可设置检查点且可立即抢占的,因此当真实任务到达时,它们会消失且不产生正确性成本。
优先级顺序:K8s 集群中推理 > 清洗;Slurm 中训练 > 清洗。推理端的自动扩缩容使用真实流量信号而非时间启发式算法,因此清洗任务在负载上升时会立即被驱逐。
结果:GPU 利用率从 约 50% 提升至 90% 以上。在集群规模下,这种差异使每个推理请求的有效成本大约减半 —— 硬件预算是固定的,但服务请求数翻了一番。
网络基础设施
我们运营自己的网络:直接进行 ISP 带宽采购、ASN、300Gbps 连接以及 Cloudflare 对等互联。这对 TTS 尤其有两个成本影响。
TTS 规模下的出口流量是不容小觑的。云提供商的出口定价具有结构性的高利润;掌握网络层完全消除了这种溢价。
延迟是第二个原因。网络往返的每一毫秒都会体现在用户感知的 TTFB 中。Cloudflare 对等互联使 Fish Audio 端点靠近通过 Cloudflare 网络路由的用户 —— 这是全球 API 流量的很大一部分。多数据中心部署意味着大多数请求无需穿越整个公网即可到达附近的推理节点。
存储:分层架构
训练数据、模型检查点和推理缓存具有不同的访问模式和成本要求。我们使用三层架构:
- 热层 (NVMe flash): 活动训练数据、用于服务的模型权重
- 温层 (混合 flash/HDD): 近期检查点、预处理过的数据集
- 冷层 (自托管 Ceph HDD 集群): 历史训练数据、长期存储
冷层取代了用于大宗数据的第三方对象存储。冷存储前面的本地缓存层意味着重复读取(在训练数据流水线中很常见)由 NVMe 而非冷盘 HDD 提供服务。
结果:这套技术栈产出了什么
横跨所有层级:
- 自定义 FP8 算子:在解码形状下比标准 cuBLAS 快 2.1–4.3 倍
- 连续批处理:从 c=1 到 c=64 吞吐量扩展 52 倍,延迟仅增加 37ms
- GPU 调度:利用率从 约 50% → 90% 以上,使单请求成本大约减半
- 自有基础设施:计算、网络和存储均去除了云服务溢价
结合起来,以前需要 四张 H200 处理的请求量,现在单张即可处理。4 倍的效率提升是使免费额度具有经济可行性的原因 —— 这不是补贴,而是结构性的成本降低。免费访问期限反映了单位经济效益是可行的;当前可用性请参阅 定价。
Fish Audio 推理栈对比
基础设施数据基于截至 2026 年 6 月的公开文档、GitHub 仓库和工程博客。
| Fish Audio S2.1 Pro | ElevenLabs | OpenAI TTS | Google Cloud TTS | |
|---|---|---|---|---|
| 推理架构 | 连续批处理 (基于 sglang) | 未披露 | 未披露 | 未披露 |
| 自定义推理算子 | ✅ fish-scales-ops (开源) | 未披露 | 未披露 | 未披露 |
| FP8 量化 | ✅ bsgemm + mxfp8 | 未披露 | 未披露 | 未披露 |
| GPU 基础设施 | 自有,约 500 张显卡,多数据中心 | 云托管 | 自有 (Azure) | 自有 (TPU) |
| 开源服务栈 | ✅ 部分 (fish-scales-ops) | ✗ | ✗ | ✗ |
| 已发布的吞吐量基准 | ✅ 8,006 tok/s @ c=64 (H200) | 未发布 | 未发布 | 未发布 |
模式非常一致:Fish Audio 是唯一一家公开记录其推理架构、开源其算子库并发布具体吞吐量数据的头部 TTS 提供商。“未披露”并非批评 —— 而是对可验证性的客观观察。关于各提供商语音质量的独立评估,请参阅我们的 TTS 提供商双盲对比测试报告。
什么是开源的
fish-scales-ops 现已可用:针对 Hopper 和 Blackwell 的生产级、CUDA 图捕获安全的 FP8 GEMM 和 FlashAttention。
如果你正在 H200 或 RTX 5090/6000 PRO 上为自回归模型构建推理基础设施,那么解码形状与标准库之间的性能差距是真实存在的,而这些算子正是为了填补这一差距。
库中包含:
- FP8 GEMM:针对 Hopper 的 bsgemm (1×128 act × 128×128 wgt);针对 Blackwell 的 MXFP8 1×32 (OCP UE8M0)
- 针对 sm_120a 的 MXFP8 FlashAttention:连续预填充、分段预填充 (extend)、带原生 GQA(通过步幅 0 K/V 广播)的分段解码
- 全程支持 CUDA 图捕获安全
未来计划
B300 支持已在路线图中。Blackwell 上原生的 FP8 Tensor Core 和 NVLink 5 带宽将进一步推高吞吐量曲线。
推理优化持续进行中。 固定的基准测试数据是防止退化的关口,而不是终极目标。每一个并发点都是需要超越的目标。
更多服务栈组件 随着其稳定性提高也有望开源 —— 包括 sglang_lite 的修改、DualAR 特有的批处理逻辑、sm_120a 的 CUDA 图处理。让免费额度得以持续的基础设施,正是我们希望社区共同构建的基础设施。
开始使用免费 TTS API
模型标识符:s2.1-pro-free。只需在现有的 Fish Audio API 调用中更改一个 Header 即可。
python
import httpx
body = {
"text": "Hello, world!",
"reference_id": "your_model_id",
"format": "mp3",
}
with httpx.Client() as client:
res = client.post(
"https://api.fish.audio/v1/tts",
headers={
"Authorization": "Bearer <YOUR_API_KEY>",
"Content-Type": "application/json",
"model": "s2.1-pro-free",
},
json=body,
)
res.raise_for_status()
with open("output.mp3", "wb") as f:
f.write(res.content)
JavaScript
import { writeFile } from "fs/promises";
const body = {
text: "Hello, world!",
reference_id: "your_model_id",
format: "mp3",
};
const res = await fetch("https://api.fish.audio/v1/tts", {
method: "POST",
headers: {
Authorization: "Bearer <YOUR_API_KEY>",
"Content-Type": "application/json",
model: "s2.1-pro-free",
},
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error(`TTS request failed: ${res.status} ${await res.text()}`);
}
const buffer = Buffer.from(await res.arrayBuffer());
await writeFile("output.mp3", buffer);
83 种语言。无硬性使用上限。无需信用卡。包含语音克隆。
所有其他顶尖的 TTS API 从第一个 token 开始收费。S2.1 Pro 不收。

