본문 바로가기

Claude

클로드 소넷 5 (Sonnet 5) 마이그레이션 가이드, 이거 안 고치면 400 에러 납니다

반응형

소넷 5로 그냥 모델 이름만 바꿔서 배포했다가 갑자기 400 에러 마주치신 분들 있으실 텐데요, 저도 처음엔 당황했어요. 앤트로픽 공식 마이그레이션 문서를 다 뒤져봤더니 소넷 5가 소넷 4.6이랑 완전히 같은 방식으로 동작하는 게 아니라 몇 가지 확실한 호환성 변경이 있더라고요. 실제로 걸리는 부분만 정리해드릴게요.

 

왜 갑자기 400 에러가 나나

소넷 5는 소넷 4.6 코드를 그대로 갖다 붙여도 되는 드롭인 업그레이드라고 공식 문서에 나와 있긴 한데, 정확히는 세 가지 동작 변경이 함께 적용돼요.

첫 번째는 어댑티브 씽킹이 기본값으로 켜진다는 거고,

두 번째는 수동 확장 사고 방식이 아예 제거됐다는 거고,

세 번째는 샘플링 파라미터를 기본값이 아닌 걸로 지정하면 에러가 난다는 거예요.

이 세 가지를 모르고 예전 코드를 그대로 돌리면 딱 위에서 말한 것처럼 400 에러를 만나게 되는 거고요.

 

어댑티브 씽킹

소넷 4.6에서는 thinking 필드를 안 넣으면 그냥 씽킹 없이 답변이 나왔어요. 그런데 소넷 5에서는 같은 요청을 보내도 어댑티브 씽킹이 자동으로 켜진 채로 실행돼요. 문제는 max_tokens가 씽킹 토큰이랑 응답 텍스트를 합친 값에 대한 하드 리밋이라는 점이에요.

그러니까 소넷 4.6에서 씽킹 없이 돌리던 워크로드를 그대로 소넷 5로 옮기면, 씽킹 토큰이 응답 공간을 잡아먹으면서 원래 나오던 응답이 중간에 잘릴 수 있어요.

씽킹을 끄고 싶으시면 명시적으로 disabled를 지정해주셔야 해요.

# 소넷 5에서 씽킹을 완전히 끄고 싶을 때
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    thinking={"type": "disabled"},
    messages=[{"role": "user", "content": "요청 내용"}]
)

이렇게 disabled로 명시하시면 소넷 4.6 때처럼 씽킹 없이 바로 응답이 나와요. 반대로 씽킹을 계속 쓰고 싶으시다면 max_tokens 값을 여유 있게 늘려두시는 게 안전해요.

 

수동 확장 사고는 이제 아예 안 됩니다

기존에 thinking: {"type": "enabled", "budget_tokens": N} 방식으로 씽킹 예산을 직접 지정하던 코드를 쓰고 계셨다면, 이 방식은 소넷 5에서 완전히 제거됐어요.

사실 소넷 4.6 때부터 이미 지원 중단(deprecated) 상태였는데, 소넷 5에서는 아예 호출하면 400 에러가 나는 걸로 바뀐 거예요. 오푸스 4.7이랑 4.8에서 이미 같은 방식으로 바뀌었던 거라 소넷 라인도 결국 따라간 셈이에요.

# 더 이상 지원 안 함 — 400 에러 발생
thinking = {"type": "enabled", "budget_tokens": 32000}

# 이렇게 바꿔야 함
thinking = {"type": "adaptive"}

 

씽킹 깊이를 조절하고 싶으시면 budget_tokens 대신 effort 파라미터로 로우, 미디엄, 하이, 맥스, 엑스하이 중에서 선택하시면 돼요. 자율적으로 여러 단계를 거치는 코딩 에이전트나 데이터 분석 파이프라인처럼 작업이 길게 이어지는 워크로드라면 하이 정도로 시작하시고, 지연 시간이나 토큰 사용량이 부담되면 미디엄으로 낮추시는 걸 앤트로픽도 권장하고 있어요.

 

temperature, top_p, top_k  제거

이 부분은 놓치기 쉬운데요, 소넷 5에서는 temperature, top_p, top_k를 기본값이 아닌 값으로 설정하면 요청 자체가 400 에러로 거부돼요. 소넷 4.5에서 소넷 4.6으로 넘어올 때는 문제없던 파라미터들이라 아무 생각 없이 그대로 두셨다면 여기서 걸리실 가능성이 높아요.

# 소넷 5에서 에러 나는 케이스
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    temperature=0.7,  # 기본값이 아니라서 400 에러
    messages=[{"role": "user", "content": "요청 내용"}]
)

# 마이그레이션할 때는 아예 파라미터를 빼야 함
response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "요청 내용"}]
)

 

모델 응답 스타일을 조정하고 싶으실 때는 이제 샘플링 파라미터 대신 시스템 프롬프트로 지시하는 방식을 쓰셔야 해요. 이것도 소넷 계열에서는 처음 생긴 제약이고, 오푸스 4.7에서 먼저 도입됐던 제약이 소넷 5까지 내려온 거예요.

 

토큰 예산도 다시 잡아야 합니다

소넷 5는 오푸스 4.7부터 쓰던 새 토크나이저를 그대로 물려받았어요. 이건 API 스펙이 바뀐 게 아니라서 요청이나 응답, 스트리밍 이벤트의 형태는 동일하고 코드 자체를 고칠 필요는 없어요. 다만 같은 입력 텍스트를 넣어도 소넷 4.6 대비 토큰이 약 30% 더 많이 나온다는 게 핵심이에요.

 

이게 실무에서 왜 문제가 되냐면, 소넷 4.6 기준으로 미리 재놓은 토큰 카운트나 max_tokens 예산을 그대로 재사용하면 안 맞는다는 거예요. 컨텍스트 윈도우 자체는 100만 토큰으로 똑같지만 토큰 하나가 담는 텍스트 양이 줄어드니까, 같은 100만 토큰이어도 실제로 들어가는 텍스트 분량은 더 적어지는 셈이에요. 배치 작업이나 RAG 파이프라인처럼 토큰 수를 정확히 계산해서 비용을 추산하시던 곳이라면, 소넷 5 기준으로 다시 토큰 카운트를 돌려보시는 걸 추천드려요.

 

마이그레이션 체크리스트

정리하면 이렇게 네 가지만 확인하시면 될 것 같아요.

먼저 씽킹 없이 돌리던 요청이 있다면 thinking에 disabled를 명시적으로 넣으셨는지 확인하시고요, budget_tokens로 씽킹 예산을 직접 지정하던 코드가 남아있는지 찾아서 adaptive 방식이나 effort 파라미터로 바꾸셔야 해요.

temperature나 top_p, top_k를 기본값 아닌 값으로 쓰고 계셨다면 그 파라미터들을 아예 제거하시고 필요하면 시스템 프롬프트로 대체하시고요.

마지막으로 토큰 예산이나 비용을 소넷 4.6 기준 수치로 관리하고 계셨다면 소넷 5 기준으로 다시 카운트해서 재조정하시면 돼요.

이 네 가지만 짚고 넘어가시면 배포 중에 갑자기 400 에러 만나는 일은 대부분 막으실 수 있을 거예요.

반응형