홍드로이드의 야매코딩

Claude API 거절 응답 요금 — 청구는 0인데 한도는 그대로 깎이고, 오류 대시보드에는 안 잡힙니다 본문

AI & Vibe Coding

Claude API 거절 응답 요금 — 청구는 0인데 한도는 그대로 깎이고, 오류 대시보드에는 안 잡힙니다

홍드로이드 2026. 8. 19. 14:54
반응형

AI에게 뭘 시켰는데 "그건 도와드릴 수 없습니다"가 돌아온 적 있으실 겁니다. 채팅창에서는 그냥 다시 물어보면 그만인데, API로 붙여 쓰는 쪽이라면 질문이 하나 더 붙습니다 — 거절당한 요청도 요금이 나갈까? 공식 문서가 이 질문만 따로 떼서 문서 두 편으로 답해놨는데, 읽어 보니 예상과 어긋나는 대목이 계속 나옵니다. 오늘 확인한 것 중 제일 실무적인 둘은 이겁니다 — 거절은 청구가 0인데 사용량 숫자는 그대로 찍히고, 거절은 오류가 아니라서 오류율 대시보드에는 영원히 안 잡힙니다.

📌 30초 요약

  • 거절은 오류가 아닙니다. HTTP 200 정상 응답으로 돌아오고, 안에 거절 표시가 들어 있습니다.
  • 출력이 하나도 안 나간 거절은 요금이 0입니다. 그런데 사용량 항목에는 토큰 숫자가 그대로 찍힙니다 — 청구가 안 될 뿐입니다.
  • 공짜는 아닙니다. 거절당한 요청도 레이트 리밋은 그대로 깎아먹습니다.
  • 다른 모델로 다시 시도하면 캐시를 처음부터 다시 써야 합니다. 그 값을 돌려주는 환불 장치가 따로 있습니다.
  • 환불 토큰은 5분짜리입니다. 서버는 그걸 저장하지도, 조회해주지도 않습니다.
  • 조용히 두 번 청구되는 경로가 하나 있습니다. 문서가 "그럴 땐 그냥 재시도하지 말라"고 직접 적어놨습니다.

거절은 에러가 아니라 성공 응답입니다

여기서부터 감이 어긋납니다. 보통 "막혔다"고 하면 4xx나 5xx 에러를 떠올리는데, 거절은 그렇게 오지 않습니다. HTTP 200, 즉 완벽하게 성공한 응답으로 돌아옵니다. 다만 응답 안에 멈춘 이유가 거절이라고 적혀 있고, 본문 내용은 비어 있습니다.

# 거절당한 요청이 실제로 돌려주는 모양 (일부 생략)
{
  "model": "claude-fable-5",
  "content": [],
  "stop_reason": "refusal",
  "stop_details": {
    "type": "refusal",
    "category": "cyber",
    "explanation": "...사람이 읽으라고 붙는 설명..."
  },
  "usage": { "input_tokens": 412, "output_tokens": 0 }
}

맨 아래 사용량 항목을 보세요. 입력 토큰이 412개라고 또렷하게 찍혀 있습니다. 그런데 문서는 이 요청이 청구되지 않는다고 명시합니다. 숫자가 보이는데 돈은 안 나가는, 조금 헷갈리는 조합입니다.

🧾 청구되는 경우와 안 되는 경우

기준은 "출력이 한 글자라도 나갔는가" 하나뿐입니다. 문서 표현을 옮기면 출력이 생성되기 전에 도착한 거절은 청구하지 않는다이고, 그 경우 응답 본문은 비어 있으며 사용량에 뜨는 토큰 수는 기록일 뿐 과금되지 않습니다. 반대로 답변이 흘러나오다가 중간에 거절로 끊긴 경우는 다릅니다 — 그때는 입력 토큰과 그때까지 나간 출력이 평소 요율 그대로 청구됩니다. 그리고 어느 쪽이든 공통으로 붙는 조건이 하나 더 있는데, 거절당한 요청도 레이트 리밋에는 그대로 카운트됩니다. 돈은 안 내지만 한도는 깎인다는 뜻이라, "거절은 공짜니까 마구 던져도 된다"는 오해는 여기서 깨집니다.

그리고 부분 출력이 남아 있더라도 문서는 그걸 완성된 답으로 쓰지 말고 버리라고 못박습니다. 중간에 끊긴 글은 불완전한 상태로 취급하라는 겁니다.

오류율 알림에는 영원히 안 잡힙니다

앞 문장이 그냥 기술 트리비아로 끝나지 않는 이유가 여기 있습니다. 거절이 200 성공 응답이라는 건, 곧 에러율이나 5xx를 감시하는 모니터링은 거절을 한 건도 못 본다는 뜻입니다. 서비스가 사용자에게 계속 빈 답을 내주고 있어도 대시보드는 초록불입니다.

문서도 이걸 알고 있어서, 거절을 별도의 신호로 계측하라고 따로 항목을 두고 지시합니다. 방법까지 구체적입니다 — 거절 1건당 이벤트 하나, 대체 모델이 답해준 응답 1건당 이벤트 하나를 남기고, 두 숫자의 차이를 경보 조건으로 걸라는 겁니다. 차이가 벌어진다는 건 거절은 났는데 아무도 대신 답해주지 못한 요청이 쌓이고 있다는 뜻이니까요.

⚠️ 판정을 어디서 하느냐도 함정입니다

거절을 감지할 때 응답 본문이 비었는지로 판단하거나, 거절 사유 안쪽 필드를 들여다보는 방식은 문서가 명시적으로 말립니다. 이유가 있습니다 — 사유를 담는 객체는 거절이면 항상 존재하지만, 그 안의 분류 이름과 설명은 둘 다 비어 있을 수 있고, 그 빈 값이 정상이자 영구적인 값입니다. 나중에 채워질 자리표시자가 아니라는 뜻이죠. 그래서 판정은 멈춘 이유가 거절인지 딱 하나로만 하라고 합니다. 설명 문구를 파싱하는 것도 금지 — 문구는 고정된 문장이 아니라서 화면에 보여주는 용도로만 쓰라고 적혀 있습니다.

왜 거절당했는지는 다섯 갈래로 나옵니다

거절 사유는 다섯 개 분류 중 하나로 붙습니다. 흥미로운 건 표 자체가 아니라, 문서가 "멀쩡한 작업도 걸릴 수 있다"고 스스로 인정한 대목이 세 군데나 있다는 점입니다.

분류 무슨 뜻인가
사이버 악성코드·취약점 개발 등 사이버 피해로 이어질 수 있는 요청. 선량한 보안 업무도 걸릴 수 있다고 문서가 명시.
생물 위험한 실험 기법 등 생물학적 피해 관련. 유익한 생명과학 연구도 걸릴 수 있음.
경쟁 모델 경쟁 AI 모델 개발을 돕는 요청. 상용 약관상 제한 항목. 평범한 머신러닝 작업도 걸릴 수 있음.
추론 추출 모델의 내부 사고 과정을 답변 텍스트로 그대로 뽑아내라는 요청. 정식 경로는 따로 있음.
일반 유해 그 밖에 유해하다고 판단된 영역. 여기도 멀쩡한 작업이 걸리는 경우가 있다고 적혀 있음.

다섯 중 셋에 "멀쩡한 작업도 걸릴 수 있다"는 단서가 달려 있다는 건, 뒤집으면 오탐을 전제로 설계했다는 얘기입니다. 실제로 이 문서 전체가 거절이 났을 때 다른 모델로 넘기는 방법에 대부분의 분량을 쓰고 있습니다. 막는 것보다 막힌 뒤를 정리하는 쪽에 무게가 실려 있는 구조죠. AI 안전장치의 등급을 나누려는 업계 흐름은 예전에 탈옥 심각도 기준 합의 글에서 정리한 적이 있는데, 그때의 논의가 실제 API 응답 필드로 내려온 셈입니다.

다른 모델로 넘길 때, 캐시값을 돌려줍니다

여기가 이 문서에서 가장 돈 얘기다운 대목입니다. 예전에 프롬프트 캐싱이 깨지는 순간들을 정리하면서 "모델만 바꿔도 대화 전체를 다시 읽는다"고 썼는데, 거절 후 재시도가 정확히 그 상황입니다. 캐시는 모델마다 따로라서, A 모델에 쌓아둔 대화 앞부분을 B 모델로 옮기면 처음부터 다시 써야 합니다. 그리고 캐시는 읽을 때보다 쓸 때가 비쌉니다.

그러니까 거절 한 번에 내 잘못도 아닌 캐시 재작성 비용을 물게 되는 구조인데, 그걸 없애는 장치가 붙었습니다. 이름은 폴백 크레딧이고, 동작은 단순합니다.

💳 환불이 붙는 흐름 네 단계

①거절날 수 있는 요청에 전용 베타 헤더를 붙여 보냅니다. ②거절 응답 안에 크레딧 토큰과, 재시도를 어떤 모양으로 보내야 하는지 알려주는 참·거짓 값 하나가 같이 옵니다. ③거절당한 요청 본문을 그대로 두고 모델만 바꾼 뒤 그 토큰을 실어서 다시 보냅니다. ④재시도는 처음부터 그 모델에서 대화했던 것처럼 계산됩니다. 즉 캐시 재작성분이 읽기 요금으로 바뀝니다. 참·거짓 값이 참이면 거절 직전까지 나온 부분 응답을 이어서 쓰는 모양으로 보내야 하고, 그 경우 이미 실행된 서버 도구는 다시 돌지 않습니다.

다만 아무 모델로나 넘길 수 있는 건 아닙니다. 거절한 모델마다 허용된 대체 모델 목록이 정해져 있고, 문서 기준으로 최상위 모델의 대체 대상은 딱 두 개입니다. 그리고 이 장치는 직접 재시도를 짜는 사람만 알면 됩니다 — API가 알아서 재시도해주는 방식이나 SDK 미들웨어를 쓰면 환불이 자동으로 적용됩니다.

⏱️ 토큰의 성격이 특이합니다

이 크레딧 토큰은 5분 뒤 만료됩니다. 그리고 서버가 토큰에 대해 아무것도 저장하지 않습니다. 조회하는 엔드포인트도, 취소하는 엔드포인트도 없습니다. 사용 범위도 좁아서 거절을 받은 조직과 워크스페이스에서만 쓸 수 있습니다. 그래서 실무적으로는 "받자마자 그 자리에서 쓰는 일회용 쿠폰"에 가깝습니다. 큐에 넣어뒀다가 나중에 처리하는 구조라면 5분을 넘기기 쉬우니 애초에 계산에서 빼는 편이 낫습니다. 참고로 배치로 보낸 요청은 거절이 나도 토큰 자체가 발급되지 않습니다.

환불이 먹혔는지 확인하는 법 (0이 실패가 아닌 이유)

"돌려줬다"는데 영수증에 환불 항목이 따로 찍히지는 않습니다. 확인 방법이 조금 우회적입니다 — 재시도 응답의 사용량에서 캐시 생성 토큰이 줄고, 캐시 읽기 토큰이 같은 양만큼 늘어나면 적용된 겁니다. 비싼 항목이 싼 항목으로 옮겨간 자국을 보는 셈이죠.

🔎 옮겨간 양이 0이어도 실패가 아닙니다

여기서 오해하기 딱 좋은 지점을 문서가 미리 짚어놨습니다. 이동량이 0이라고 해서 토큰이 거부된 게 아닙니다. 문서 설명은 토큰은 정상적으로 받아들여졌는데 다시 매길 게 없었던 경우이고, 대표적인 예로 재시도할 모델의 캐시가 이미 따뜻했던 상황을 듭니다. 즉 0 = 손해 없음이지 0 = 환불 실패가 아닙니다. 로그에 경보를 걸어두실 거라면 이 구분을 넣어두는 게 좋습니다.

재시도가 거부되는 경우도 있는데, 문서는 사다리처럼 내려가라고 안내합니다. ①이어쓰기 모양이 거부되면 본문을 손대지 않은 원래 모양으로 다시. ②그것도 거부되고 오류 메시지가 토큰을 지목하면 토큰을 빼고 재시도. 크레딧은 날아가지만 요청 자체는 통과합니다. 다만 "잠시 사용 불가"라는 문구가 뜨면 그건 사다리를 내려갈 신호가 아니라 일시적인 상태라서, 같은 토큰으로 5분 안에 그대로 다시 보내라고 되어 있습니다.

조용히 두 번 청구되는 경로 하나

문서에서 가장 실전적인 경고는 여기 있습니다. 방금 말한 사다리의 마지막 칸, 토큰을 빼고 재시도하기항상 안전한 선택은 아니라는 겁니다.

두 번 도는 것, 두 번 청구되는 것

거절이 서버 도구가 이미 실행된 뒤에 도착한 경우가 있습니다. 검색을 돌렸거나 코드를 실행한 다음에 막힌 상황이죠. 이때 토큰을 버리고 맨 처음 본문으로 재시도하면 그 도구들이 처음부터 다시 돌고, 다시 청구됩니다.

그래서 문서는 이 경우 "조용히 토큰 없는 재시도로 흘러가지 말고, 비용이나 오류를 호출한 쪽에 드러내라"고 지시합니다. 자동 복구가 오히려 아무도 모르는 청구서를 만드는 자리라서요.

이어쓰기 모양이 존재하는 이유도 바로 이겁니다 — 이미 끝난 도구 호출을 다시 돌리지 않으려고 만든 장치입니다. 그런데 이어쓰기가 원천적으로 불가능한 조합이 있습니다. 출력 형식을 강제했거나 도구 사용을 강제한 요청이면 이어쓰기를 못 쓰고, 거기에 서버 도구가 이미 돌아버린 상황이 겹치면 원래 모양도 못 씁니다. 두 문이 다 닫히는 거죠. 흔한 경우는 아니지만, 도구를 강제로 쓰게 해둔 파이프라인이라면 알고는 있어야 하는 구석입니다.

빠뜨리기 쉬운 자리 다섯 곳

문서 마지막에 흔한 실수 목록이 붙어 있는데, 절반 이상이 "거기까지는 안 걸어놨다" 유형입니다. 정리하면 이렇습니다.

빠지는 자리 왜 문제인가
서브에이전트 호출 도구 실행 안에서 다시 모델을 부르면 대체 모델 설정이 그쪽으로 전달되지 않습니다. 따로 걸어줘야 합니다.
재시도·복구 분기 에러 복구 코드나 백그라운드 워커가 요청을 다시 쏘면서 설정을 빠뜨리면, 가장 필요한 요청에서 보호가 사라집니다.
전역 플래그로 관리 공유 설정값이나 토글로 켜두면 조용히 어긋납니다. 문서는 요청마다 직접 붙이라고 권합니다.
재시도 예산 단위 한 턴에서 거절이 여러 번 날 수 있습니다(본체 + 하위 호출). 세션이 아니라 요청 단위로 잡아야 합니다.
같은 모델로 재시도 거절한 모델에 그대로 다시 보내면 또 거절당하는 게 보통입니다. 방향을 바꿔야 합니다.

그리고 잘 안 알려진 함정 하나 더. 재시도 본문이 원본과 정확히 일치해야 환불이 성립하는데, 여기서 베타 헤더 하나만 달라도 실패합니다. 문제는 그때 나오는 400 오류 메시지가 본문이 다를 때와 똑같은 문구라서, 헤더 문제를 본문 문제로 착각하고 몇 시간 헤매기 딱 좋다는 점입니다. 문서가 이 오독 가능성을 직접 경고할 정도니, 재시도가 계속 400을 뱉으면 본문보다 헤더를 먼저 대조해보시는 게 빠릅니다.

🧭 거절과 무관하게 그냥 안 먹을 때는

여기서 본 환불 장치는 거절 뒤 다른 모델로 넘길 때의 이야기입니다. 거절과 상관없이 캐시가 안 먹는 경우를 위한 진단 기능은 따로 있습니다특히 「요청은 안 바뀌었는데 캐시가 안 먹었다」가 나오면 내 코드가 아니라 호출 간격이나 캐시 유지 설정을 봐야 합니다. 두 기능은 담당하는 문제가 서로 다릅니다.

자주 묻는 질문

Q. 채팅으로 쓰는 구독 사용자도 해당되나요?

아닙니다. 오늘 정리한 내용은 API로 직접 호출하는 경우의 응답 형식과 과금 규칙입니다. 구독 요금제는 요청 단위로 돈을 매기지 않으니 "거절당하면 얼마 나가나"라는 질문 자체가 성립하지 않습니다. 다만 거절이 오류가 아니다라는 성격은 같아서, 채팅에서 답을 못 받았을 때 서비스 장애로 오해할 필요는 없다 정도가 전달되는 부분입니다.

Q. 거절이 안 되는 모델을 쓰면 그만 아닌가요?

실제로 같은 성능인데 분류기가 빠진 모델이 문서상 존재하긴 합니다. 다만 일반 판매 대상이 아니라 심사를 통과한 조직에만 제한 공급되는 형태라, 대부분의 개발자에게는 선택지가 아닙니다. 문서도 접근 권한이 없으면 일반 공급 모델을 쓰라고 안내합니다. 이 모델을 둘러싼 규제 논의는 예전에 수출통제 해제 뉴스에서 다룬 적이 있습니다.

Q. 캐시 요금이 얼마나 되길래 환불까지 만들었나요?

업체마다 다르지만 공통점은 읽기는 아주 싸고 쓰기는 비싸다는 구조입니다. 그래서 모델을 옮기느라 처음부터 다시 쓰는 상황이 유독 비싸집니다. 3사 요금 구조를 실제 숫자로 비교한 건 캐시 요금 3사 비교 글에 정리해뒀습니다.

🧭 정직하게 덧붙이면

①오늘 내용은 전부 공식 문서를 직접 열어 확인한 것이고, 제가 실제로 거절을 유발해 요금을 측정한 결과는 아닙니다. 청구 0원 여부를 콘솔에서 대조하지 못했습니다. ②폴백 크레딧과 서버측 대체 모델 기능은 둘 다 베타입니다. 필드 이름과 헤더는 바뀔 수 있습니다. ③플랫폼별로 지원 범위가 갈립니다 — 서버측 대체는 일부 클라우드에서 아직 안 되고, 대체 모델 목록을 조회하는 방법도 플랫폼마다 다릅니다. ④분류 다섯 종의 구체적 판정 기준은 공개되어 있지 않아, 어떤 요청이 걸리는지는 문서만으로 예측할 수 없습니다.

✨ 거절은 에러가 아니라 200입니다 — 청구는 0이어도 한도는 깎이고, 대시보드는 조용합니다

AI에 나가는 돈을 항목별로 뜯어본 글들은 AI 지출 정리 허브에 모아두고 있습니다. 오늘 글은 그 목록에 "안 나가는 줄 알았는데 나가는 돈" 쪽으로 한 칸을 더 채운 셈입니다.

출처: Anthropic 공식 개발자 문서 Refusals and fallback · Fallback credit · Introducing Claude Fable 5 and Claude Mythos 5(2026-08-19 직접 열람). 베타 기능이 포함되어 있어 필드명·헤더·지원 플랫폼은 변경될 수 있습니다. 요금 관련 서술은 문서 기재 내용이며 실제 청구서 대조는 하지 않았습니다.

반응형
Comments