Gladia、Deepgram、AssemblyAI、Speechmatics、Soniox 和 ElevenLabs,按 bot 选择,使用你自己的 API key、自己的区域,并完整透传每个服务商的专属选项。

选择一家语音转文字服务商,并不是一次性的决定。在你所在领域的准确率、每小时的费用、所需的语言支持、服务商是否愿意签署 DPA 并将数据留在欧盟境内,以及三人同时说话时说话人分离的效果——这一切都在不断变化,每位客户的答案也各不相同。
所以我们不再替你选择。你可以按 bot 选择服务商,也可以对已有的录像重新做出选择。
可选的服务商
| 服务商 | 批量 | 实时 |
|---|---|---|
gladia | ✅ | ✅ |
deepgram | ✅ | ✅ |
assemblyai | ✅ | ✅ |
speechmatics | ✅ | ✅ |
soniox | ✅ | ✅ |
elevenlabs | — | ✅ |
ElevenLabs 仅支持流式传输,其余五家均支持批量和实时两种模式。
批量模式是大多数人的选择:会议结束后,音频被提交,webhook 返回带有说话人标签和词级时间戳的转写结果。实时模式是指在会议进行时,转写片段通过 WebSocket 持续推送,适用于需要在会议中即时响应的场景。
两种模式独立配置,如果你希望同时获得快速的实时结果和更准确的最终转写,可以在同一个 bot 上使用不同的服务商分别运行。
批量模式
{
"meeting_url": "https://meet.google.com/abc-defg-hij",
"bot_name": "Recording Bot",
"transcription_enabled": true,
"transcription_config": {
"provider": "speechmatics",
"region": "eu2",
"api_key": null,
"custom_params": null
}
}共四个字段。省略 provider 时默认值为 "gladia"。region、api_key 和 custom_params 均默认为 null,详见下文说明。
当 transcription_enabled 为 true 时,transcription_config 为必填项;为 false 时该字段被忽略。

bot 完成后,transcription_provider 和 transcription_ids 会出现在 bot 记录和 webhook payload 中,GET /v2/bots/:bot_id/status 实时反映从服务商直接轮询的 transcription_status:not-applicable、not-started、queued、processing、done 或 error。
区域锁定
这些服务商大多支持多个区域,对于我们的很多客户来说,这正是关键所在。
| 服务商 | 批量区域 | 实时区域 |
|---|---|---|
gladia | 仅全球 endpoint | us-west、eu-west |
deepgram | global、eu | global、eu |
assemblyai | us、eu | us、eu |
speechmatics | eu1、eu2、us1、us2、au1 | 同上 |
soniox | us、eu、jp | 同上 |
elevenlabs | — | global、us、eu、in |
如果传入的区域该服务商不支持,bot 创建时会返回 400,并列出允许的值,而不是在之后才出现问题。Gladia 的批量 API 仅支持全局 endpoint,因此在批量配置中传入 region 并设置 provider: "gladia" 会被拒绝。其实时 API 则支持区域设置。
将 region 留空时,我们会选择合理的默认值:Deepgram 和 AssemblyAI 默认为 eu,Speechmatics 默认为 eu1,Soniox 默认为 us。
如果需要确保音频不离开特定司法管辖区,请配合使用自带存储。服务商通过存储桶上的签名 URL 获取音频,因此存储桶位置和服务商区域共同决定音频的实际流向。
自带 API Key
传入 api_key 后,我们将使用你在该服务商的账号,而不是我们的账号。
{
"transcription_config": {
"provider": "deepgram",
"region": "eu",
"api_key": "your-deepgram-key"
}
}API key 在存储前使用 AES-256-GCM 加密,传输至 bot 的过程中保持加密状态,bot 在使用时才进行解密。删除 bot 数据时,存储的 key 会被覆写。
使用自带 key 有两个原因。第一是成本:使用我们的 key 转写按每小时 0.25 个 token 计费,使用你的 key 则为每小时 0.05 个 token。第二是某些功能只能在你自己的账号上实现,例如你已训练的自定义词汇表,或与服务商签订的我们所没有的合同条款。
BYOK 适用于所有套餐,包括按量计费套餐。在 transcription_config 中传入你的服务商 API key,无需升级套餐。
服务商选项,直接透传
我们有意没有构建统一的选项层。每个服务商都有其他服务商没有的功能,如果将其抹平为最小公分母,就等于丢弃了你选择该服务商的理由。
custom_params 基本按你写的原样传递给服务商:
{
"transcription_config": {
"provider": "speechmatics",
"region": "eu2",
"custom_params": {
"transcription_config": {
"language": "en",
"diarization": "speaker",
"operating_point": "enhanced"
}
}
}
}如果更便于构建,也可以使用点号表示法:
{ "custom_params": { "diarization_config.min_speakers": 2 } }在实时配置中,字段在验证前会先展开,因此验证的是服务商实际接收的结构。在批量配置中,扁平 key 按原样验证,并在提交时才展开。
在实时配置中,有四个字段由 pipeline 设置,发送这些字段会被拒绝:encoding、sample_rate、bit_depth、channels。采样率尤其是按服务商从会议音频中协商确定的,覆盖它会破坏流。请改用 streaming_config.audio_frequency。
说话人分离默认开启,因为不开启会得到一大段没有说话人标签的文字,并且至少有一家服务商在未明确请求时会静默返回空的话语列表。在 custom_params 中显式设置的值优先。
注意:批量和实时接受不同的参数结构
这是让很多人耗费半天时间的问题,值得直接说清楚。对于同一个服务商,实时 API 和批量 API 接受的参数结构并不相同。
Gladia 是最典型的例子。批量模式在顶层接受翻译配置,而实时模式需要将其嵌套在 realtime_processing 下:
{
"streaming_config": {
"mode": "transcription",
"output_url": "wss://your-app.example.com/transcripts",
"audio_frequency": 24000,
"transcription": {
"provider": "gladia",
"region": "eu-west",
"api_key": "your-gladia-key",
"custom_params": {
"language_config": { "languages": ["ru"] },
"realtime_processing": {
"translation": true,
"translation_config": { "target_languages": ["en"] }
}
}
}
}
}实时参数使用严格模式验证,因为实时 session API 会直接拒绝未知 key,我们宁愿在 bot 创建时报错,也不愿在会议中失败。当你发送了一个应该在下一层级的 key 时,错误信息会告诉你它应该放在哪里:
'translation' is not a top-level field of the gladia live API —
did you mean 'realtime_processing.translation'?
(the live API shape differs from batch)批量和实时参数在 bot 创建时都会根据各服务商自身的 schema 进行校验,因此拼写错误会在一秒内以 400 返回,而不是一小时后转写失败。关于校验严格程度有两点说明:批量解析是宽松的,未知的批量 key 会通过验证并转发给服务商处理;只有实时模式会拒绝未知 key。ElevenLabs 的实时参数不经验证直接透传,因为没有已发布的 schema 供我们校验。
实时输出
启用 mode: "transcription" 后,我们会打开服务商 session,将会议音频输入其中,并将事件以 JSON 格式转发到你的 output_url:
{
"event": "transcript.segment",
"bot_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"text": "so the migration lands Thursday",
"isFinal": true,
"utteranceStart": 12.44,
"utteranceEnd": 14.91,
"confidence": 0.97,
"speaker": { "name": "Alice", "id": 1 },
"words": []
}
}此外还包括 session.started(所用服务商)、translation(如有请求)以及 error。我们每 30 秒发送一次 ping,防止中间件因空闲 socket 而断开连接。
一项限制:在我们平台 key 下的实时 session 仅限于我们托管的一组服务商,目前为 Gladia。使用其他服务商进行实时转写需要提供 BYOK key,否则在 bot 创建时会以 FST_ERR_STREAMING_TRANSCRIPTION_KEY_UNAVAILABLE 拒绝,而不是等到会议开始时才发现问题。
更换服务商
POST /v2/bots/:bot_id/retranscribe{
"transcription": {
"provider": "assemblyai",
"region": "eu",
"api_key": "your-assemblyai-key"
}
}系统会将存储的音频重新提交至另一家服务商,并更新 bot 的配置。这就是你在自己的会议上对比两家服务商的方式,而不是依赖他们的演示音频;也是恢复失败转写的方法。
删除 bot 数据时,转写结果也会从服务商侧一并删除(默认行为,由 ?delete_from_provider=true 控制),如果你提供了自己的 key 则使用该 key 操作。
服务商出现故障时的处理
提交失败后会重试两次,分别在 5 秒和 15 秒后,共计三次尝试。只有重试可能有效的错误才会触发重试:rate limit、5xx、连接和轮询超时、网络层故障,以及服务商返回 2xx 但响应体中不含 job id 的情况。身份验证错误、无效输入和不支持的操作不会重试,因为重试结果完全相同。
每次重试在重新提交前都会轮换 callback secret。这解决了一个真实存在的竞态问题:如果服务商实际上接受了一个请求,但响应在我们这端超时,其 callback 会命中一个已不存在的 secret 并被拒绝,而不是与重试的请求竞争,为同一个片段生成两份转写结果。
不会自动故障转移至第二家服务商,我宁愿直接说清楚,也不想让你在事故中才发现。如果你选择的服务商在重试后仍然失败,bot 会以 failed 结束,TRANSCRIPTION_FAILED,录像和音频文件仍然保留。恢复方法是调用 retranscribe,可选择指定不同的服务商。静默切换服务商意味着转写结果可能存储在你未同意的司法管辖区,费用也可能超出你的预期,因此这个决定由你来做。
相关内容
- 自带存储 — 控制服务商读取的音频实际存放的位置
- Meeting BaaS API 参考文档