Streaming response

스트리밍 응답

Appending each token to the screen as it is generated, instead of waiting for the whole answer to finish.

Also known as: Token streamingTypewriter response
···
html
<div class="chat">
  <div class="bubble user">이번 분기 매출 요약해줘</div>
  <div class="bubble ai"><span id="txt"></span><span class="caret">▍</span></div>
</div>
css
.chat{width:min(280px,92%);display:grid;gap:8px}
.bubble{padding:9px 12px;border-radius:12px;font-size:12px;line-height:1.55;max-width:92%}
.bubble.user{justify-self:end;background:var(--accent);color:#fff;border-bottom-right-radius:4px}
.bubble.ai{justify-self:start;background:var(--surface);border:1px solid var(--line);color:var(--fg);border-bottom-left-radius:4px}
.caret{display:inline-block;color:var(--accent);animation:blink 1s step-end infinite}
@keyframes blink{50%{opacity:0}}
js
const full = '3분기 매출은 전 분기 대비 상승했고, 특히 구독 갱신 비중이 늘었어요. 신규 유입보다 재구매가 더 크게 기여했습니다.';
const el = document.getElementById('txt');
let i = 0, timer = null;
function step() {
  el.textContent = full.slice(0, i);
  i++;
  if (i <= full.length) { timer = setTimeout(step, 26 + Math.random() * 30); }
  else { timer = setTimeout(() => { i = 0; el.textContent = ''; step(); }, 1800); }
}
step();

An LLM doesn't produce an answer in one shot — it predicts the next token in sequence. Streaming just pipes that process straight to the screen, so the server side is fairly simple: Server-Sent Events or a chunked HTTP response. The client keeps appending each arriving piece to the end of the existing text.

The payoff is perceived speed. Total response time is unchanged, but the moment the first token arrives (TTFT, time to first token) tells the user something is already happening, and reading along as it grows makes the wait feel shorter than it is. A blinking caret (▍) exists because plain text alone can't signal "not finished yet."

While markdown is mid-stream, a list or code block can briefly render unclosed — the parser re-renders incomplete markdown on every chunk, so pick a renderer that doesn't flicker or jump the layout. And if the user has scrolled up to read something earlier, arriving tokens shouldn't force the view back down.

When to use

Make it the default for any conversational UI whose answers run more than a sentence or two. For very short answers or ones that render straight into structured UI, the typing effect can feel out of place.