LabHub

LLM 서빙 · 토큰 스트리밍과 SSE · 실습

토큰 스트리밍 서버 직접 구현하기

LabHub 에서 이어서 보기

목표

SSE 로 토큰을 흘려보내는 서버를 직접 만들고, TTFT 와 토큰 간 지연을 따로 측정하고, 클라이언트 중단 시 생성이 실제로 멈추는지 증명한다.

왜 중요한가

총 생성 시간이 6초로 같아도, 6초 뒤 한꺼번에 나오는 것과 200ms 뒤부터 흘러나오는 것은 완전히 다른 제품입니다. 그래서 LLM 서비스에서 스트리밍은 기본이고, 그 순간부터 측정 방식도 바뀝니다 — 응답 완료 시각 하나가 아니라 첫 청크까지의 시간과 청크 간 간격을 따로 재야 합니다. 이 실습에서 특히 놓치기 쉬운 것이 7번 스텝입니다. 사용자가 긴 응답 중간에 다른 질문으로 넘어가는 패턴은 매우 흔한데, 취소 처리가 없으면 그 요청들이 배치 슬롯을 계속 차지하며 아무도 안 보는 토큰을 만듭니다. 동시 처리량이 이유 없이 떨어지고 GPU 청구서만 늘어납니다. 조용하고 비싼 사고이고, 그래서 한 스텝을 통째로 배정했습니다.

단계

1. /root/ls/gen.pygenerate(prompt, n) 를 만든다. 같은 프롬프트와 n 이면 항상 같은 토큰 열을 돌려줘야 한다. /root/ls/gen1.txt/root/ls/gen2.txt 를 같은 인자로 만들어 두 파일 내용이 같아야 한다.
2. /root/ls/server.py 를 127.0.0.1:8170 에 띄운다. POST /generate{"prompt":"hello","max_tokens":20} 을 받아 {"text":"...","usage":{"prompt_tokens":<n>,"completion_tokens":20}} 를 준다.
3. GET /stream?prompt=hello&max_tokens=20Content-Type: text/event-stream 으로 응답하고 각 토큰을 data: {"token":"..."} 와 빈 줄로 보낸다. 응답 본문에 data: 로 시작하는 줄이 20줄 이상이어야 한다.
4. 스트림 마지막에 data: [DONE] 을 보낸다.
5. /root/ls/ttft.py 로 첫 청크까지의 시간을 재어 /root/ls/ttft.txtttft_ms=<정수> 를 적는다. 0보다 크고 3000 미만이어야 한다.
6. /root/ls/itl.txtcount=<n> p50_ms=<수> p99_ms=<수> 를 적는다. count 는 19 이상이어야 한다.
7. max_tokens=100 으로 스트림을 열고 5청크만 받은 뒤 끊는다. GET /_debug/generated직전 스트림 요청에서 서버가 실제로 만든 토큰 수를 알려 주게 하고(누적 합계도 함께 실어 두면 편하다), 그 값을 /root/ls/cancel.txtrequested=100 generated=<n> 으로 적는다. generated 는 30 이하여야 한다.
8. /root/ls/report.txtttft_ms=<n>, itl_p50_ms=<수>, tokens=<n>, throughput_tps=<수> 네 줄을 적는다.

참고

단계 8개

  1. 결정적 토큰 생성기 만들기
  2. 비스트리밍 엔드포인트 만들기
  3. SSE 로 청크 전송하기
  4. 종료 신호 보내기
  5. 첫 토큰까지의 시간 재기
  6. 토큰 간 지연 분포 내기
  7. 클라이언트 중단 시 생성 멈추기
  8. 지표 보고서 만들기