박승율 1회기 종료멘트 자동전환 실패
— LiveKit 완료 이벤트 누락 원인 분석 분석 완료 · 수정 미적용
마지막 업데이트 2026-09-12
결론
agent_response_completed 이벤트가 누락되어, 클라이언트가 자동전환의 최종 관문인 assistant_audio_stopped를 만들지 못했다. 그 결과 Auto-finish triggered와 진행자 전달 이벤트가 모두 발생하지 않았다.중요한 구분: 화면의 하이라이트 및 Checking auto-finish phrase는 “조건 후보 텍스트를 보관”했다는 뜻이다. 실제 전환은 AI 발화 완료 이벤트가 도착한 뒤에만 실행된다.
증상과 범위
아동이 회고 활동에서 종료 멘트 “오늘 호덕이랑 태린이가 너에게 큰 도움을 받은 것 같대… 진짜 멋졌어!”를 발화했다. 멘트는 종료 조건과 매칭되어 화면에서 하이라이트됐지만, 진행자 화면의 활동 자동전환은 일어나지 않았다.
시각 타임라인 — 감지는 됐고, 완료 신호에서 멈췄다
Checking auto-finish phrase — response-8 텍스트에 종료 멘트가 포함됨. 조건 후보 2개가 로드된 상태.
LiveKit는 agent_response_terminal_boundary를 여러 번 수신. 텍스트 생성 경계 이벤트다.
누락: 해당 response-8에 대한 agent_response_completed, AI speech ended, processing auto-finish, Auto-finish triggered가 모두 없음.
Step changed by host — 진행자 발신 스텝 변경이 아동에 도착. 자동전환이 아니라 수동 변경.
guest-step-update가 활동 6 / 스텝 0으로 발생. 이는 위 진행자 변경을 반영한 후속 상태 통지다.
실행 경로 — 실제로 끊긴 경계
텍스트 수신
responseDataRefagent_response_completedassistant_audio_stoppedAuto-finish triggeredguest-session-auto-finishLiveKit agent_response_completed → liveKitDataToVoiceSessionEvent(...) → assistant_audio_stopped → shouldProcessAutoFinishOnAssistantAudioEnd(...) === true → autoFinish.handlePingpongSpeech(...) → 1초 뒤 onAutoFinish(...) → 게스트 스텝 이동 및 진행자 동기화
문제 응답은 첫 줄이 없었으므로 이후 체인이 시작되지 않았다.
코드 근거
| 경로 | 확인한 동작 | 사건과의 관계 |
|---|---|---|
apps/web/lib/voice-agent/livekit-client-session.ts | agent_response_completed만 assistant_audio_stopped로 변환한다. | 문제 응답은 완료 이벤트가 없어 변환 불가. |
apps/web/lib/voice-agent/session-events.ts | LiveKit 발화 종료는 raw 이벤트가 agent_response_completed일 때만 자동종료 처리한다. | terminal_boundary만으로는 의도적으로 실행하지 않음. |
apps/web/entities/guest-session/model/use-ai-session.ts | 발화 종료 시 저장된 transcript를 다시 매칭하고 Auto-finish triggered를 호출한다. | 발화 종료 이벤트 미도달로 이 분기에 진입하지 않음. |
apps/web/entities/guest-page-session/model/use-guest-page-session.ts | 자동종료 콜백에서 다음 스텝 이동을 수행한다. | 콜백 자체가 호출되지 않음. |
정상 사례와의 비교
| 상태 | 문제 활동 5 | 동일 세션의 정상 활동 6 |
|---|---|---|
| 종료 멘트 텍스트 | 있음 | 있음 |
agent_response_terminal_boundary | 있음 | 있음 |
agent_response_completed | 없음 | 16:18:22.512 수신 |
AI speech ended, processing auto-finish | 없음 | 16:18:22.517 발생 |
| 자동전환 | 없음; 32.7초 후 진행자 수동 변경 | 16:18:23.526 자동전환 발생 |
배제한 가설과 남은 불확실성
- 자동전환 OFF: 배제. 종료 조건 검사 로그가 활성 상태로 남아 있다.
- 아동 소켓 업링크 단절: 직접 원인 아님. 문제 후 진행자 스텝 변경 및 아동의
guest-step-update가 정상 처리됐다. - 진행자 수신 실패: 발생 전제인 자동종료 이벤트가 아동에서 생성되지 않았으므로, 이 로그만으로 진행자 수신 실패라고 볼 수 없다.
- 왜 LiveKit 에이전트가 완료 이벤트를 누락했는가: 미확정. 제공 파일은 아동 로그뿐이라 에이전트/서버 측 원인은 별도 관측이 필요하다.
검증과 후속 조치
수행한 검증: JSONL 9,980건을 room·responseId·KST 시각으로 정렬하고, 동일 세션의 성공 자동전환 사례와 이벤트 순서를 비교했다. 소스에서 LiveKit 이벤트 변환과 자동종료 게이트 조건도 대조했다.
우선 확인할 Loki 범위
{service="ppi-socket", env=~"prod"} |= "3263d165-9cf8-4ccb-9e2f-4f0236b3dd66_1"
# 2026-08-16 16:16:45~16:17:30 KST
# 확인 대상: guest-session-auto-finish / Host changed step / Guest step update
같은 증상의 다른 경로: 완료 이벤트는 정상 도착했지만 AI가 다음 스텝의 종료멘트를 앞 스텝에서 미리 발화해 현재 스텝 문구와 미매칭으로 폐기되는 사례가 별도로 있다 — 이윤준 8회기 종료멘트 선발화 자동전환 실패 — 스텝 미매칭 원인 분석. 두 경로의 판별 기준은 agent_response_completed의 유무다.
최소 보완 방향
- LiveKit 에이전트에서
agent_response_terminal_boundary뒤agent_response_completed가 누락되는 이유를 responseId 단위로 계측한다. - 종료 조건이 매칭됐는데 완료 이벤트가 일정 시간 오지 않을 때의 진단 로그/경보를 추가한다.
- 완료 이벤트 대체 타임아웃은 실제 음성이 끝나기 전에 활동을 넘길 위험이 있으므로, 재현과 재생 종료 기준을 검증한 뒤 도입한다.