사용자 지정 LLM 통합
개요
ElevenAgents의 네이티브 Twilio 통합은 ElevenLabs가 LLM을 호스팅하는 경우를 다룹니다. 자체 모델, RAG 파이프라인, 함수 호출 라우팅 또는 기타 서버 측 추론 등 자체 서버에서 LLM 두뇌를 완전히 제어해야 하면서 에이전트는 Twilio 전화번호에서 작동해야 할 때 이 가이드를 사용하세요.
사용자 지정 LLM 부분은 Speech Engine SDK를 통해 제공되며, 이는 ElevenLabs와 서버 간에 WebSocket을 열어 통화가 진행되는 동안 LLM이 응답을 스트리밍으로 다시 보낼 수 있게 합니다. Twilio 부분에서는 Media Streams를 사용하여 통화 오디오를 에이전트로 중계합니다.
아키텍처
Speech Engine SDK는 에이전트의 대화 시스템에서 두 개의 WebSocket 엔드포인트를 제공합니다.
- brain WebSocket은 서버에서 실행됩니다. ElevenLabs는 여기에 연결하여 트랜스크립트를 전달하고 LLM 생성 텍스트를 받습니다.
- conversation WebSocket은 ElevenLabs에서 실행됩니다. 클라이언트는 여기에 연결하여 오디오를 보내고 합성된 오디오를 다시 받습니다. Twilio 브리지는 서명된 URL을 통해 연결하고 양방향으로 μ-law 오디오를 중계합니다.
Twilio Media Streams와 Speech Engine은 모두 ulaw_8000을 사용하므로, 브리지는 트랜스코딩 없이 base64 인코딩 오디오를 중계합니다.
편리하다면 브리지와 brain 서버를 동일한 프로세스에서 실행할 수 있습니다. 아래 예시에서는 둘을 결합합니다.
이 패턴을 사용할 때
이 가이드와 네이티브 Twilio 통합은 모두 Twilio 전화번호에서 에이전트를 작동시킵니다. 차이점은 LLM의 소유 주체입니다.
- 네이티브 통합: ElevenLabs가 LLM을 호스팅하며, 에이전트를 통해 구성합니다. 더 간단합니다.
- Speech Engine SDK를 통한 사용자 지정 LLM(이 가이드): 자체 서버에서 LLM을 호스팅합니다. 모델, RAG, 함수 호출 및 비즈니스 로직을 완전히 제어할 수 있습니다. 구성 요소가 더 많습니다.
LLM 로직이 표준 에이전트 구성 안에서 작동한다면 네이티브 통합을 사용하세요. 두뇌가 자체 인프라에서 코드를 실행해야 할 때 이 가이드를 사용하세요.
이 패턴은 서버와 ElevenLabs API 간 통신에 WebSocket 연결을 사용하는 Speech Engine SDK를 사용합니다. Speech Engine SDK 대신 OpenAI 호환 HTTP 엔드포인트를 사용하는 사용자 지정 LLM 가이드를 사용할 수도 있습니다.
두 방식의 주요 차이점은 WebSocket과 HTTP 요청입니다. WebSocket을 사용하면 각 턴마다 새 HTTP 연결을 설정하는 대신 단일 연결을 유지하므로 지연 시간이 개선될 수 있습니다.
사전 요구 사항
- Twilio 계정 및 음성 통화가 가능한 전화번호
- Speech Engine 리소스. Speech Engine 빠른 시작을 따라 리소스를 만들고 brain 서버 패턴을 알아보세요.
- 공개 HTTPS 터널(예: ngrok). Twilio는 공용 인터넷을 통해 브리지에 연결합니다.
- Python 3.9+ 또는 Node.js 18+.
μ-law 오디오용 에이전트 구성
Twilio Media Streams는 8kHz μ-law 오디오를 사용합니다. 브리지에서 트랜스코딩할 필요가 없도록 Speech Engine이 동일한 형식을 수신하고 출력하도록 구성하세요.
eleven_flash_v2는 텍스트 음성 변환 지연 시간을 낮게 유지하므로 전화 통화에서 중요합니다. request_headers 블록은 모든 brain WebSocket 연결에 x-api-key: <shared-secret>를 포함하도록 ElevenLabs에 지시합니다. brain 서버는 헤더를 확인하여 Speech Engine만 연결할 수 있도록 합니다.
브리지 서버 구축
브리지는 세 가지 라우트를 제공합니다.
POST /incoming-call— Twilio 웹훅입니다. Twilio에/media-stream으로 Media Stream을 열도록 지시하는 TwiML을 반환합니다.GET /media-stream— Twilio Media Streams WebSocket입니다. Speech Engine conversation WebSocket으로 오디오를 중계하고 다시 받습니다.GET /ws— Brain WebSocket입니다. 대화가 시작되면 ElevenLabs가 여기에 연결합니다. 표준engine.serve()/engine.attach()서버를 실행합니다.
Speech Engine용 서명된 URL 생성
브리지는 새 통화가 도착할 때마다 서명된 URL을 요청합니다. URL에는 Speech Engine ID와 일회성 서명이 포함되므로 브리지에 원본 API 키가 필요하지 않습니다.
TwiML 응답 제공
통화가 도착하면 Twilio는 /incoming-call에 POST 요청을 보냅니다. 응답은 브리지 자체의 /media-stream WebSocket으로 Media Stream을 여는 TwiML입니다.
RequestValidator(Python) 및 twilio.webhook({ validate: true })(Node)는 X-Twilio-Signature 헤더를 TWILIO_AUTH_TOKEN과 비교하여 확인합니다. 유효성 검사가 없으면 공용 인터넷의 누구나 /incoming-call에 POST 요청을 보내 계정에 통화 요금을 청구할 수 있습니다.
Media Stream 브리지 연결
Media Stream은 connected, start, media(오디오 페이로드), stop 순서의 JSON 이벤트를 전송하는 WebSocket입니다. 브리지는 start에서 Speech Engine conversation WebSocket을 열고 스트림이 닫힐 때까지 양방향으로 오디오를 중계합니다.
Speech Engine의 interruption 이벤트는 Twilio 스트림에서 clear 이벤트를 트리거하여 버퍼링된 오디오를 모두 삭제하므로 끼어들기 기능이 깔끔하게 작동합니다. ping 이벤트에는 pong으로 응답하여 conversation WebSocket 연결을 유지합니다.
brain 서버 함께 실행
brain 서버는 빠른 시작에 표시된 표준 Speech Engine 서버입니다. 유일한 추가 사항은 WebSocket 업그레이드 시 공유 시크릿을 확인하는 것입니다. x-api-key가 Speech Engine에 설정한 값과 일치할 때만 연결을 수락하세요.
LLM 호출과 스트리밍 응답을 포함한 전체 on_transcript 구현은 Speech Engine 빠른 시작을 참조하세요.
Twilio를 브리지로 연결
Speech Engine ws_url 업데이트
ElevenLabs가 연결할 위치를 알 수 있도록 speech_engine.ws_url을 brain 엔드포인트의 공개 WebSocket URL로 설정하세요.
프로덕션 고려 사항
- 웹훅 유효성 검사:
/incoming-call에서 항상X-Twilio-Signature를 검증하세요. 위 예시는 Twilio의 헬퍼 라이브러리를 사용합니다. 이 단계를 건너뛰지 마세요. - 공유 시크릿: brain WebSocket에서 공유 시크릿을 적용하세요. 그렇지 않으면 ngrok URL을 추측한 누구나 연결하여 ElevenLabs를 사칭할 수 있습니다.
- 안정적인 호스트: ngrok 무료 티어 URL은 재시작할 때마다 변경됩니다. 재시작할 때마다 Speech Engine
ws_url과 Twilio 웹훅을 업데이트하지 않도록 예약된 ngrok 도메인 또는 실제 호스트 이름을 사용하세요. - 지연 시간: 각 통화는 LLM의 첫 토큰 생성 시간에 더해 두 번의 네트워크 홉을 추가합니다. 지연 시간이 짧은 모델을 사용하고 응답을 스트리밍하여 체감 지연 시간을 낮게 유지하세요.
- 하나의 프로세스 또는 두 개: 예시에서는 단일 ngrok 터널이 모든 것을 처리하도록 브리지와 brain을 같은 포트에 배치합니다. 프로덕션 환경에서는 각각 공개 URL이 있는 한 두 서비스로 분리할 수 있습니다.
- 프롬프트 인젝션: 전화 통화의 음성 입력은 신뢰할 수 없는 사용자 입력입니다. 도구 호출이나 데이터베이스 쓰기에 영향을 주기 전에 트랜스크립트를 검증하세요.