본문 바로가기
AI2026년 8월 4일6분 읽기

LLM 스트리밍 UX — 토큰이 흐를 때의 경험 설계

YS
김영삼
조회 11
LLM 스트리밍 UX — 토큰이 흐를 때의 경험 설계

LLM 스트리밍 UX는 모델이 토큰을 하나씩 생성하는 동안 그 결과를 실시간으로 화면에 흘려보내며 사용자 경험을 설계하는 일이다. 같은 응답이라도 "다 만들어진 뒤 한 번에" 보여주는 것과 "타이핑하듯 흘려" 보여주는 것은 체감 속도가 완전히 다르다. 스트리밍은 실제 지연을 줄이지 못해도 체감 지연을 극적으로 줄인다.

구현 자체(SSE로 토큰 받기)는 어렵지 않다. 진짜 어려운 건 그 위에 얹는 UX 결정들이다. 멈춤 버튼은 어떻게 걸지, 도구를 호출하는 동안 뭘 보여줄지, 추론 모델의 긴 침묵을 어떻게 메울지. 나는 데모에선 멀쩡하던 채팅이 실사용에서 "왜 이렇게 답답하냐"는 피드백을 받고서야 이 층의 중요성을 깨달았다.

왜 스트리밍이 체감을 바꾸나

핵심 지표는 두 가지다. TTFT(Time To First Token, 첫 토큰까지 시간)토큰 생성 속도. 스트리밍을 켜면 사용자는 전체 응답이 끝나길 기다리지 않고 첫 글자가 뜨는 순간 "반응이 왔다"고 느낀다. 그래서 TTFT를 낮추는 게 전체 완료 시간을 낮추는 것보다 만족도에 더 크게 작용하는 경우가 많다.

# 스트리밍의 뼈대 (Anthropic 예시)
with client.messages.stream(
    model="claude-opus-4-8", max_tokens=64000,
    messages=[{"role": "user", "content": prompt}],
) as stream:
    for event in stream:
        if event.type == "content_block_delta" and \
           event.delta.type == "text_delta":
            emit(event.delta.text)   # UI로 델타 전송
    final = stream.get_final_message()  # 완성본은 별도로 확보

참고로 출력 한도(max_tokens)를 크게 잡을 때는 스트리밍이 사실상 필수다. 논스트리밍으로 큰 응답을 받으면 HTTP 타임아웃에 걸리기 쉽다. 긴 응답 = 스트리밍이라고 외워두면 편하다.

꼭 챙겨야 할 UX 패턴

  • 멈춤(stop) 버튼: 스트리밍 중 사용자가 언제든 중단할 수 있어야 한다. 이미 나온 텍스트는 유지하되 생성만 끊는다. 이게 없으면 엉뚱한 긴 답을 끝까지 지켜봐야 한다.
  • 렌더 버퍼링: 토큰마다 DOM을 갱신하면 과하게 깜빡인다. 몇 토큰씩 모아 갱신하거나 requestAnimationFrame으로 묶으면 부드럽다.
  • 마크다운 점진 렌더: 코드블록이 절반만 왔을 때 깨진 마크다운이 번쩍이지 않도록, 미완성 블록을 안정적으로 처리하는 파서가 필요하다.
  • 자동 스크롤 예외: 사용자가 위로 스크롤해 읽는 중이면 자동 스크롤을 멈춘다. 안 그러면 읽던 위치를 자꾸 놓친다.

도구 호출·추론이 끼면 달라진다

추론 모델은 답을 쓰기 전에 오래 "생각"한다. 이 동안 화면에 아무것도 안 뜨면 사용자는 멈춘 줄 안다. 생각 요약을 흘리거나, 최소한 "분석 중…" 같은 상태 표시를 줘야 한다.

에이전트처럼 도구를 호출하는 흐름은 더 복잡하다. 텍스트가 흐르다가 도구 호출 구간에서 뚝 끊기고, 도구가 실행되는 동안(웹 검색, 코드 실행 등) 또 침묵이 생긴다. 이 빈 구간을 그냥 두면 "멈췄나?" 싶다. 그래서 이렇게 메운다.

구간사용자가 보는 것 없으면권장 표시
첫 토큰 대기멈춘 듯한 느낌타이핑 인디케이터
추론 중긴 침묵생각 요약/상태
도구 실행 중멈춘 듯한 느낌"검색 중…" 배지

도구 호출 상태를 노출하면 신뢰도까지 올라간다. "지금 사내 문서를 뒤지는 중"이라는 걸 보여주면 사용자는 답을 더 믿는다. 반대로 아무 설명 없이 답만 툭 나오면 "이거 어디서 가져온 거야?" 하고 의심한다.

끊김·에러 처리

네트워크가 불안정하면 스트림이 중간에 끊긴다. 이때 이미 받은 텍스트는 살리고, 재연결하거나 사용자에게 "이어서 생성" 옵션을 주는 설계가 필요하다. 그리고 스트림 도중 에러(율제한, 안전 거부 등)가 올 수 있으니, 완성본은 항상 스트림 종료 시점의 최종 메시지로 다시 확인하는 게 안전하다. 델타만 이어붙인 문자열을 최종본으로 믿었다가 낭패 본 적이 있다.

자주 묻는 질문

스트리밍을 켜면 실제로 더 빨라지나요?

전체 완료 시간은 거의 그대로다. 스트리밍은 체감 속도를 바꾼다. 첫 토큰이 빨리 뜨니 사용자는 훨씬 반응이 빠르다고 느낀다. 지연이 사용자 눈에 보이는 대화형 UI에서는 이 체감 차이가 만족도를 크게 좌우한다.

추론 모델의 긴 침묵은 어떻게 다루나요?

생각 과정을 요약해 흘려보내는 옵션이 있으면 켜서 진행 중임을 보여주고, 없으면 최소한 "분석 중" 같은 상태 표시라도 둔다. 아무 표시 없는 침묵이 가장 나쁘다. 사용자는 몇 초만 반응이 없어도 멈췄다고 판단한다.

토큰마다 화면을 갱신해도 되나요?

권하지 않는다. 매 토큰 DOM 갱신은 과한 리렌더와 깜빡임을 만든다. 몇 토큰씩 모아서, 혹은 애니메이션 프레임 단위로 묶어 갱신하면 훨씬 부드럽다. 특히 마크다운/코드 렌더링은 미완성 블록을 안정적으로 처리하는 것이 관건이다.

멈춤 버튼은 서버 비용을 아껴주나요?

경우에 따라 그렇다. 생성을 중단하면 이후 출력 토큰이 더 만들어지지 않으니 그만큼 비용을 아낄 수 있다. 무엇보다 사용자가 원치 않는 긴 답을 끝까지 기다리지 않아도 되니 경험이 좋아진다. 중단 시 이미 나온 부분은 유지하는 게 자연스럽다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록