OpenAI API 스트리밍 응답 처리하기
문제 상황
챗봇 기능을 구현하면서 OpenAI API의 응답 대기 시간이 UX 문제가 되었다. 특히 긴 답변의 경우 사용자가 10초 이상 빈 화면을 보게 되는 상황이 발생했다.
스트리밍 적용
OpenAI API는 stream: true 옵션으로 SSE(Server-Sent Events) 방식의 스트리밍을 지원한다.
// 백엔드 (Express)
app.post('/api/chat', async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: req.body.messages,
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
res.write(`data: ${JSON.stringify({ content })}\n\n`);
}
res.end();
});
// 프론트엔드 (React)
const fetchStream = async (messages: Message[]) => {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages }),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.startsWith('data:'));
lines.forEach(line => {
const data = JSON.parse(line.slice(5));
setResponse(prev => prev + data.content);
});
}
};
결과
첫 토큰이 1초 내에 표시되면서 체감 속도가 크게 개선되었다. 에러 핸들링과 타임아웃 처리는 추가 작업이 필요하지만, 기본적인 스트리밍 구조는 안정적으로 동작했다.