🤖
ChatGPT 스트리밍은 어떻게 동작하나?
SSE로 토큰 단위 실시간 응답 전달
OpenAI의 Chat Completions API에 stream: true를 설정하면, 응답이 한꺼번에 오지 않고 SSE(Server-Sent Events) 형식으로 토큰이 생성될 때마다 전송됩니다. 클라이언트는 EventSource나 fetch + ReadableStream으로 이 스트림을 수신하며, 각 chunk는 data: {"choices":[{"delta":{"content":"안"}}]} 형식입니다. 마지막에 data: [DONE]이 오면 스트림 종료. 사용자는 LLM이 생각하는 동안 결과를 실시간으로 볼 수 있습니다.
구조 다이어그램
🌐
ChatGPT UI
fetch + ReadableStream
① POST stream:true
→
text/event-stream
←
data: {"delta":{"content":"안"}}
←
data: {"delta":{"content":"녕"}}
←
data: {"delta":{"content":"하"}}
←
data: {"delta":{"content":"세"}}
←
data: [DONE]
🧠
OpenAI API
LLM 토큰 생성
토큰 하나씩 생성 → 즉시 전송
화면에 보이는 모습:
안녕하세
핵심: LLM이 전체 답변을 완성할 때까지 기다리지 않고 <strong>토큰 생성 즉시 SSE로 전송</strong>
왜 SSE인가? (WebSocket 아닌 이유)
- 요청은 1회(POST), 응답만 스트리밍 → 단방향이면 충분
- HTTP 기반이라 CDN/프록시 호환성 좋음
- 연결 끊김 시 새 요청으로 재시도 (stateless)
- WebSocket 대비 서버 구현이 단순
동작 흐름
1
클라이언트가 POST /v1/chat/completions에 stream: true로 요청
2
서버가 Content-Type: text/event-stream으로 응답 시작
3
LLM이 토큰 생성 → data: {"delta":{"content":"안"}} 즉시 전송
4
클라이언트가 각 chunk를 받아 UI에 append
5
모든 토큰 생성 완료 → data: [DONE] 전송
6
클라이언트가 스트림 종료 처리
장점
- ✓ 체감 응답 속도 대폭 향상 (TTFT 최소화)
- ✓ LLM 전체 생성 완료를 기다릴 필요 없음
- ✓ HTTP 기반이라 구현 단순
- ✓ 중간에 취소 가능 (AbortController)
단점
- ✗ 토큰 단위 처리 로직 필요
- ✗ 에러 처리 복잡 (중간 끊김)
- ✗ 총 토큰 수를 미리 알 수 없음
- ✗ 클라이언트 버퍼링 관리 필요
사용 사례
ChatGPT / Claude 웹 UI
AI 코딩 어시스턴트
AI 챗봇 인터페이스
문서 요약/번역 실시간 표시