Claude로 챗봇이나 긴 응답을 다루는 앱을 만들면 스트리밍이 거의 필수입니다. 응답을 한 번에 받는 대신 토큰이 생성되는 대로 받아 화면에 흘려보내면 체감 속도가 크게 좋아지고, 큰 max_tokens 요청에서 HTTP 타임아웃도 피할 수 있습니다. 이 글은 공식 문서 기준 스트리밍 이벤트 구조와 SDK 사용법을 정리합니다.
스트리밍 이벤트 흐름
스트리밍은 SSE(Server-Sent Events)로 전달되며, 각 이벤트는 이름과 JSON 데이터를 가집니다. 공식 문서 기준 한 스트림의 흐름은 다음과 같습니다.
message_start—content가 빈Message객체로 시작.- 여러 개의 content block — 각 블록은
content_block_start→ 하나 이상의content_block_delta→content_block_stop으로 구성. 각 블록은 최종content배열에서의 위치를 가리키는index를 가짐. - 하나 이상의
message_delta— 최종Message의 상위 레벨 변화(예:stop_reason) 전달. 여기 담긴 usage 토큰 수는 누적치입니다. - 마지막에
message_stop.
중간에 ping 이벤트가 섞일 수 있고, 사용량이 많은 시기에는 스트림 안에서 error 이벤트(예: overloaded_error, 비스트리밍이면 HTTP 529에 해당)가 올 수 있습니다. 버전 정책상 새 이벤트 타입이 추가될 수 있으니 알 수 없는 이벤트 타입은 무시하도록 안전하게 처리해야 합니다.
delta(증분) 타입
각 content_block_delta는 해당 index의 블록을 갱신하는 delta를 담습니다. 주요 타입:
- text_delta — 텍스트 조각. 예:
{"type":"text_delta","text":"Hello"} - input_json_delta — 도구 사용(
tool_use) 블록의input갱신. 부분 JSON 문자열로 오므로,content_block_stop까지 모은 뒤 파싱하거나 SDK 헬퍼로 점진 파싱합니다. (최종tool_use.input은 항상 객체) - thinking_delta — extended thinking 스트리밍 시 사고 과정 조각.
content_block_stop직전에 무결성 검증용signature_delta가 한 번 옵니다.
SDK로 스트리밍하기
공식 Python·TypeScript SDK는 여러 스트리밍 방식을 제공합니다(Python은 동기·비동기 모두). PHP SDK는 createStream()으로 스트리밍합니다. 대표적인 두 패턴:
① 실시간 토큰 출력
토큰이 도착하는 즉시 처리하려면 컨텍스트 매니저로 스트림을 열고 text_stream을 반복합니다.
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
model="claude-opus-4-8",
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
② 최종 메시지만 받기
토큰을 실시간으로 처리할 필요가 없다면, 내부적으로는 스트리밍을 쓰되 완성된 Message 객체를 받을 수 있습니다. .create()와 동일한 결과를 주며, 큰 max_tokens 요청에서 HTTP 타임아웃을 피하는 용도로 특히 유용합니다.
with client.messages.stream(
max_tokens=128000,
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
model="claude-opus-4-8",
) as stream:
message = stream.get_final_message()
print(message.content[0].text)
언어별로 누적 방식이 다릅니다. Python get_final_message(), TypeScript finalMessage(), Go는 루프 안에서 message.Accumulate(event), Java는 MessageAccumulator, Ruby는 .accumulated_message를 사용합니다. 직접 HTTP 연동이 아니라면 가능한 한 공식 SDK를 쓰는 것이 권장됩니다.
스트리밍 중 에러 복구
네트워크 문제·타임아웃으로 스트림이 중단되면 처음부터 다시 받지 않고 이어받을 수 있습니다. 공식 문서는 모델 세대에 따라 방법이 다르다고 명시합니다.
- Claude 4.5 이하: 받은 부분 응답을 assistant 메시지의 시작 부분으로 넣어 이어서 요청.
- Claude 4.6 이상: 부분 응답을 담은 user 메시지로 "중단된 지점부터 계속하라"고 지시. (예: "Your previous response was interrupted and ended with [...]. Continue from where you left off.")
주의: tool_use·thinking 블록은 부분 복구가 안 되며, 가장 최근의 text 블록부터 이어받을 수 있습니다. 가능하면 SDK의 메시지 누적·에러 처리 기능을 활용하세요.
정리
스트리밍의 핵심은 ① SSE 이벤트 흐름(start→delta→stop) 이해, ② delta 타입별 처리(text·input_json·thinking), ③ SDK로 실시간 출력 또는 최종 메시지 수신, ④ 알 수 없는 이벤트·에러 안전 처리, ⑤ 세대별 복구 전략입니다. 함께 보면 좋은 글: Claude SDK 시작하기, 에러 처리·재시도 가이드.
본 글은 Anthropic 공식 문서(platform.claude.com/docs)의 공개 정보를 바탕으로 정리했습니다. SDK API와 이벤트 형식은 버전에 따라 달라질 수 있으니 실제 구현 시 공식 문서를 확인하세요. 본 사이트는 Anthropic 공식 사이트가 아닙니다.