codecamp

Grok Voice 3.0 与转写模型

语音这一块最容易被旧教程带偏。中文资料里还大量写着 grok-voice-2.0,而官方已把它标为弃用;转写模型 grok-voice-transcribe-1.0 更是有明确的 EOL 日期,请求会被路由到新版本。照着旧 slug 写,代码可能还能跑,但你不知道自己实际在用哪一版、按什么价结算。

这一节把语音的三个接口与模型版本讲清,并给一个「模型名解析」的判据。

一、问题不是「能不能说话」,而是「你在用哪一版」

按 2026-11-04 官方 Voice 页与 release-notes,语音能力分三条线:

  • 语音到语音:wss://api.x.ai/v1/realtime,用 WebSocket 做实时对话,支持工具调用与会话配置。
  • 文本转语音:POST /v1/tts,传 text、voice_id、language,返回音频。
  • 语音转文本:POST /v1/stt,默认模型 grok-voice-transcribe-2.0。

版本上要知道三件事:grok-voice-3.0 已上线,grok-voice-latest 指向它;grok-voice-2.0 已弃用;grok-voice-transcribe-1.0 在 2026-10-02 到期(EOL),请求路由到 2.0,官方说明同价、更高准确率。

二、最小可运行示例:模型名解析器

下面的脚本不联网、不需要真实密钥。它把常见的语音模型名映射成「实际版本 + 别名类型 + 状态」,避免把弃用或 EOL 的名字当成可用版本。

"""语音模型名解析:别名指向、弃用与 EOL 状态。"""

CATALOG = {
    "grok-voice-latest": ("grok-voice-3.0", "别名", "可用,指向当前版本"),
    "grok-voice-3.0": ("grok-voice-3.0", "显式", "可用"),
    "grok-voice-2.0": ("grok-voice-2.0", "显式", "已弃用"),
    "grok-voice-transcribe-2.0": ("grok-voice-transcribe-2.0", "显式", "可用(当前默认)"),
    "grok-voice-transcribe-1.0": ("grok-voice-transcribe-2.0", "显式", "2026-10-02 EOL,已路由到 2.0"),
}

def resolve(name: str) -> str:
    if name not in CATALOG:
        return "未知模型名:核对官方页当前列表"
    target, kind, status = CATALOG[name]
    return f"{target}|{kind}|{status}"

def offline_check() -> None:
    for name in [
        "grok-voice-latest",
        "grok-voice-3.0",
        "grok-voice-2.0",
        "grok-voice-transcribe-1.0",
        "grok-voice-4",
    ]:
        print(f"{name} -> {resolve(name)}")

if __name__ == "__main__":
    offline_check()

真正上线时,把 CATALOG 换成你核对过的清单;每次官方 release-notes 更新后重跑一遍,别让「别名指向变了」悄悄改变你的行为。

三、三条语音线的关键参数

接口 端点 关键参数
语音到语音 wss://api.x.ai/v1/realtime model、voice、instructions、turn_detection、tools
文本转语音 POST /v1/tts text、voice_id、language
语音转文本 POST /v1/stt model、file

三件要强调的事:

  • 客户端不要直接带 API Key。官方为客户端应用提供 Ephemeral Tokens,用短期凭证连接,避免把长期密钥写进前端。
  • 默认声音是 eve。TTS 与语音到语音都可指定 voice_id;自定义声音需要先用参考音频创建(官方说明参考片段最长 120 秒)。
  • 转写能力比想象中全。官方写明支持 15 种音频格式、词级时间戳、多声道、说话人分离、Smart Turn 断句与 38 种以上语言;选型时别只盯着「能不能转」。

四、预期输出与异常分支

运行解析器,预期输出:

grok-voice-latest -> grok-voice-3.0|别名|可用,指向当前版本
grok-voice-3.0 -> grok-voice-3.0|显式|可用
grok-voice-2.0 -> grok-voice-2.0|显式|已弃用
grok-voice-transcribe-1.0 -> grok-voice-transcribe-2.0|显式|2026-10-02 EOL,已路由到 2.0
grok-voice-4 -> 未知模型名:核对官方页当前列表

换成真实接入时,若出现异常,按下面顺序定位:

现象 优先怀疑 第一步动作
行为突然变化 用了 -latest 别名 改为显式版本并记录
报模型不存在 用了已退役 slug 核对 release-notes 的 EOL 日期
前端暴露密钥 直接下发长期 Key 改用短期凭证
声音不对 voice_id 与预期不符 确认默认 eve 与自定义 ID

最后一行尤其重要:-latest 让升级「自动发生」,也让行为漂移难以复现。生产环境写显式版本,是本节最该带走的一条。

五、判据卡

判断项 该这么做 不该这么做
生产环境 写显式版本号 依赖 -latest
退役信息 带 EOL 日期核对 照旧教程写
客户端接入 用短期凭证 下发长期 API Key
声音选择 显式指定 voice_id 依赖默认值
模型清单 随 release-notes 更新 一次写死不再看

这张卡的重点是版本要可复现。五条里有三条在说:别名会漂、弃用会变、EOL 有日期,三者都不能靠记忆。

六、来源与核验

  • 官方 Voice 概览:https://docs.x.ai/developers/model-capabilities/audio/voice(核验日期 2026-11-04)。三条语音线的端点与参数、默认声音 eve、Ephemeral Tokens、转写支持的格式与语言能力、自定义声音参考片段 120 秒上限,均以该页为准。
  • 官方 Release Notes:https://docs.x.ai/developers/release-notes(核验日期 2026-11-04)。grok-voice-3.0 上线、grok-voice-latest 指向它、grok-voice-2.0 弃用、grok-voice-transcribe-1.0 于 2026-10-02 EOL 并路由到 2.0(同价、更高准确率)来自该页。
  • 语音价目按分钟、转写按小时、TTS 按百万字符;具体数值以官方定价页与控制台当前显示为准。

七、动手试

  1. 把你项目里所有语音模型名列出来,逐个查 release-notes,标出「显式 / 别名 / 已弃用 / 已 EOL」。
  2. 设计一个别名监控:当 -latest 指向的版本变化时告警。写出你要对比的字段与频率。
  3. 给一段 3 分钟的中文录音设计转写流程:用哪个模型、要不要说话人分离、时间戳怎么存。说明每项选择的理由。
Grok Imagine 图像与视频计价
Grok 错误码该不该重试
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }