실시간 및 멀티모달 에이전트
OpenAI의 Realtime API 또는 Google의 Gemini Live API에 대한 실시간 저지연 연결을 통해 실시간으로 말하고, 듣고, 보고, 행동하는 에이전트를 구축하세요.
실시간 에이전트는 요청/응답 방식의 챗봇이 아닙니다. 에이전트는 열린 세션을 유지합니다. 사용자의 마이크 스트림이 계속해서 들어오고, 모델은 오디오와 실시간 트랜스크립트를 다시 스트리밍하며, 사용자가 말하기 시작하고 멈추는 시점을 감지하고, 문장 중간에 끼어들 수 있으며(바지인), 카메라의 프레임을 볼 수 있고, 사용자의 도구를 호출한 뒤 그 결과를 말할 수 있습니다. 이 모든 과정은 "통화"를 끝내지 않고 이루어집니다.
ADK-Rust이 처음이신가요? 먼저 소개와 빠른 시작을 읽어 보세요. 이 섹션에서는 에이전트, 도구 및 세션이 무엇인지 알고 있다고 가정합니다.
구축할 수 있는 것
| 기능 | 의미 | 페이지 |
|---|---|---|
| 음성 대화 | VAD 및 끼어들기를 지원하는 양방향 PCM16 오디오 | 아키텍처 |
| 두 공급자, 하나의 API | 세션별로 교체 가능한 OpenAI Realtime(GA) 또는 Gemini Live | 공급자 |
| 서버 측 도구 | 모델이 process_refund(...)을 호출하고, Rust가 이를 실행하면 모델이 결과를 말합니다 | 도구 |
| 멀티모달 비전 | 카메라 프레임을 스트리밍하면 에이전트가 사용자가 보여 주는 것을 봅니다 | 멀티모달 |
| 감정 인식 대화 | 에이전트가 사용자의 감정적 어조를 읽고 그에 맞게 조정합니다(Gemini 네이티브 오디오) | 감정 인식 대화 |
| 장기 메모리 | 세션 시작 시 에이전트가 읽고 학습하면서 관리하는 지식 그래프 | 메모리 |
| 웹 앱 | 서버를 통해 연결된 브라우저 프런트엔드(마이크 + 카메라) | 웹 앱 구축 |
그런 다음 실행 가능한 네 가지 예제 앱을 확인하세요.
멘탈 모델
두 개의 계층이 있으며, 대부분의 애플리케이션은 상위 계층을 사용합니다.
IntegratedRealtimeRunner ← sessions, memory, tools, plugins (use this)
│ wraps
RealtimeRunner ← event loop + tool dispatch
│ drives
RealtimeSession (a transport) ← the live WebSocket to the provider
│ created by
RealtimeModel (OpenAI | Gemini)
RealtimeModel(예:OpenAIRealtimeModel,GeminiRealtimeModel)는connect()하고RealtimeSession— 활성 transport — 를 생성하는 방법을 알고 있습니다.- **
RealtimeRunner**는 해당 세션을 관리합니다. 이벤트를 처리하고, 모델이 도구를 요청하면 핸들러를 실행한 다음 결과를 다시 전송합니다. - **
IntegratedRealtimeRunner**는 runner를 래핑하고 이를 ADK의 나머지 기능 —SessionService(transcript 영속성),MemoryService(recall + storage),EnhancedPluginManager(hooks), 그리고 모든adk-coreTool를 실시간 세션에서 실행할 수 있게 하는 bridge — 에 연결합니다. 예제에서 사용하는 것이 바로 이것입니다.
(간단한 음성 전용 agent를 위한 상위 수준의 RealtimeAgent도 있으며, 직접 transport인 WebRTC, LiveKit, Vertex AI
Live는 해당 문서에 설명되어 있습니다.)
설치
# Voice + tools + the integration layer (recommended)
adk-realtime = { version = "2.1.0", features = ["openai", "gemini", "integration"] }
| 기능 | 추가 내용 |
|---|---|
openai | OpenAI Realtime (WebSocket) |
gemini | Gemini Live (WebSocket) |
integration | IntegratedRealtimeRunner — 세션, 메모리, 플러그인, 도구 브리지 |
openai-webrtc | OpenAI을 통한 WebRTC (cmake 필요) |
vertex-live | Vertex AI Live를 통한 Gemini (OAuth2 / ADC) |
livekit | LiveKit WebRTC 브리지 |
60초 빠른 시작
헤드리스 음성 턴: 연결하고, 텍스트로 요청한 다음, 스트리밍 응답을 계속 처리합니다.
use adk_realtime::config::{RealtimeConfig, VadConfig};
use adk_realtime::events::ServerEvent;
use adk_realtime::integration::{IntegratedRealtimeRunner, IntegrationConfig};
use adk_realtime::model::BoxedModel;
use adk_realtime::openai::OpenAIRealtimeModel;
use adk_session::{CreateRequest, InMemorySessionService, SessionService};
use std::sync::Arc;
# async fn run() -> anyhow::Result<()> {
let model: BoxedModel = Arc::new(OpenAIRealtimeModel::new(
std::env::var("OPENAI_API_KEY")?,
"gpt-realtime-2.1",
));
let config = RealtimeConfig::default()
.with_instruction("You are a friendly assistant. Keep replies short.")
.with_voice("marin")
.with_audio_only()
.with_vad(VadConfig::server_vad()) // model decides turn boundaries
.with_transcription(); // emit a text transcript too
let sessions = Arc::new(InMemorySessionService::new());
sessions.create(CreateRequest {
app_name: "demo".into(), user_id: "u1".into(),
session_id: Some("s1".into()), state: Default::default(),
}).await?;
let runner = IntegratedRealtimeRunner::builder()
.model(model)
.config(config)
.identity("demo", "u1", "s1")
.session_service(sessions)
.integration_config(IntegrationConfig::default())
.build()?;
runner.connect().await?;
runner.send_text("Say hello in one short sentence.").await?;
runner.create_response().await?; // text input needs an explicit trigger
while let Some(event) = runner.next_event().await {
match event? {
ServerEvent::TranscriptDelta { delta, .. } => print!("{delta}"),
ServerEvent::AudioDelta { .. } => { /* PCM16 to play */ }
ServerEvent::ResponseDone { .. } => break,
_ => {}
}
}
runner.close().await?;
# Ok(()) }
실제 앱에서는 send_text 대신 runner.send_audio(base64_pcm16)로 마이크 오디오를 스트리밍하며, 서버 VAD가 자동으로 응답을 구동하므로 create_response()이 필요하지 않습니다. 웹 앱 빌드를 참조하세요.