一、先判断该不该用:同传,还是离线转写后翻译
Qwen3.8-LiveTranslate 是阿里通义千问推出的实时同声传译大模型,已通过千问 AI 平台与阿里云百炼以 WebSocket 实时接口开放。它要解决的问题很明确:让一句话在说话人还没说完时,就被翻成另一种语言、并用接近原说话人的声音念出来。如果你的需求是"此刻正在发生的对话要立刻被听懂",它就是为这个场景而生;如果是"先录音、事后慢慢翻",它未必是第一选择。
先钉死两个口径,这是全站铁律,也是最容易写错的地方。其一,2.3 秒是字均延迟(LAAL,Length-Adaptive Average Lagging)的官方口径,表示译文整体比源语音平均慢 2.3 秒,它不是端到端首包延迟,不要把 2.3 秒理解成"你说完第一个字 2.3 秒后就出声",那是对指标的误用和外推。其二,60 种和 29 种是两个不同口径:60 种是识别输入(能听懂),29 种是语音输出(能念出来),剩下 31 种只出文本、不出声音。营销稿里"支持 60 种语言"落到工程上,你该追问:目标语言在不在那 29 个能出声的里面。
同传与离线转写后翻译的核心区别在时延容忍度。离线方案先整段转写再整段翻译,能做后处理、整篇一致、批量压低成本,代价是用户要等;实时同传在语音流进来的同时就吐译文,体验是"边说边懂",代价是每句上下文窗口更短、单位成本更高、工程更复杂。
适用:跨国会议同传、跨境直播字幕、视频本地化、国际展会、出海客服与培训、医疗问诊口译辅助、个人出境游随身翻译。慎重:对术语一致性要求极高且允许事后打磨的合同法律文书、需要"信达雅"的文学翻译、数据不能出公有云合规受限的场景。端到端语音方案边界参见 /zh/posts/realtime-interpretation-comparison-review,与 GPT 系实时模型对比见 /zh/posts/gpt-live-1-release-hotspot。关键判断:你的业务能否接受"翻译跟着人声走、专有名词偶尔需长上下文消歧"?能接受就上手,否则先离线。
二、凭据与环境准备
第一步拿 API Key,且用正确姿势拿。登录千问 AI 平台或在阿里云百炼开通服务后创建 Key。铁律贴在显示器上:密钥只进环境变量,不进源码、不进仓库、不进前端打包产物。一旦写进代码并提交,它会出现在版本历史、日志、前端 bundle 里,任何人都能拿走。泄露后的标准动作只有一条:立刻到控制台吊销旧 Key,重建新 Key,并轮换所有用到它的服务。
做法:把密钥放进 shell 环境变量或密钥管理系统(KMS、Vault),代码里只通过 os.getenv("DASHSCOPE_API_KEY") 读取,变量名以官方文档为准。切勿在代码里写死字符串,也不要把 .env 提交 Git,在 .gitignore 里排除本地密钥文件。
环境:Python 3.10 及以上,安装 WebSocket 客户端依赖,官方示例用 websocket-client,也可用阿里云百炼 DashScope SDK(版本以官方文档为准)。无论哪种语言,本质都是事件驱动的 WebSocket 协议:开长连接,收 session.created,持续推音频、持续收事件。
一个必踩坑提前说:浏览器建 WebSocket 握手时无法自行设置 Authorization 头,所以不能把 Key 塞进前端让浏览器直连。正确架构是你自己的服务端持密钥建连,浏览器通过自有信令通道收发音视频。换句话说,前端"实时同传网页"只是壳,鉴权与连接都在后端。
三、跑通最小实时流
最小实时流目标:音频流进,双语文本与译文语音出。下面骨架依据 Qwen Cloud 与阿里云百炼官方文档事件字段;若你看到的控制台字段与这里不一致,一律以官方文档为准。
# 依赖:pip install websocket-client
import json
import base64
import os
import websocket # 来自 websocket-client
API_KEY = os.getenv("DASHSCOPE_API_KEY") # 仅从环境变量读取,绝不写进源码或仓库
if not API_KEY:
raise SystemExit("未设置 DASHSCOPE_API_KEY 环境变量")
# 端点以官方文档为准;此处为 Qwen Cloud 公共端点示例
WS_URL = "wss://maas.qwencloudapi.com/api-ws/v1/realtime?model=qwen3.8-livetranslate-flash-realtime"
# 浏览器无法在 WebSocket 握手时设置 Authorization 头,生产环境应由你自己的服务端持有密钥并中转
HEADERS = [f"Authorization: Bearer {API_KEY}"]
def on_open(ws):
# 连接就绪后先配置会话,再开始推音频
cfg = {
"type": "session.update",
"session": {
"output_modalities": ["text", "audio"], # 仅文本用 ["text"]
"translation": {"language": "en"}, # 目标语种,必填
"input_audio_transcription": {"language": "zh"}, # 源语种,省略则自动识别
# 以下为可选能力,字段名以官方文档为准
"enable_voice_clone": False, # 音色克隆开关
"voice_clone_options": {"frequency": "once"},
"corpus": {"phrases": {"千问": "Qwen"}} # 热词,上限以官方文档为准
}
}
ws.send(json.dumps(cfg))
print("会话已配置,开始推送音频")
def on_message(ws, message):
evt = json.loads(message)
t = evt.get("type")
if t == "conversation.item.input_audio_transcription.delta":
print("[源]", evt.get("delta", ""), end="", flush=True) # 源语言原文(ASR)
elif t == "response.audio_transcript.delta":
print("[译]", evt.get("delta", ""), end="", flush=True) # 译文文本,与音频同源流式返回
elif t == "response.audio.delta":
audio = base64.b64decode(evt.get("delta", "")) # 译文语音分片,24kHz PCM
# play(audio)
elif t == "response.done":
print("\n[本段翻译结束]")
elif t == "session.finished":
ws.close()
def on_error(ws, error):
print("错误:", error)
def on_close(ws, code, msg):
print("连接关闭", code, msg)
ws = websocket.WebSocketApp(WS_URL, header=HEADERS,
on_open=on_open, on_message=on_message,
on_error=on_error, on_close=on_close)
# ws.run_forever() # 实际运行由下方采集循环驱动,关闭前务必发送 session.finish会话配置最关键。单独把 session.update 字段拆开,便于对照控制台。qwen3.8 与旧版字段有差异,官方明确提示旧版代码不能直接改个模型名复用,请逐字段核对。
{
"type": "session.update",
"session": {
"output_modalities": ["text", "audio"],
"translation": { "language": "en" },
"input_audio_transcription": { "language": "zh" },
"enable_voice_clone": true,
"voice_clone_options": { "frequency": "always" },
"corpus": { "phrases": { "千问": "Qwen", "通义": "Tongyi" } }
}
}字段含义(以官方文档为准):output_modalities 决定只出文本还是文本加语音;translation.language 是目标语种,必填,无隐式默认;input_audio_transcription.language 是源语种,省略则自动识别;enable_voice_clone 开启后译文用原说话人音色,此时预设音色失效,需把 voice 设为 default 或已克隆音色 ID;voice_clone_options.frequency 支持 never(用预克隆档案)、once(会话开始克隆一次)、always(每次响应前重新克隆,适合多人);corpus.phrases 是热词映射,提升专有名词准确率。
音频持续发送 input_audio_buffer.append,音频为 Base64 编码的 PCM。官方口径 16kHz、16bit、单声道输入,输出 24kHz PCM。下面本地麦克风采集并推送的循环示意。
import pyaudio, base64, json
pa = pyaudio.PyAudio()
stream = pa.open(format=pyaudio.paInt16, channels=1,
rate=16000, input=True, frames_per_buffer=2048)
print("开始采集,按 Ctrl+C 结束")
try:
while True:
chunk = stream.read(2048)
ws.send(json.dumps({
"type": "input_audio_buffer.append",
"audio": base64.b64encode(chunk).decode()
}))
except KeyboardInterrupt:
ws.send(json.dumps({"type": "session.finish"})) # 等待 session.finished 后由回调关闭
finally:
stream.stop_stream(); stream.close(); pa.terminate()收尾纪律:断开前务必发 session.finish,直接关 socket 最后一段会丢。服务端收到后,有声时返回 conversation.item.input_audio_transcription.completed 与 session.finished,收到 session.finished 再真正关闭。视频或图像经 input_image_buffer.append 发送,要求 JPG/JPEG、建议 480p 到 720p、单张 Base64 前不超 500KB、速率不超每秒 2 张,且必须先发过至少一帧音频。
四、场景一:跨国会议同传纪要
跨国会议最对味,三项能力一次用足:实时说话人分离、音色克隆、原文译文同帧同出。
说话人分离在 qwen3.8 默认开启,默认断句配置 speaker_detection:你持续推音频,服务端自动判断谁在说、何时说完并触发翻译。价值不止分清谁说话,更在于后端音色克隆据此稳定复刻每个说话人声音。API 暴露克隆频率开关 voice_clone_options.frequency,多人交替场景设为 always,能在每次响应前重新克隆,避免甲的声音漂到乙身上。音色克隆工具对比见 /zh/posts/ai-voice-cloning-tools-comparison-review,语音到语音技术背景见 /zh/posts/speech-to-speech-resource。
双语同帧是第二个红利。服务端从两条流给内容:一条 conversation.item.input_audio_transcription.delta 是源语言原文(ASR,官方口径免费),另一条 response.audio_transcript.delta 是译文文本,两者时间上对齐、天然同帧同出,你无需自己做对齐。对会议纪要意味着:原文与译文按时间戳并排落盘,事后无论用源语言还是目标语言关键词都能定位到同一句。长上下文消歧保证人名术语在一小时会议里始终翻成同一词,不出现前半场"李总"后半场"李先生"的漂移。
工程建议两条:第一,每条 delta 的时间戳或序号都写进存储,别等 completed 才落盘,否则断线丢中间段;第二,纪要精修(摘要、待办、归因)别交给同传模型,它不支持函数调用、结构化输出、批处理与微调,这些交给另一个文本模型做下游处理。
五、场景二:跨境直播与视频本地化双语字幕
跨境直播和视频本地化把同帧同出用到另一种形态:字幕。区别在于,会议是双向实时对话,直播常是单向长流,且往往带画面。
视频输入是支持能力:实时视频帧经 input_image_buffer.append 送进去,模型用口型、手势、屏幕文字等视觉信息辅助消歧,在嘈杂或歧义环境更稳。约束是速率与体积:建议每秒不超 2 张图、单张 Base64 前不超 500KB、格式 JPG/JPEG、且必须先发音频。画面是消歧锦上添花,不是主输入,别逐帧猛灌。
字幕落地三件事:分片、时间戳对齐、译文字幕输出。分片沿用服务端 delta 粒度,无需客户端切固定时长;时间戳对齐利用同源流式返回,原文与译文共享时间线,把每条 delta 到达时刻记下即可生成带时间轴字幕。译文字幕把 response.audio_transcript.delta 累积成句、配时间码写 SRT 或 WebVTT;要保留原声对照,把 conversation.item.input_audio_transcription.delta 并排写入另一轨道。
误区:有人想"整段视频离线翻完再上架",那更适合离线转写翻译流水线,而非实时同传。实时同传适合直播、适合边播边出双语字幕的现场感。云端与本地语音方案取舍见 /zh/posts/cloud-vs-local-voice-ai-review,同类实时翻译资源汇总见 /zh/posts/hibiki-resource。直播提醒两条:第一,公网延迟与观众地理位置强相关,尽量选近地域端点并用服务端中转稳定链路;第二,译文语音默认 24kHz PCM,喂给网页 <audio> 前需解码成可播格式,这一步别漏。
六、延迟与成本优化
先把 2.3 秒放回该在的位置:这是字均延迟 LAAL 的官方口径,是译文相对源语音的平均滞后,不是端到端首包延迟,也别外推成"任何一句都只慢 2.3 秒"。真实体验延迟是下面四段相加。
| 阶段 | 含义 | 你能在工程上影响的程度 |
|---|---|---|
| 音频采集 | 麦克风采样与本地前处理 | 高:选低延迟采集、减小本地缓冲、避免额外重采样 |
| 网络传输 | 上行音频到服务端、下行译文返回 | 中:就近地域、服务端中转、用稳定链路替代浏览器直连 |
| 模型推理 | Interleave 架构同传延迟,官方口径 LAAL 2.3 秒 | 低:由模型决定,可用流式输出摊薄等待感 |
| 播放 | 译文语音解码与扬声器输出 | 中:边收边播、不要等整段到齐再放 |
定位瓶颈的正确姿势,是把延迟按这四段分别打点:采集端记推帧时刻,收到首个 response.audio.delta 记模型出声时刻,扬声器真正播出记可听时刻。采集到出声长,先看网络和模型;出声到可听长,问题在你的播放管线。一慢就怪模型,是把不属于它的账算到它头上。
分片与缓冲:别为省流量把音频攒大块再发,大块会人为造延迟;按建议帧大小持续推送,让 speaker_detection 自然断句。播放端边收边播,收到 delta 立刻解码入队,而非等 response.done 才动。
并发与限流:官方文档给出默认配额口径(例如常见每分钟请求数与每分钟令牌数),但具体数值随地域、账号、活动变动,一律以千问 AI 平台与阿里云百炼官方文档及控制台显示为准,不凭记忆写死。关键认知:默认 RPM 对单人试用绰绰有余,但要做给整个旅行团或整场直播用的服务,第一晚就可能被自己并发打爆。多房间多流场景请提前评估配额并向官方申请提额。
成本:官方按令牌计费,音频输入输出各有每秒令牌消耗口径(常见输入约 7 令牌/秒、输出约 12.5 令牌/秒),具体单价与地域(如北京、新加坡)以官方文档为准。它不支持函数调用、结构化输出、批处理、微调与联网搜索,所以同传只产出译文文本与译文语音,下游摘要、术语强制、CRM 回写请交给别的文本模型。设计时把翻译与后续处理切成两层,互不拖累。
七、踩坑速查与上线检查清单
六条最常踩的坑:
- 把 2.3 秒当成首包延迟承诺给用户,现场体验与预期不符。记住它是字均延迟 LAAL。
- 浏览器直连同传服务,发现
Authorization头设不上、连不上。做法是你自己的服务端持密钥建连、前端走自有通道。 - 忘发
session.finish就关连接,最后一段永远丢失。收尾先发session.finish,等session.finished再关。 - 用旧版 LiveTranslate 代码只改模型名跑 qwen3.8,字段对不上(如
modalities与output_modalities、voice在克隆开启时失效)。逐字段核对官方文档。 - 以为 60 种都能语音互译,结果目标语言只在能识别的 60 里、不在能出声的 29 里,只拿到文本没语音。先查表。
- 把音频攒大块再发或用本地额外重采样,人为把延迟做高。持续小帧推送、减少本地缓冲。
上线前检查清单(逐条确认):
- API Key 仅来自环境变量或密钥管理系统,未写进源码、未进仓库、未进前端 bundle
- 已把
.env等密钥文件加入.gitignore,CI 里也不打印完整 Key - 如发生泄露,已规划"吊销旧 Key、重建新 Key、轮换服务"的标准流程
- 服务端持密钥建连,前端通过自有通道收发音频,未尝试浏览器直连带鉴权头
- 已确认目标语言在 29 个支持语音输出的语种内(而非仅在 60 个识别语种内)
- 已发送
session.update且目标语种必填,源语种按需设置或留空自动识别 - 音频按 16kHz/16bit/单声道 PCM 采集并 Base64 后
input_audio_buffer.append - 视频帧(如用)遵守每秒不超 2 张、单张不超 500KB、先发音频的约束
- 关闭前发送
session.finish并等待session.finished再断开 - 已把延迟按采集、网络、模型、播放四段分别打点定位瓶颈,并评估默认配额是否满足并发
常见问题
Q1:2.3 秒是端到端首包延迟吗?能不能外推成每一句都只慢 2.3 秒?
A1:不是。2.3 秒是字均延迟(LAAL,Length-Adaptive Average Lagging)的官方口径,表示译文整体相对源语音的平均滞后,不是"你说第一个字后 2.3 秒出声"的首包延迟,也不应外推到单句。真实可听延迟要把音频采集、网络传输、模型推理、播放四段加起来看。
Q2:模型说支持 60 种语言,是不是 60 种都能语音互译?
A2:不是同一口径。60 种是识别输入(能听懂),其中只有 29 种支持语音输出(能念出来),其余 31 种只出文本、不出声音。接入前先确认目标语言在不在那 29 个能出声的语种里。
Q3:前端网页能直接用 WebSocket 连同传服务吗?
A3:不能。浏览器在 WebSocket 握手时无法自行设置 Authorization 请求头,所以不能把 API Key 放前端直连。正确架构是你自己的服务端持有密钥并与同传服务建连,浏览器通过自有信令通道收发音视频。这也是密钥不进前端的安全要求。
Q4:怎么开启"译文用原说话人声音念出来"的音色克隆?
A4:在 session.update 里把 enable_voice_clone 设为 true,并按需设 voice_clone_options.frequency:never 用预克隆档案、once 会话开始克隆一次、always 每次响应前重新克隆(多人场景推荐)。开启后预设系统音色失效,需把 voice 设为 default 或已克隆音色 ID。字段名以官方文档为准。
Q5:Qwen3.8-LiveTranslate 开源吗?能下载权重本地部署吗?
A5:不开源,也没有公开代码仓或权重下载,它是通过千问 AI 平台与阿里云百炼提供的 API 服务。所有调用走官方托管 WebSocket 实时接口,无法在本地自行部署该模型本身。