k
korAI
중급 전체
중급2026-09-047분

응답이 잘리거나 느릴 때: 토큰 관리 + 스트리밍으로 UX 살리기

max_tokens 설정 실수로 응답이 중간에 끊기거나, 긴 응답을 기다리다 사용자가 이탈하는 문제를 토큰 예산 설계와 스트리밍 API로 동시에 해결하는 방법을 다룹니다.

token-managementstreamingapi-optimization

토큰이 왜 중요한가? — 비용·품질·한계의 교차점

Claude API 요금은 입력 토큰 + 출력 토큰 합산입니다. 토큰을 모르고 쓰면 세 가지 문제가 동시에 터집니다.

  1. 응답 절단: max_tokens가 너무 작으면 문장 중간에서 stop_reason: "max_tokens"로 잘림
  2. 비용 폭탄: 불필요하게 긴 시스템 프롬프트를 매 요청마다 재전송
  3. 사용자 이탈: 긴 응답을 전부 받을 때까지 빈 화면 → 스트리밍으로 해결 가능

토큰 예산 설계 원칙

| 구성 요소 | 토큰 절감 방법 | |---|---| | 시스템 프롬프트 | 반복 내용은 캐싱(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를 기록하고 있는가?