Claude Fable 5와 Claude Opus 5에는 요청을 거절할 수 있는 안전 분류기가 포함되어 있습니다. 이런 일이 발생하면 오류가 아니라 stop_reason: "refusal"이 포함된 정상 응답을 받게 됩니다. 일반적으로 동일한 요청을 다른 Claude 모델로 보내면 여전히 답변을 받을 수 있습니다. 이 페이지에서는 거부를 인식하는 방법과 해당 재시도를 설정하는 방법을 보여줍니다.
Claude Fable 5 또는 Claude Opus 5를 기반으로 구축하면서 거절된 요청이 자동으로 다른 모델로 넘어가기를 원할 때 이 페이지를 읽어보세요. 응답에서 방금 "refusal"을 확인했고 다음에 무엇을 해야 할지 알고 싶을 때도 해당됩니다.
관련 페이지:
stop_reason 값의 전체 목록.가장 간단한 설정은 Claude API에서 베타로 제공됩니다. fallbacks를 "default"로 설정하면 API가 거절된 요청을 해당 거부 카테고리에 대해 Anthropic이 권장하는 폴백 모델에서 재시도합니다. 권장 폴백이 없는 카테고리의 경우 거부가 그대로 유지됩니다.
client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks="default",
betas=["server-side-fallback-2026-07-01"],
)
print(response.model)다음 섹션에서는 거부 응답에 포함된 내용, 서버 측 또는 클라이언트 측 폴백을 사용해야 하는 시점, 각각의 과금 방식을 다룹니다.
거부는 stop_reason: "refusal"이 포함된 성공적인 HTTP 200 응답입니다:
{
"id": "msg_01XFUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-fable-5",
"content": [],
"stop_reason": "refusal",
"stop_details": {
"type": "refusal",
"category": "cyber",
"explanation": "This request was declined because it could enable cyber harm."
},
"usage": {
"input_tokens": 412,
"output_tokens": 0
}
}stop_details 객체는 거절 사유를 설명합니다:
category: 분류기를 트리거한 정책 영역의 이름입니다.explanation: 사람이 읽을 수 있는 설명입니다. 텍스트는 안정적이지 않으므로 파싱하지 말고 표시만 하세요.null입니다. 이 null은 자리 표시자가 아니라 정상적이고 영구적인 값입니다.refusal 이외의 모든 중지 이유에 대해 stop_details 자체가 null입니다.category | 의미 |
|---|---|
"cyber" | 요청이 멀웨어 또는 익스플로잇 개발과 같은 사이버 피해를 가능하게 할 수 있습니다. 무해한 사이버 보안 작업도 이 카테고리를 트리거할 수 있습니다. |
"bio" | 요청이 위험한 실험실 방법과 같은 생물학적 피해를 가능하게 할 수 있습니다. 유익한 생명 과학 작업도 이 카테고리를 트리거할 수 있습니다. |
"frontier_llm" | 요청이 경쟁 AI 모델의 개발을 지원할 수 있으며, 이는 Anthropic의 상업 약관에 따라 제한됩니다. 무해한 머신 러닝 작업도 이 카테고리를 트리거할 수 있습니다. |
"reasoning_extraction" | 요청이 모델에게 응답 텍스트에서 내부 추론을 재현하도록 요구합니다. 대신 구조화된 형태로 추론을 얻으려면 적응형 사고를 사용하세요. |
"general_harms" | 요청이 유해하다고 판단된 영역과 관련될 수 있습니다. 무해한 작업도 때때로 이 카테고리를 트리거할 수 있습니다. |
거부는 출력이 시작되기 전에 도착할 수도 있고, 부분 출력 후 스트림 중간에 도착할 수도 있습니다. 어느 경우든 부분 출력은 불완전한 것으로 간주하고 폐기하세요.
거부의 과금 방식: 출력이 시작되기 전에 도착한 거부에 대해서는 과금되지 않습니다. content는 비어 있고, 토큰 수는 usage에 표시되지만 청구되지 않습니다. 요청은 여전히 속도 제한에 포함됩니다. 스트림 중간의 거부는 입력 토큰과 이미 스트리밍된 출력에 대해 정상 요율로 과금됩니다.
거부된 요청을 다른 모델에서 재시도하는 방법은 세 가지입니다. 적합한 방법은 실행 환경과 필요한 제어 수준에 따라 다릅니다.
| 상황 | 사용 | 이유 |
|---|---|---|
| Claude API, 가장 간단한 설정 | 서버 측 폴백 | 하나의 요청, 하나의 응답. API가 재시도를 처리합니다. |
| 모든 플랫폼, Anthropic SDK 사용 | SDK 미들웨어 | 클라이언트에서 한 번만 구성합니다. 재시도가 자동으로 이루어집니다. |
| 원시 HTTP 또는 사용자 정의 재시도 로직 | 폴백 크레딧을 사용한 수동 재시도 | 완전한 제어. 폴백 크레딧이 비용을 낮춰줍니다. |
서버 측 폴백과 SDK 미들웨어는 폴백 크레딧을 자동으로 적용합니다. 재시도를 직접 구축하는 경우에만 폴백 크레딧 페이지가 필요합니다.
서버 측 폴백은 단일 API 호출 내에서 거부된 요청을 재시도합니다. 기본 모드에서는 기본 모델이 거절하고 거부 카테고리에 권장 폴백이 있는 경우, API가 해당 카테고리에 대해 Anthropic이 권장하는 모델에서 동일한 요청을 실행합니다. 대신 최대 세 개의 자체 폴백 모델을 지정할 수도 있습니다(아래 참조). 어느 쪽이든 응답한 모델의 이름이 포함된 하나의 응답을 받게 되므로, 사용자는 한 번의 왕복으로 답변을 받습니다.
서버 측 폴백은 Claude API에서 베타로 제공됩니다. fallbacks 매개변수는 Message Batches API에서 지원되지 않으며(이를 포함하는 배치 항목은 오류 결과로 반환됨), Amazon Bedrock, Google Cloud, Microsoft Foundry에서는 사용할 수 없습니다. 해당 플랫폼에서는 대신 SDK 미들웨어를 사용한 클라이언트 측 폴백을 사용하세요.
fallbacks 매개변수를 문자열 "default"로 설정하고 server-side-fallback-2026-07-01 베타 헤더를 보내세요. 그러면 API가 요청된 모델의 서버 정의 기본 라우팅을 적용하며, 이는 분류기가 보고하는 거부 카테고리를 기반으로 권장 폴백 모델을 선택하므로, 권장 사항이 변경되더라도 모델 목록을 유지 관리하지 않고도 거부된 요청이 처리됩니다.
client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks="default",
betas=["server-side-fallback-2026-07-01"],
)
# usage.iterations에 fallback_message 항목이 있으면 폴백 모델이 실행되었다는 의미입니다.
# stop_reason과 함께 확인하여 폴백이 응답을 제공했는지 검증하세요.
fallback_ran = any(
iteration.type == "fallback_message"
for iteration in response.usage.iterations or []
)
served_by_fallback = fallback_ran and response.stop_reason != "refusal"
print(
json.dumps(
{
"stop_reason": response.stop_reason,
"model": response.model,
"served_by_fallback": served_by_fallback,
}
)
)Anthropic은 모델의 역량에 맞춰 각 모델별, 각 정책 카테고리별로 안전장치를 개별적으로 설정합니다. 카테고리에 따라 플래그가 지정된 요청은 역량이 낮은 모델로 폴백되거나 거절될 수 있습니다. "default" 모드는 이러한 모델별, 카테고리별 권장 사항을 인코딩하므로, 거부된 요청은 해당 카테고리에 대해 Anthropic이 권장하는 모델에서 재시도됩니다. 폴백은 어느 쪽이든 확인할 수 있습니다. 응답에는 처리한 모델의 이름이 포함되고, fallback 콘텐츠 블록이 전환 지점을 표시합니다.
라우팅은 서버 측에서 적용되며 Models API에서 모델별로 게시되지 않습니다. 거부된 요청을 어떤 모델이 처리했는지 확인하려면, 이 페이지의 샘플처럼 응답의 최상위 model 필드를 확인하고 usage.iterations에서 fallback_message 항목을 찾으세요.
안전 분류기의 거절만이 폴백을 트리거합니다. 요청된 모델의 속도 제한, 과부하 또는 서버 오류는 그대로 반환됩니다.
베타 헤더는 정확히 2026-07-01 날짜(아래의 "default"와 명시적 목록 형식을 모두 지원) 또는 2026-06-01(명시적 목록 형식만 허용)을 포함해야 합니다. 다른 server-side-fallback-* 값에서는 fallbacks 매개변수가 400 오류와 함께 거부됩니다. 이 기능의 이전 프리뷰를 기반으로 구축했다면, 베타 헤더와 요청 및 응답 형식을 이 페이지의 것으로 함께 업데이트하세요.
기본 라우팅 대신 fallbacks를 최대 세 개의 모델 목록으로 설정할 수 있습니다. 요청된 모델이 거절하면 API가 체인의 다음 모델에서 동일한 요청을 실행합니다. 애플리케이션에서 검증한 모델을 고정하는 등 거부된 요청을 처리할 모델을 정확히 제어하려는 경우 이 형식을 사용하세요.
client = Anthropic()
response = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
fallbacks=[{"model": "claude-opus-4-8"}],
betas=["server-side-fallback-2026-07-01"],
)
print(response.model)fallbacks 목록에는 몇 가지 규칙이 적용됩니다:
allowed_fallback_models로 게시됩니다.model을 지정하며 해당 시도에 한해 max_tokens, thinking, output_config, speed를 재정의할 수 있습니다.명시적 목록 형식은 server-side-fallback-2026-06-01 베타 헤더에서도 작동하지만, "default" 모드는 작동하지 않습니다.
응답은 두 모드 모두 동일한 형태를 가집니다. 해당 턴을 처리한 모델이 최상위 model 필드에 나타나고, fallback 콘텐츠 블록이 전환 지점을 표시하며, usage.iterations가 각 시도를 기록합니다.
응답은 다른 메시지와 동일하게 보이지만 두 가지가 추가됩니다:
model 필드는 반환된 메시지를 생성한 모델을 보고합니다. 이는 요청된 모델일 수도 있고 폴백 모델일 수도 있습니다.fallback 콘텐츠 블록은 content에서 한 모델의 출력이 다음 모델로 넘어가는 각 지점을 표시합니다: {"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}.
from.model은 거절한 홉이 요청된 모델인 경우 보낸 모델 문자열을 그대로 반환합니다.to.model은 항상 계속 진행하는 모델의 확인된 ID입니다.출력이 시작되기 전의 거부에서는 fallback 블록이 첫 번째 콘텐츠 블록입니다. 예를 들어 기본 라우팅이 해당 거부 카테고리에 대해 Claude Opus 4.8을 선택하는 경우:
{
"id": "msg_01XFUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-opus-4-8",
"content": [
{
"type": "fallback",
"from": { "model": "claude-fable-5" },
"to": { "model": "claude-opus-4-8" }
},
{ "type": "text", "text": "Hi! How can I help you today?" }
],
"stop_reason": "end_turn",
"stop_details": null,
"usage": {
"input_tokens": 412,
"output_tokens": 264,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0,
"iterations": [
{
"type": "message",
"model": "claude-fable-5",
"input_tokens": 535,
"output_tokens": 0,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
},
{
"type": "fallback_message",
"model": "claude-opus-4-8",
"input_tokens": 412,
"output_tokens": 264,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
]
}
}usage.iterations 배열은 모든 시도를 기록합니다. 거절한 모델은 일반 message 항목으로 나타나고, 해당 턴을 처리한 모델은 fallback_message 항목으로 나타납니다. 체인의 모든 모델이 거절하면 응답은 마지막 모델의 거부가 되며, 이전 각 홉에 대한 message 항목과 마지막 홉에 대한 fallback_message 항목이 포함됩니다.
다음 턴에서는 받은 그대로 어시스턴트 콘텐츠를 다시 보내세요. 출력 중간 폴백 이후에는 content에 거절한 모델이 전환 전에 생성한 블록 유형이 포함될 수 있습니다. 다음 표는 턴을 다시 보낼 때 유지할 것과 제거할 것을 다룹니다.
| 블록 유형 | 다음 턴에서 |
|---|---|
fallback | 나타난 위치에 정확히 유지하세요. API는 그 위치를 사용하여 주변의 thinking 블록을 검증하므로, 블록이 생략되거나 이동되면 경계 양쪽의 thinking 블록을 다시 보내는 요청이 거부됩니다. |
text | 유지. |
마지막 fallback 블록 이후의 모든 블록 | 유지. |
마지막 fallback 블록 이전의 thinking, redacted_thinking 또는 connector_text | 제거. |
마지막 fallback 블록 이전의 클라이언트 측 tool_use | 제거. |
마지막 fallback 블록 이전의 server_tool_use | 결과와 쌍을 이루는 경우 유지. 일치하는 결과가 없는 경우 제거. |
connector_text 블록은 일부 도구 사용 응답이 도구 호출 사이에 포함하는 설명 텍스트를 담고 있습니다.
스트리밍 요청에서는 재시도가 동일한 스트림에서 이루어지며, 이미 받은 내용은 무효화되지 않습니다. 표시되는 내용은 거절이 발생하는 시점에 따라 다릅니다.
출력이 시작되기 전에 거절이 발생하는 경우:
message_start가 폴백 모델의 이름을 포함하고, fallback 블록이 첫 번째 콘텐츠 블록입니다.message_start는 폴백 시도가 시작될 때까지 기다리므로, 첫 바이트까지의 시간에 거절된 시도가 포함됩니다.출력 중간에 거절이 발생하는 경우:
fallback 블록(델타가 없는 일반 content_block_start와 content_block_stop 쌍)이 경계를 표시합니다.text 블록만 컨텍스트로 폴백 모델에 전달되며, 다른 블록 유형은 content에 남아 있습니다.message_start는 이미 요청된 모델의 이름을 포함했으므로, 처리 모델은 fallback 블록의 to.model과 최종 message_delta의 usage.iterations에 있는 fallback_message 항목에서 읽으세요.비스트리밍 요청에서는 출력 중간 거절이 다르게 동작합니다. 응답에서 거절한 모델의 부분 출력이 생략되고, 폴백 모델이 처음부터 답변합니다. 결과는 출력이 시작되기 전의 거절처럼 보이며, fallback 블록이 먼저 나옵니다. 거절된 시도와 그 출력 토큰은 여전히 usage.iterations에 나타납니다.
도구 사용 중의 거절: 완료된 도구 작업은 폴백을 차단하지 않습니다. 요청 내에서 서버 도구(예: 웹 검색 또는 코드 실행)가 실행을 완료한 후 거절이 발생하면 폴백 시도가 진행됩니다. 완료된 도구 결과가 이어지고, 폴백 모델은 서버 도구를 계속 호출할 수 있습니다. 재시도되지 않는 유일한 경우는 스트림에서 어떤 유형이든 도구 사용 블록(클라이언트 도구, 서버 도구 또는 MCP 도구 호출)이 아직 열려 있는 동안 발생하는 스트리밍 거절입니다. 해당 거부는 직접 반환되며, fallback-credit-2026-07-01 헤더가 설정된 경우 부분 응답을 계속하여 사용할 수 있는 크레딧 토큰이 여전히 포함됩니다. 비스트리밍 요청은 영향을 받지 않습니다. API가 부분 작업을 지우고 응답하기 전에 재시도합니다.
모든 Anthropic SDK에는 거부-폴백 미들웨어가 포함되어 있습니다. 폴백 모델 목록으로 클라이언트에서 한 번만 구성하면 됩니다. 그러면 client.beta.messages를 통한 호출이 모든 플랫폼에서 거부된 요청을 자동으로 재시도합니다. 미들웨어는 처리하는 모든 요청에 fallback-credit-2026-07-01 베타 헤더도 보내므로, 요청별 설정 없이 재시도 가격이 재조정됩니다.
미들웨어를 클라이언트 생성자에 전달하고, 대화의 요청 간에 하나의 BetaFallbackState 인스턴스를 공유하세요.
from anthropic import Anthropic, BetaFallbackState, BetaRefusalFallbackMiddleware
# 거부 시 미들웨어는 나열된 폴백 모델로 재시도하고
# 처리하는 모든 요청에 폴백 크레딧 베타 헤더를 자동으로 전송합니다.
client = Anthropic(
middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])],
)
state = BetaFallbackState() # pins follow-ups to the model that accepted
# 스트리밍: 거부 시 미들웨어는 폴백 모델로 재시도하고
# 해당 이벤트를 열려 있는 스트림에 이어 붙입니다.
with (
state,
client.beta.messages.stream(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
) as stream,
):
for text in stream.text_stream:
print(text, end="", flush=True)
final_message = stream.get_final_message()
print(f"\nserved by: {final_message.model}")
# 비스트리밍: 상태를 재사용하면 대화가 고정된 상태로 유지됩니다.
with state:
message = client.beta.messages.create(
max_tokens=1024,
model="claude-fable-5",
messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(f"served by: {message.model}")fallback 경계 블록뿐입니다.fallback 콘텐츠 블록이 포함됩니다. 미들웨어가 이후 요청에서 해당 블록을 관리합니다.BetaFallbackState에 기록되므로, 상태를 공유하는 후속 요청은 거부한 모델에 다시 요청하지 않고 해당 모델에 고정됩니다.미들웨어와 서버 측 fallbacks 매개변수는 동일한 역할을 합니다. 둘 중 하나만 구성하고, 동일한 요청에 둘 다 사용하지 마세요. 미들웨어를 설치한 애플리케이션에서 서버 측 fallbacks 요청을 보내려면 미들웨어가 없는 별도의 클라이언트 인스턴스를 사용하세요.
Message Batch에서 거부된 요청은 stop_reason: "refusal"과 함께 result.type: "succeeded"로 반환됩니다. 배치 결과는 동기 응답과 동일한 stop_details 객체를 포함하므로, stop_reason 또는 stop_details.type을 통해 거부를 감지할 수 있습니다. 한 가지 차이점은 배치 거부는 폴백 크레딧을 발행하지 않으므로, 배치 결과의 stop_details에는 fallback_credit_token이 포함되지 않는다는 것입니다.
서버 측 폴백은 배치에서 사용할 수 없습니다(fallbacks를 포함하는 배치 요청은 항목별 오류 결과를 생성합니다). 거부된 배치 항목을 재시도하려면:
fallbacks 매개변수는 도구 실행 내부에서 이루어지는 모델 호출로 전파되지 않습니다.usage.iterations의 fallback_message 항목이 후자를 표시)를 발행한 다음, 두 수치 간의 차이에 대해 알림을 설정하세요.content나 내부 stop_details 필드가 아니라 stop_reason 또는 stop_details.type으로 분기하세요. stop_details 객체는 거부 시 항상 존재하지만, category와 explanation 필드는 null일 수 있습니다. stop_reason이 "refusal"과 같은지 직접 확인하세요.재시도를 직접 구축할 때 프롬프트 캐시 비용을 이중으로 지불하지 않도록 하세요.
모든 stop_reason 값과 처리 방법.
거부-폴백 헬퍼를 포함한 SDK 미들웨어의 작동 방식.
기존 애플리케이션을 Claude Fable 5로 이전하세요.
Was this page helpful?