Azure Realtime

Azure Realtime

AzureRealtimeModel은 Azure의 realtime 음성-대-음성을 서버 측 Pydantic AI 에이전트 루프와 연결해요. Azure OpenAI GA 프로토콜(기본) 또는 Azure AI Voice Live(옵트인) 중 하나로요. realtime 퀵스타트텍스트-음성 예제로 시작하세요.

출처: 문서

본문

설정

Azure OpenAI realtime은 OpenAI realtime 스택을 사용하므로 pydantic-ai-slimopenai-realtime 옵션 그룹과 함께 설치하세요:

pip install "pydantic-ai-slim[openai-realtime]"
uv add "pydantic-ai-slim[openai-realtime]"

Azure AI Foundry 프로바이더처럼 AZURE_OPENAI_ENDPOINTAZURE_OPENAI_API_KEY를 설정하세요. Azure 배포 이름 뒤에 azure: 프리픽스를 사용하세요:

from pydantic_ai import Agent

agent = Agent(instructions='You are a helpful voice assistant.')


async def main():
    async with agent.realtime('azure:my-realtime-deployment').session() as session:
        transcripts = session.stream_transcripts()  # subscribe before prompting
        await session.send('Say hello.')

        async for part in transcripts:
            print(f'{part.speaker}: {part.transcript}')
            #> assistant: Hello from the realtime assistant.
            if part.speaker == 'assistant':
                break  # keep listening in a real call; we stop after one reply

(이 예제를 실행하려면 asyncio를 import하고 asyncio.run(main())을 추가하세요. 다른 변경은 필요 없어요.)

명시적 구성을 위해 AzureProvider.for_realtime()을 사용하세요. 알몸의 리소스 엔드포인트나 그 /openai/v1 형식을 받아요. GA realtime 프로토콜은 /openai/v1/realtime을 사용하고 api_version을 받지 않아요. 요청은 기본적으로 리소스 API 키로 인증하거나, credential이 전달되면 Microsoft Entra ID 토큰으로 인증해요(브라우저 WebRTC와 Microsoft Entra ID 참고).

모델 이름

Azure 배포 이름을 전달하세요. 그것은 모델이 배포될 때 선택되고 기본 모델 ID와 일치할 필요가 없어요. 사용 가능한 realtime 모델과 리전은 Azure OpenAI realtime 문서에 문서화돼 있어요.

설정

Azure는 OpenAIRealtimeModelSettings를 사용해요. 모델 실행 설정의 realtime 대응물이며 공유 설정에 더해:

  • 프로바이더 음성용 openai_voice;
  • openai_input_noise_reductionopenai_output_speed;
  • 서버 또는 시맨틱 VAD용 openai_turn_detection(턴 감지 참고);
  • 세션 컨텍스트 관리용 openai_truncation.

공유 설정은 OpenAI 설정을 참고하세요. Azure realtime은 Pydantic AI를 통해 temperature를 노출하지 않아요.

입력 전사 배포

Azure는 input_transcription_model 설정을 리소스의 배포에 대해 해결해요. 기본 'auto'gpt-realtime-whisper를 선택하고, 일치하는 배포가 없는 리소스는 매 턴 DeploymentNotFound 전사 오류를 방출해요.

gpt-realtime-whispergpt-4o-transcribe 같은 realtime 지원 전사 모델을 배포하고 input_transcription_model을 그 배포 이름으로 설정하세요. 고전적인 whisper 배포는 받아들여지지 않아요. 필드를 None으로 설정해 전사를 비활성화하고, 말로 한 턴이 오디오로 남아야 한다면 audio_retention='input_audio'를 사용하세요.

브라우저 WebRTC와 Microsoft Entra ID

Azure OpenAI는 OpenAI와 같은 브라우저 WebRTC 흐름을 지원해요. 오디오가 브라우저 ↔ Azure 사이를 직접 흐르고 백엔드가 제어 평면 사이드밴드를 실행해요. 토폴로지는 프론트엔드 연결을, AgentRealtime.answer_webrtc_offer / AgentRealtime.create_client_secret 사용은 OpenAI에서와 정확히 참고하세요. Azure는 webrtcfilter=on으로 offer를 릴레이하는데, 브라우저에 전달되는 이벤트를 안전한 부분집합으로 제한해서 세션 인스트럭션이 서버의 제어 연결에 남게 해요.

사이드밴드 전사 캡처는 배포된 전사 모델이 필요하다

WebRTC 호출의 서버 측은 사용자의 오디오를 절대 받지 않아요(브라우저 ↔ Azure 직접 흐름). 그래서 사용자가 말하는 단어 를 포착하는 유일한 방법은 전사 모델이에요. audio_retention='input_audio' 폴백은 적용될 수 없어요(보존할 오디오가 없으니까요). 그것이 없으면 사용자의 턴은 여전히 이력으로 표현되지만 콘텐츠 없는 SpeechPart로 나타나요. 사용자가 말하는 것을 포착하려면 Azure 리소스에 전사 모델을 배포하세요(기본 gpt-realtime-whisper는 배포할 때까지 DeploymentNotFound로 실패하거나, input_transcription_model을 당신이 가진 전사 배포로 가리키세요).

브라우저의 필터링된 이벤트 스트림은 원시 프로토콜과 다르다

webrtcfilter=on은 Azure가 브라우저의 데이터 채널로 전달하는 이벤트가 프라이버시 안전 부분집합임을 뜻해요. 브라우저는 말하기 상태를 위해 output_audio_buffer.started / output_audio_buffer.stopped를 보고 원시 response.created / response.done을 보지 못해요. "어시스턴트가 말하고 있다" 또는 지연 텔레메트리를 response.*에 키잉하는 프론트엔드는 output_audio_buffer.* 이벤트를 매핑해야 해요. 이것은 데이터 채널을 직접 읽는 클라이언트 코드에만 영향을 줘요. 서버 측 세션의 이벤트 스트림은 영향받지 않아요. 라이브로 검증됨: 세션이 output_audio_buffer.* 프레임을 완전히 받아 RealtimeOutputSpeechStartEvent / RealtimeOutputSpeechEndEvent로 보고하므로, 듣기/말하기 표시는 브라우저에서 재구성하지 않고 서버에서 구동할 수 있어요(프론트엔드 연결 참고).

Azure 요청은 기본적으로 리소스의 API 키로 인증해요. 대신 Microsoft Entra ID를 사용하려면(리소스가 관리 ID로 잠겨 있을 때처럼 API 키가 관여하지 않도록) credential(모든 azure.identity 자격증명, 예: DefaultAzureCredential)을 전달하세요. 그것은 리소스에 대한 모든 요청 — realtime WebSocket 세션과 WebRTC 시그널링 — 을 Azure OpenAI 데이터 평면의 베어러 토큰(범위 https://ai.azure.com/.default)으로 인증하고, 리소스에 Cognitive Services User 역할이 필요해요:

from azure.identity import DefaultAzureCredential

from pydantic_ai.providers.azure import AzureProvider
from pydantic_ai.realtime.azure import AzureRealtimeModel

model = AzureRealtimeModel(
    'gpt-realtime',
    # `entra_authenticated=True` so no resource key is required -- a resource locked to managed
    # identity has none. Omit `provider=` entirely to take the endpoint from `AZURE_OPENAI_ENDPOINT`.
    provider=AzureProvider.for_realtime(
        azure_endpoint='https://my-resource.openai.azure.com', entra_authenticated=True
    ),
    credential=DefaultAzureCredential(),
)
# The realtime session, `answer_webrtc_offer`, and `create_client_secret` now authenticate with an Entra
# bearer token; the browser only ever receives the short-lived ephemeral secret, never it or the API key.

Azure AI Voice Live

Azure AI Voice Live는 Microsoft의 관리형 음성-대-음성 서비스로, GA realtime API보다 세션 옵션이 더 많고 모델 카탈로그가 넓어요. gpt-4o, gpt-4.1, gpt-5 같은 모델 위의 캐스케이드 파이프라인(Azure 음성-텍스트 → 채팅 모델 → Azure 텍스트-음성)을 포함해요. 같은 나의 AzureRealtimeModel: azure_voice_live=True를 설정하면 모델이 Voice Live 엔드포인트와 베타 세션 프로토콜을 대상으로 해요.

Voice Live는 자체 자격증명을 가진 별개의 Azure 리소스예요. AZURE_VOICELIVE_ENDPOINT, AZURE_VOICELIVE_API_KEY, AZURE_VOICELIVE_API_VERSION을 설정하거나 AzureProvidervoice_live_endpoint, voice_live_api_key, voice_live_api_version을 전달하세요. 각 값은 명시적 인자, 그다음 자신의 AZURE_VOICELIVE_* 변수, 그다음 Azure OpenAI 엔드포인트/키 순으로 해결돼요. 그래서 리소스 하나만 가진 Voice Live 사용자는 둘 다 구성할 필요가 없고, 둘 다 가진 사용자는 절대 둘의 혼합을 얻지 않아요.

from pydantic_ai import Agent
from pydantic_ai.providers.azure import AzureProvider
from pydantic_ai.realtime import RealtimeTurnCompleteEvent
from pydantic_ai.realtime.azure import AzureRealtimeModel, AzureRealtimeModelSettings

provider = AzureProvider(
    voice_live_endpoint='https://my-voice-live.services.ai.azure.com',
    voice_live_api_key='...',
    voice_live_api_version='2026-04-10',
)

agent = Agent(instructions='You are a helpful voice assistant.')
# Pass the Voice Live `provider`, and set `azure_voice_live` on the model rather than per session so
# `model.profile` reflects Voice Live (see the note below).
model = AzureRealtimeModel(
    'gpt-realtime', provider=provider, settings=AzureRealtimeModelSettings(azure_voice_live=True)
)


async def main():
    async with agent.realtime(model).session() as session:
        await session.send('Say hello.')
        async for event in session:
            if isinstance(event, RealtimeTurnCompleteEvent):
                break  # keep listening in a real call; we stop after one reply

Voice Live 전용 노브는 azure_voice_live_* 프리픽스를 사용해요(예: azure_voice_live_turn_detection). Voice Live는 배포 이름이 gpt-realtime으로 시작하면 입력 전사를 기본 whisper-1로, 그 외에는 azure-speech로 설정해요. 이것은 이름 일치라서, profile=로 라우팅된 커스텀 이름의 gpt-realtime 배포는 azure-speech 기본값을 받아요. 의도한 배포가 아닐 때는 input_transcription_model을 명시적으로 설정하세요.

Voice Live는 상속된 openai_* 설정과 thinking, parallel_tool_calls를 조용히 무시해요. 가능하면 Voice Live 특화 설정을 사용하세요.

어떤 모델이 어떤 API를 쓰는가

azure_voice_live가 항상 필요한 것은 아니에요. AzureRealtimeModel은 모델로 라우팅해요. 두 API는 겹치지만 어느 것도 다른 것을 포함하지 않아서, 각 인식된 모델은 GA realtime API, Voice Live, 또는 둘 다로 서빙돼요:

  • 둘 다(예: gpt-realtime, gpt-realtime-mini) — 기본은 GA; azure_voice_live=True가 Voice Live를 선택.
  • Voice Live 전용(예: gpt-5와 다른 캐스케이드 채팅 모델, phi4-mm-realtime) — 설정 유무와 무관하게 자동으로 Voice Live로 라우팅.
  • GA 전용(예: gpt-realtime-2, gpt-4o-realtime-preview) — Voice Live가 서빙하지 않으므로 azure_voice_live=TrueUserError 발생.

인식되지 않는 모델(미래 릴리스, 또는 다른 것으로 이름 붙은 배포)은 기본 GA이고 azure_voice_live=True에서만 Voice Live에 도달해요. 배포 이름이 모델과 일치하지 않을 때는 라우팅을 고치기 위해 azure_realtime_apis가 있는 profile= AzureRealtimeModelProfile을 전달하세요:

from pydantic_ai.providers.azure import AzureProvider
from pydantic_ai.realtime.azure import AzureRealtimeModel, AzureRealtimeModelProfile

# A Voice-Live-only model deployed under a custom name.
model = AzureRealtimeModel(
    'my-voice-bot',
    provider=AzureProvider(
        voice_live_endpoint='https://my-voice-live.services.ai.azure.com', voice_live_api_key='...'
    ),
    profile=AzureRealtimeModelProfile(azure_realtime_apis=frozenset({'voice_live'})),
)

브라우저 WebRTC는 Voice Live에서 WebSocket 전용이다

브라우저 WebRTC 흐름은 GA Azure OpenAI realtime 경로용이에요. Voice Live는 자체 WebSocket 제어 채널로 WebRTC를 협상하는데, 그것이 아직 구현되지 않았어요. 그래서 세션이 Voice Live로 해결될 때마다 answer_webrtc_offer / create_client_secretUserError를 발생시켜요. azure_voice_live=True로 설정했거나, 모델이 Voice Live에서만 서빙되어(예: gpt-5) 자동 라우팅된 경우예요. 지금은 Voice Live에 WebSocket 세션을 사용하세요(issue #6702).

supports_webrtc모델이 Voice Live로 해결될 때마다 False를 보고해요. 구성 시 azure_voice_live=True로 강제되거나, Voice Live 전용 모델에 대해 자동 라우팅된 경우예요. profile은 모델의 속성이라 세션별로 전달된 model_settings를 볼 수 없어요. 그래서 그 외에는 GA인 모델의 세션별 azure_voice_live=True는 플래그에 반영되지 않아요. 그 경우에도 시그널링 메서드는 사용 시점에서 거부하므로, 플래그는 조기 검사이고 사용 시점 가드가 안전망이에요.

기능 지원과 한계

기능 지원 참고
오디오 형식 전체 기능 지원 모노 PCM16, 24kHz 입력·출력
텍스트 출력 전체 기능 지원 output_modality='text'로 선택
이미지 입력 전체 기능 지원 이미지가 다음 턴의 컨텍스트를 제공
수동 턴 전체 기능 지원 turn_detection=False + commit/create 동사
중단/자르기 전체 기능 지원 interrupt(played_ms=...)가 들은 컷오프를 기록
입력 전사 제한된 매개변수 지원 Azure 리소스에 호환 전사 배포 필요
네이티브 툴 미지원 웹 기능에 로컬 폴백 구성
사용량 전체 기능 지원 토큰, 오디오, 캐시 세분화
재연결 전체 기능 지원 Pydantic AI가 완성된 로컬 이력을 재생; 진행 중 미디어는 손실

프로바이더 무관 워크플로우는 오디오, 이미지, 전사, 턴과 중단, , 연결 라이프사이클을 참고하세요.

프로바이더별 특이점

  • 실패한 입력 전사는 사용자 턴을 사용 가능할 때 보존된 오디오로, 그렇지 않으면 콘텐츠 없는 SpeechPart로 남겨요.
  • Azure AI Voice Live는 azure_voice_live=True 뒤의 같은 모델을 타고 자체 리소스와 베타 세션 프로토콜을 써요. 브라우저 WebRTC는 지금은 GA 전용이에요.

더 알아보기 (Learn more)