클로드 캐시 만료 방지 도구 'Claude-thermos'
클로드 코드(Claude Code)를 사용할 때 하위 에이전트 작업 등으로 5분 이상 대기하면 메인 에이전트의 프롬프트 캐시가 만료되어 막대한 재인코딩 비용이 발생합니다. Claude-thermos는 로컬 프록시를 통해 백그라운드에서 캐시를 주기적으로 따뜻하게 유지(warming)하여, 전체 요금의 약 22%에 달하는 불필요한 비용 지출을 방지해 줍니다. 개발자는 기존 CLI 명령어 대신 uvx claude-thermos를 실행하는 것만으로 쉽게 적용할 수 있습니다.
claude-thermos: 더 이상 클로드 코드 캐시를 재구성하느라 돈을 낭비하지 마세요.
메인 에이전트가 하위 에이전트(subagent)를 기다리느라 5분 이상 대기하게 되면, 프롬프트 캐시가 조용히 만료됩니다. 그리고 다음 차례에서는 저렴한 읽기 요금으로 불러올 수 있었던 전체 대화 내용을 비싼 쓰기(write) 요금으로 다시 인코딩하게 됩니다. 여러 하위 에이전트를 사용하는 긴 세션의 경우, 이 과정에서 전체 요금의 약 20%가 낭비됩니다. claude-thermos가 캐시를 따뜻하게 유지해 이 불필요한 비용(세금)을 지불하지 않도록 도와줍니다.
사용법은 평소처럼 클로드 코드를 실행하면 되지만, claude 대신 uvx로 claude-thermos를 실행하기만 하면 됩니다:
uvx claude-thermos
대신 사용: claude
uvx claude-thermos -p "버그 수정"
클로드의 모든 인자(arguments)를 그대로 전달할 수 있습니다.
Python 3.11 이상과 PATH에 설정된 claude CLI가 필요합니다. 준비물은 이게 전부입니다. 캐시 워밍 작업은 백그라운드에서 자동으로 실행됩니다. 명령어를 바꾸지 않고 특정 실행에만 워밍을 비활성화하려면 CLAUDE_WARMER_DISABLE=1 환경변수를 설정하면 됩니다.
세부 조정 (모두 선택 사항): 플래그 | 기본값 | 의미 --idle | 270 | 워밍이 시작되기 전까지 메인 에이전트가 유휴 상태로 대기해야 하는 시간(초) --interval | 270 | 워밍 사이클 간격(초) --max-cycles | 4 | 유휴 상태당 최대 워밍 횟수 (무제한은 auto) --subagent-window | 540 | 하위 에이전트가 '여전히 활성 상태'로 간주되는 시간(초)
왜 캐시가 계속 만료될까요? 클로드 코드의 프롬프트 캐시는 5분의 TTL(Time-To-Live)을 사용합니다. 캐시가 살아있는 한 매 차례마다 전체 대화 기록을 전체 요금으로 다시 보내는 대신, 입력 가격의 0.1배(0.1x)에 해당하는 저렴한 캐시 가격으로 불러올 수 있습니다. 동일한 접두사(prefix)를 가진 요청 사이에 5분 이상이 지나면 캐시가 만료됩니다. 이 5분의 공백을 유발하는 주된 이유는 사용자가 생각하는 시간이 아닙니다. 바로 메인 에이전트가 5분 이상 실행되는 하위 에이전트 때문에 차단되어 있기 때문입니다.
하위 에이전트는 다른 시스템 프롬프트와 도구 세트를 가지고 있으므로, 해당 요청은 다른 캐시 접두사를 사용하며 메인 에이전트의 캐시를 절대 새로고침하지 않습니다. 하위 에이전트가 작동하는 동안 메인 에이전트의 캐시된 기록은 아무도 건드리지 않은 채로 오래되고, 5분이 지나면 사라집니다. 하위 에이전트가 반환되면 메인 에이전트는 바이트가 완전히 동일한 추가 전용(append-only) 기록으로 작업을 재개하지만 캐시가 사라진 것을 발견하게 됩니다. 결국 1.25배의 높은 쓰기 요금으로 전체를 다시 인코딩해야 합니다.
이 시점이 되면 기록의 크기가 매우 크기 때문에 재인코딩 비용이 비쌉니다. 개별적으로 무너진 캐시를 복구할 때마다 20만~50만 개의 토큰을 다시 작성해야 합니다. 약 185개의 로컬 세션에서 측정한 결과, 이러한 재구성 작업이 전체 요금의 약 22%를 차지했으며, 이는 불과 몇 순간 전까지만 해도 캐시되어 있던 콘텐츠를 다시 인코딩하는 데 낭비된 돈입니다.
작동 원리 claude-thermos는 작은 로컬 역방향 프록시(reverse proxy) 뒤에서 클로드 코드를 실행합니다(ANTHROPIC_BASE_URL을 로컬 루프백 포트로 지정하지만, 모든 트래픽은 여전히 실제 Anthropic API로 전달됩니다).
관찰 (Observe). 프록시는 /v1/messages 트래픽을 감시하여 이를 세션과 계통(lineage)으로 그룹화합니다. 계통은 하나의 캐시 접두사를 의미하며 모델 + 도구 세트 + 시스템 텍스트를 키로 사용합니다. 도구를 포함하는 첫 번째 계통이 메인 에이전트이고 나머지는 하위 에이전트입니다.
위험 구간 감지 (Detect the danger window). 메인 계통이 유휴 상태이고 하위 에이전트가 활발하게 실행 중일 때, 메인 접두사은 만료될 위험이 있습니다.
워밍 (Warm). 5분의 TTL 이내의 간격으로 메인 에이전트의 마지막 실제 요청을 워밍 요청으로 재생합니다. 이때 캐시 가능한 접두사은 동일하지만, max_tokens를 1로 설정하고 스트리밍을 끕니다. 반환된 단일 토큰은 버려집니다. 핵심은 전체 캐시된 접두사을 읽고 새로고침하는 사전 채우기(prefill)에 있습니다. 워밍 요청은 실제 트래픽을 방해하지 않도록 프록시를 거치지 않고 API로 직접 전송됩니다.
결과 (Result). 하위 에이전트가 작업을 마치면 메인 에이전트의 캐시가 여전히 따뜻하게 유지됩니다. 전체를 다시 작성하는 대신 저렴한 읽기 비용만 지불하면 됩니다. 각 워밍은 캐시 읽기 비용(0.1배)만 발생시킵니다. 반면 이것이 막아주는 재작성은 훨씬 더 큰 접두사에 대해 쓰기 비용(1.25배)을 발생시켰을 것이므로, 이 교환은 사용자에게 압도적으로 유리합니다.
이벤트 로그 및 비용 절감
모든 세션은 다음 경로에 기록됩니다:
~/.claude-thermos/logs/
events.jsonl은 각 요청/응답의 토큰 사용량과 모든 워밍 결정을 기록합니다 (warm_fired, warm_result, cap_reached, resume_detected 등). summary.json은 주로 사용자가 읽게 되는 롤업 파일입니다: 필드 | 의미 warms_fired | 전송된 워밍 요청 수 cache_read_total | 해당 워밍으로 다시 읽어온 토큰 수 episodes | 하위 에이전트를 동반한 유휴 상태 에피소드 수