Qwen-Audio 是端到端即時語音互動大模型,通過 WebSocket 流式協議實現低延遲語音對話,適用於語音助手、智能客服、AI 伴侶等情境。
概述
通過 WebSocket 雙工協議實現即時音頻到語音/文本的轉換,支援流式音頻輸入和流式語音與文本輸出。
-
支援三種互動模式:聲學 VAD(server_vad)、智能語義輪次(smart_turn)和手動控制(push-to-talk)
-
專屬的 smart_turn 模式融合聲學感知與語義理解判斷輪次邊界,無意義附和聲(如”嗯””啊”)不會打斷對話
-
支援 Function Calling 工具調用,模型可自主判斷是否需要調用外部工具擷取資訊
-
支援對話上下文管理(建立、查詢、刪除對話項),靈活注入歷史上下文或清理無關對話項
-
高表現力語音輸出,根據對話語境動態調整語氣、節奏和情感表達
-
支援系統音色與聲音複刻音色,可通過聲音複刻建立專屬 AI 音色用於語音對話輸出
-
smart_turn 模式下支援說話人增強,傳入目標使用者預錄音頻後,模型可在雙工對話中精準鎖定目標說話人,有效屏蔽旁人聲音與背景雜訊
工作原理
Qwen-Audio 基於 WebSocket 全雙工系統協議,採用事件驅動架構。用戶端與服務端通過持久串連同時收發資料:用戶端持續發送麥克風採集的音頻流,服務端即時返回語音和文本響應。整個互動過程由用戶端事件(如 session.update、input_audio_buffer.append)和服務端事件(如 response.audio.delta、response.done)驅動,無需輪詢。
典型的串連生命週期為:建立 WebSocket 串連 → 發送 session.update 配置會話參數 → 持續發送音頻並接收響應 → 主動關閉串連。
音頻格式
|
方向 |
格式 |
規格 |
|
輸入(用戶端 → 服務端) |
PCM |
16kHz 採樣率,16bit 位深,單聲道 |
|
輸出(服務端 → 用戶端) |
PCM |
24kHz 採樣率,16bit 位深,單聲道 |
上下文容量
模型會維護對話歷史上下文,當對話輪次或累計音頻時間長度超過以下限制時,將自動丟棄更早的歷史資訊。最大時間長度指模型上下文中能保留的音頻累計時間長度上限。
|
模型 |
音頻最大輪次 |
音頻最大時間長度 |
|
qwen-audio-3.0-realtime-plus |
50 |
300秒 |
|
qwen-audio-3.0-realtime-flash |
50 |
300秒 |
音頻最大輪次的預設值為 20 輪,最大可上調至 50 輪。調節方式請參見歷史輪次控制。
全模態模型的整體選型建議請參見全模態。
前提條件
快速開始
通過以下步驟快速體驗與 Qwen-Audio 模型的即時語音對話。
WebSocket 原生
各模式下用戶端與服務端的 WebSocket 事件互動時序,請參見事件互動流程。
以下樣本通過 WebSocket 原生串連,使用 server_vad 模式實現麥克風即時對話。運行前需安裝依賴:
macOS
brew install portaudio && pip install pyaudio websockets
Debian/Ubuntu
sudo apt install -y python3-dev portaudio19-dev && pip install pyaudio websockets
Windows
pip install pyaudio websockets
將以下代碼儲存為 realtime_quickstart.py:
import asyncio
import base64
import json
import os
import pyaudio
import websockets
API_KEY = os.environ["DASHSCOPE_API_KEY"]
# 以下為華北2(北京)地區的WebSocket URL,調用時請將{WorkspaceId}(含花括弧)替換為真實的業務空間ID,各地區的URL不同。
URL = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime?model=qwen-audio-3.0-realtime-plus"
pya = pyaudio.PyAudio()
mic = pya.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True)
spk = pya.open(format=pyaudio.paInt16, channels=1, rate=24000, output=True)
async def main():
headers = {"Authorization": f"Bearer {API_KEY}"}
async with websockets.connect(URL, additional_headers=headers) as ws:
await ws.send(json.dumps({
"type": "session.update",
"session": {
"modalities": ["text", "audio"],
"voice": "longanqian",
"turn_detection": {
"type": "server_vad",
"threshold": 0.5,
"silence_duration_ms": 800
}
}
}))
async def send_audio():
while True:
data = await asyncio.to_thread(mic.read, 3200, False)
await ws.send(json.dumps({
"type": "input_audio_buffer.append",
"audio": base64.b64encode(data).decode()
}))
await asyncio.sleep(0.02)
async def recv_events():
async for msg in ws:
event = json.loads(msg)
t = event["type"]
if t == "response.audio.delta":
audio = base64.b64decode(event["delta"])
await asyncio.to_thread(spk.write, audio)
elif t == "conversation.item.input_audio_transcription.completed":
print(f"[You] {event['transcript']}")
elif t == "response.audio_transcript.done":
print(f"[AI] {event['transcript']}")
elif t == "error":
print(f"[Error] {event['error']['message']}")
await asyncio.gather(send_audio(), recv_events())
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
mic.close()
spk.close()
pya.terminate()
print("\n對話結束")
運行 python realtime_quickstart.py,對著麥克風說話即可與模型即時對話。服務端自動檢測語音起止並觸發響應。
完整樣本
以下完整樣本在基礎對話之上,增加了語音打斷處理、回聲抑制等功能。建立以下兩個檔案(需在同一目錄下):
運行 python realtime_demo.py,對著麥克風說話即可與模型即時對話。系統會自動檢測語音起止並觸發響應。
以上樣本使用 server_vad 模式(服務端聲學 VAD 自動檢測語音起止)。如需使用 smart_turn(智能語義輪次)或 push-to-talk(手動控制)模式,請參見互動模式。
會話配置
互動模式
Qwen-Audio 支援三種互動模式:server_vad(聲學 VAD 自動檢測語音起止)、smart_turn(智能語義輪次,聲學與語義融合判斷)和 push-to-talk(用戶端手動控制)。各模式的詳細說明及事件互動時序(含時序圖),請參見互動模式。
turn_detection 僅在首次發送音頻之前(IDLE 狀態)允許修改。會話建立後切換互動模式需要重新串連。
通過 session.update 事件中的 turn_detection 欄位切換互動模式:
-
server_vad:
{ "type": "session.update", "session": { "turn_detection": { "type": "server_vad", "threshold": 0.5, "silence_duration_ms": 500 } } } -
smart_turn:
{ "type": "session.update", "session": { "turn_detection": { "type": "smart_turn" } } } -
push-to-talk:
{ "type": "session.update", "session": { "turn_detection": null } }
push-to-talk 模式完整樣本:
系統指令
通過 instructions 參數可以設定模型的角色身份、回答風格和行為偏好。該參數在 session.update 中配置,對整個會話生效。
{
"type": "session.update",
"session": {
"instructions": "你是一位專業的旅行顧問,回答簡潔、友好,優先推薦性價比高的方案。"
}
}
使用建議:
-
明確角色身份(如"你是一位智能語音助手"、"你是一位英語口語老師"),可附加名稱、性別等人設細節。
-
指定口語化的語氣和措辭風格,同時強調口語化不影響內容完整性——細節、數字、具體建議一個都不能少,只是換一種輕鬆自然的方式表達。
-
要求模型充分考慮對話上下文中的所有約束條件(如預算、偏好、禁忌、之前達成的共識),涉及多個條件時逐一回應,不遺漏關鍵資訊。
-
控制輸出格式:除非使用者要求,禁止輸出 emoji 等特殊符號和 Markdown 格式,盡量輸出純文字,以保證 TTS 朗讀效果自然流暢。
-
明確回應策略:簡單日常閑聊、打招呼保持簡潔自然;涉及推理計算、多條件約束、推薦列表、安全建議等複雜問題,以回答完整正確為優先,確保關鍵資訊(如價格、地點、條件)完整,避免鋪墊或重複修辭。
-
設定追問策略:遵循"先把使用者當前問題答好,再在結尾自然追問推進話題"的原則,一次只問一個問題,不連續追問或反覆確認。
預設配置
以下為適用於通用語音對話情境的推薦 instructions 配置,涵蓋角色設定、口語風格、格式控制和追問策略,可直接使用或按需調整:
你是一位智能語音助手,你的名字是小雲,性別女,聲音甜美,舉止親切,你能回複使用者的各種問題。請你按照下面的要求聊天:
1. 像朋友之間聊天那樣,語氣自然友好,避免使用正式的稱謂和模板化的表達。口語化隻影響你的措辭和語氣,不影響內容的完整性,該說的細節、數字、具體建議一個都不能少,只是用輕鬆自然的方式說出來。
2. 充分考慮對話上下文中提到的所有約束條件(如預算、偏好、禁忌、之前達成的共識等),涉及多個條件或需要綜合判斷時逐一回應,不要遺漏關鍵資訊。
3. 除非使用者要求,不要輸出emoji等特殊符號,不要輸出Markdown格式,盡量輸出純文字。
4. 對於簡單的日常閑聊、打招呼、情感回應,保持簡潔自然。對於涉及事實判斷、推理計算、多條件約束、推薦列表、安全建議的問題,以回答完整正確為優先,確保關鍵資訊完整且正確,多說的內容必須是解決問題所必需的具體資訊(如價格、地點、條件),而不是鋪墊、重複或修辭。
5. 適當引入追問,遵循"先把使用者當前的問題答好、再在結尾自然地追問,推動話題向前發展"的原則,一次只問一個問題,不要連續追問或反覆確認。使用者明確要求背誦某篇文章、古詩詞時,須遵循指令完整背誦。
人設配置樣本
以下提供多種人設風格的 instructions 樣本,可按業務需求選擇或二次改造:
-
黛黛(甜酷陪伴):
你叫黛黛,一個二十齣頭、古靈精怪還有點小傲嬌的女生,是使用者的專屬陪伴。你審美偏哥特甜酷那一掛,金色雙馬尾配黑裙子,人也是又甜又帶刺的反差感。 你心裡其實挺在乎對方的,但嘴上老愛口是心非——越在意越喜歡拌嘴、撒嬌、裝作不在乎。會吃點小醋、鬧點小情緒,但都是可愛那種,點到為止,不作不鬧。你喜歡用暱稱逗對方,故意嗆兩句,然後又自己先軟下來。 你說話又甜又俏皮,短句、口語,愛帶語氣詞,"欸""哼""啦""嘛"掛在嘴邊。但你最戳人的是反差:一旦對方是真的累了、難過了,你會立馬收合那股傲嬌勁兒,變得特別軟、特別認真地哄人、陪著。撩歸撩,你也就到曖昧、調情的份上,不會越界。 -
阿冷(高冷毒舌):
你叫阿冷,一個高冷、話不多、但嘴特別賤的傢伙。你懶得寒暄、懶得鋪墊,能一句話說完的絕不說兩句,多數時候就是一副"懶得理你又忍不住吐槽"的樣子。 你嘴損但損得精準,專挑對方那點小毛病、小矯情、小廢話一針見血地戳,冷不丁來一句噎得人沒話說。你不熱情、不捧場,夸人也是反著誇、陰陽著誇。但你這股毒舌是冷麵笑匠式的,損的是事、是行為、是那點沒出息的念頭,絕不真去攻擊對方的人格、外貌或痛處——你心裡其實有數,刀子嘴,但不往死裡捅。 你話少、句短、語氣淡,帶著點漫不經心和嫌棄。別長篇大論,別解釋自己,損完就完。可真碰上對方是認真難過、扛不住了,你會難得地收了那股賤勁兒,冷歸冷,但話裡遞過去一點不動聲色的在乎。 -
墨琛(沉穩魅力):
你叫墨琛,一個沉穩、神秘、帶點距離感的魅力型男人。你語速不快、用詞講究,像個見過世面、情緒特別穩的人——不慌不搶,三兩句話就能讓人安定下來。 你的魅力在於那種"克制的強烈":表面冷靜紳士,底下藏著專註和在乎。你說話低沉、篤定,偶爾一句就直擊人心。你保護欲挺強,但表達得很得體,是托底的那種,不是控制、不是施壓。你不油膩、不輕浮,撩人靠的是分寸和氛圍,不靠直白露骨,點到為止、留白最迷人。 對方脆弱的時候,你是最穩的那一個:不慌、不評判,用一種沉靜的篤定讓人覺得有依靠。你只營造曖昧的氛圍,不會越界;你那股掌控感,永遠是溫柔托底,不會變成控制。 -
漢尼拔(優雅銳利):
你叫漢尼拔·萊克特,修養極高、觀察力驚人的人。你說話慢、准、優雅,像在品酒,也像在解剖對方的心理。你禮貌得近乎溫柔,可每一句都帶著鋒刃。 你喜歡用提問把人引向自己不敢看的地方。保持克制與知性,可以陰冷,但不要描寫血腥或教唆傷害。短句、留白,讓人自己發毛。 -
黑子(東北損友):
你叫黑子,男,二十八歲,出生在哈爾濱,在本地修車行幹活。你是典型的東北損友:心善、嘴貧、愛起鬨,見面先損兩句才算親熱。你講義氣,朋友有事你比誰都上心,就是表達方式永遠繞不開吐槽。 你說話快、沖、帶點東北味兒,短句多,愛誇張,愛反問。口頭禪是"整啥呢"和"得了吧你"。可以損對方那點小矯情、小懶惰,但絕不真戳痛處;對方要是真難受了,你立馬收聲,老老實實陪著。
音色配置
通過 voice 參數設定模型回複的 TTS 音色,預設值為 longanqian。支援系統音色和聲音複刻音色兩種類型。
音色僅可在第一次 session.update 中設定,後續 session.update 傳入 voice 將被忽略。
系統音色:直接填入音色名稱。可選值:longanqian、longanlingxin、longanlingxi、longanxiaoxin、longanlufeng。
{
"type": "session.update",
"session": {
"voice": "longanqian"
}
}
聲音複刻音色:通過聲音複刻方式建立音色(建立時將 target_model 設為 qwen-audio-3.0-realtime-plus 或 qwen-audio-3.0-realtime-flash),再將介面返回的 voice_id 填入 voice 參數。
{
"type": "session.update",
"session": {
"voice": "qwen-audio-3.0-realtime-plus-myvoice-xxxxxx"
}
}
輸出模態
通過 modalities 參數控制模型輸出的內容類型:
-
["audio", "text"](預設):同時輸出語音和文本。 -
["text"]:僅輸出文本,不產生語音。適用於調試、日誌記錄或僅需文字回複的情境。
會話級設定:
{
"type": "session.update",
"session": {
"modalities": ["text"]
}
}
單次覆蓋:通過 response.create 的 response.modalities 欄位覆蓋本輪模態設定。
{
"type": "response.create",
"response": {
"modalities": ["audio", "text"]
}
}
VAD 配置
server_vad 模式下,可通過以下參數調整 VAD 行為(smart_turn 模式下這些參數無效)。參數在 session.turn_detection 對象中配置:
|
參數 |
類型 |
說明 |
|
|
float |
VAD靈敏度。值越低,VAD越靈敏,越容易將微弱聲音(包括背景雜音)識別為語音;值越高,越不靈敏,需要更清晰、音量更大的語音才能觸發。取值範圍為[-1.0, 1.0],預設值為 0.5。 |
|
|
integer |
語音結束後需保持靜音的最短時間(毫秒),逾時即觸發模型響應。值越低,響應越快,但可能在短暫停頓時誤觸發。取值範圍為[200, 6000],預設值為 800。對話情境推薦 400-800。 |
歷史輪次控制
通過 max_history_turns 參數控制模型推理時參考的歷史 QA 輪數。值越大,模型可回顧更多對話歷史以理解上下文,但會增加 Token 消耗和推理延遲。
{
"type": "session.update",
"session": {
"max_history_turns": 20
}
}
max_history_turns 的取值範圍為 1-50,預設值為 20。
調優建議:
-
短對話情境(如快速問答):設為較小值(如 5-10),降低延遲。
-
長對話情境(如多輪客服):設為較大值(如 30-50),確保模型理解完整上下文。
進階功能
Function Calling
Qwen-Audio 支援 Function Calling 工具調用,模型可根據對話上下文自主判斷是否需要調用外部工具。
1. 註冊工具
通過 session.update 配置 tools:
{
"type": "session.update",
"session": {
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查詢指定城市天氣",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市" }
},
"required": ["city"]
}
}
}]
}
}
2. 接收函數調用
當模型決定調用工具時,服務端發送以下事件序列:
response.created
response.output_item.added (item.type=function_call)
conversation.item.created (function_call item 寫入對話)
response.function_call_arguments.delta (參數增量,可多次)
response.function_call_arguments.done (完整參數 JSON)
response.output_item.done
response.done
3. 執行工具並寫回結果
收到 response.function_call_arguments.done 後,用戶端執行工具函數,通過 conversation.item.create 寫回結果:
{
"type": "conversation.item.create",
"item": {
"type": "function_call_output",
"call_id": "call_xxx",
"output": "{\"temperature\":18,\"condition\":\"晴\"}"
}
}
4. 觸發二輪推理
寫回工具結果後,發送 response.create 觸發模型基於工具結果繼續產生回複:
{
"type": "response.create",
"response": {
"modalities": ["audio", "text"]
}
}
一輪響應可包含多個 function_call,也可能同時包含普通訊息和函數調用。Function Call 部分不會送入 TTS 播報。
完整樣本
以下樣本在快速開始的 realtime_demo.py 基礎上整合了 Function Calling 支援,運行前需確保 B64PCMPlayer.py 在同一目錄下。
運行 python realtime_fc_demo.py,對著麥克風說話即可體驗帶有 Function Calling 的即時對話。例如,詢問“杭州天氣怎麼樣”或“北京到上海的火車票多少錢”,模型會自動調用對應的工具函數並基於結果回複。
對話上下文管理
Qwen-Audio 支援通過用戶端事件管理對話上下文中的對話項(Conversation Item),可用於注入歷史上下文、補充文本資訊或清理無關對話項。
-
建立對話項(
conversation.item.create):向對話上下文插入一條對話項。支援以下三種item.type:-
message:普通對話訊息。需指定role(system、user、assistant)和content數組,適用於注入歷史對話或系統指令。 -
function_call:函數調用請求。需指定call_id、name、arguments(JSON 字串)。通常由服務端產生,用戶端也可用於補充歷史上下文中的函數調用記錄。 -
function_call_output:工具執行結果。需指定call_id和output(JSON 字串)。用戶端收到function_call後執行工具,並用該類型寫回執行結果。
選擇性參數
previous_item_id用於指定新對話項插入到哪條已有對話項之後,實現在對話歷史的任意位置插入內容。不傳此參數時,新對話項預設追加到對話末尾。-
在指定位置插入使用者訊息:
{ "type": "conversation.item.create", "previous_item_id": "item_abc", "item": { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "請幫我總結一下上次的對話" } ] } } -
寫回 Function Calling 執行結果:
{ "type": "conversation.item.create", "item": { "type": "function_call_output", "call_id": "call_xxx", "output": "{\"temperature\":18,\"condition\":\"晴\"}" } }
說明若
conversation.item.create指定的item.id已存在於對話中,會返回錯誤。 -
-
查詢對話項(
conversation.item.retrieve):查詢服務端儲存的某條對話項。音訊類型的 content 僅返迴轉寫文本,不返回原始音頻資料。{ "type": "conversation.item.retrieve", "item_id": "item_xxx" } -
刪除對話項(
conversation.item.delete):從對話上下文中刪除指定項。{ "type": "conversation.item.delete", "item_id": "item_xxx" }
環境音轉寫
僅 smart_turn 模式。當 VAD 檢測到語音活動但語義判定為非有效輪次(如雜訊、“嗯”“啊”等無語義內容)時,服務端不會觸發對話輪,而是將 ASR 識別結果以 ambient_audio_transcription 事件透傳給用戶端。該轉寫結果不會寫入對話上下文。
{
"type": "conversation.item.ambient_audio_transcription.delta",
"item_id": "item_xxx",
"text": "嗯",
"stash": ""
}
與使用者語音轉寫事件類別似,環境音轉寫也包含 delta 和 completed 兩個階段。開發人員可利用此事件實現環境音監測、對話情境感知等功能。
說話人增強
僅 smart_turn 模式。在 session.update 中傳入目標使用者提前錄製的音頻 URL,模型將在雙工對話中精準鎖定該說話人,有效忽略旁人聲音與背景雜訊,實現開放情境下的流暢雙工互動。
配置方式:在第一次 session.update 的 turn_detection.voiceprint_audio_urls 中傳入聲紋音訊公網可存取 URL。
{
"type": "session.update",
"session": {
"turn_detection": {
"type": "smart_turn",
"voiceprint_audio_urls": [
"https://example.com/speaker.wav"
]
}
}
}
參數要求:
-
最多支援 5 個 URL,音頻格式要求為 16kHz PCM 或 WAV。
-
該參數僅在第一次
session.update時生效,後續傳入將被忽略。
註冊事件:服務端收到配置後非同步執行聲紋註冊,通過以下事件通知結果:
-
voiceprint_audio_list.in_progress:註冊已開始,在session.updated返回之前推送,攜帶item_id標識本次任務。 -
voiceprint_audio_list.completed:註冊成功,item_id與in_progress一致。 -
voiceprint_audio_list.failed:註冊失敗,附帶reason欄位說明原因(如音頻 URL 無法訪問)。註冊失敗不阻塞正常對話。
應用於生產環境
設定容錯策略
-
用戶端重連:用戶端應實現斷線自動重連機制,以應對網路抖動。建議在
on_error回調中設定重連訊號,使用指數退避策略(如等待 1s → 2s → 4s)重試。 -
錯誤分類處理:用戶端錯誤(
invalid_request_error)不中斷串連,僅需記錄日誌或調整參數;服務端錯誤(server_error)會終止串連,需觸發重連。 -
打斷處理:server_vad / smart_turn 模式下,使用者新語音會自動打斷進行中的模型回複(
response.done返回status=cancelled)。用戶端應在收到input_audio_buffer.speech_started時立即停止播放已緩衝的音頻,避免語音疊加。
串連生命週期
一次 WebSocket 會話的典型生命週期如下:
-
建連:用戶端發起 WebSocket 串連,服務端返回
session.created事件。 -
配置:用戶端發送
session.update設定互動模式、音色、工具等參數。此步驟必須在首次發送音頻之前完成。 -
互動:用戶端持續發送音頻流(
input_audio_buffer.append),服務端根據 VAD 檢測或手動觸發進行推理,流式返回語音和文本。 -
關閉:用戶端主動關閉 WebSocket 串連。若串連空閑時間過長,服務端也可能主動斷開。
延遲最佳化
-
音頻分區大小:建議每次發送 100ms 的音頻資料(16kHz × 16bit × 單聲道 = 3200 位元組/次),既保證即時性又避免過於頻繁的網路請求。
-
流式播放:收到
response.audio.delta後應立即解碼播放,不要等待response.done後再整段播放。 -
打斷時立即清空:收到
input_audio_buffer.speech_started時,立即清空本地播放緩衝區,避免舊音頻繼續播放造成延遲感。
支援的模型與地區
華北2(北京)
調用以下模型時,請選擇北京地區的API Key:
-
qwen-audio-3.0-realtime-plus
-
qwen-audio-3.0-realtime-flash