agent_activity.py:3390_reserve_realtime_audio_for_eot() → :3416commit_audio() (커밋 시각 + 2.5초 = 기한)
agent_activity.py:3455_recover_realtime_audio_for_eot() — commit 응답·final 대기, 기한 확인 후 조용히 return
agent_activity.py:3596_admit_realtime_audio_for_eot() → :3769skipping Half Cascade turn without exact provider final (턴 폐기, 응답 생성 안 함)
vendor/livekit-plugins-openai/…/realtime/realtime_model.py:2433 / :2459 / :2535 — delta·completed 수신, item별 final 대기
2. 목적 요약
HC(Half Cascade) 모드에서는 아동 턴을 커밋한 뒤 OpenAI 리얼타임 전사(gpt-4o-transcribe)의 completed(final)를 2.5초 안에 받아야 응답한다. 기한을 넘기면 agent가 그 턴을 조용히 버리고, AI는 아무 말도 하지 않는다. 이 문서는 한 수업에서 연달아 난 4건을 로그 시각 그대로 그림으로 옮겨, 폐기 턴이 정상 턴과 어디서 갈리는지 보여 준다.
요점: 4건 모두 짧은 발화였고 interim은 정상 시각(+0.5~0.6초)에 왔다. 갈린 곳은 interim이 끝난 뒤 completed까지의 공백 하나다. 같은 수업의 정상 턴 중에도 이 공백이 1.4~1.7초로 늘어나 기한 직전에 겨우 통과한 턴이 3개 있었다.
3. 입출력 흐름 — 한 건을 구성 요소별로 (HR01 turn-5)
시각은 agent 서버 시계(KST). 아동 PC 시계는 agent보다 약 1.5초 느려 보정했다.
그림 1. 초 단위 시각만 표시(17:32 생략). 정상 턴이었다면 completed 직후 입력 게이트 판정 → 응답 생성 → Typecast 합성 순으로 약 1.5초 안에 소리가 났다.
아동 대답 → 무음 2.4초 → 커밋 → interim +0.6초 (정상) → completed 미도착 → 커밋 +2.5초 턴 폐기 → AI 무응답 → 진행자 텍스트 → AI 응답 (회복)
4. 세부 — 폐기 4건 vs 같은 수업의 정상 턴 (커밋 시점 정렬)
각 줄을 그 턴의 커밋 시각을 0초로 맞춰 겹쳤다. 빨간 점선이 2.5초 기한이다.
그림 2. 아동 발화가 끝나고 정확히 2.4초 뒤 커밋되며, interim은 어느 줄이나 +0.5~0.6초에 온다. 차이는 interim 뒤 공백(주황·빨강 막대)뿐이다. 정상 턴은 0.2초, 아슬아슬 통과 턴은 1.4~1.7초, 폐기 턴은 1.9초를 넘겨 기한에 걸렸다.
턴
커밋
발화 길이 / 재개
첫 interim
마지막 interim
final
interim 끝 → final
진행자 텍스트
AI 응답 시작
HR01 turn-4 · 정상
17:32:38.038
0.6초 / 0회
+0.60
+0.60
+0.81
0.21초
—
+1.5초
WS01② turn-4 · 아슬아슬 통과
17:47:18.954
2.8초 / 1회
+0.55
+0.58
+1.95
1.37초
—
+2.5초
WS01① turn-7 · 아슬아슬 통과
17:45:48.448
0.6초 / 0회
+0.63
+0.63
+2.30
1.67초
—
+3.0초
WS01① turn-4 · 아슬아슬 통과
17:45:17.848
2.8초 / 0회
+0.62
+0.92
+2.35
1.43초
—
+3.0초
HR01 turn-5 · 폐기
17:32:51.187
0.5초 / 0회
+0.61
+0.62
없음
1.88초+ (미도착)
+5.7초 (1글자)
+7.2초
HR03 turn-1 · 폐기 (활동 첫 발화)
17:41:11.596
5.3초 / 2회
+0.53
+0.61
없음
1.89초+ (미도착)
+12.2초 (10글자)
+14.0초
WS01① turn-1 · 폐기 (활동 첫 발화)
17:44:30.397
1.3초 / 0회
+0.52
+0.60
없음
1.90초+ (미도착)
+7.9초 (8글자)
+9.3초
WS01② turn-8 · 폐기
17:48:08.455
2.7초 / 0회
+0.50
+0.60
없음
1.90초+ (미도착)
+9.7초 (15글자)
+11.5초
읽는 법
발화 길이는 원인이 아니다. 폐기 턴의 발화는 0.5~5.3초로 짧고, 통과 턴(최대 2.8초)과 겹친다. 긴 발화가 전사를 늦추는 유형(본 분석 문서 4-5절 유형 ①)과 다르다.
전사 시작도 정상이다. 첫 interim이 모든 턴에서 +0.50~0.63초로 같다(유형 ②의 "시작 지연" 아님).
갈리는 곳은 completed 공백 하나다. 전체 정상 턴의 기준선은 마지막 interim → final 0.21초(p90 0.26초)인데, 이 수업에서는 통과 턴 3개가 1.37~1.67초, 폐기 턴 4개가 1.88초 이상이었다(유형 ③).
"안 옴"보다 "늦게 옴"에 가깝다. 같은 시간대에 공백이 1.4~1.7초인 턴이 기한 직전에 통과한 것으로 보아, 폐기 4건은 같은 지연이 조금 더 길어진 끝자락일 가능성이 크다. 폐기 후에는 item을 삭제해 늦게 온 completed를 관측할 수 없으므로 확정은 아니다.
활동 첫 대답이 2건(HR03·WS01① turn-1)이다. 아동 입장에서는 활동을 시작하자마자 AI가 대답하지 않았다.
4건 모두 진행자가 텍스트(1~15글자)를 보내 회복했다. 무응답은 4.7~14.0초 이어졌다.
배제한 원인 (이 수업 기준)
후보
결과
아동측 마이크·업링크
배제 — VAD가 발화를 감지했고 interim이 정상 생성됨
commit 응답(committed) 누락 → 격리·재연결
배제 — 4개 job 모두 commit acknowledgement·quarantined 경고 0건
agent 이벤트 루프 정체
배제 — 정체 경고는 세션 시작·종료 시점뿐, 폐기 구간에 0건
OpenAI 전사 실패 알림
배제 — failed to transcribe 0건
5. 주의사항 · 이슈 히스토리
판별법: agent 로그(CloudWatch /ppi/livekit/prod/agent)에서 skipping Half Cascade turn without exact provider final(provider_final_not_admitted)가 같은 job의 user_turn_committed +2.50초에 찍히면 이 메커니즘이다. 경고에 turn_id가 없으므로 직전 커밋으로 귀속한다. 같은 job에서 1ms 앞에 session close Half Cascade flush timed out이 있으면 수업 종료 시점 정리라 무응답이 아니다.
로그 한계: agent의 interim 로그에는 item_id가 없어 "기다리던 item의 delta"인지 확정하지 못한다. 폐기 후 늦게 온 completed는 로그 없이 버려진다.
시계 보정: 이 아동 PC는 agent보다 약 1.5초 느렸다(데이터 이벤트 227건 중앙값). 아동 세션 로그 시각을 그대로 쓰면 순서가 뒤집혀 보일 수 있다.
대응 현황: 폐기 시 "(판독 불가)" 기록 + LLM 되묻기로 연결하는 수정(PPI-1348)이 본 분석 문서 7절에 정리돼 있다. 이 사례는 그 수정 이전 동작이다. 원인 확정을 위한 원인 로그(commit 응답·delta·completed의 item_id와 도착 시각, 폐기 후 늦은 completed 관측)는 아직 없다.
규모: 9/14~30 전체 agent에서 같은 폐기가 399건(수업 종료 flush 제외), 9/29 하루 79건. 이 수업이 속한 9/29 17~18시에도 다른 수업에서 26건이 났다.