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

스트리밍이 필요한 이유와 SSE 형식

~12 min · streaming, sse, wire-format

Level 0불씨
0 XP0/35 lessons0/10 achievements
0/140 XP to next level140 XP to go0% complete

스트리밍이 줄여 주는 건 첫 토큰까지의 기다림이야

Gemini 2.5 Flash가 첫 토큰을 내놓는 시간(TTFT)은 보통 200–400ms야. 500단어 답변의 마지막 토큰까지는 3–8초가 걸려. 스트리밍이 모델 자체를 빠르게 만드는 건 아니야. 사용자가 빈 화면을 보며 기다리는 대신 진행 중인 결과를 보게 만드는 거지.

스트리밍을 쓰지 않을 때 치르는 제품의 비용은 "이 앱은 느려"와 "이 앱은 살아 있어"라는 인상의 차이야. 걸린 시간은 같아도 체감은 달라.

Server-Sent Events — 전송 형식

Gemini의 스트리밍 엔드포인트는 Server-Sent Events(SSE)를 써. 각 이벤트는 data:로 시작하는 줄과 완전한 JSON 객체로 이뤄져. 일반 응답과 같은 구조지만 parts 배열에는 텍스트 조각만 들어 있어.

두 가지 엔드포인트 형태

URL은 같고 쿼리 문자열만 달라:

  • /streamGenerateContent?alt=sse를 빼면 버퍼링된 JSON 배열을 반환해. 스트리밍 청크는 받고 싶지만 SSE를 파싱하고 싶지 않을 때 써.
  • /streamGenerateContent?alt=sse — SSE를 반환해. 브라우저로 스트림을 중계하거나 한 줄씩 파싱할 때 써.

마지막 청크가 usageMetadata를 담아

토큰 수는 스트림의 마지막 청크에만 나타나. 호출 비용을 계산하거나 기록하려면 모든 청크에서 텍스트를 이어 붙이고, usageMetadata가 든 청크를 잡아 둬.

Code

원시 SSE 전송 — 소켓에서 나오는 형태·text
POST .../models/gemini-2.5-flash:streamGenerateContent?alt=sse
x-goog-api-key: $GEMINI_API_KEY
Content-Type: application/json

# Response headers:
Content-Type: text/event-stream

# Response body (each block separated by blank line):
data: {"candidates":[{"content":{"parts":[{"text":"Hello"}],"role":"model"}}]}

data: {"candidates":[{"content":{"parts":[{"text":" world"}],"role":"model"}}]}

data: {"candidates":[{"content":{"parts":[{"text":"!"}],"role":"model"},"finishReason":"STOP"}],"usageMetadata":{"promptTokenCount":4,"candidatesTokenCount":3,"totalTokenCount":7}}
청크 구조 — 같은 외피, 부분 텍스트·json
{
  "candidates": [{
    "content": {
      "parts": [{"text": "hello"}],
      "role": "model"
    },
    "finishReason": "STOP"
  }],
  "usageMetadata": {
    "promptTokenCount": 10,
    "candidatesTokenCount": 5,
    "totalTokenCount": 15
  }
}
curl로 스트림 직접 받기·bash
curl -N \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"parts":[{"text":"Tell me a haiku about coffee."}]}]}'

# -N disables curl's output buffering so you actually see chunks as they arrive.

External links

Exercise

위 curl 명령을 -N과 함께 실행한 뒤, -N 없이 다시 실행해 청크가 도착하는 방식의 차이를 관찰해. 출력을 tee stream.log로 보내 마지막 이벤트에만 usageMetadata가 있는지도 확인해. ?alt=sse-N 조합이 스트림 디버깅의 표준 curl 명령인 이유를 한 문장으로 써.

Progress

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

댓글 0

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

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