실시간 대화형 시각 AI를 구축하려면 핵심적인 엔지니어링 병목 현상인 '지연 시간(레이턴시)'을 해결해야 합니다. 기존의 합성 비디오 생성 파이프라인은 비동기 배치 모드로 작동하므로 MP4 비디오 파일을 렌더링, 인코딩 및 전달하는 데 수 초에서 수 분까지 소요됩니다. AI 영업 담당자, 가상 의료 어시스턴트, 고객 지원 아바타, 대화형 디지털 튜터와 같은 상호작용 중심의 유스케이스에서는 수 초의 지연만으로도 대화 흐름이 끊기고 사용자 몰입도가 크게 떨어집니다.
D-ID는 저지연 비디오 생성 알고리즘과 WebRTC 및 LiveKit 데이터 전송을 결합한 실시간 스트리밍 인프라를 통해 이 문제를 해결합니다. D-ID의 스트리밍 엔진은 디스크에 완전한 비디오 파일을 생성하는 대신, 립싱크된 아바타 비디오 프레임을 실시간으로 렌더링하여 1초 미만의 응답 시간으로 클라이언트 브라우저에 직접 스트리밍합니다. 초기 구현은 레거시 Talks 및 Clips 스트리밍 엔드포인트(/talks/streams)에 의존했지만, 현재 D-ID의 최신 아키텍처는 D-ID Agents 프레임워크와 공식 @d-id/client-sdk를 중심으로 구성되어 있습니다.
본 가이드에서는 백엔드 에이전트 구성, WebRTC 세션 협상, 프론트엔드 미디어 스트림 연결, 대화 상호작용 패턴, 지연 시간 최적화, 크레딧 수명 주기 관리를 포함하여 D-ID Streaming API를 대형 언어 모델(LLM)과 통합하기 위한 완전한 아키텍처 파이프라인을 살펴봅니다.
아키텍처 개요: 대화형 아바타 파이프라인
실시간 대화형 아바타 애플리케이션은 사용자 입력, 언어 추론, 음성 합성, 얼굴 애니메이션 및 피어 투 피어 미디어 전달에 걸친 유기적인 루프로 작동합니다:
+-------------+ Audio / Text +-------------------+
| | ---------------------> | Application Logic |
| User Client | | (STT / LLM / RAG) |
| (Browser) | <--------------------- +-------------------+
| | WebRTC Video / Audio |
| | <---------------------------+ | Text / Audio Chunks
+-------------+ | v
+-------------------+
| D-ID Streaming |
| Engine & Agents |
+-------------------+
개발자는 일반적으로 인프라 요구 사항에 따라 다음 두 가지 통합 패러다임 중 하나를 채택합니다:
- 매니지드 D-ID Agent 워크플로: D-ID가 내부적으로 LLM 시스템 프롬프트, 외부 지식 기반(검색 증강 생성 / RAG) 및 텍스트 음성 변환(TTS) 음성 제공자를 관리합니다. 클라이언트 애플리케이션은
@d-id/client-sdk를 사용하여 에이전트에 직접 연결하고agentManager.chat()을 통해 사용자 프롬프트를 전송합니다. - 커스텀 백엔드 오케스트레이션 워크플로: 개발자의 백엔드가 대화 상태, 사용자 인증, 전용 도구, 벡터 데이터베이스 및 LLM 호출(예: OpenAI GPT-4o, Anthropic Claude 또는 자체 호스팅 모델)에 대한 완전한 제어권을 보유합니다. 이후 백엔드는 생성된 텍스트나 합성된 오디오를
agentManager.speak()또는 REST 스트리밍 엔드포인트를 통해 D-ID로 스트리밍하여 아바타를 움직입니다.
1단계: REST API를 통한 Agent 프로비저닝 및 구성
실시간 스트림을 열기 전에 개발자는 아바타의 페르소나, 음성 특성 및 인텔리전스 계층을 구성해야 합니다. D-ID Studio 인터페이스를 통해 에이전트를 생성할 수도 있지만, 프로덕션 애플리케이션에서는 일반적으로 REST API를 통해 이러한 프로비저닝을 자동화합니다.
에이전트 생성
D-ID API 키로 인증하여 https://api.d-id.com/agents로 POST 요청을 전송합니다:
curl -X POST "https://api.d-id.com/agents" \
-H "Authorization: Basic <YOUR_BASE64_ENCODED_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"presenter": {
"type": "clip",
"presenter_id": "v2_public_Amber@0zSz8kflCN",
"voice": {
"type": "microsoft",
"voice_id": "en-US-JennyMultilingualV2Neural"
}
},
"llm": {
"type": "openai",
"provider": "openai",
"model": "gpt-4o",
"instructions": "You are an AI customer success specialist for an enterprise SaaS platform. Keep responses under two sentences, maintain an empathetic and professional tone, and guide users to relevant product features."
}
}'
주요 구성 매개변수
| 구성 객체 | 매개변수 | 설명 |
|---|---|---|
presenter | type | 아바타 렌더링 유형: talk(사진 기반 V2), clip(사전 렌더링된 스튜디오 발표자 V3), 또는 expressive(LiveKit 기반 V4 아바타). |
presenter | presenter_id 또는 source_url | 기본 제공 D-ID 발표자의 식별자 또는 커스텀 사진 아바타를 위한 공개 접근 가능한 HTTPS 이미지 URL. |
presenter.voice | type | 음성 제공자 엔진, 주로 microsoft(Azure Neural) 또는 elevenlabs. |
presenter.voice | voice_id | 제공자 카탈로그와 일치하는 특정 음성 모델 식별자(예: en-US-JennyMultilingualV2Neural). |
llm | type 및 provider | 네이티브 매니지드 완성을 위한 openai, 외부 백엔드 라우팅을 위한 custom. |
llm | instructions | 아바타의 페르소나, 제약 조건 및 대화 범위를 정의하는 시스템 지침. |
API는 고유한 agentId가 포함된 JSON 응답을 반환합니다. 이 식별자를 애플리케이션 데이터베이스에 저장하십시오.
클라이언트 자격 증명 보안
프로덕션 웹 및 모바일 애플리케이션은 기본 D-ID API 키를 클라이언트 측 코드에 직접 노출해서는 안 됩니다. 대신 백엔드를 통해 범위가 제한된 Client Key를 생성하십시오:
curl -X POST "https://api.d-id.com/agents/<AGENT_ID>/client-key" \
-H "Authorization: Basic <YOUR_BASE64_ENCODED_API_KEY>" \
-H "Content-Type: application/json"
D-ID Studio 대시보드에서 무단 사용을 방지하기 위해 Allowed Domains 설정을 사용하여 이 클라이언트 키를 프로덕션 도메인으로 제한하십시오.
2단계: 저지연 WebRTC 스트림 설정
실시간 상호작용을 위해서는 클라이언트 브라우저와 D-ID 렌더링 클러스터 간의 WebRTC 피어 연결이 필요합니다. D-ID는 두 가지 통합 경로를 제공합니다: 자동화된 @d-id/client-sdk(적극 권장) 및 REST 기반 직접 WebRTC 시그널링입니다.
방법 A: @d-id/client-sdk를 통한 클라이언트 통합 (권장)
공식 @d-id/client-sdk는 세션 협상, 세션 기술 프로토콜(SDP) 오퍼/앤서 교환, 대화형 연결 설정(ICE) 후보 수집을 간소화된 JavaScript 인터페이스로 추상화합니다.
1. SDK 설치
npm install @d-id/client-sdk
2. AgentManager 초기화 및 미디어 트랙 바인딩
import * as did from "@d-id/client-sdk";
// DOM 요소
const videoElement = document.getElementById("avatar-video");
const statusElement = document.getElementById("connection-status");
const chatInputElement = document.getElementById("chat-input");
const sendButton = document.getElementById("send-btn");
let agentManager = null;
async function initializeAvatar() {
const agentId = "agt_xxxxxxxxxxxxxxxx";
const clientKey = "YOUR_CLIENT_KEY";
agentManager = await did.createAgentManager(agentId, {
auth: {
type: "key",
clientKey: clientKey
},
callbacks: {
// D-ID WebRTC 피어로부터 수신된 연결 미디어 스트림
onSrcObjectReady(mediaStream) {
videoElement.srcObject = mediaStream;
videoElement.play().catch((err) => console.error("Video autoplay error:", err));
},
// 연결 상태 전환 추적: connecting, connected, disconnected, closed
onConnectionStateChange(state) {
statusElement.textContent = `Status: ${state}`;
console.log("WebRTC Connection State:", state);
},
// 수신되는 대화 턴 처리
onNewMessage(messages) {
const latest = messages[messages.length - 1];
console.log(`[${latest.role}]: ${latest.content}`);
},
// 아바타 음성 수명 주기 모니터링
onVideoStatusChange(status) {
console.log("Avatar Video Status:", status); // 예: "playing", "idle"
},
onError(error, errorData) {
console.error("D-ID Agent Error:", error, errorData);
}
}
});
// WebRTC 세션 연결
await agentManager.connect();
}
initializeAvatar().catch(console.error);
방법 B: 수동 WebRTC 시그널링 핸드셰이크 (내부 메커니즘)
헤드리스 환경, 비브라우저 클라이언트(네이티브 모바일 앱 또는 임베디드 디바이스 등) 또는 레거시 시스템의 경우 개발자는 D-ID의 REST 엔드포인트를 사용하여 직접 WebRTC 핸드셰이크를 수행할 수 있습니다:
-
스트림 세션 초기화:
https://api.d-id.com/agents/{agentId}/streams(또는 레거시/talks/streams)로POST요청을 보냅니다. D-ID는 다음을 반환합니다:id: 고유 스트림 세션 ID.session_id: 세션 추적 식별자.offer: D-ID의 WebRTC 미디어 서버에서 생성한 SDP 오퍼.ice_servers: NAT 통과에 필요한 STUN 및 TURN 서버 자격 증명 목록.
-
로컬
RTCPeerConnection초기화: 클라이언트는 D-ID의ice_servers로 구성된RTCPeerConnection인스턴스를 생성합니다:const pc = new RTCPeerConnection({ iceServers: response.ice_servers }); -
원격 설명 설정 및 로컬 응답 생성:
await pc.setRemoteDescription(new RTCSessionDescription(response.offer)); const answer = await pc.createAnswer(); await pc.setLocalDescription(answer); // SDP 응답을 D-ID에 제출 await fetch(`https://api.d-id.com/agents/${agentId}/streams/${response.id}/sdp`, { method: "POST", headers: { "Authorization": `Basic ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ answer: answer, session_id: response.session_id }) }); -
ICE 후보 교환: 클라이언트 피어 연결에서
onicecandidate이벤트를 감지하고 각 후보를 D-ID의 ICE 엔드포인트로 전달합니다:pc.onicecandidate = (event) => { if (event.candidate) { fetch(`https://api.d-id.com/agents/${agentId}/streams/${response.id}/ice`, { method: "POST", headers: { "Authorization": `Basic ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ candidate: event.candidate.candidate, sdpMid: event.candidate.sdpMid, sdpMLineIndex: event.candidate.sdpMLineIndex, session_id: response.session_id }) }); } }; -
미디어 트랙 수신: 미디어 트랙이 도착하면 원격 스트림을 DOM에 바인딩합니다:
pc.ontrack = (event) => { videoElement.srcObject = event.streams[0]; };
3단계: 대화 상호작용: chat() 대 speak()
WebRTC 세션이 활성화되면 개발자는 SDK에서 제공하는 두 가지 기본 메서드를 사용하여 아바타 애니메이션을 트리거합니다.
패턴 1: 자율 대화 턴 (chat)
에이전트에 내장 LLM 로직이 구성되어 있는 경우 에이전트의 대화 스레드에 직접 텍스트 메시지를 보냅니다:
// 사용자가 UI를 통해 프롬프트를 제출
async function handleUserSubmit(userText) {
if (!agentManager) return;
// 사용자 메시지를 에이전트에 전송. 에이전트가 LLM을 쿼리하고 음성을 생성하며 비디오를 스트리밍함
await agentManager.chat(userText);
}
D-ID 에이전트는 사용자 턴 추적, LLM 추론, TTS 생성 및 비디오 합성을 자동으로 처리하며, 토큰과 메시지가 확인되는 대로 onNewMessage 콜백을 호출합니다.
패턴 2: 커스텀 백엔드 오케스트레이션 (speak)
애플리케이션 로직에 엔터프라이즈 데이터베이스를 대상으로 한 멀티턴 RAG 쿼리, 도구 호출 기능이 있는 LangChain 에이전트, 커스텀 LLM 엔드포인트와 같은 독점적인 워크플로가 필요한 경우 개발자는 speak() 메서드를 사용합니다. 이를 통해 백엔드는 독립적으로 응답을 생성하고 아바타에 특정 콘텐츠를 발화하도록 지시할 수 있습니다.
텍스트 입력 전송
// 에이전트에 구성된 TTS 음성을 사용하여 아바타가 임의의 텍스트를 말하도록 지시
await agentManager.speak({
type: "text",
input: "Welcome back, Sarah. I have pulled your quarterly analytics report."
});
사전 합성된 오디오 전송
특수 음성 엔진(예: 커스텀 음성 복제 또는 독자적인 음성 모델)을 사용하는 애플리케이션의 경우 공개 접근 가능한 HTTPS 오디오 URL을 직접 전달할 수 있습니다:
// 아바타의 입 모양과 표정이 제공된 오디오와 동기화되어 움직임
await agentManager.speak({
type: "audio",
audio_url: "https://storage.yourdomain.com/audio/response_chunk_01.mp3"
});
프로덕션 지연 시간 최적화 및 성능 전략
대화형 AI에서 지연 시간에 대한 인간의 내성은 매우 낮습니다. 1,000~1,500밀리초 이상의 대화 중단은 부자연스럽게 느껴집니다. 유연한 대화를 구현하려면 파이프라인의 모든 단계를 최적화해야 합니다.
1. 연결 프리워밍(사전 예열)
WebRTC 연결 수립(SDP 교환, STUN/TURN 후보 검색, ICE 연결 확인)에는 네트워크 상태에 따라 일반적으로 800ms에서 2,500ms가 소요됩니다.
- 안티패턴: 사용자가 첫 번째 쿼리를 제출한 후에만
agentManager.connect()를 호출하는 방식. - 모범 사례: 사용자가 애플리케이션 뷰를 열거나, 채팅 입력창에 포커스를 두거나, 인증을 완료하는 즉시 백그라운드에서 WebRTC 연결을 사전 예열(Pre-warming)합니다. 사용자가 첫 메시지를 보낼 때 아바타는 이미 연결되어 있어 즉시 응답을 렌더링할 수 있습니다.
2. 긴 LLM 응답을 위한 스트림 청킹
LLM이 여러 문장으로 구성된 전체 단락 생성을 완료할 때까지 기다린 후 speak()를 호출하면 상당한 지연(첫 번째 토큰 생성 시간 + 전체 완료 시간)이 발생합니다.
체감 지연을 최소화하려면:
- 백엔드에서 LLM의 Server-Sent Events(SSE) 토큰 스트림을 버퍼링합니다.
- 자연스러운 문장 구분 기호(
.,?,!)에서 수신 텍스트를 분할합니다. - LLM이 후속 문장을 계속 생성하는 동안 첫 번째 문장을 즉시 D-ID로 전달합니다.
- 후속 문장을 큐에 넣어 끊김 없는 연속 음성을 유지합니다.
3. 끼어들기 및 인터럽트 처리 (Barge-In)
자연스러운 대화를 위해서는 사용자가 아바타의 발화 도중 끼어들 수 있어야 합니다. D-ID의 최신 스트리밍 아키텍처에서는 원활한 스트리밍 제어를 통해 인터럽트 기능을 기본적으로 지원합니다:
// 아바타가 말하는 동안 사용자의 음성이 감지되었을 때 처리
function onUserSpeechDetected() {
if (agentManager) {
// 현재 음성 재생을 중단하고 아바타를 대기(경청) 상태로 되돌림
agentManager.interrupt();
}
}
인터럽트 이벤트가 발생하면 D-ID는 서버의 활성 음성 대기열을 잘라내고 비디오 전송을 중지하여 아바타가 사용자의 말을 가로막지 않도록 보장합니다.
4. LiveKit 기반 Expressive 아바타 (V4)
자연스러운 존재감을 우선시하는 애플리케이션을 위해 D-ID의 V4 Expressive Avatars는 표준 점대점 WebRTC 대신 LiveKit 전송 방식을 사용합니다. Expressive 아바타는 대화 턴 사이에도 지속적인 유휴 동작(자연스러운 눈 깜빡임, 미세한 고개 움직임, 호흡 리듬)을 유지하므로 기존 엔진에서 흔히 발생하던 정지 화면 현상을 방지합니다.
리소스 수명 주기 관리 및 과금 정책
실시간 비디오 아바타를 대규모로 배포하려면 세션 종료 규칙과 크레딧 정산 정책을 엄격하게 준수해야 합니다.
1. 정상적인 세션 종료
종료되지 않은 WebRTC 세션은 서버 리소스를 계속 소비하며 예상치 못한 크레딧 소진으로 이어질 수 있습니다. 컴포넌트 마운트 해제 및 윈도우 언로드 이벤트에서 항상 명시적인 연결 해제 핸들러를 구현하십시오:
// 창 언로드 시 세션 정리
window.addEventListener("beforeunload", () => {
if (agentManager) {
agentManager.disconnect().catch(console.error);
}
});
// 단일 페이지 애플리케이션에서 정리 (React / Vue / Svelte 마운트 해제 시)
function cleanupAvatarSession() {
if (agentManager) {
agentManager.disconnect();
agentManager = null;
}
}
REST 구현의 경우 세션 종료 시 https://api.d-id.com/agents/{agentId}/streams/{streamId}로 DELETE 요청을 실행하십시오.
2. 크레딧 소비 및 15초 올림 규칙
D-ID는 계정의 통합 분 단위 잔액(Creative Reality™ Studio와 API 간 공유)에서 비디오 생성 사용량을 직접 차감합니다.
- 15초 올림 단위: Streaming API를 통해 생성된 비디오 길이는 요청당 가장 가까운 15초 단위로 올림 처리됩니다. 예를 들어 4초 길이의 음성 응답을 생성하면 15초 분량의 API 비디오 크레딧이 차감됩니다.
- 최적화 시사점: 비용 효율성을 극대화하려면 "예", "알겠습니다", "확인했습니다"와 같은 극도로 짧은 한 단어 확인 응답을 개별
speak()요청으로 보내지 마십시오. 간결한 긍정 문구를 후속 안내와 함께 묶어 전송하거나 텍스트 UI 표시기를 활용하여 마이크로 확인을 처리하는 것이 좋습니다.
3. 유휴 시간 초과 및 비활성 보호
사용자가 브라우저 탭을 열어둔 채 방치할 때 발생하는 고아 세션을 방지하기 위해 비활성 타이머를 구현하십시오. 90초에서 120초 동안 사용자 상호작용이 없으면 사용자에게 확인을 요청하거나 agentManager.disconnect()를 사용하여 WebRTC 연결을 자동으로 종료하십시오.
통합 체크리스트 요약
| 단계 | 핵심 작업 | 권장 도구 / 엔드포인트 |
|---|---|---|
| 프로비저닝 | 음성, 페르소나 및 LLM 지침이 포함된 에이전트 생성 | POST /agents |
| 보안 | 도메인 허용 목록이 적용된 범위 제한 클라이언트 키 발급 | POST /agents/{agentId}/client-key |
| 연결 수립 | WebRTC 피어 세션 수립 및 <video> 스트림 연결 | @d-id/client-sdk (agentManager.connect()) |
| 상호작용 | 대화형 프롬프트 또는 외부 LLM 텍스트 청크 전송 | agentManager.chat() 또는 agentManager.speak() |
| UX 최적화 | 사용자 끼어들기(Barge-in) 및 백그라운드 연결 프리워밍 활성화 | 마이크 활동 감지 시 agentManager.interrupt() |
| 수명 주기 | 페이지 이탈 또는 유휴 시간 초과 시 WebRTC 스트림 종료 | agentManager.disconnect() / DELETE /streams/{id} |
D-ID의 실시간 스트리밍 엔진을 체계적인 LLM 프롬프트 오케스트레이션 및 클라이언트 측 WebRTC 수명 주기 관리와 결합함으로써, 개발 팀은 웹과 모바일 플랫폼 전반에서 엔터프라이즈급 성능을 발휘하는 빠르고 자연스러운 대화형 AI 아바타를 구축할 수 있습니다.