본문 바로가기
C.W.K.
Stream
Lesson 06 of 06 · published

Token Renderer 만들기 — SSE 와 UI 사이의 contract

~22 min · renderer, ui, production

Level 0Tokenizer
0 XP0/54 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

renderer 는 SSE 에서 받은 조각을 UI 에 보여주는 경계야. token 마다 바로 append 해 UI 를 계속 다시 그리거나 취소를 무시하면 버벅여. 좋은 renderer 는 frame 시간 안에서 모아 반영하고, cancel() 을 제공하며, 완료될 때 남은 text 를 모두 flush 해.

16ms frame 간격으로 모아 그려

초당 50 token 이 올 때마다 React 를 다시 render 하면 reconciliation 부담이 커져. 새 token 을 accumulator 에 모으고 16ms requestAnimationFrame tick 마다 한 번씩 반영해. 사용자는 차이를 알아채지 못하지만 UI 는 훨씬 부드러워져. cwkPippa frontend 도 이 방식을 써.

취소는 stream 까지 전달돼야 해

사용자가 Stop 을 누르면 renderer 는 SSE stream 을 닫아 server 생성도 멈추고, 지금까지 모은 text 를 UI 에 반영한 뒤 partial output 을 보존해야 해. 취소 신호가 consumer 까지 이어지지 않으면 화면만 숨겨지고 server 는 계속 token 을 만들 수 있어.

cwkPippa 의 renderer

메시지마다 accumulator 를 두고 16ms requestAnimationFrame loop 에서 flush 해. abort signal 은 SSE consumer 까지 전달되고, 중간에 멈춰도 partial text 는 JSONL 에 남겨. React 나 Streamlit 앱에도 적용할 수 있는 패턴이야.

Code

Token renderer with cursor + cancel·python
import sys
import signal

class TokenRenderer:
    def __init__(self):
        self.buffer = ""
        self.cancelled = False

    def on_token(self, token: str):
        """Append a token to the display."""
        if self.cancelled:
            return
        self.buffer += token
        sys.stdout.write(token)
        sys.stdout.flush()

    def on_done(self, usage=None):
        """Stream complete."""
        print()  # newline
        if usage:
            print(f"[{usage.get('total_tokens', '?')} tokens]")

    def on_error(self, error):
        """Handle streaming error."""
        print(f"\\n[Error: {error}]")

    def cancel(self):
        """Stop processing further tokens."""
        self.cancelled = True
        print("\\n[Cancelled]")

# Usage with streaming
renderer = TokenRenderer()
stream = client.responses.create(
    model="gpt-5.4", input="Tell me a story.", stream=True,
)
for event in stream:
    if event.type == "response.output_text.delta":
        renderer.on_token(event.delta)
    elif event.type == "response.completed":
        renderer.on_done()

External links

Exercise

token 을 stdout 으로 보여주는 CLI renderer 를 만들어. Ctrl-C 를 누르면 stream 을 닫고 지금까지 표시한 text 를 출력하며, [DONE] 뒤에는 마지막 newline 을 flush 해. 첫 token 전, stream 중간, [DONE] 뒤 세 지점에서 취소를 시험해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.