
질문을 던지면 답이 한 글자씩 흘러나옵니다.
챗GPT도, 클로드도, 제미나이도 똑같습니다.
다 쓰고 한 번에 보여주면 될 텐데 왜 저렇게 만들까요.
이유가 있고, 그 이유를 담당하는 기술이 SSE입니다.
에그코드는 외주와 자체 서비스 양쪽에서 실시간 기능을 다뤄왔습니다.
무엇이고, 언제 쓰고, 어디에 들어가 있는지 정리했습니다.
한 방향으로만 열린 통로입니다
SSE는 Server-Sent Events의 줄임말입니다.
이름 그대로 서버가 보내는 이벤트라는 뜻입니다.
보통의 웹은 브라우저가 물어봐야 서버가 답합니다.
SSE는 연결을 한 번 열어두고 서버가 계속 흘려보냅니다.
브라우저는 받기만 합니다.
HTML 표준이라 따로 설치할 라이브러리가 없습니다.
브라우저의 EventSource 한 줄이면 통로가 열립니다.
특별한 프로토콜도 아닙니다.
평범한 HTTP 응답에 text/event-stream이라는 표시를 달 뿐입니다.

왜 한 글자씩 보낼까
AI는 답변을 통째로 완성해두고 내보내지 않습니다.
단어 조각을 앞에서부터 하나씩 만들어냅니다.
긴 답변 하나를 다 만드는 데 20초에서 30초가 걸리기도 합니다.
그동안 화면이 비어 있으면 사용자는 고장 났다고 봅니다.
조각을 그때그때 내보내면 이야기가 달라집니다.
첫 글자가 1초 안에 뜹니다.
전체 시간은 그대로인데 체감 시간이 줄어듭니다.
주기적으로 물어보는 방식으로는 이걸 못 만듭니다.
0.5초마다 물으면 서버만 그만큼 두들겨 맞습니다.
답은 여전히 0.5초씩 끊깁니다.

이럴 때 씁니다
하나, 서버만 말하면 될 때.
알림, 진행률, 시세처럼 되돌려줄 말이 없는 구조입니다.
둘, 결과가 오래 걸릴 때.
AI 답변, 파일 변환, 배포 로그처럼 중간 과정을 보여줘야 합니다.
셋, 끊겨도 알아서 이어져야 할 때.
연결이 끊기면 브라우저가 스스로 다시 붙습니다.
재연결 코드를 짤 필요가 없습니다.
넷, 서버 부담을 줄이고 싶을 때.
SSE는 기존 HTTP 위에서 돌아서 인증도 프록시도 그대로 씁니다.

실제 사례
챗GPT의 API가 이 방식입니다.
스트리밍 옵션을 켜면 조각마다 data: 한 줄씩 날아옵니다.
끝나면 [DONE]이 옵니다.
클로드도 같습니다.
content_block_delta라는 이름표를 붙여 글자 조각을 내보냅니다.
제미나이도 마찬가지입니다.
주소 뒤에 alt=sse를 붙이면 같은 규격으로 응답합니다.
| 서비스 | 스트리밍 신호 | 전송 방식 |
|---|---|---|
| 챗GPT | data: {…} / data: [DONE] | SSE |
| 클로드 | event: content_block_delta | SSE |
| 제미나이 | ?alt=sse | SSE |
| MCP | HTTP + SSE | SSE (스트리밍 구간) |
세 회사가 합의한 적도 없는데 방식이 같습니다.
HTML 표준이라 특정 회사 소유가 아니기 때문입니다.
AI를 외부 도구와 연결하는 MCP도 처음엔 이 방식이었습니다.
지금은 구조가 바뀌었지만 스트리밍 구간은 그대로입니다.

한계 3가지
하나, 되받을 수 없습니다.
서버에서 브라우저로 가는 한 방향뿐입니다.
사용자가 보낼 말은 별도 요청으로 보내야 합니다.
둘, 연결 개수에 제한이 있습니다.
HTTP/1.1에서는 도메인당 6개까지만 열립니다.
탭을 여러 개 켜면 막힙니다.
HTTP/2에서는 기본 100개로 늘어납니다.
셋, 헤더를 붙일 수 없습니다.
브라우저 기본 기능은 GET 요청만 되고 인증 헤더를 넣지 못합니다. 쿠키를 쓰거나 별도 라이브러리를 얹습니다.

마치며
실시간이라고 다 같은 실시간이 아닙니다.
서버끼리 사건을 알리는 거면 웹훅입니다.
서버가 일방적으로 흘려보내면 SSE입니다.
양쪽이 계속 주고받아야 하면 웹소켓입니다.
순서를 거꾸로 잡으면 안 써도 될 비용이 붙습니다.
"누가 먼저 말을 거는가"를 먼저 정하십시오.
이 질문 하나로 구조가 갈립니다.

함께 읽어보세요 — 웹소켓을 언제 쓰고 언제 피해야 하는지 · 폴링 대신 웹훅을 쓰는 이유 5가지 · 대화가 길어질수록 AI가 헛소리하는 3가지 이유