모델

qwen-audio-3.0-realtime-plus

Markdown · JSON

qwen-audio-3.0-realtime-plus

음성과 텍스트를 입력받고 음성 또는 텍스트로 응답하는 실시간 음성 대화 모델입니다. 자연스러운 대화 속도와 도구를 이용한 상호작용을 고려해 설계되었습니다.

모델 소개

이 설명은 모델의 기능을 다룹니다. Ailoot에서 사용할 수 있는 입력, 출력 및 옵션은 아래에 선택한 메서드별로 표시됩니다.

Qwen-Audio-3.0-Realtime-Plus는 실시간 음성 대화를 위한 Alibaba 모델입니다. 음성과 텍스트를 입력받고 오디오와 텍스트로 응답하며, 자연스럽게 말을 주고받는 양방향 대화를 지원합니다. 소리를 나누어 전송하고 수신할 수 있어, 대화가 진행되는 동안 상호작용이 이어집니다.

상대방의 말이 끝났는지 판단하기

발화의 끝을 판단하는 방식은 음성 활동, 의미상의 완결성, 명시적 제어 등 여러 가지입니다. 개발사 서비스에서는 첫 오디오를 전송하기 전에 모드를 선택하며, 대화를 시작한 뒤 변경하려면 새 연결이 필요합니다. 이러한 제어의 지원 여부는 선택한 호출 방식에 따라 달라집니다. 의미 기반 모드는 멈춤과 간투사를 고려하므로, 잠시 머뭇거렸다고 해서 반드시 사용자가 말을 마쳤다고 판단하지는 않습니다. 사용자가 새로 말하면 생성 중인 응답을 중단하고 다음 발화를 반영해 대화를 이어갈 수 있습니다. 의미 기반 모드에서는 선택한 상대방의 음성 샘플에 맞춰 인식을 유도하여 다른 사람의 목소리와 배경 소음에 덜 반응하도록 할 수 있습니다.

지시로 도우미의 역할과 대화 스타일을 정합니다. 음성 표현은 어조, 속도, 감정을 반영할 수 있습니다. 3.0 버전에는 시스템 음성 5개와 음성 샘플을 기반으로 한 목소리가 마련되어 있습니다. 모델은 러시아어를 포함한 11개 언어와 개발사가 명시한 중국어 방언 변형을 지원합니다. 개발사 서비스에서는 세션 설정을 처음 업데이트할 때 목소리를 지정하며, 같은 대화에서 이후에 전달한 새 목소리는 무시됩니다. 이러한 설정을 사용하려면 선택한 호출 방식이 이를 지원해야 합니다.

도구와 대화 기록

함수 호출을 지원합니다. 모델이 필요한 작업을 제시하면 연결된 애플리케이션이 이를 실행하고 결과를 대화로 반환합니다. 이를 통해 실제 데이터를 바탕으로 대화하고 작업 수행 후에도 이어갈 수 있습니다. 음성 도우미는 대화 맥락을 유지하면서 도구의 결과를 활용할 수 있습니다. 개발사의 기능에는 내장 웹 검색도 포함되지만, 선택한 호출 방식이 이를 제공해야 합니다. 한 세션에서 웹 검색과 함수 호출을 동시에 활성화할 수는 없습니다.

기본 대화 기록은 20턴이며, 1~50턴 범위를 설정할 수 있습니다. 누적 오디오는 300초로 제한되며, 제한을 넘으면 오래된 기록 부분이 삭제됩니다. 이는 개별 발화의 길이와 다릅니다. 기록은 대화를 이어갈 때 이전 자료 중 어느 부분을 사용할 수 있는지를 정합니다.

텍스트 컨텍스트와 오디오

공식 컨텍스트 크기는 40 960토큰입니다. 최대 입력 길이는 16 384토큰, 출력은 8192토큰입니다. 추론 모드에도 같은 입력·출력 제한이 명시되어 있으며, 별도로 추론 과정은 1024토큰으로 제한됩니다.

스트리밍 오디오는 16비트 단일 채널 PCM을 사용합니다. 입력 샘플링 주파수는 16kHz, 출력은 24kHz입니다. 텍스트와 오디오 데이터는 하나의 대화에 속합니다. 이 특정 모델의 시각 입력과 이미지 출력은 발표되지 않았으며, 음성, 텍스트, 음성 상호작용에 특화되어 있습니다.

Ailoot · 실시간 음성 GET /v1/realtime?model=qwen-audio-3.0-realtime-plus qwen-audio-3.0-realtime-plus

qwen-audio-3.0-realtime-plus

Alibaba /qwen-audio-3.0-realtime-plus

시작하기

음성과 텍스트를 입력받고 음성 또는 텍스트로 응답하는 실시간 음성 대화 모델입니다. 자연스러운 대화 속도와 도구를 이용한 상호작용을 고려해 설계되었습니다.

허용 입력
텍스트 · 오디오
결과
텍스트 · 오디오

Ailoot에서 사용 가능 · 입력 및 메서드

Ailoot · 실시간 음성 GET /v1/realtime?model=qwen-audio-3.0-realtime-plus
입력
text, audio
출력
text, audio
출력 형식
세션 이벤트
필드유형요건값과 한도기본값
필드query.model유형string요건필수값과 한도
qwen-audio-3.0-realtime-plus
기본값—
필드session.input_audio_format유형string요건선택 사항값과 한도
pcm16, pcm
기본값—
필드session.output_audio_format유형string요건선택 사항값과 한도
pcm16, pcm
기본값—
필드session.instructions유형string요건선택 사항값과 한도
한도 적용 대상: 선택한 세션 정책
기본값—
필드session.max_history_turns유형integer요건선택 사항값과 한도
최솟값: 1
한도 적용 대상: 선택한 세션 정책
기본값—
필드input_audio_buffer.append.audio유형base64_string요건필수값과 한도
입력 콘텐츠: PCM16 모노; 입력 16 kHz, 출력 24 kHz; 비어 있지 않은 짝수 바이트 길이
기본값—
입력 자료 조합

realtime_text_audio

메서드 매개변수와 수명 주기
매개변수명세
매개변수material_types명세text, audio
매개변수required명세null
매개변수optional_controls명세null
매개변수content_type명세WebSocket

수명 주기: exact retained published method

메서드 형식과 ID는 정확합니다. 공급자의 기능 지원과 요청 수락은 별개입니다.

요금

Ailoot 메서드 요금

Ailoot 실시간 음성GET /v1/realtime?model=qwen-audio-3.0-realtime-plus
입력
US$0.0008 / 1K
출력
US$0.0064 / 1K
입력
US$0.0048 오디오 분당
출력
US$0.018 출력 오디오 분당

Ailoot는 요청 전에 예상 금액을 미리 확보합니다. 결과를 받은 뒤 측정된 사용량을 기준으로 최종 요금을 정산합니다. 스트리밍 정산에는 최종 사용량 기록을 사용합니다. 금액 확보와 정산 방식 →

요청 예제

Ailoot · 실시간 음성

Python WebSocket · 텍스트Python WebSocket · 오디오
# Install the documented client once: python3 -m pip install websockets
import base64, json, os, time, wave
from pathlib import Path
from websockets.sync.client import connect

key = os.environ.get("AILOOT_API_KEY", "")
if not key.strip():
    raise SystemExit("Set your AILOOT_API_KEY before connecting")
file = Path(os.environ.get("AILOOT_TEXT_FILE", ""))
if not file.is_file(): raise SystemExit("Set AILOOT_TEXT_FILE to your actual UTF-8 material")
material = file.read_text(encoding="utf-8")
if not material.strip(): raise SystemExit("Text material must not be empty")
out = Path("realtime-results")
out.mkdir(exist_ok=True)
audio, texts, complete = {}, {}, []
current_response = None
pending = False
deadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.

def receive(ws, log):
    global current_response, pending
    left = deadline - time.monotonic()
    if left <= 0:
        raise TimeoutError("Client session limit; preserve IDs and partial results, do not replay")
    event = json.loads(ws.recv(timeout=min(60, left)))
    log.write(json.dumps(event, ensure_ascii=False) + "\n")
    log.flush()
    kind = event.get("type")
    if kind == "error":
        raise RuntimeError(json.dumps(event, ensure_ascii=False))
    if kind == "response.created":
        current_response = event["response"]["id"]
    if kind in {"response.audio.delta", "response.output_audio.delta", "response.text.delta", "response.output_text.delta", "response.audio_transcript.delta", "response.output_audio_transcript.delta", "response.text.done", "response.audio_transcript.done"}:
        identity = (event["response_id"], event["item_id"], event["output_index"], event["content_index"])
        if kind in {"response.audio.delta", "response.output_audio.delta"}:
            raw = base64.b64decode(event["delta"], validate=True)
            if len(raw) % 2: raise ValueError("Output PCM16 chunk must have an even byte length")
            audio.setdefault(identity, bytearray()).extend(raw)
        elif kind.endswith(".done"):
            texts[identity] = event.get("text", event.get("transcript", ""))
        else:
            texts[identity] = texts.get(identity, "") + event["delta"]
            print(event["delta"], end="", flush=True)
    if kind == "response.done":
        response = event["response"]
        complete.append(response)
        if current_response is None: current_response = response["id"]
        if response["id"] == current_response: pending = False
    return event

def wait_for(ws, log, kind):
    while True:
        event = receive(ws, log)
        if event.get("type") == kind: return event

def send(ws, event):
    ws.send(json.dumps(event, ensure_ascii=False))

try:
    # One exact model query; no reconnect/retry loop and no provider credentials.
    with connect("wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus", additional_headers={"Authorization": "Bearer " + key}) as ws:
        with (out / "events.jsonl").open("w", encoding="utf-8") as log:
            wait_for(ws, log, "session.created")
            send(ws, {"type":"session.update", "session":{"modalities":["audio","text"], "input_audio_format":"pcm", "output_audio_format":"pcm", "turn_detection":None}})
            wait_for(ws, log, "session.updated")
            send(ws, {"type":"conversation.item.create", "item":{"type":"message", "role":"user", "content":[{"type":"input_text", "text":material}]}})
            send(ws, {"type":"response.create"})
            pending = True
            try:
                while pending: receive(ws, log)
            except KeyboardInterrupt:
                # Cancel the actual current inference, then preserve its returned status.
                send(ws, {"type":"response.cancel"})
                while pending: receive(ws, log)
    if not complete or complete[-1].get("status") != "completed":
        raise RuntimeError("Response did not complete normally; inspect saved events and status")
finally:
    manifest = {"responses":complete, "parts":[]}
    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):
        record = {"response_id":identity[0], "item_id":identity[1], "output_index":identity[2], "content_index":identity[3]}
        if identity in audio:
            raw = bytes(audio[identity])
            pcm_file = out / ("audio-" + str(number) + ".pcm")
            wav_file = out / ("audio-" + str(number) + ".wav")
            pcm_file.write_bytes(raw)
            with wave.open(str(wav_file), "wb") as wav:
                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)
            record.update({"pcm":str(pcm_file), "wav":str(wav_file), "sample_rate_hz":24000})
        if identity in texts:
            text_file = out / ("text-" + str(number) + ".txt")
            text_file.write_text(texts[identity], encoding="utf-8")
            record["text"] = str(text_file)
        manifest["parts"].append(record)
    (out / "results.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
    print("\nSaved every received event and result in", out)
# Install the documented client once: python3 -m pip install websockets
import base64, json, os, time, wave
from pathlib import Path
from websockets.sync.client import connect

key = os.environ.get("AILOOT_API_KEY", "")
if not key.strip():
    raise SystemExit("Set your AILOOT_API_KEY before connecting")
file = Path(os.environ.get("AILOOT_AUDIO_FILE", ""))
if not file.is_file(): raise SystemExit("Set AILOOT_AUDIO_FILE to your raw PCM16 mono 16-kHz recording")
material = file.read_bytes()
if not material or len(material) % 2 or material.startswith(b"RIFF"):
    raise SystemExit("Use nonempty signed little-endian PCM16 mono 16-kHz bytes, not a WAV header")
out = Path("realtime-results")
out.mkdir(exist_ok=True)
audio, texts, complete = {}, {}, []
current_response = None
pending = False
deadline = time.monotonic() + 570  # Local client bound; lower server/session limits still apply.

def receive(ws, log):
    global current_response, pending
    left = deadline - time.monotonic()
    if left <= 0:
        raise TimeoutError("Client session limit; preserve IDs and partial results, do not replay")
    event = json.loads(ws.recv(timeout=min(60, left)))
    log.write(json.dumps(event, ensure_ascii=False) + "\n")
    log.flush()
    kind = event.get("type")
    if kind == "error":
        raise RuntimeError(json.dumps(event, ensure_ascii=False))
    if kind == "response.created":
        current_response = event["response"]["id"]
    if kind in {"response.audio.delta", "response.output_audio.delta", "response.text.delta", "response.output_text.delta", "response.audio_transcript.delta", "response.output_audio_transcript.delta", "response.text.done", "response.audio_transcript.done"}:
        identity = (event["response_id"], event["item_id"], event["output_index"], event["content_index"])
        if kind in {"response.audio.delta", "response.output_audio.delta"}:
            raw = base64.b64decode(event["delta"], validate=True)
            if len(raw) % 2: raise ValueError("Output PCM16 chunk must have an even byte length")
            audio.setdefault(identity, bytearray()).extend(raw)
        elif kind.endswith(".done"):
            texts[identity] = event.get("text", event.get("transcript", ""))
        else:
            texts[identity] = texts.get(identity, "") + event["delta"]
            print(event["delta"], end="", flush=True)
    if kind == "response.done":
        response = event["response"]
        complete.append(response)
        if current_response is None: current_response = response["id"]
        if response["id"] == current_response: pending = False
    return event

def wait_for(ws, log, kind):
    while True:
        event = receive(ws, log)
        if event.get("type") == kind: return event

def send(ws, event):
    ws.send(json.dumps(event, ensure_ascii=False))

try:
    # One exact model query; no reconnect/retry loop and no provider credentials.
    with connect("wss://api.ailoot.ai/v1/realtime?model=qwen-audio-3.0-realtime-plus", additional_headers={"Authorization": "Bearer " + key}) as ws:
        with (out / "events.jsonl").open("w", encoding="utf-8") as log:
            wait_for(ws, log, "session.created")
            send(ws, {"type":"session.update", "session":{"modalities":["audio","text"], "input_audio_format":"pcm", "output_audio_format":"pcm", "turn_detection":None}})
            wait_for(ws, log, "session.updated")
            for offset in range(0, len(material), 640):
                send(ws, {"type":"input_audio_buffer.append", "audio":base64.b64encode(material[offset:offset+640]).decode("ascii")})
                time.sleep(0.02)
            send(ws, {"type":"input_audio_buffer.commit"})
            wait_for(ws, log, "input_audio_buffer.committed")
            send(ws, {"type":"response.create"})
            pending = True
            try:
                while pending: receive(ws, log)
            except KeyboardInterrupt:
                # Cancel the actual current inference, then preserve its returned status.
                send(ws, {"type":"response.cancel"})
                while pending: receive(ws, log)
    if not complete or complete[-1].get("status") != "completed":
        raise RuntimeError("Response did not complete normally; inspect saved events and status")
finally:
    manifest = {"responses":complete, "parts":[]}
    for number, identity in enumerate(dict.fromkeys(list(audio) + list(texts))):
        record = {"response_id":identity[0], "item_id":identity[1], "output_index":identity[2], "content_index":identity[3]}
        if identity in audio:
            raw = bytes(audio[identity])
            pcm_file = out / ("audio-" + str(number) + ".pcm")
            wav_file = out / ("audio-" + str(number) + ".wav")
            pcm_file.write_bytes(raw)
            with wave.open(str(wav_file), "wb") as wav:
                wav.setnchannels(1); wav.setsampwidth(2); wav.setframerate(24000); wav.writeframes(raw)
            record.update({"pcm":str(pcm_file), "wav":str(wav_file), "sample_rate_hz":24000})
        if identity in texts:
            text_file = out / ("text-" + str(number) + ".txt")
            text_file.write_text(texts[identity], encoding="utf-8")
            record["text"] = str(text_file)
        manifest["parts"].append(record)
    (out / "results.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
    print("\nSaved every received event and result in", out)

결과 수신 및 저장

Ailoot · 실시간 음성

세션 이벤트

완료된 결과 모두 보관

반환된 완전한 응답, 파일, 콘텐츠 부분을 모두 보관하세요.

각 실제 응답 ID에 대해 반환된 모든 오디오 델타와 텍스트/이벤트 결과를 조합하세요.

원래 응답을 확인해야 할 경우

실제 세션/응답/이벤트 ID와 처리 기록을 보존하세요.

오류와 다음 단계
응답조건다음 단계
응답426 · invalid_request_error조건WebSocket 업그레이드 없음다음 단계Upgrade: websocket을 사용하는 WebSocket 클라이언트를 사용하세요.

별칭

모델 별칭

Ailoot qwen-audio-3.0-realtime-plus

메서드 경로 별칭

위에 표시된 메서드 경로를 사용하세요.

관련 호출용 ID

qwen-audio-3.0-realtime-plus

FAQ · qwen-audio-3.0-realtime-plus
어떤 입력과 결과를 사용할 수 있나요?

GET /v1/realtime?model=qwen-audio-3.0-realtime-plus · qwen-audio-3.0-realtime-plus: text, audio → text, audio

어떤 제한이 적용되나요?

GET /v1/realtime?model=qwen-audio-3.0-realtime-plus · qwen-audio-3.0-realtime-plus: session.max_history_turns.minimum: 1

자세히 보기

Claude Code, OpenCode, Hermes, 자체 앱에 Ailoot를 연결하세요.

회사와 그 프로젝트 포트폴리오

회사와 그 프로젝트 포트폴리오: 수백만 고객, 매월 수십억 규모의 매출.

할인받아 토큰을 구매하세요.

정기 작업에는 구독 할인, 토큰 구매에는 최대 50% 프로모션 코드.

구독
정기 요청에 맞는 할인 요금제를 선택하세요.
최대 50% 프로모션 코드
구매할 때 코드를 넣으면 진행 중 행사에 따라 가격을 다시 계산합니다.
이력의 지출
요청마다 모델, 토큰, 금액을 저장합니다.

구독 선택 · 모델 가격 보기

판매하는 제품에 API를 연결하세요.

Ailoot 공식 이용 조건과 라이선스 계약으로 SaaS, 앱, 봇에 사용하세요. 재판매에는 리셀러 라이선스를 요청하세요.

상업용 앱
서비스의 유료 기능에 텍스트, 이미지, 영상, 소리 생성을 넣으세요.
리셀러 라이선스
프로젝트 설명과 접근 구조를 보내 사용·재판매의 서면 조건을 요청하세요.
사이트의 문서
연결 전에 공식 이용 조건, 라이선스 계약, 데이터 처리 정책을 읽을 수 있습니다.

리셀러 라이선스 요청 · 공식 이용 조건과 라이선스 계약