Twilio Conversation Relay를 사용해 PHP(Mezzio + Swoole)로 실시간 AI 음성 에이전트를 구축하는 단계별 튜토리얼이다. WebSocket을 통해 발신자 음성을 STT로 전사하고 OpenAI로 응답을 생성한 뒤 TTS로 재생하는 전체 파이프라인을 코드 수준에서 다룬다. 가상 항공사 "Owl Air"를 예제로 비행 상태 조회, 수하물 정책 문의 등 실제 도구 호출(function calling)까지 구현한다.
핵심 포인트- Conversation Relay는 STT-WebSocket-TTS 음성 파이프라인 전체를 추상화해 개발자가 AI 로직에만 집중할 수 있게 한다.
- Mezzio-Swoole WebSocket 핸들러가 setup/prompt/interrupt/error 4가지 메시지 유형을 처리하고 OpenAI 스트리밍 응답을 토큰 단위로 실시간 전달한다.
- Deepgram nova-3-general 모델(Flux)로 STT를 처리하여 발화 종료 감지 지연을 200~600ms 줄이고 false interruption을 약 30% 감소시킨다.
- OpenAI function calling으로 비행 상태 조회를 구현, 응답 중간에 외부 데이터를 조회한 뒤 자연스럽게 이어 응답한다.
- Conversation Relay 응답 지연 중앙값 0.5초 미만, Swoole Table로 전체 워커 간 연결 상태와 메시지 이력을 공유한다.
상세 정리- 아키텍처 흐름: 발신자 전화 → Twilio가 TwiML 요청 → 서버가 `<ConversationRelay>` 동사 반환 → WebSocket 연결 수립 → STT 전사 → OpenAI 추론 → TTS 재생.
- 필수 스택: PHP 8.4, Composer, Mezzio 프레임워크, mezzio-swoole-websocket, OpenAI PHP 클라이언트, Twilio PHP 헬퍼 라이브러리, ngrok.
- TwiML 설정: /twiml 엔드포인트에서 `<ConversationRelay>` 동사를 반환하며 domain, welcomeGreeting, STT/TTS 제공자를 지정한다.
- Conversation Relay 주요 속성: ttsProvider=ElevenLabs, transcriptionProvider=Deepgram, speechModel=nova-3-general, eotThreshold=0.8, ignoreBackchannel=true, interruptible=any.
- Swoole Table 설계: ConnectionTable(1024행, 통화 SID 저장)과 MessageTable(10000자, 메시지 이력)으로 전체 워커 간 상태를 동기화한다.
- 음성 최적화 시스템 프롬프트 규칙: 마크다운/이모지 금지, 숫자 철자 표기("30달러" 대신 "thirty dollars"), 응답 최대 2~3문장으로 TTS 품질을 높인다.
- 도구 호출 흐름: 모델이 finishReason=tool_calls를 반환하면 executeTool() 실행 → 결과를 담은 두 번째 스트림 호출로 자연스러운 응답 완성.
- 서버 실행: DOMAIN과 OPENAI_API_KEY 환경변수 설정 후 laminas mezzio:swoole:start, 포트 8080, 워커 2개 + 태스크 워커 2개.
- 테스트 시나리오: 수하물 정책, 충성도 포인트, 비행 변경, 비행 상태 조회(OA205 40분 지연, OA318 취소, OA999 없는 편 우아한 처리) 등 6가지 케이스 검증.
- 확장 방향: 인간 에이전트 전환(end-session 메시지), TwiML Parameter로 발신자 개인화 데이터 주입, 실시간 DB 연동으로 모의 데이터 교체.
왜 읽나PHP로 실시간 AI 음성 에이전트를 처음 구축하는 개발자에게 STT-WebSocket-LLM-TTS 전체 파이프라인을 코드 수준에서 따라갈 수 있는 완전한 구현 레퍼런스다.