실시간 음성 에이전트
실시간 에이전트는 양방향 오디오 스트리밍을 사용하여 AI 비서와 음성 기반 상호 작용을 가능하게 합니다. adk-realtime 크레이트는 OpenAI의 Realtime API 및 Google의 Gemini Live API와 함께 작동하는 음성 지원 에이전트를 구축하기 위한 통합 인터페이스를 제공합니다.
개요
실시간 에이전트는 여러 주요 방식에서 텍스트 기반 LlmAgent와 다릅니다.
| 기능 | LlmAgent | RealtimeAgent |
|---|---|---|
| 입력 | 텍스트 | 오디오/텍스트 |
| 출력 | 텍스트 | 오디오/텍스트 |
| 연결 | HTTP 요청 | WebSocket |
| 지연 시간 | 요청/응답 | 실시간 스트리밍 |
| VAD | 해당 없음 | 서버 측 음성 감지 |
아키텍처
┌─────────────────────────────────────────┐
│ Agent Trait │
│ (name, description, run, sub_agents) │
└────────────────┬────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌──────▼──────┐ ┌─────────▼─────────┐ ┌─────────▼─────────┐
│ LlmAgent │ │ RealtimeAgent │ │ SequentialAgent │
│ (text-based)│ │ (voice-based) │ │ (workflow) │
└─────────────┘ └───────────────────┘ └───────────────────┘
RealtimeAgent는 LlmAgent와 동일한 Agent trait을 구현하며 다음을 공유합니다.
- 지침 (정적 및 동적)
- Tool 등록 및 실행
- 콜백 (before_agent, after_agent, before_tool, after_tool)
- Sub-agent 핸드오프
빠른 시작
설치
Cargo.toml에 추가:
[dependencies]
adk-realtime = { version = "0.2.0", features = ["openai"] }
기본 사용법
use adk_realtime::{
RealtimeAgent, RealtimeModel, RealtimeConfig, ServerEvent,
openai::OpenAIRealtimeModel,
};
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("OPENAI_API_KEY")?;
// Create the realtime model
let model: Arc<dyn RealtimeModel> = Arc::new(
OpenAIRealtimeModel::new(&api_key, "gpt-4o-realtime-preview-2024-12-17")
);
// Build the realtime agent
let agent = RealtimeAgent::builder("voice_assistant")
.model(model.clone())
.instruction("You are a helpful voice assistant. Be concise.")
.voice("alloy")
.server_vad() // Enable voice activity detection
.build()?;
// Or use the low-level session API directly
let config = RealtimeConfig::default()
.with_instruction("You are a helpful assistant.")
.with_voice("alloy")
.with_modalities(vec!["text".to_string(), "audio".to_string()]);
let session = model.connect(config).await?;
// Send text and get response
session.send_text("Hello!").await?;
session.create_response().await?;
// Process events
while let Some(event) = session.next_event().await {
match event? {
ServerEvent::TextDelta { delta, .. } => print!("{}", delta),
ServerEvent::AudioDelta { delta, .. } => {
// Play audio (delta is base64-encoded PCM)
}
ServerEvent::ResponseDone { .. } => break,
_ => {}
}
}
Ok(())
}
지원되는 제공자
| 제공자 | 모델 | Feature Flag | 오디오 형식 |
|---|---|---|---|
| OpenAI | gpt-4o-realtime-preview-2024-12-17 | openai | PCM16 24kHz |
| OpenAI | gpt-realtime | openai | PCM16 24kHz |
gemini-2.0-flash-live-preview-04-09 | gemini | PCM16 16kHz/24kHz |
참고:
gpt-realtime은 향상된 음성 품질, 감정, FunctionTool 호출 기능을 갖춘 OpenAI의 최신 실시간 모델입니다.
RealtimeAgent Builder
RealtimeAgentBuilder는 Agent를 구성하기 위한 fluent API를 제공합니다:
let agent = RealtimeAgent::builder("assistant")
// Required
.model(model)
// Instructions (same as LlmAgent)
.instruction("You are helpful.")
.instruction_provider(|ctx| format!("User: {}", ctx.user_name()))
// Voice settings
.voice("alloy") // Options: alloy, coral, sage, shimmer, etc.
// Voice Activity Detection
.server_vad() // Use defaults
.vad(VadConfig {
mode: VadMode::ServerVad,
threshold: Some(0.5),
prefix_padding_ms: Some(300),
silence_duration_ms: Some(500),
interrupt_response: Some(true),
eagerness: None,
})
// Tools (same as LlmAgent)
.tool(Arc::new(weather_tool))
.tool(Arc::new(search_tool))
// Sub-agents for handoffs
.sub_agent(booking_agent)
.sub_agent(support_agent)
// Callbacks (same as LlmAgent)
.before_agent_callback(|ctx| async { Ok(()) })
.after_agent_callback(|ctx, event| async { Ok(()) })
.before_tool_callback(|ctx, tool, args| async { Ok(None) })
.after_tool_callback(|ctx, tool, result| async { Ok(result) })
// Realtime-specific callbacks
.on_audio(|audio_chunk| { /* play audio */ })
.on_transcript(|text| { /* show transcript */ })
.build()?;
음성 활동 감지 (VAD)
VAD는 사용자가 말을 시작하고 멈추는 시점을 감지하여 자연스러운 대화 흐름을 가능하게 합니다.
Server VAD (권장)
let agent = RealtimeAgent::builder("assistant")
.model(model)
.server_vad() // Uses sensible defaults
.build()?;
사용자 지정 VAD 구성
use adk_realtime::{VadConfig, VadMode};
let vad = VadConfig {
mode: VadMode::ServerVad,
threshold: Some(0.5), // 음성 감지 민감도 (0.0-1.0)
prefix_padding_ms: Some(300), // 음성 전에 포함할 오디오
silence_duration_ms: Some(500), // 발화 종료 전 침묵 지속 시간
interrupt_response: Some(true), // Agent 중단 허용
eagerness: None, // SemanticVad 모드용
};
let agent = RealtimeAgent::builder("assistant")
.model(model)
.vad(vad)
.build()?;
Semantic VAD (Gemini)
Gemini 모델의 경우 의미를 고려하는 semantic VAD를 사용할 수 있습니다:
let vad = VadConfig {
mode: VadMode::SemanticVad,
eagerness: Some("high".to_string()), // 낮음, 중간, 높음
..Default::default()
};
도구 호출
Realtime agent는 음성 대화 중에 도구 호출을 지원합니다:
use adk_realtime::{config::ToolDefinition, ToolResponse};
use serde_json::json;
// Define tools
let tools = vec![
ToolDefinition {
name: "get_weather".to_string(),
description: Some("Get weather for a location".to_string()),
parameters: Some(json!({
"type": "object",
"properties": {
"location": { "type": "string" }
},
"required": ["location"]
})),
},
];
let config = RealtimeConfig::default()
.with_tools(tools)
.with_instruction("Use tools to help the user.");
let session = model.connect(config).await?;
// Handle tool calls in the event loop
while let Some(event) = session.next_event().await {
match event? {
ServerEvent::FunctionCallDone { call_id, name, arguments, .. } => {
// Execute the tool
let result = execute_tool(&name, &arguments);
// Send the response
let response = ToolResponse::new(&call_id, result);
session.send_tool_response(response).await?;
}
_ => {}
}
}
다중 에이전트 핸드오프
전문 에이전트 간에 대화를 전송합니다:
// Create sub-agents
let booking_agent = Arc::new(RealtimeAgent::builder("booking_agent")
.model(model.clone())
.instruction("Help with reservations.")
.build()?);
let support_agent = Arc::new(RealtimeAgent::builder("support_agent")
.model(model.clone())
.instruction("Help with technical issues.")
.build()?);
// Create main agent with sub-agents
let receptionist = RealtimeAgent::builder("receptionist")
.model(model)
.instruction(
"Route customers: bookings → booking_agent, issues → support_agent. \
Use transfer_to_agent tool to hand off."
)
.sub_agent(booking_agent)
.sub_agent(support_agent)
.build()?;
model이 transfer_to_agent를 호출하면, RealtimeRunner가 핸드오프를 자동으로 처리합니다.
오디오 형식
| 형식 | 샘플 속도 | 비트 | 채널 | 사용 사례 |
|---|---|---|---|---|
| PCM16 | 24000 Hz | 16 | Mono | OpenAI (기본값) |
| PCM16 | 16000 Hz | 16 | Mono | Gemini 입력 |
| G711 u-law | 8000 Hz | 8 | Mono | 전화 통신 |
| G711 A-law | 8000 Hz | 8 | Mono | 전화 통신 |
use adk_realtime::{AudioFormat, AudioChunk};
// Create audio format
let format = AudioFormat::pcm16_24khz();
// Work with audio chunks
let chunk = AudioChunk::new(audio_bytes, format);
let base64 = chunk.to_base64();
let decoded = AudioChunk::from_base64(&base64, format)?;
이벤트 유형
서버 이벤트
| 이벤트 | 설명 |
|---|---|
SessionCreated | 연결 설정됨 |
AudioDelta | 오디오 청크 (base64 PCM) |
TextDelta | 텍스트 응답 청크 |
TranscriptDelta | 입력 오디오 스크립트 |
FunctionCallDone | 도구 호출 요청 |
ResponseDone | 응답 완료됨 |
SpeechStarted | VAD 음성 시작 감지됨 |
SpeechStopped | VAD 음성 끝 감지됨 |
Error | 오류 발생 |
클라이언트 이벤트
| 이벤트 | 설명 |
|---|---|
AudioInput | 오디오 청크 전송 |
AudioCommit | 오디오 버퍼 커밋 |
ItemCreate | 텍스트 또는 도구 응답 전송 |
CreateResponse | 응답 요청 |
CancelResponse | 현재 응답 취소 |
SessionUpdate | 구성 업데이트 |
예시
포함된 예시를 실행합니다:
# Basic text-only session
cargo run --example realtime_basic --features realtime-openai
# Voice assistant with VAD
cargo run --example realtime_vad --features realtime-openai
# Tool calling
cargo run --example realtime_tools --features realtime-openai
# Multi-agent handoffs
cargo run --example realtime_handoff --features realtime-openai
모범 사례
Server VAD사용: 서버가 음성 감지를 처리하여 지연 시간을 줄입니다.- 인터럽션 처리:
interrupt_response를 활성화하여 자연스러운 대화를 구현합니다. - 명령을 간결하게 유지: 음성 응답은 간결해야 합니다.
- 텍스트로 먼저 테스트: 오디오를 추가하기 전에 텍스트로
agent로직을 디버그합니다. - 오류를 정상적으로 처리:
WebSocket연결에서는 네트워크 문제가 흔합니다.
OpenAI Agents SDK 와(과) 비교
ADK-Rust의 실시간 구현은 OpenAI Agents SDK 패턴을 따릅니다.
| 기능 | OpenAI SDK | ADK-Rust |
|---|---|---|
Agent 기본 클래스 | Agent | Agent trait |
실시간 agent | RealtimeAgent | RealtimeAgent |
| 도구 | 함수 정의 | Tool trait + ToolDefinition |
| 핸드오프 | transfer_to_agent | sub_agents + 자동 생성된 도구 |
| 콜백 | Hooks | before_* / after_* callbacks |
이전: ← Graph Agents | 다음: Model Providers →