SSE(Server-Sent Events)를 활용한 실시간 스트리밍 도입 고민
최근 웹 애플리케이션에서 실시간 기능의 중요성이 점점 더 커지고 있는 것을 체감하고 있는 중에 벨루가도 SSE(Server-Sent Events) 을 적용하여 AI 답변을 제공하면 어떨까를 고민하며 프로젝트를 진행해보고 그 경험을 공유하고자 합니다. 지금도 벨루가는 스트리밍 방식으로 AI답변을 제공하고 있지만 단순 텍스트를 스트리밍하고 있는 구조로 되어 있어 클라이언트 개발자의 부담이 크며 유지보수 또한 쉽지 않은 구조로 이루어져 있습니다. 모든 메타데이터(출처, 답변생성 프로세스등..)를 답변과 함께 텍스트로 전달 되기 때문입니다. SSE(Server-Sent Events)란 무엇인가? SSE(Server-Sent Events) 는 서버가 클라이언트(웹 브라우저)에 정보를 푸시하는 방식입니다. 웹에서는 보통 클라이언트가 서버에 요청(request)을 보내고 서버가 응답(response)을 반환하는 구조인데, SSE는 이와 반대로 서버에서 초기 연결 후 계속해서 데이터를 클라이언트에게 보낼 수 있게 해줍니다. 이 기술은 특히 뉴스 피드, 실시간 알림, 또는 챗봇과 같은 애플리케이션에 매우 유용합니다. 이미지 출처: Exploring SSE (Server-Sent Events): Real-Time Updates for Your Applications! SSE의 선택 이유 WebSocket과 같은 다른 기술들도 고려했지만, SSE를 선택한 이유는 서버 설정이 간단하고, 양방향이 아닌 클라이언트와의 단방향 통신만 하면 되기 때문입니다. SSE는 HTTP를 사용하기 때문에 기존 웹 인프라와의 호환성도 뛰어나다는 장점이 있습니다. 구현 과정 API 서버 Python의 FastAPI 프레임워크를 사용하여 서버를 구축했습니다. 이 서버는 사용자로부터 질문을 받아 OpenAI의 GPT-3.5 모델에 전달하고, 생성된 응답을 실시간으로 사용자에게 스트리밍하는 역할을 합니다. 챗봇 서버 생성: FastAPI를 사용하여 웹 서버를 구축하고, CORS 설정을 통해 모든 출처에서의 접근을 허용했습니다. GPT-3.5 연동: 사용자의 입력을 받아 처리한 후, 생성된 텍스트를 실시간으로 스트리밍하기 위해 SSE를 구현했습니다. 스트리밍 로직: sse_generator 함수는 GPT 모델로부터 받은 데이터를 yield를 통해 클라이언트에 전송하고 await asyncio.sleep(0) 을 사용하여 이벤트 루프의 블로킹을 방지하고 다른 네트워크 태스크에 CPU 자원을 제공해서 클라이언트가 실시간으로 데이터를 받을 수 있도록 구현했습니다. 클라이언트 서버 웹 클라이언트는 React를 사용하여 구현했습니다. React를 선택한 이유는 특별한 이유가 있다기 보다는 벨루가 클라이언트가 React로 개발되어 있기 때문입니다. React는 동적인 UI를 구축하기에 적합하며, 컴포넌트 기반의 구조 덕분에 유지보수와 코드 관리가 용이하다는 장점이 있고 무엇보다 중요한건 Server-Sent Events(SSE) 를 활용하여 서버로부터의 스트리밍 데이터를 효과적으로 처리할 수 있다는 것입니다.