Skip to content

Qwen Audio 实时语音 ​

qwen-audio-3.0-realtime-plus 和 qwen-audio-3.1-realtime-plus 支持通过 WebSocket 持续发送文本或音频,并接收流式语音、文本和工具调用事件。实际可用性以账户权限和平台配置为准。

连接与鉴权 ​

text
wss://cubicspaces.cloud/v1/realtime?model=qwen-audio-3.0-realtime-plus
wss://cubicspaces.cloud/v1/realtime?model=qwen-audio-3.1-realtime-plus

握手时携带 Authorization: Bearer <CUBICSPACES_API_KEY>。这是 WebSocket 接口,请勿发送普通的 Chat Completions 请求。

Python 示例在服务端运行。浏览器原生 WebSocket 无法设置任意握手请求头;网页语音应用可由自己的后端建立连接并转发事件,平台 API Key 保存在后端。

可运行的完整示例 ​

下载 qwen_realtime.py,安装 pip install websocket-client,然后设置环境变量。PowerShell 示例:

powershell
$env:CUBICSPACES_API_KEY = "你的平台 API Key"
python qwen_realtime.py --text "你好,请简短介绍自己。"
python qwen_realtime.py --model qwen-audio-3.1-realtime-plus --text "你好,请简短介绍自己。"
python qwen_realtime.py --mode audio --input question.wav --output answer.wav
python qwen_realtime.py --mode search --text "请联网查询杭州今天的天气,并给出来源。"
python qwen_realtime.py --mode function

macOS / Linux 使用 export CUBICSPACES_API_KEY='你的平台 API Key' 设置变量。脚本支持文本转语音、音频文件转语音、联网搜索、真实客户端函数调用四种模式,输出为可直接播放的 24 kHz WAV。函数示例实际执行 17 + 25,把 42 回传给模型后接收语音回答;搜索和函数模式使用独立连接。

音频文件模式要求 16 kHz、单声道、16 位 PCM WAV。可先转换录音:

bash
ffmpeg -i recording.wav -ar 16000 -ac 1 -c:a pcm_s16le question.wav

脚本会读取 WAV 中的 PCM 数据,按每 20 ms 一块发送,不发送 WAV 文件头。它是文件输入示例;实时麦克风应用需要持续采集音频,并同时接收事件、播放音频。

文本输入与语音输出示例 ​

两个版本使用相同的 WebSocket 事件协议。3.0 Plus 的默认音色为 longanqian,3.1 Plus 为 longanqian_v3.1。脚本的 --model 参数会选择相应默认音色,也可以用 --voice 指定音色。voice 只能在首次 session.update 中设置,后续修改会被忽略。

将下面的 3.0 示例迁移到 3.1 时,把 URL 中的模型改为 qwen-audio-3.1-realtime-plus,并把音色改为 longanqian_v3.1。输入仍为 16 kHz PCM,输出仍为 24 kHz PCM。

安装 websocket-client,在环境变量 CUBICSPACES_API_KEY 中设置平台 API Key:

bash
pip install websocket-client
python
import base64
import json
import os
import websocket

url = "wss://cubicspaces.cloud/v1/realtime?model=qwen-audio-3.0-realtime-plus"
ws = websocket.create_connection(
    url,
    header={"Authorization": "Bearer " + os.environ["CUBICSPACES_API_KEY"]},
    timeout=60,
)

def send(event):
    ws.send(json.dumps(event))

try:
    with open("reply.pcm", "wb") as audio:
        while True:
            event = json.loads(ws.recv())
            kind = event.get("type")
            if kind == "session.created":
                send({"type": "session.update", "session": {
                    "modalities": ["text", "audio"],
                    "voice": "longanqian",
                    "instructions": "请简短回答。",
                    "turn_detection": {"type": "smart_turn"}
                }})
            elif kind == "session.updated":
                send({"type": "conversation.item.create", "item": {
                    "type": "message", "role": "user",
                    "content": [{"type": "input_text", "text": "你好"}]
                }})
                send({"type": "response.create"})
            elif kind == "response.audio.delta":
                audio.write(base64.b64decode(event["delta"]))
            elif kind in ("response.text.delta", "response.audio_transcript.delta"):
                print(event.get("delta", ""), end="", flush=True)
            elif kind == "response.done":
                print("\nResponse status:", event["response"].get("status"))
                break
            elif kind == "error":
                raise RuntimeError(event.get("error"))
finally:
    ws.close()

输出文件是 24 kHz、16 位、单声道裸 PCM,不包含 WAV 文件头。播放示例:

bash
ffplay -f s16le -ar 24000 -ac 1 reply.pcm

音频输入 ​

输入必须是 16 kHz、16 位、单声道 PCM,每块音频以 Base64 编码,通过 input_audio_buffer.append 发送。输入和输出采样率不同,客户端需按方向分别处理。

json
{"type":"input_audio_buffer.append","audio":"<Base64 PCM>"}

使用 server_vad 或 smart_turn 时,由服务自动检测说话结束。在手动模式下,首次 session.update 设置 turn_detection: null;发送音频后依次发送:

json
{"type":"input_audio_buffer.commit"}
{"type":"response.create"}

上述两行是两条独立的 WebSocket 消息。turn_detection 应在发送第一块音频前设置。

事件与工具调用 ​

  • session.created / session.updated:会话创建或配置完成。
  • response.audio.delta:Base64 音频分块。
  • response.audio_transcript.delta / response.text.delta:增量文本。
  • response.function_call_arguments.delta / .done:工具参数增量或完成。客户端执行工具后,用 conversation.item.create 提交 function_call_output,再发送 response.create。
  • response.done:本轮结束;检查 response.status,区分 completed、cancelled 和 failed。
  • error:错误详情位于 error 对象中。

音频、文本、VAD、工具调用和自定义事件字段保持原始格式;显式的 false、0 和 null 不会在转发时被移除。response.cancel 用于取消正在进行的回复。收到新的用户语音或取消事件后,客户端应清空尚未播放的旧音频。

此接口提供 WebSocket 接入,不提供 WebRTC 或 AOQ 连接。

打断与继续对话 ​

回复进行中发送 response.cancel,会收到 status: cancelled、status_details.reason: client_cancelled 的 response.done。连接保持可用,可以提交下一条消息并发送 response.create。

在 server_vad 模式下,回复过程中检测到新的用户语音也会取消当前回复,原因为 turn_detected;随后继续处理新语音并自动生成下一轮回复。客户端应在检测到插话时立即停止播放并清空旧音频队列。

取消事件可能不含 usage,客户端不要将其误判为连接失败,也不要假设每个 response.done 都有该字段。

主动取消并继续对话的消息顺序如下。先发送第一条,等待当前回复的 response.done 确认取消,再发送后两条:

json
{"type":"response.cancel"}
{"type":"conversation.item.create","item":{"type":"message","role":"user","content":[{"type":"input_text","text":"换个话题,请只回答好的。"}]}}
{"type":"response.create"}

自动插话模式在首次配置中设置:

json
{"type":"session.update","session":{"modalities":["text","audio"],"voice":"longanqian","turn_detection":{"type":"server_vad","silence_duration_ms":500}}}

持续发送麦克风音频;收到 input_audio_buffer.speech_started 时立即停止当前播放,清空待播放队列,并丢弃已经取消的旧回复后续音频。可按音频事件的 response_id 管理每轮队列,避免取消后迟到的旧音频混入新回复。自动模式不需要每次发送 input_audio_buffer.commit 和 response.create;不要在模型正在回复时重复触发生成。

联网搜索与 Function Calling ​

通过 session.update 中的 enable_search: true 启用搜索;需要来源时,同时设置 search_options: {"enable_source": true}。模型自行决定是否搜索,可检查最终响应的 search_info.search_results。搜索结果不保证回答事实准确。

tools 与 enable_search 不能同时启用。工具定义使用 {"type":"function","function":{"name":"...","parameters":{...}}}。客户端执行函数后,通过同一个 call_id 的 function_call_output 回传结果,再发送 response.create。

搜索会话配置示例,等待 session.updated 后再发送问题:

json
{"type":"session.update","session":{"modalities":["text","audio"],"voice":"longanqian","enable_search":true,"search_options":{"enable_source":true}}}

完整 Python 示例中的 --mode function 包含工具声明、完整参数接收、参数检查、函数执行、结果回传和后续语音接收。工具结果中的 output 是 JSON 字符串,call_id 必须取自该次工具调用,不能自行生成。客户端只应执行自己声明并允许的函数。

常见问题 ​

现象检查方法
握手未返回 HTTP 101检查 WebSocket 地址、平台 API Key 和模型使用权限。
音频变速或噪声分别检查输入 16 kHz、输出 24 kHz;均为单声道、16 位小端 PCM,发送时不包含 WAV 文件头。
发送音频后没有回复手动模式需依次 commit 和 response.create;自动模式需发送完整语音并留出静音结束段。
已取消仍播放旧回复取消生成不会清空客户端播放器;停止播放、清空队列并按 response_id 丢弃旧分块。
工具调用后没有最终回答等参数接收完整后执行函数,回传相同 call_id 的 function_call_output,再触发 response.create。

收到 error 时读取错误对象;收到 response.done 时检查状态。连接关闭后重新建立连接会创建新会话,需要重新发送配置;不要将重连当作旧会话自动恢复。