Prompt caching — Claude Developer Documentation
매달 Claude API 비용이 몇백 달러씩 나가는데, 실시간 응답이 필요 없는 작업까지 실시간 API로 돌리고 있지 않나요? Batch API를 쓰면 입력·출력 토큰 비용을 정확히 50% 줄일 수 있습니다. 일일 요약, 대량 분류, 데이터 추출처럼 "지금 당장 결과가 필요하지 않은" 작업만 골라내면 되죠. 이 글에서는 어떤 작업을 배치로 넘겨야 하는지 판단 기준부터 JSONL 요청 작성, 결과 매칭, 프롬프트 캐싱 조합까지 실전 절차를 단계별로 보여드립니다.
준비물
Claude API 키가 필요합니다. Python 3.x 환경이나 cURL이 설치된 터미널이면 충분해요. JSONL 파일을 편집할 텍스트 에디터도 준비하세요. 배치 요청은 최대 100,000개 또는 256MB까지 한 번에 보낼 수 있고, 결과는 대부분 1시간 안에 나옵니다. 최대 24시간까지 걸릴 수 있지만, 실제로는 훨씬 빠르더군요. 결과는 생성 후 29일간 보관되니 여유 있게 조회할 수 있습니다.
어떤 작업을 배치로 넘겨야 할까요?
실시간 응답이 필요하지 않고, 대량으로 처리해야 하는 작업이 배치 후보입니다. 제가 직접 옮긴 케이스를 보면 일일 뉴스레터 요약(매일 오전 6시 발송), 고객 문의 자동 분류(1시간 단위 배치), CSV 데이터 추출(주말 야간 처리)이 대표적이에요.
판단 기준은 간단합니다. 결과를 받는 데 1시간 정도 기다려도 되는가? 요청 개수가 수십 건 이상인가? 두 조건을 모두 만족하면 배치로 넘기세요. 월 $200 쓰던 프로젝트에서 일일 요약만 배치로 옮겼더니 첫 달 청구서가 $140으로 떨어졌습니다.
반대로 챗봇 응답, 사용자 쿼리 실시간 처리처럼 즉각 결과가 필요한 건 실시간 API로 남겨야 합니다. 배치는 최소 몇 분에서 1시간 이상 걸리니까요.
JSONL 요청 파일은 어떻게 만드나요?
배치 요청은 JSONL 형식으로 작성합니다. 한 줄이 하나의 요청이에요. customid는 필수인데, 이걸 빼먹으면 나중에 결과와 원본을 매칭할 때 순서가 보장되지 않아서 꼬입니다. 실제로 customid 없이 인덱스로 매칭했다가 순서가 뒤바뀌어 3시간 날린 적이 있어요.
예를 들어 고객 문의 3건을 분류한다면 이렇게 작성하죠.
{"custom_id": "inquiry-001", "params": {"model": "claude-sonnet-5-20250219", "max_tokens": 100, "messages": [{"role": "user", "content": "환불 요청입니다."}]}}
{"custom_id": "inquiry-002", "params": {"model": "claude-sonnet-5-20250219", "max_tokens": 100, "messages": [{"role": "user", "content": "배송 문의드립니다."}]}}
{"custom_id": "inquiry-003", "params": {"model": "claude-sonnet-5-20250219", "max_tokens": 100, "messages": [{"role": "user", "content": "제품 사양 질문입니다."}]}}
custom_id는 나중에 결과에서 그대로 돌아오니 원본 데이터베이스 ID나 파일명을 넣으면 편합니다. params는 실시간 Messages API와 동일한 구조예요. 비전, 툴 호출, 프롬프트 캐싱 전부 쓸 수 있습니다.
배치를 생성하고 결과를 조회하려면?
JSONL 파일을 준비했으면 배치를 생성합니다. cURL로 보내는 예시를 보죠.
curl https://api.anthropic.com/v1/messages/batches \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"requests": [
{"custom_id": "inquiry-001", "params": {...}},
{"custom_id": "inquiry-002", "params": {...}}
]
}'
응답으로 id 필드가 돌아옵니다(예: batchabc123). 이걸 저장해두세요. 처리 상태는 GET /v1/messages/batches/{batchid}로 폴링하면 돼요. processing_status가 ended가 될 때까지 기다리면 됩니다.
결과 조회는 이렇게 하죠.
curl https://api.anthropic.com/v1/messages/batches/batch_abc123/results \
-H "x-api-key: $ANTHROPIC_API_KEY"
결과도 JSONL 형식으로 돌아옵니다. 각 줄에 custom_id가 포함되어 있으니 이걸 키로 원본과 매칭하면 됩니다. 순서는 보장되지 않으니 인덱스로 매칭하면 안 됩니다.
프롬프트 캐싱까지 조합하면 얼마나 아낄까요?
배치 API만 써도 50% 절감인데, 프롬프트 캐싱을 함께 쓰면 더 줄일 수 있어요. 시스템 프롬프트나 긴 문서를 반복해서 보내는 작업에 유리합니다. 캐시 읽기는 원래 입력 토큰의 약 0.1배, 쓰기는 1.25배(5분 TTL) 또는 2배(1시간 TTL)예요.
예를 들어 Sonnet 5로 입력 200만 토큰, 출력 30만 토큰을 처리한다고 해보죠. 2026년 8월 31일까지 도입가는 입력 $2/100만, 출력 $10/100만입니다.
실시간 API로 처리하면:
- 입력: 200만 × $2/100만 = $4
- 출력: 30만 × $10/100만 = $3
- 총 $7
배치 API로 넘기면(50% 할인):
- 입력: 200만 × $2/100만 × 0.5 = $2
- 출력: 30만 × $10/100만 × 0.5 = $1.5
- 총 $3.5
여기서 시스템 프롬프트 100만 토큰을 캐싱하고(5분 TTL, 쓰기 1.25배) 10회 재사용하면 이렇게 바뀝니다.
- 캐시 쓰기(첫 요청): 100만 × $2/100만 × 1.25 = $2.5
- 캐시 읽기(9회): 100만 × 9 × $2/100만 × 0.1 = $1.8
- 일반 입력(요청당 10만): 10만 × 10 × $2/100만 × 0.5 = $1
- 출력: $1.5
- 총 $6.8
배치만 쓰면 $3.5인데 캐싱을 넣으니 $6.8로 오히려 비싸 보이지만, 이건 10회만 재사용했을 때예요. 요청이 100회라면 캐시 쓰기 $2.5, 캐시 읽기(99회) $19.8, 일반 입력 $10, 출력 $15로 총 $47.3이 됩니다. 캐싱 없이 배치만 쓰면 입력 $110 + 출력 $15 = $125니까 캐싱 조합이 훨씬 유리합니다.
요청이 2회 이상이면 5분 TTL이, 3회 이상이면 1시간 TTL이 손익분기예요. 배치 작업은 보통 수십~수백 건이니 캐싱을 적극 활용하세요.
캐시 히트를 확인하려면 응답의 cachereadinput_tokens 값을 보세요. 0이면 캐시가 안 된 거예요. 최소 프리픽스는 모델마다 다릅니다. Sonnet 5는 1024 토큰, Haiku 4.5는 4096 토큰이에요. 프리픽스가 이보다 짧으면 조용히 캐싱이 안 되니 주의하세요.
흔한 실수와 해결법
제가 실제로 겪은 삽질 세 가지를 공유합니다.
첫째, customid 없이 인덱스로 매칭했다가 순서가 뒤바뀌어 3시간 날렸어요. 배치 결과는 순서를 보장하지 않으니 반드시 customid를 넣고, 결과 조회 후 이 키로 매칭하세요.
둘째, 캐시 프리픽스가 1024 토큰 미달이라 cachecreationinput_tokens가 0으로 뜨는데 왜 캐싱이 안 되는지 몰라 하루를 헤맸습니다. 모델별 최소 토큰을 확인하세요. Sonnet 5는 1024, Haiku 4.5는 4096입니다.
셋째, 시스템 프롬프트에 현재 시각을 넣었더니 매 요청마다 프리픽스가 달라져서 캐시가 전부 무효화됐어요. 시스템 프롬프트나 툴 목록 순서를 바꾸면 캐시가 깨지니, 고정 부분만 캐싱 대상으로 넣으세요.
다음 행동
배치 API는 "나중에 써봐야지"가 아니라 "오늘 당장 넘길 작업"을 찾는 게 핵심입니다. 일일 요약, 주간 리포트, 야간 데이터 추출처럼 스케줄 작업부터 시작하면 다음 달 청구서에서 바로 확인할 수 있어요. 프롬프트 캐싱은 시스템 프롬프트가 고정된 작업부터 테스트해보세요.
자주 묻는 질문
Q. 배치 API 결과는 얼마나 보관되나요? A. 생성 후 29일간 보관됩니다. 그 안에 조회해서 로컬에 저장하세요.
Q. 배치 처리 중 실패한 요청은 어떻게 확인하나요? A. 결과 JSONL에서 result.type이 error인 항목을 찾으면 됩니다. custom_id로 원본과 매칭해 재시도하세요.
Q. 프롬프트 캐싱 TTL은 어떻게 선택하나요? A. 요청이 2회 이상이면 5분 TTL, 3회 이상이면 1시간 TTL이 손익분기입니다. 배치 작업은 보통 수십 건 이상이니 1시간 TTL을 권장해요.
Q. Amazon Bedrock이나 Google Vertex AI에서도 배치 API를 쓸 수 있나요? A. 안 됩니다. 배치 API는 Claude 공식 플랫폼에서만 제공됩니다.