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

SSE Wire Format — 100 줄짜리 spec

~22 min · sse, wire-format, raw

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

Server-Sent Events 규격은 의외로 작아. data: <json>\n\n 가 event 하나고, 빈 줄이 event 경계를 나눠. OpenAI stream 은 data: [DONE] 으로 끝나.

frame 구조

frame 하나는 한 줄 이상의 field: value 로 이루어지고 빈 줄에서 끝나. OpenAI 에서는 JSON payload 를 담는 data: 와 일부 proxy 가 keep-alive 용으로 넣는 : comment 를 볼 수 있어. comment 는 무시하고 literal data: [DONE] 을 종료 신호로 처리해.

SDK 를 써도 형식은 알아야 해

SDK 의 iter_lines() 가 framing 을 처리해주지만, proxy 가 : 로 시작하는 keep-alive comment 를 넣으면 직접 만든 parser 가 깨질 수 있어. 규격을 알면 어느 줄을 무시해야 하는지 바로 찾을 수 있어.

raw httpx 로 한 번 parsing 해봐

client.stream 과 iter_lines 로 frame 을 받고, data: prefix 를 떼고, JSON 을 읽고, [DONE] 을 감지해. SDK 가 감춰주는 일을 직접 확인해두면 wire 문제를 진단하기 쉬워져.

Code

httpx.stream 으로 raw SSE 읽기·text
data: {"id":"chatcmpl-...","choices":[{"delta":{"content":"Hello"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","choices":[{"delta":{"content":" world"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","choices":[{"delta":{},"finish_reason":"stop"}]}

data: [DONE]
data: 라인과 [DONE] sentinel parse·text
event: response.created
data: {"type":"response.created","response":{...},"sequence_number":1}

event: response.output_text.delta
data: {"type":"response.output_text.delta","delta":"Hello","sequence_number":5}

event: response.completed
data: {"type":"response.completed","response":{...},"sequence_number":15}

External links

Exercise

SDK 없이 raw httpx.stream 으로 streaming Chat Completions 를 호출하고 SSE frame 을 직접 parsing 해. data event 수, ':' keep-alive comment 수, [DONE] 종료 신호를 출력해.

Progress

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

댓글 0

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

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