⚡ 중급2026-09-047분
응답이 잘리거나 느릴 때: 토큰 관리 + 스트리밍으로 UX 살리기
max_tokens 설정 실수로 응답이 중간에 끊기거나, 긴 응답을 기다리다 사용자가 이탈하는 문제를 토큰 예산 설계와 스트리밍 API로 동시에 해결하는 방법을 다룹니다.
token-managementstreamingapi-optimization
토큰이 왜 중요한가? — 비용·품질·한계의 교차점
Claude API 요금은 입력 토큰 + 출력 토큰 합산입니다. 토큰을 모르고 쓰면 세 가지 문제가 동시에 터집니다.
- 응답 절단:
max_tokens가 너무 작으면 문장 중간에서stop_reason: "max_tokens"로 잘림 - 비용 폭탄: 불필요하게 긴 시스템 프롬프트를 매 요청마다 재전송
- 사용자 이탈: 긴 응답을 전부 받을 때까지 빈 화면 → 스트리밍으로 해결 가능
토큰 예산 설계 원칙
| 구성 요소 | 토큰 절감 방법 |
|---|---|
| 시스템 프롬프트 | 반복 내용은 캐싱(cache_control) 활용 |
| 대화 히스토리 | 오래된 turn 요약 후 압축 삽입 |
| max_tokens | 유스케이스별로 다르게 설정 (챗봇 512 / 문서 작성 4096) |
| 모델 선택 | 간단한 작업은 claude-haiku-4-5, 복잡한 추론은 claude-sonnet-4-6 |
스트리밍으로 체감 속도 올리기
스트리밍은 첫 토큰이 도착하는 순간부터 UI에 표시하므로, 체감 응답 속도가 수 초 단축됩니다. Python anthropic SDK의 스트리밍 예제입니다.
import anthropic
client = anthropic.Anthropic()
def stream_response(user_message: str, max_tokens: int = 1024) -> None:
"""
스트리밍으로 응답을 받아 토큰 사용량까지 추적하는 함수.
claude-sonnet-4-6: 복잡한 분석 작업에 적합
"""
print(f"[스트리밍 시작 | max_tokens={max_tokens}]\n")
total_input = 0
total_output = 0
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=max_tokens,
system="당신은 간결하고 핵심만 전달하는 기술 문서 작성 전문가입니다.",
messages=[{"role": "user", "content": user_message}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True) # 토큰 단위로 즉시 출력
# 스트림 완료 후 메타데이터 수집
final_message = stream.get_final_message()
usage = final_message.usage
total_input = usage.input_tokens
total_output = usage.output_tokens
stop_reason = final_message.stop_reason
print(f"\n\n--- 사용량 리포트 ---")
print(f"입력 토큰 : {total_input}")
print(f"출력 토큰 : {total_output}")
print(f"stop_reason: {stop_reason}")
# 응답이 잘렸을 때 경고
if stop_reason == "max_tokens":
print("⚠️ 응답이 max_tokens 한계로 절단됐습니다. 값을 늘리거나 요청을 분할하세요.")
stream_response(
"Python의 GIL이 멀티스레딩 성능에 미치는 영향을 설명하고 "
"실전 우회 전략 3가지를 코드 예시와 함께 알려주세요.",
max_tokens=2048,
)
stop_reason 값을 항상 확인하는 습관이 중요합니다. "end_turn"이면 정상 완료, "max_tokens"면 절단입니다.
체크리스트
- [ ]
stop_reason값을 로깅/모니터링 파이프라인에 포함했는가? - [ ] 유스케이스별로
max_tokens기본값을 분리해 설정했는가? (챗봇 ≠ 문서 생성) - [ ] 사용자 대면 기능에는 스트리밍(
stream=True)을 기본 적용했는가? - [ ] 긴 대화 히스토리를 매번 전부 전송하지 않고 요약·압축 전략을 갖추었는가?
- [ ] 비용 추적을 위해 요청별
usage.input_tokens + output_tokens를 기록하고 있는가?