k
korAI
중급 전체
중급2026-05-077분

긴 응답이 뚝뚝 끊길 때: Streaming + 토큰 관리로 UX 살리기

max_tokens 초과나 느린 첫 응답으로 사용자가 이탈하기 전에, Streaming API와 토큰 예산 전략을 함께 적용해 체감 속도와 비용을 동시에 잡는 방법을 소개합니다.

streamingtoken-managementapi-options

문제: 왜 응답이 늦거나 잘리는가

max_tokens를 크게 잡으면 전체 생성이 끝날 때까지 사용자는 빈 화면을 봅니다. 반대로 작게 잡으면 문장 중간에 응답이 잘립니다. 두 문제를 동시에 해결하는 열쇠가 Streaming토큰 예산 계획입니다.

Streaming으로 첫 글자를 빠르게

import anthropic

client = anthropic.Anthropic()

def stream_response(user_query: str, context: str = "") -> str:
    """
    Streaming으로 응답을 출력하면서 전체 텍스트도 누적 반환.
    context: RAG 등으로 주입할 배경 문서 (토큰 절약을 위해 미리 요약 권장)
    """
    system_prompt = (
        "당신은 간결한 기술 문서 작성 전문가입니다. "
        "답변은 핵심만 담아 500자 이내로 작성하세요."
    )
    if context:
        system_prompt += f"\n\n[참고 문서]\n{context[:1500]}"  # 컨텍스트 길이 캡

    collected_text = []

    # stream() 컨텍스트 매니저 사용
    with client.messages.stream(
        model="claude-sonnet-4-6",
        max_tokens=700,          # 예상 출력 + 20% 여유
        temperature=0.3,         # 사실 기반 작업엔 낮은 temperature
        system=system_prompt,
        messages=[{"role": "user", "content": user_query}],
    ) as stream:
        for text_chunk in stream.text_stream:
            print(text_chunk, end="", flush=True)  # 실시간 출력
            collected_text.append(text_chunk)

    print()  # 줄바꿈
    full_response = "".join(collected_text)

    # 사용 토큰 확인 (과금 모니터링)
    final_message = stream.get_final_message()
    usage = final_message.usage
    print(f"\n[토큰 사용] 입력: {usage.input_tokens} / 출력: {usage.output_tokens}")

    return full_response


if __name__ == "__main__":
    query = "Transformer 아키텍처의 Attention 메커니즘을 초보자에게 설명해줘"
    result = stream_response(query)

코드 핵심 포인트

| 옵션 | 설정값 | 이유 | |---|---|---| | temperature | 0.3 | 사실 기반 답변의 일관성 확보 | | max_tokens | 700 | 목표 길이(500자) × 약 1.4 (한국어 토큰 비율 고려) | | context 캡 | 1500자 | 불필요한 입력 토큰 낭비 방지 | | stream.get_final_message() | 스트림 종료 후 | 실제 사용량 로깅·알림에 활용 |

토큰 예산 3원칙

1. 입력 토큰 줄이기

  • system 프롬프트는 재사용 가능한 구조로 고정하고, 변하는 부분만 user 메시지에 넣습니다.
  • 긴 문서를 통째로 붙이지 말고, 관련 청크만 추출해 주입하세요 (RAG의 핵심).

2. 출력 토큰 예측하기

  • 한국어 기준 1토큰 ≈ 0.5~0.7글자입니다. 500자 답변이면 max_tokens는 700~800이 적당합니다.
  • stop_sequences를 활용해 특정 구분자에서 생성을 조기 종료할 수도 있습니다.

3. stop_reason 반드시 확인하기

if final_message.stop_reason == "max_tokens":
    # 응답이 잘렸음 → 사용자에게 안내하거나 재요청
    print("⚠️ 응답이 max_tokens 한도로 잘렸습니다.")

적용 체크리스트

  • [ ] stream() 컨텍스트 매니저를 사용해 첫 토큰 도달 시간(TTFT)을 단축했는가?
  • [ ] max_tokens를 목표 출력 길이 기준으로 계산해 설정했는가?
  • [ ] stop_reason == "max_tokens" 케이스를 에러 핸들링에 포함했는가?
  • [ ] usage.input_tokens + usage.output_tokens를 로그로 기록하고 있는가?
  • [ ] 사실 기반 작업에 temperature를 0.1~0.4로 낮춰 일관성을 확보했는가?
  • [ ] 컨텍스트 문서를 주입할 때 길이 상한(예: 1500자)을 두어 토큰 폭증을 방지했는가?