ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프롬프트 캐싱이 안 되는 이유: 같은 문서인데 캐시를 못 읽는 경우
    AI Agent 2026. 9. 9. 12:53
    728x90
    반응형

    집게로 묶은 카드 뭉치 끝에 놓인 파란 카드

    집게로 묶은 카드 뭉치 끝에 놓인 파란 카드. 이해를 돕기 위한 AI 생성 개념 이미지입니다.

    같은 문서를 여러 번 보내는데 매번 입력 비용이 그대로라면, 문서 내용보다 요청의 앞부분이 바뀌는지부터 볼 필요가 있습니다. 프롬프트 캐싱은 비슷한 질문에 예전 답을 그대로 돌려주는 기능과 다릅니다.

    캐시를 쓰려면 반복되는 접두부를 고정하고, 응답의 캐시 읽기 토큰을 따로 확인하세요.

    저장하는 것은 답변이 아니라 재사용할 입력 처리입니다

    Claude의 프롬프트 캐싱 문서는 캐시 구간이 정확히 일치해야 한다고 설명합니다. 안정적인 지침과 자료를 앞에 두고, 매번 달라지는 질문을 뒤에 놓는 구조가 중요한 이유입니다.

    가상의 공개 설명서 질의 앱이라면 “고정 지침 → 설명서 → 오늘의 질문” 순서를 생각할 수 있습니다. 반대로 요청 시각을 맨 앞에 붙이면 같은 설명서가 뒤에 있어도 접두부는 달라집니다. 문서 파일이 같다는 확인만으로 캐시 적중을 판단할 수 없습니다.

    Claude API에서 구조를 표현하면 다음처럼 됩니다. 모델 ID와 문서 내용은 예시이며, 핵심은 cache_control을 질문이 아니라 반복되는 system 블록 끝에 두는 점입니다.

    response = client.messages.create(
        model="MODEL_ID",
        max_tokens=1024,
        system=[{
            "type": "text",
            "text": "공통 지침과 공개 설명서 본문...",
            "cache_control": {"type": "ephemeral"}
        }],
        messages=[{
            "role": "user",
            "content": "오늘의 질문..."
        }]
    )

    현재 Claude 문서는 top-level cache_control을 쓰는 automatic caching과 블록별 cache_control을 지정하는 explicit breakpoint를 구분합니다. 멀티턴 대화는 automatic caching이 편할 수 있지만, 고정 접두부와 가변 접미부를 명확히 나누려면 explicit breakpoint가 원인을 추적하기 쉽습니다. 이 예시는 Claude API 전용 구조이므로 다른 제공자의 같은 이름 필드로 일반화하지 않습니다.

    바뀌는 값은 어디에 들어가는지 비교합니다

    다음 두 요청은 개념을 설명한 예시입니다. 실제 API 요청 형식이나 측정 결과는 아닙니다.

    요청 A: [시각 09:00] [공통 지침] [설명서] [질문 1]
    요청 B: [시각 09:01] [공통 지침] [설명서] [질문 2]

    시각이 요청마다 꼭 필요하다면 공통 구간 뒤로 옮길 수 있는지 검토합니다. 도구 정의 순서, 이미지, 지침 수정도 함께 비교합니다. 다만 캐시를 맞추겠다고 필요한 최신 문서를 오래된 문서로 고정해서는 안 됩니다. 자료가 바뀐 요청에서 캐시를 새로 쓰는 것은 정상적인 비용일 수 있습니다.

    생성 토큰과 읽기 토큰을 따로 봅니다

    같은 공식 문서는 응답의 usage에서 캐시 생성, 캐시 읽기, 나머지 입력을 나눠 제공합니다. Claude API의 해당 필드를 읽을 때 총입력을 일반 입력 필드 하나로 오해하면 안 됩니다.

    아래는 구분을 위한 가상 장부입니다.

    요청캐시 생성 입력캐시 읽기 입력나머지 입력
    첫 질문4,000080
    후속 질문04,000120

    두 번째 요청에서 처리한 총입력은 산술상 4,120토큰입니다. 120토큰만 읽었다는 뜻이 아닙니다. 반대로 캐시 생성이 있었다는 기록은 후속 요청에서 읽었다는 증거가 아닙니다. 이 수치는 모델별 최소 길이를 뜻하지 않으며 실제 청구 기록도 아닙니다.

    자주 묻지 않는 자료는 따로 판단합니다

    현재 Claude 문서는 기본 ephemeral 캐시 수명을 5분으로 설명하고, 필요하면 1시간 TTL을 별도 지정할 수 있다고 안내합니다. 최소 캐시 가능 입력 토큰 수는 모델과 제공 플랫폼별로 다르며, 너무 짧은 프롬프트는 오류 없이 캐싱되지 않을 수 있습니다. 따라서 이 값은 고정 상수가 아니라 사용 모델의 현재 문서에서 확인해야 합니다.

    긴 문서를 넣었다는 이유만으로 항상 절감되는 것은 아닙니다. 후속 요청이 드물거나 문서가 매번 바뀌면 생성 비용을 회수할 기회도 달라집니다. 캐시 생성은 첫 응답이 시작된 뒤 이용 가능해지므로, 첫 요청과 거의 동시에 보낸 병렬 요청은 적중하지 않을 수도 있습니다.

    캐시가 잘 맞는데 전체 대기가 길다면 출력 길이나 외부 도구 호출 시간이 큰지 볼 수 있습니다. 입력 처리를 재사용한다고 응답 생성과 모든 외부 작업이 사라지는 것은 아니기 때문입니다.

    캐시가 안 맞을 때 요청 전체를 해시처럼 비교합니다

    문서 본문만 비교하면 원인을 놓치기 쉽습니다. 캐시 경계 앞에 포함되는 요소를 직렬화된 요청 기준으로 봐야 합니다.

    비교 대상흔한 변화확인 방법
    시스템 지침빌드 시간·사용자 이름 삽입최종 전송 문자열 저장
    도구 정의도구 순서·설명·스키마 변경요청별 도구 JSON 비교
    문서 블록공백·정렬·전처리 결과캐시 구간 바이트/토큰 비교
    이미지변환·메타데이터 차이실제 전송 블록 비교
    모델·캐시 설정모델 또는 TTL 변경요청 메타데이터 기록
    breakpoint매번 바뀌는 마지막 블록에 표시마지막으로 동일한 블록에 명시적으로 이동
    대화 길이이전 cache write에서 20블록 이상 멀어짐lookback window와 추가 breakpoint 확인
    가변 질문고정 구간 앞에 배치고정 접두부 뒤로 이동 검토

    로그에 원문 전체를 남기기 어렵다면 개인정보와 비밀 값을 제거한 뒤 캐시 구간의 버전 식별자와 해시를 기록할 수 있습니다. 두 요청의 해시가 다르면 “같은 문서”라는 파일명보다 실제 직렬화 차이를 먼저 조사합니다. 해시가 같아도 제공사 조건과 수명을 만족했는지는 usage로 확인해야 합니다.

    usage를 요청 단위 장부로 읽는 방법

    가상의 로그 구조를 다음처럼 둡니다.

    {
      "request_id": "r-002",
      "prompt_version": "support-v4",
      "document_digest": "sha256:...",
      "cache_creation_input_tokens": 0,
      "cache_read_input_tokens": 4000,
      "input_tokens": 120,
      "output_tokens": 260
    }

    여기서 캐시 적중 여부는 cache_read_input_tokens로 확인합니다. 전체 입력 처리량을 계산할 때는 제공 문서가 구분한 필드를 임의로 하나로 덮지 않습니다. 비용 계산도 각 토큰 종류의 당시 단가를 따로 곱해야 하며, 위 숫자만으로 실제 금액을 만들 수는 없습니다.

    관측할 비율은 목적에 따라 다릅니다. “후속 요청 가운데 캐시를 읽은 요청 비율”과 “전체 입력 토큰 가운데 캐시에서 읽은 토큰 비율”은 서로 다릅니다. 짧은 질문 열 개가 모두 적중해도 긴 요청 하나가 실패하면 토큰 비율은 낮을 수 있습니다.

    캐시를 위한 구조 변경이 손해가 되는 경우

    고정 접두부를 만들겠다고 사용자마다 달라야 할 권한 지침을 하나로 합치면 안 됩니다. 최신 정책 문서를 캐시하려고 갱신을 늦추거나, 민감 자료를 더 넓은 요청에서 재사용하는 것도 잘못된 최적화입니다. 정확성·격리·최신성은 적중률보다 우선합니다.

    다음 경우에는 캐시를 억지로 맞추기보다 사용하지 않는 선택이 가능합니다.

    • 같은 접두부의 후속 요청이 거의 없습니다.
    • 문서가 매 요청마다 실질적으로 바뀝니다.
    • 고정 구간이 모델의 최소 조건보다 짧습니다.
    • 응답 지연의 대부분이 출력 생성이나 외부 도구에 있습니다.
    • 사용자별 격리 때문에 공통 접두부를 공유하면 안 됩니다.

    반대로 긴 정책·코드베이스 설명을 같은 버전으로 여러 번 묻는다면 요청을 “안정적인 지침과 자료 → 가변 질문” 순서로 만들고 실제 usage를 비교할 근거가 있습니다. 예상 절감액은 요청 빈도, 캐시 수명, 생성·읽기 단가를 넣어 계산하며, 측정 전 추정과 측정 후 청구를 구분해 기록합니다.

    재현 가능한 점검 순서

    1. 같은 모델과 캐시 설정으로 첫 요청을 보냅니다.
    2. 응답의 캐시 생성 토큰과 요청 ID를 저장합니다.
    3. 유효 시간 안에 고정 접두부는 그대로 두고 질문만 바꿉니다.
    4. 두 번째 응답에서 캐시 읽기 토큰을 확인합니다.
    5. 0이라면 직렬화된 접두부, 도구 정의, 이미지, 캐시 경계를 비교합니다. 현재 Claude 문서의 explicit breakpoint는 이전에 실제로 기록된 cache write를 기준으로 뒤쪽을 확인하므로, 안정된 블록 뒤에 breakpoint를 두지 않았다고 앞쪽의 안정된 내용을 자동으로 저장해 주지는 않습니다.
    6. 긴 대화에서는 breakpoint 사이의 lookback window도 확인합니다. 현재 문서는 한 breakpoint에서 최대 20개 위치를 확인한다고 설명하므로, 더 긴 대화는 별도 breakpoint를 검토합니다.
    7. 적중했다면 입력 처리뿐 아니라 전체 지연과 출력 토큰도 따로 기록합니다.

    이 절차는 성공률을 보장하는 레시피가 아니라 무엇이 측정됐는지 분리하는 방법입니다.

    이 글의 범위

    2026년 9월 7일의 Claude 문서 기준입니다. 다른 API의 같은 이름 필드에 이 계산법을 그대로 적용하지 마세요. 실제 요청을 보내 적중률이나 절감률을 측정하지 않았으며, 사용 모델의 현재 조건을 확인한 뒤 응답 원본으로 판단해야 합니다.

    728x90
    반응형
Designed by Tistory.