Home / Strands 음성 AI / BidiAgent — 실시간 음성
Note

BidiAgent — 실시간 음성

양방향 스트리밍 실시간 음성 대화

⏱ 40분 103 / 189

BidiAgent — 실시간 음성

양방향 스트리밍 실시간 음성 대화

에이전트와 대화한다 — 목소리로

Speech-to-Speech 양방향 음성 에이전트 — 텍스트 변환 없는 직접 처리

BidiAgent 구현

BidiAudioIO · 양방향 스트림 · 도구 통합

PART 3 · BidiAgent 구현

BidiAgent

BidiNovaSonicModel · BidiAudioIO · 도구 — 양방향 음성 에이전트의 3층 구성

BidiAgent

양방향 세션 전용 에이전트 — 도구 호출 중에도 음성 스트림을 유지합니다

  • BidiNovaSonicModel — 모델 래퍼
  • BidiAudioIO — 마이크·스피커 I/O
  • 에이전틱 루프 — 기존 Strands와 동일
  • LPCM 입력 16kHz / 출력 24kHz
takeaway

모델이 toolUse를 요청하면 루프가 도구를 실행하고 결과를 음성 스트림에 주입합니다 — 대화가 끊기지 않습니다.

PART 3 · BidiAgent 구현

BidiAgent 전체 구현

BidiNovaSonicModel + BidiAudioIO + 도구를 결합한 음성 에이전트 완성 코드

핵심 포인트

@tool
음성 대화 중 모델이 호출하는 도구 — 텍스트 에이전트와 동일한 데코레이터
BidiNovaSonicModel
Nova 2 Sonic 모델 ID + client_config(region)로 양방향 스트림 연결
BidiAgent
모델 + 도구 + system_prompt 조립 — 에이전트 구성은 기존과 동일
await agent.run()
inputs·outputs에 마이크·스피커 연결 — asyncio 기반 양방향 세션

코드

python
import asyncio
from strands import tool
from strands.experimental.bidi import BidiAgent, BidiAudioIO
from strands.experimental.bidi.models import BidiNovaSonicModel
@tool
def get_weather(city: str) -> dict:
    """도시의 현재 날씨를 조회합니다."""
    return {"city": city, "temp": 22, "condition": "sunny"}

async def main():
    model = BidiNovaSonicModel(model_id="amazon.nova-2-sonic-v1:0",
                               client_config={"region": "us-east-1"})
    agent = BidiAgent(model=model, tools=[get_weather],
                      system_prompt="You are a helpful voice assistant.")
    audio_io = BidiAudioIO()  # 마이크 입력 · 스피커 출력
    await agent.run(inputs=[audio_io.input()], outputs=[audio_io.output()])
asyncio.run(main())
PART 3 · BidiAgent 구현

양방향 오디오 처리 흐름

마이크 입력부터 스피커 출력까지 — 실시간 양방향 오디오 파이프라인

  1. 1
    Mic Capture

    시스템 마이크에서 16kHz PCM 오디오를 512프레임 버퍼(기본값) 단위로 캡처. BidiAudioIO는 PyAudio 기반.

  2. 2
    Audio Event 변환

    16kHz LPCM 프레임을 오디오 입력 이벤트로 감싸 전송 큐에 적재. 압축 없이 원시 PCM 그대로 전달.

  3. 3
    Stream to Model

    HTTP/2 양방향 스트림으로 인코딩된 오디오 청크를 Nova Sonic에 실시간 전송. 발화 중에도 모델이 처리 시작.

  4. 4
    Model Response

    모델이 오디오 토큰으로 응답을 생성. toolUse 이벤트 발생 시 에이전틱 루프가 도구를 실행하고 결과 반환.

  5. 5
    PCM Buffering

    모델이 반환한 24kHz LPCM 오디오 청크를 버퍼링. 청크 간 끊김 없이 연속적인 재생 보장.

  6. 6
    Speaker Output

    디코딩된 PCM 오디오를 스피커로 실시간 재생. 첫 청크 도착 즉시 재생 시작하여 체감 레이턴시 최소화.

takeaway

캡처부터 재생까지 전 구간이 스트리밍입니다 — 첫 청크 도착 즉시 재생을 시작해 체감 레이턴시를 최소화합니다.

PART 3 · BidiAgent 구현

BidiAgent 핵심 컴포넌트

양방향 음성 에이전트를 구성하는 3개 레이어와 역할 분담

BidiNovaSonicModel

Bedrock Nova 2 Sonic 모델 래퍼 — HTTP/2 양방향 스트림 관리

BidiAudioIO

마이크 입력 · 스피커 출력 · LPCM 스트림을 통합하는 오디오 I/O 레이어

BidiAgent(에이전틱 루프)

도구 호출 판단 · 실행 · 결과 반환 — 기존 Strands 루프와 동일

takeaway

모델 래퍼 · 오디오 I/O · 에이전틱 루프 — 세 레이어의 역할 분담이 양방향 음성 에이전트의 전부입니다.

멀티 프로바이더

Gemini Live · OpenAI Realtime · 프로바이더 전환

PART 4 · 멀티 프로바이더

멀티 프로바이더

Nova Sonic · Gemini Live · OpenAI Realtime — 동일 인터페이스로 전환

멀티 프로바이더

모델 클래스만 교체하면 나머지 코드는 그대로 — 프로바이더 전환의 아키텍처 변화 최소화

  • BidiNovaSonicModel — HTTP/2 bidi
  • BidiGeminiLiveModel — WebSocket
  • BidiOpenAIRealtimeModel — WebSocket
  • 도구 · BidiAudioIO — 그대로 재사용
takeaway

프로바이더마다 레이턴시·언어 지원·감정 표현 수준이 다릅니다 — 한국어가 필요하면 Gemini Live·OpenAI Realtime이 현재 선택지입니다.

PART 4 · 멀티 프로바이더

멀티 프로바이더 비교

SDK 클래스·프로토콜·코덱·세션 제한은 상이 — Strands 통합 인터페이스는 셋 모두 동일(실험적)

항목Nova 2 SonicGemini LiveOpenAI Realtime
SDK 클래스BidiNovaSonicModelBidiGeminiLiveModelBidiOpenAIRealtimeModel
전송 프로토콜HTTP/2 bidi streamWebSocketWebSocket
오디오 코덱LPCM16-bit PCM (raw PCM 전용)PCM16 / G.711
샘플레이트입력 16kHz / 출력 24kHz16kHz / 24kHz24kHz
도구 호출toolUse 이벤트function_callfunction_call
세션 제한연결 8분오디오 15분 (연결 ~10분, 재개 토큰 2시간)최대 60분
Strands 통합✓ (실험적)✓ (실험적)✓ (실험적)
takeaway

SDK 클래스와 프로토콜·코덱은 달라도 Strands 통합 인터페이스는 동일합니다 — 셋 모두 아직 실험적(experimental) 단계입니다.

PART 4 · 멀티 프로바이더

Gemini Live 연동

BidiGeminiLiveModel로 교체 — 나머지 코드 변경 없이 프로바이더 전환

핵심 포인트

BidiGeminiLiveModel
모델 클래스만 교체 — Live는 native-audio 계열 모델 사용
client_config(api_key)
프로바이더 인증 — Nova Sonic의 region 자리에 API 키
BidiAudioIO
오디오 I/O는 그대로 재사용 — 변경 없음
BidiAgent
구성 코드는 Nova Sonic과 완전 동일 — 도구·프롬프트 유지

코드

python
from strands.experimental.bidi import BidiAgent, BidiAudioIO
from strands.experimental.bidi.models import BidiGeminiLiveModel

# Gemini Live 모델로 교체 — 인터페이스 동일 (Live는 native-audio 계열)
model = BidiGeminiLiveModel(
    model_id="gemini-2.5-flash-native-audio-preview-09-2025",
    client_config={"api_key": "GEMINI_API_KEY"},
)
audio_io = BidiAudioIO()  # 오디오 I/O는 그대로 재사용

# BidiAgent 코드는 Nova Sonic과 완전 동일
agent = BidiAgent(
    model=model,
    tools=[get_weather, search_db],
    system_prompt="You are a helpful voice assistant.",
)
PART 4 · 멀티 프로바이더

텍스트 에이전트 → 음성 에이전트 전환

기존 텍스트 기반 에이전트에서 음성 에이전트로 전환 시 변경 사항

텍스트 에이전트 음성 에이전트
모델 클래스 BedrockModel
텍스트 입출력 전용
BidiNovaSonicModel
HTTP/2 양방향 오디오 스트림
I/O 레이어 텍스트 stdin/stdout
또는 REST API
BidiAudioIO
마이크+스피커+LPCM 스트림
실행 패턴 agent("질문 텍스트")
동기 호출, 결과 텍스트 반환
await agent.run(inputs=..., outputs=...)
비동기 세션, 실시간 스트림
도구 정의 변경 없음
@tool 데코레이터 그대로
변경 없음
동일한 도구를 그대로 사용
음성은 에이전트의 가장 자연스러운 인터페이스입니다.

Nova Sonic · BidiAgent · WebRTC — 음성으로 대화하는 에이전트