느린 AI를 위한 로딩 상태 설계: 40초의 문제
요약
추론 모델과 에이전트 루프의 등장으로 AI 응답 시간이 기존의 UX 임계값을 크게 초과함에 따라, 새로운 로딩 상태 설계 전략이 필요함을 강조합니다. 단순한 스피너는 긴 대기 시간 동안 사용자에게 불확실성을 주어 이탈을 유발하므로, 정보 중심의 새로운 접근법이 요구됩니다.
핵심 포인트
- AI 추론 모델의 긴 지연 시간은 기존 UX의 10초 임계값을 쉽게 초과함
- 불확정적 스피너는 긴 대기 시간 동안 시스템 오류와 성공을 구분하지 못함
- 토큰 생성량 예측이 불가능하므로 퍼센트 기반의 진행 바는 부적절함
- 사용자의 주의력이 분산되는 긴 대기 시간을 고려한 인터페이스 설계가 필수적임
로딩 디자인의 근간이 되는 상호작용 연구는 3초가 재앙이었던 시대를 위해 작성되었습니다. 검색(retrieval) 단계가 포함된 추론 모델(reasoning model)은 40초가 걸릴 수 있습니다. 당신이 물려받은 모든 경험칙은 그 규모에서 깨지며, 그 대체안은 단순히 찾아보는 것이 아니라 도출해내야 합니다.
세 가지 응답 시간 제한
Jakob Nielsen의 Usability Engineering (1993)은 대화형 트랜잭션의 응답 시간에 관한 Robert B. Miller의 1968년 연구를 바탕으로 세 가지 임계값을 제시합니다. 이 임계값들은 특정 시대의 하드웨어가 아닌 인간의 지각에 근거하고 있기 때문에 30년 동안 유지되어 왔습니다:
- 0.1초 — 결과가 마치 사용자가 직접 일으킨 것처럼 즉각적으로 느껴지는 한계.
- 1초 — 사고의 흐름이 끊기지 않는 한계. 사용자가 지연을 인지하지만 흐름을 놓치지는 않습니다.
- 10초 — 작업에 대한 주의(attention)를 유지할 수 있는 한계. 이 시간을 넘어서면 사용자는 다른 일을 하기 시작하며, 인터페이스는 사용자의 주의를 붙잡는 것이 아니라 사용자가 돌아왔을 때를 대비하여 설계되어야 합니다.
이제 실제 수치를 대입해 봅시다. 대형 모델의 첫 번째 토큰 생성 시간(Time to first token)은 아무것도 추가하지 않았을 때도 보통 1초 이상입니다. 프리필(prefill)은 프롬프트(prompt) 길이에 따라 증가하므로, 긴 시스템 프롬프트와 검색된 컨텍스트(retrieved context)는 이를 더 지연시킵니다. 추론 모델은 첫 번째 가시적인 토큰이 나오기 전에 숨겨진 사고 토큰(hidden thinking tokens)을 소비합니다. 또한 p95가 p50보다 몇 배 높은 것은 병리적인 현상이 아닌 일반적인 현상입니다. 이것이 바로 지연 시간(latency)이 백분위수(percentiles)로 보고되는 이유입니다. 세 번의 도구 호출(tool calls)이 포함된 에이전트 루프(agent loop)는 운이 좋은 날이라도 세 번째 임계값을 여유롭게 넘어섭니다.
따라서 디자인 문제는 "어떻게 제한 시간 내에 머무를 것인가"가 아닙니다. "우리는 이미 주의력 한계를 넘어섰습니다. 그렇다면 인터페이스는 다음 30초 동안 사용자에게 무엇을 제공해야 하는가"입니다.
스피너(spinner)는 디자인이 아닌 이유
불확정적 스피너(indeterminate spinner)는 정확히 단 1비트의 정보만을 전달합니다: '무언가 진행 중이다'라는 사실 말입니다. 이는 800밀리초(ms) 동안에는 적절하지만, 30초가 흐르는 시점에서는 무용지물이 됩니다. 이는 미학적인 이유가 아닌 구조적인 이유 때문입니다. 즉, 40초 동안 돌아가고 있는 스피너는 응답이 없는(dead) 요청에 붙어 있는 스피너와 구별할 수 없습니다. 사용자는 느린 성공(success)과 중단된 소켓(hung socket)을 구분할 수 없으므로, 합리적인 선택은 페이지를 새로고침하는 것입니다. 이는 두 번째 유료 생성(billed generation)을 시작하게 만들고 첫 번째 요청을 포기하게 합니다.
명확한 해결책인 확정적 진행 바(determinate progress bar)는 사용할 수 없습니다. 답변이 몇 개의 토큰(tokens)이 될지 알 수 없기 때문입니다. 아무도 알 수 없습니다. 모델은 진행하면서 언제 멈출지를 스스로 결정합니다. 퍼센트(%)를 표시하는 것은 허구일 뿐이며, 지금까지 방출된 토큰으로부터 퍼센트를 도출할 정직한 방법은 없습니다. 따라서 흥미로운 질문이 남습니다: 정보적이면서도 사실인 것 중 무엇을 보여줄 수 있는가?
거짓 없이 보여줄 수 있는 진행 상황
대기 시간 동안 진정으로 알 수 있는 네 가지 요소가 있으며, 이 네 가지는 모두 퍼센트보다 더 가치가 있습니다:
| 신호 (Signal) | 설명 |
|---|---|
| 경과 시간 (Elapsed time) | 항상 사실이며 항상 사용 가능합니다. 또한 모호한 멈춤 상태를 진행 중인 프로세스로 전환해 줍니다. 몇 초가 지난 시점부터 보여주되, 0부터 시작하지 마십시오. 0.1초부터 시작하는 카운터는 빠른 응답조차 느리게 느껴지게 만듭니다. |
| ... |
패턴에 주목하십시오: 각 신호는 시스템이 이미 보유하고 있는 사실입니다. 진행 표시(progress display)가 시스템이 할 수 없는 추정치를 요구하는 순간, 그것은 소통(communication)의 영역을 벗어나 장식(decoration)의 영역으로 넘어가게 되며, 사용자들은 이를 무시하는 법을 배우게 됩니다.
대기 상태 머신 (The wait-state machine)
경과 시간에 따라 상태는 격상됩니다. 왜냐하면 사용자가 2초 시점에 필요로 하는 것과 25초 시점에 필요로 하는 것은 서로 다르기 때문입니다. 한 번 구현하여 재사용할 수 있도록 상태 머신(machine) 형태로 작성하면 다음과 같습니다:
idle
-> submit -> pending(t=0)
...
30초 지점의 상태는 대부분의 제품이 건너뛰지만 가장 중요한 상태입니다. 약 30초가 지나면 정직한 설계는 더 나은 스피너(spinner)를 보여주는 것이 아니라, 다른 방식의 상호작용(interaction)을 제공하는 것입니다. 즉, 작업을 백그라운드 작업(background job)으로 넘기고, 인터페이스를 자유롭게 하며, 완료 시 알림을 보내는 것입니다. 언제 생성 작업을 요청 경로에서 분리해야 하는지를 참조하세요.
취소(Cancel)는 지연 시간(latency)을 위한 기능입니다
취소는 보통 에러 처리(error handling) 범주로 분류됩니다. 하지만 모델의 메커니즘에서 기인하는 세 가지 이유로 인해, 취소는 여기에 속해야 합니다.
- 대기 중 사용자의 주도권(agency)을 회복시켜 줍니다. 40초 동안 진행되는 생성을 멈출 수 없는 사용자는 갇힌 상태이지만, 이를 멈출 수 있는 사용자는 선택에 의해 기다리는 상태입니다. 시스템의 동작은 동일할지라도 사용자 경험(experience)은 전혀 다릅니다.
- 비용 제어 수단입니다. 스트림(stream)을 중단하면 생성이 멈추며, 생성은 비용이 많이 드는 단계입니다. 중단된 스트림이 어떻게 청구되는지는 제공업체마다 다르지만, 요청을 중단한 이후의 토큰(token)에 대해 비용을 청구하는 곳은 없습니다.
- 이중 청구되는 새로고침을 방지합니다. 취소 기능이 없다면 사용자가 찾는 탈출구는 페이지 새로고침입니다. 이는 첫 번째 생성을 중단하지 않은 채 방치하고 두 번째 생성을 시작하게 만듭니다.
취소 기능은 그 이전에 스트리밍된 내용은 그대로 유지해야 합니다. 부분적인 답변을 지워버리는 취소 기능은 사용자가 기능을 사용한 것에 대해 벌을 주는 격이며, 사용자는 이를 두 번 사용하지 않을 것입니다.
이 모든 것이 실제로 작동할지를 결정하는 한 가지 구현상의 주의사항이 있습니다. 클라이언트 요청을 중단(aborting)하는 것이 실제로 업스트림(upstream) 요청을 중단시켜야 한다는 점입니다. EventSource를 닫거나 fetch 리더(reader)를 드롭(dropping)하는 것은 프로세스의 읽기를 중단할 뿐입니다. 중단 신호(abort signal)가 제공업체 호출(provider call)까지 끝까지 전달되지 않는다면, 생성은 계속 진행되고 비용은 전액 청구되며, 당신이 취소한 유일한 것은 당신 자신의 주의력뿐입니다. 이는 테스트 중에는 절대 나타나지 않다가 청구서에서 나타나는 종류의 버그입니다.
마지막으로, 기다림을 더 즐겁게 만들고 싶다는 충동을 억제하십시오. 회전하는 메시지, 가짜 진행률(fake progress), 애니메이션 마스코트는 모두 새로움을 통해 인내심을 사려는 시도이며, 근본적인 대기 시간은 변하지 않는 반면 이러한 요소들은 두 번째 노출될 때부터 효과가 떨어집니다. 위에서 언급한 상태 머신(state machine)의 모든 항목은 사용자가 가지고 있지 않았던 정보입니다. 그중 어떤 것도 장식이 아니며, 디자인을 재검토할 때 반드시 유지해야 할 속성입니다.
자신의 트래픽 요구 사항에 맞춰 이러한 임계값(thresholds)의 크기를 정할 때는 평균(average)보다는 분포(distribution)를 고려해야 합니다. 평균값은 소수의 느린 요청들에 의해 모든 실제 요청보다 높게 끌어올려지므로, 대기 상태(wait-state) 디자인은 p95를 기준으로 구축되어야 합니다. Multigrid는 첫 번째 토큰 생성 시간(time to first token)을 전체 시간과 별도로 기록하며, 두 가지 모두를 백분위수(percentiles)로 보고합니다. 이것이 바로 이 페이지에서 다루는 구분입니다. 첫 번째 숫자는 대기(wait) 디자인을 결정하고, 두 번째 숫자는 스트리밍(streaming) 디자인을 결정합니다.
관련 항목
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기