Claude로 스트리밍 응답 구현하기: 개발자를 위한 완전 가이드
요약
LLM 애플리케이션의 사용자 경험을 개선하기 위해 Claude API를 사용하여 스트리밍 응답을 구현하는 방법을 설명합니다. Python과 Node.js 환경에서 SSE(Server-Sent Events)를 활용해 지연 시간을 줄이고 실시간 텍스트를 전달하는 가이드를 제공합니다.
핵심 포인트
- 스트리밍을 통해 첫 번째 토큰까지의 시간(TTFT)을 단축하여 UX 개선
- Anthropic SDK의 이터레이터와 이벤트 리스너를 활용한 스트림 처리
- Python의 messages.stream()을 이용한 백엔드 구현 방법
- Node.js와 Express를 사용하여 웹 클라이언트로 SSE 스트리밍 구현
4분 읽기 · 789 단어
LLM (Large Language Model) 기반 애플리케이션을 구축할 때, 사용자 경험은 지연 시간 (latency)에 의해 결정됩니다. 전체 응답이 렌더링될 때까지 5~10초를 기다리게 되면 앱이 고장 난 것처럼 느껴집니다. 스트리밍 응답 (Streaming responses)은 첫 번째 토큰까지의 시간 (TTFT, Time to First Token)을 몇 백 밀리초로 단축하여, 사용자의 참여를 유지하는 실시간 텍스트 전달을 제공합니다.
이 가이드에서는 Python과 Node.js를 모두 사용하여 Anthropic의 Claude API로부터 응답을 스트리밍하는 방법, 스트림 생명주기 (stream lifecycle) 이벤트를 처리하는 방법, 그리고 토큰을 브라우저 클라이언트로 직접 파이프라이닝 (piping)하는 방법을 배웁니다.
Claude 스트리밍 작동 원리
내부적으로 Claude 스트리밍은 SSE (Server-Sent Events)에 의존합니다. 전체 응답을 생성한 후 단일 JSON 페이로드 (payload)를 반환하는 대신, Anthropic API는 HTTP 연결을 열고 토큰이 생성됨에 따라 작은 JSON 청크 (chunks, deltas)를 푸시합니다.
Anthropic SDK는 원시 SSE 처리를 두 가지 인터페이스 패러다임을 노출하는 편리한 스트림 헬퍼 (stream helpers)로 추상화합니다:
- 이터레이터 (Iterators): 문자열 델타 (string deltas)로서 원시 토큰을 생성 (yield)합니다.
- 이벤트 리스너 (Event Listeners): 정밀한 생명주기 추적을 위해 명명된 이벤트(예: 스트림 시작, 텍스트 델타, 완료)를 방출 (emit)합니다.
옵션 1: Python에서의 스트리밍
Python 서비스, 백엔드 스크립트 또는 CLI 도구의 경우, 표준 접근 방식은 messages.stream() 컨텍스트 매니저 (context manager)를 사용하는 것입니다. 이는 HTTP 연결을 자동으로 열고 닫는 역할을 합니다.
사전 요구 사항
공식 Anthropic Python SDK를 설치하세요:
pip install anthropic
환경 변수에 ANTHROPIC_API_KEY가 설정되어 있는지 확인하세요.
코드 예시: Python 콘솔 스트림
import os
import anthropic
...
핵심 요소
stream.text_stream: 불필요한 메타데이터 파싱을 건너뛰고 텍스트 델타만 생성하는 이터레이터입니다.flush=True: Python이 버퍼링 없이 stdout에 청크를 즉시 출력하도록 보장합니다.
옵션 2: 웹 클라이언트로 스트리밍하기 (Node.js + Express)
웹 애플리케이션을 구축할 때는 일반적으로 Node.js 백엔드를 통해 요청을 프록시(proxy)하고, SSE (Server-Sent Events)를 통해 브라우저로 토큰을 스트리밍합니다.
사전 요구 사항
필요한 패키지를 설치하세요:
npm install @anthropic-ai/sdk express
코드 예시: Express SSE 서버
import Express from 'express';
import Anthropic from '@anthropic-ai/sdk';
...
프론트엔드에서 이를 사용하는 방법
클라이언트 측에서는 네이티브 EventSource API를 사용하거나, 가독 가능한 스트림 (readable streams)을 포함한 fetch를 사용하여 이 엔드포인트를 소비합니다:
const eventSource = new EventSource('/api/stream?prompt=Hello');
eventSource.onmessage = (event) => {
...
스트림 이벤트 이해하기
토큰 사용량 지표를 추적하거나 도구 호출 (tool calls)을 캡처하는 등 응답 객체에 대한 완전한 제어가 필요한 경우, 가공되지 않은 텍스트 대신 특정 SSE 이벤트를 수신하세요:
| 이벤트 이름 | 설명 |
|---|---|
message_start | 상위 수준의 메타데이터 (모델, 입력 토큰 수)를 포함합니다. |
| ... |
필수 권장 사항
- 클라이언트 연결 끊김: 연결 끊김을 깔끔하게 처리하세요. Node.js에서는
req.on('close')를 리스닝하고stream.controller.abort()를 호출하여 API 생성을 종료함으로써, 소비되지 않은 토큰에 대한 비용 지불을 방지해야 합니다. - 버퍼 관리 (Buffer Management): 스트리밍 경계에 걸쳐 있는 불완전한 JSON을 파싱하려고 시도하지 마세요. 메시지를 단순한 SSE 이벤트(
data: {...}\n\n) 형식으로 유지하세요. - 에러 경계 (Error Boundaries): 스트리밍 초기화 과정을
try/catch블록으로 감싸세요. 네트워크 장애는 스트리밍 도중에 발생할 수 있으므로, UI가 부분적인 출력을 유연하게 처리할 수 있도록 해야 합니다.
결론
Claude 응답을 스트리밍하면 느린 LLM 왕복 시간 (roundtrips)을 유동적이고 즉각적인 사용자 인터페이스로 전환할 수 있습니다. Python의 스트림 컨텍스트 반복자 (stream context iterator)를 사용하든, SSE를 사용하는 Node.js 이벤트 훅 (event hooks)을 사용하든, 스트리밍 통합에는 50줄 미만의 코드만 필요합니다.
여러분은 어떤 스트리밍 패턴이나 UI 프레임워크를 Claude와 결합하여 사용하고 계신가요? 여러분의 방식을 공유하거나 아래 댓글로 질문을 남겨주세요!
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기