[V2] vLLM 스트리밍 응답 to WebSocket - 100-hours-a-week/6-nemo-ai GitHub Wiki
(SSE → WebSocket Proxy)
📌 왜 WebSocket으로 직접 스트리밍이 불가능한가?
vLLM
은 기본적으로 HTTP 기반 SSE(Server-Sent Events) 로 스트리밍 응답을 제공합니다.- 즉,
stream: true
옵션을 사용하면data:
형식의 SSE 응답을 HTTP로 전달합니다. - 그러나 WebSocket은 전혀 다른 프로토콜로, vLLM은 이를 직접 지원하지 않습니다.
- 따라서 FastAPI 등에서 vLLM과 직접 WebSocket 연결은 불가능합니다.
❗ WebSocket으로 클라이언트에 스트리밍하려면, 중간에서 SSE를 수신하고 WebSocket으로 전달하는 프록시(Proxy) 구조가 필요합니다.
✅ SSE → WebSocket 프록시가 필요한 이유
- 일부 클라이언트(예: 웹 UI, 채팅 앱)는 SSE를 지원하지 않고 WebSocket만 사용합니다.
- 이런 환경에서 FastAPI가 중간에서 vLLM의 SSE 응답을 받아 WebSocket으로 중계해야 합니다.
- 이를 통해 클라이언트는 WebSocket으로 실시간 응답을 받을 수 있습니다.
🔧 FastAPI에서 SSE → WebSocket 프록시 구현 개요
-
클라이언트 → FastAPI
- 클라이언트가 WebSocket 연결을 엽니다.
예:
ws://yourserver.com/stream
- 클라이언트가 WebSocket 연결을 엽니다.
예:
-
FastAPI → vLLM
-
FastAPI가
httpx.AsyncClient()
로 vLLM에 POST 요청{ "prompt": "...", "stream": true }
-
-
FastAPI가 vLLM의 SSE 응답 수신
- 응답 스트림은
data: {json}
형태의 텍스트 [DONE]
이 오면 종료
- 응답 스트림은
-
FastAPI가 SSE 데이터를 WebSocket으로 전송
if line.startswith("data: "): data = line[6:] if data.strip() == "[DONE]": break token = json.loads(data)["choices"][0]["delta"]["content"] await websocket.send_text(token)
-
SSE 종료 또는 에러 발생 시 WebSocket도 종료
⚠️ 요약: 왜 직접 WebSocket 연결이 안 되는가?
- vLLM은 WebSocket을 전혀 지원하지 않음
- HTTP 방식의 SSE만 지원하며, WebSocket 요청은 거절됨
- 따라서 WebSocket 기반 클라이언트를 지원하려면:
- FastAPI 서버가 SSE를 수신 → WebSocket으로 중계해야 함
📎 장점과 주의사항
✅ 장점
- WebSocket만 사용하는 클라이언트도 지원 가능
- vLLM의 빠른 토큰 스트리밍을 그대로 전달
- FastAPI의 비동기 처리와 자연스럽게 통합
⚠️ 주의사항
- SSE 응답은
httpx
나aiohttp
같은 비동기 HTTP 클라이언트로 처리 - WebSocket 연결 종료, 에러 핸들링 필수
data: [DONE]
등의 종료 신호를 정확히 처리해야 스트림이 정상 종료됨