⚡ 중급2026-07-157분
Streaming과 토큰 관리로 UX와 비용을 동시에 잡는 법
Anthropic SDK의 스트리밍 API를 활용하면 긴 응답도 첫 글자부터 즉시 표시해 체감 속도를 높일 수 있습니다. max_tokens 제어와 조합하면 응답 품질을 유지하면서 API 비용도 예측 가능하게 관리됩니다.
streamingtoken-managementapi
Streaming이 필요한 상황
챗봇, 코드 생성기, 긴 보고서 작성 도구처럼 응답이 수 초 이상 걸리는 기능에서 사용자는 빈 화면을 기다리는 것을 싫어합니다. 스트리밍은 모델이 토큰을 생성하는 즉시 클라이언트에 전달해 첫 번째 토큰까지의 지연(TTFT) 만큼만 기다리면 됩니다.
max_tokens로 비용 예측하기
토큰 관리의 핵심 원칙은 다음과 같습니다.
| 설정 | 역할 | 권장값 |
|---|---|---|
| max_tokens | 출력 상한 강제 | 용도별로 명시 |
| temperature | 창의성 vs 일관성 | 0.0~0.3(사실형), 0.7~1.0(창작형) |
max_tokens를 명시하지 않으면 모델이 필요 이상으로 길게 응답해 비용이 튀는 경우가 있습니다. 응답 유형별 상한을 미리 정의해두는 것이 좋습니다.
import anthropic
client = anthropic.Anthropic()
# 응답 유형별 토큰 예산 정의
TOKEN_BUDGET = {
"summary": 256,
"code_review": 1024,
"full_report": 4096,
}
def stream_response(
prompt: str,
response_type: str = "summary",
temperature: float = 0.3,
) -> str:
"""
스트리밍으로 응답을 출력하고, 완성된 전체 텍스트를 반환합니다.
"""
max_tokens = TOKEN_BUDGET.get(response_type, 512)
full_text = ""
print(f"[{response_type} | max_tokens={max_tokens} | temp={temperature}]\n")
# stream 컨텍스트 매니저 사용
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=max_tokens,
temperature=temperature,
messages=[{"role": "user", "content": prompt}],
) as stream:
for text_chunk in stream.text_stream:
print(text_chunk, end="", flush=True) # 실시간 출력
full_text += text_chunk
# 스트림 종료 후 사용량 확인
final_message = stream.get_final_message()
usage = final_message.usage
print(f"\n\n--- 사용량 ---")
print(f"입력 토큰: {usage.input_tokens}")
print(f"출력 토큰: {usage.output_tokens}")
print(f"출력 토큰 한도 대비: {usage.output_tokens}/{max_tokens} ({usage.output_tokens/max_tokens*100:.1f}%)")
return full_text
if __name__ == "__main__":
result = stream_response(
prompt="Python의 GIL(Global Interpreter Lock)이 멀티스레딩 성능에 미치는 영향을 설명해줘.",
response_type="summary",
temperature=0.2,
)
스트리밍 + 에러 핸들링 패턴
스트림 도중 네트워크가 끊기거나 max_tokens에 도달해 응답이 잘릴 수 있습니다. stop_reason을 확인해 불완전한 응답을 감지하세요.
final = stream.get_final_message()
if final.stop_reason == "max_tokens":
print("\n⚠️ 응답이 토큰 한도로 잘렸습니다. max_tokens를 늘리거나 프롬프트를 단축하세요.")
elif final.stop_reason == "end_turn":
print("\n✅ 정상 완료")
적용 체크리스트
- [ ] 응답 유형별
max_tokens예산을 코드에 상수로 정의했다 - [ ]
client.messages.stream()컨텍스트 매니저를 사용해 스트림을 안전하게 닫는다 - [ ] 스트림 종료 후
get_final_message().stop_reason을 확인한다 - [ ]
stop_reason == "max_tokens"일 때 사용자에게 경고 또는 재시도 로직을 추가했다 - [ ] 사실 기반 응답에는
temperature 0.0~0.3, 창작에는0.7~1.0을 적용했다