본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 30. 03:18

프롬프트 캐싱 (Prompt Caching)은 나쁜 AI 아키텍처를 보조하고 있다

요약

프롬프트 캐싱이 비용을 절감해주지만, 동시에 비효율적인 AI 아키텍처와 워크플로우의 낭비를 은폐하는 부작용을 낳고 있다고 분석합니다. 현대적인 에이전트 워크플로우는 상태 유지와 분기형 구조를 가지므로, 단순한 호출 로그를 넘어선 새로운 차원의 텔레메트리가 필요함을 강조합니다.

핵심 포인트

  • 프롬프트 캐싱은 입력 비용을 크게 절감하지만 아키텍처적 낭비를 가릴 수 있음
  • 현대 AI 워크플로우는 상태 유지, 분기, 하위 에이전트 호출 등 복잡한 구조를 가짐
  • 기존의 단일 요청 중심 텔레메트리로는 에이전트의 효율성을 측정하기 어려움
  • 프롬프트 간의 계보와 워크플로우의 맥락을 파악하는 분석 도구가 필수적임

Brian의 최근 포스트인 Claude Code의 실제 비용은 현대 AI 코딩 도구 이면에 숨겨진 보조금(subsidy) 문제를 살펴보았습니다. 저는 제 자신의 워크플로우 내부에서 그 보조금이 실제로 무엇을 위해 지불되고 있는지 확인하고 싶었습니다. 그래서 제 paper CLI 세션 데이터에서 19일간의 Claude Code 세션 데이터를 추출했습니다: 두 개의 프로젝트와 세 개의 모델 (Opus, Sonnet, Haiku)에 걸친 3,697개의 메시지입니다. 모든 요청이 HTTP 경계에서 캡처되었기 때문에, 사용된 모델, 토큰 수(token counts), 캐시 읽기 및 쓰기(cache reads and writes), 그리고 각 메시지가 이전 메시지들과 연결되는 방식을 파악할 수 있었습니다. 이는 단순한 청구서나 단일 트랜스크립트가 보여줄 수 있는 것 이상의 정보입니다.

프롬프트 캐싱 (Prompt Caching)은 제 입력 비용의 82%를 절감해 주었습니다. 이러한 절감 효과는 실재하지만, 동시에 특정 종류의 아키텍처적 낭비를 무시할 수 있을 만큼 저렴하게 만듭니다. 즉, 한계 없이 커지는 프롬프트, 잘못된 작업에 부착된 컨텍스트 블록(context blocks), 부모의 캐시 접두사(cache prefix)를 다시 쓰는 서브 에이전트(sub-agents) 등이 그 예입니다. 캐싱은 이러한 아키텍처를 건강해 보이는 집계된 숫자 속에 파묻어 버림으로써 이를 보조합니다. 무엇이 보조되고 있는지 확인하는 유일한 방법은 그 아래에 있는 워크플로우를 살펴보는 것입니다: 어떤 프롬프트가 안정적으로 유지되었는지, 어떤 것이 계속 변이(mutating)했는지, 부모가 자식으로 어떻게 분기(forked)되었는지, 그리고 재사용된 컨텍스트가 실제로 유용한 작업에 기여했는지 등을 확인해야 합니다.

프롬프트 캐싱은 더 깊은 시스템의 관찰 가능한 표면에 불과합니다: AI 워크플로우는 상태 유지(stateful) 및 분기형 시스템(branching systems)으로 동작하지만, 현재의 텔레메트리(telemetry)는 이를 고립된 호출로만 인식합니다.

AI 워크플로우는 전통적인 텔레메트리 (telemetry)의 범위를 넘어섰다

몇 년 전, "AI 호출"은 단일 요청이었습니다. 하나의 프롬프트가 들어가고, 하나의 응답이 나오는 방식이었죠. 로그(Logs), 트레이스(traces), 그리고 빌링 대시보드(billing dashboards)만으로도 이를 추론하기에 충분했습니다.

그 시대는 끝났습니다. 현대적인 에이전트 워크플로(agent workflows)는 다섯 가지 축에서 동시에 변화하고 있습니다. 즉, 실행 시간이 길고, 턴(turns) 전반에 걸쳐 상태(state)를 유지하며, 하위 작업(sub-tasks)으로 분기되고, 다른 에이전트를 호출하며, 진행 과정에서 스스로의 프롬프트(prompts)를 다시 작성합니다. 단 한 번의 코딩 세션이 하위 에이전트(sub-agents)를 생성하고, 수십 개의 파일을 읽고, 도구(tools)를 실행하며, 결국 시작 지점과는 거의 닮지 않은 프롬프트로 끝날 수 있습니다. 개별 모델 호출(model call)은 저렴하고 계측(instrumented)이 잘 된 부분입니다. 그 주변을 둘러싼 워크플로가 작업이 효율적이었는지, 내구성이 있었는지, 아니면 낭비였는지를 결정합니다. 전통적인 텔레메트리(telemetry)는 이 중 그 어느 것도 포착하지 못합니다.

요청 로그(Request logs)는 한 번에 하나의 요청만을 보여줍니다. 분산 트레이스(Distributed traces)는 서비스 간의 흐름을 보여줄 뿐, 프롬프트 간의 계보(prompt-to-prompt lineage)를 보여주지 않습니다. 빌링 대시보드(Billing dashboards)는 모든 것을 합산하여 총계로 보여줍니다. 워크플로가 분석의 단위가 되었을 때 중요한 다음 질문들에 대해 그 중 어느 것도 답을 주지 못합니다:

  • 세션 전반에 걸쳐 어떤 프롬프트가 안정적으로 유지되고, 어떤 프롬프트가 계속 변이(mutating)하는가?
  • 부모 에이전트가 하위 에이전트를 생성할 때, 자식 에이전트가 부모의 프롬프트 접두사(prompt prefix)를 상속받는가, 아니면 자체적으로 구축하는가?
  • 컨텍스트(context)가 어디에서 분기되고, 어디에서 병합되는가?
  • 어떤 세션이 결국 보상(payback)을 받지 못할 캐시(cache)를 생성하는 데 비용을 지불했는가?
  • 워크플로의 프롬프트 형태(prompt shape)가 주 단위로 어떻게 드리프트(drifting)하고 있는가?

이러한 질문들은 프롬프트 계보(prompt lineage), 컨텍스트 상속(context inheritance), 캐시 토폴로지(cache topology), 프롬프트 변이(prompt mutation), 하위 에이전트 발산(sub-agent divergence), 그리고 시간에 따라 추적되는 세션 구조(session structure)와 같은 서로 다른 프리미티브(primitives)를 필요로 합니다.

경제적 효율성 vs. 아키텍처적 효율성

저렴한 재사용이 곧 좋은 아키텍처는 아닙니다.

경제적 효율성(Economic efficiency)은 우리가 토큰을 저렴하게 재사용하는지를 묻습니다. 아키텍처적 효율성(Architectural efficiency)은 이 컨텍스트를 재사용해야 했는지 자체를 묻습니다. 이들은 서로 다른 질문이며, 프롬프트 캐싱(prompt caching)은 오직 첫 번째 질문에만 답할 수 있습니다.

워크플로는 경제적으로는 효율적이지만 아키텍처적으로는 낭비적일 수 있습니다. 또한 작업 자체가 많이 반복되지 않을 때는 아키텍처적으로는 깔끔하지만 경제적으로는 비용이 많이 들 수도 있습니다. 이 둘을 혼동하면 구체적인 운영 비용이 발생합니다:

  • 통제 불능의 컨텍스트 성장 (Runaway context growth). 프롬프트에 규칙과 메모가 추가되는 속도가 이를 제거하는 속도보다 빠릅니다.
  • 숨겨진 비용 증폭 (Hidden cost amplification). 캐싱 혜택이 관대할 때는 낭비적인 워크플로우가 저렴해 보이지만, 할인 혜택이 약해지는 순간 비용이 급격히 상승합니다.
  • 프롬프트 엔트로피 (Prompt entropy). 하위 에이전트(Sub-agents)와 프로젝트들이 서서히 서로 다른 방향으로 표류하며, 이에 따라 캐시 재사용성도 저하됩니다.
  • 저하된 캐시 재사용 (Degraded cache reuse). 높은 총합 캐시 적중률(Cache hit rate)이 자신의 접두사(Prefix)를 계속해서 다시 쓰는 세션들을 은폐할 수 있습니다.
  • 디버깅의 어려움 (Hard to debug). 두 세션이 다르게 동작할 때, 그 동작을 유발한 프롬프트에서 무엇이 변했는지 비교할 방법이 없습니다.
  • 아키텍처 비교의 어려움 (Hard to compare architectures). 한 팀의 에이전트 설계가 다른 팀보다 컨텍스트를 더 잘 재사용하는지 물을 방법이 없습니다.

이 중 그 어떤 것도 청구서에는 나타나지 않습니다. 대신 시간이 흐르며 포착된 세션들의 토폴로지(Topology)에 나타납니다.

데이터가 보여준 것

19일 동안 저의 Claude Code 사용량은 1억 260만 개의 입력 토큰(Input tokens)에 93.0%의 캐시 적중률(Cache hit rate)을 기록했습니다. 구체적으로는 기본 입력 가격의 10%로 책정된 9,550만 개의 캐시 읽기(Cache reads), 기본 입력 가격의 125%로 책정된 500만 개의 캐시 쓰기(Cache writes), 그리고 전체 가격이 적용된 210만 개의 새로운 토큰(Fresh tokens)이 사용되었습니다. 여기서와 본문 전반에 걸쳐 "캐시 적중률"은 19일 전체 기간 동안 계산된, 캐시 읽기로 제공된 입력 토큰의 비율을 의미합니다. 이는 명목상 1억 260만 토큰 대비 약 1,790만 개의 기본 상당 토큰(Base-equivalent tokens)에 해당하며, 입력 비용의 82%를 절감한 결과입니다.

금액으로 환산하면, 실제 입력 비용은 $232였으며 캐시를 사용하지 않았을 경우의 비용인 $1,321와 비교해 $1,089를 절약했습니다. 캐시를 사용하지 않았을 경우의 비용은 제 월 $200짜리 Claude Code Max 플랜 가격의 약 6.6배에 달했을 것이므로, 캐시 보조금과 플랜 보조금이 서로 중첩되어 효과를 냅니다.

모델실제 비용캐시 미사용 시 비용절감액
Opus 4.6$220$1,274$1,053 (82.7%)
...
달러 금액은 정수로 반올림되었습니다. 백분율은 반올림되지 않은 기초 값을 기준으로 계산되었으므로, 일부 행의 합계가 시각적으로 일치하지 않을 수 있습니다.

청구서는 제가 무엇을 소비했는지는 알려주지만, 어떤 세션, 어떤 모델, 또는 어떤 프롬프트 형태(prompt shapes)가 그 비율에 책임을 지고 있는지, 혹은 그 작업 중 어떤 것이 애초에 재사용 가능했는지까지는 알려주지 못합니다. 그다음으로 가장 집계된 수치는 캐시 히트율(cache hit rate)입니다. 이는 입력값 중 얼마나 많은 양이 재사용되었는지를 알려줍니다. 하지만 재사용된 컨텍스트(context)가 그곳에 있을 가치가 있었는지까지는 알려주지 못합니다.

95%의 캐시 히트율은 안정적인 워크플로우(workflow)를 구축했다는 의미일 수도 있습니다. 하지만 이는 매우 효율적인 '잡동사니 서랍(junk drawer)'을 만들었다는 의미일 수도 있습니다.

히트율을 모델과 워크로드 형태(workload-shape)별로 분해했을 때, 저는 많은 것을 배웠습니다.

모델 (Model)메시지 (Messages)입력 토큰 (Input tokens)캐시 히트율 (Cache hit rate)신규 토큰 (Fresh tokens)
Opus 4.676782.7M95.6%0.1M
...

Haiku는 478개의 메시지를 처리하기 위해 353개의 별도 루트 세션(root sessions)을 실행했는데, 이는 메시지당 대략 하나의 세션에 해당합니다. 데이터셋 내의 거의 모든 신규 토큰(세 모델 전체 2.2M 중 2.1M)은 저의 원샷(one-shot) 모델이었던 Haiku에서 발생했습니다: 제목 생성, 빠른 분류, 중복 확인, 작은 판단 작업 등입니다. 각 요청은 고유한 형태를 가졌으며, 재사용할 수 있는 긴 공유 접두사(shared prefix)를 갖는 경우가 드물었습니다. 반면 Opus와 Sonnet은 접두사가 한 번 설정된 후 지속적으로 재사용되는 길고 안정적인 세션 내에서 실행되었습니다. Opus의 95.6% 히트율은 프롬프트 캐싱(prompt caching)이 주력 워크로드(workhorse workloads)에서 원래 해야 할 일을 정확히 수행하고 있음을 보여줍니다.

건강한 AI 워크플로우는 하나의 보편적인 캐시 히트율을 갖지 않습니다. 작업의 종류에 따라 서로 다른 캐시 형태(cache shapes)를 가지며, 단일 스칼라(scalar) 값은 이러한 차이점들을 하나로 뭉뚱그려 버립니다.

만약 저렴한 원샷 모델이 비싼 롱 컨텍스트(long-context) 모델과 동일한 캐시 프로필을 가지고 있다면, 둘 중 하나는 자신의 역할에 대해 거짓말을 하고 있는 것입니다.

모델별 분해조차 여전히 행당 하나의 숫자에 불과합니다. 두 세션은 내부적으로 완전히 다르게 동작하면서도 동일한 히트율을 기록할 수 있습니다. 그 차이가 바로 캐시 토폴로지(cache topology)입니다. 즉, 세션 전반에 걸친 쓰기(writes), 읽기(reads), 분기(branches), 변이(mutations), 그리고 병합(merges)의 실제 시퀀스입니다. 이것이 바로 집계 수치가 뭉개버리는 '형태'이며, 반드시 직접적으로 포착되어야 하는 요소입니다.

chart of Cache topology examples
(https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu6cvj4jvvpnhjm2bjw30.png)

안정적인 워크호스(workhorse) 행을 보여주는 제 데이터의 가장 명확한 예시는 4월 29일의 Opus 세션입니다: 728개의 메시지, 총 4,290만(42.9M) 개의 입력 토큰, 그중 4,220만(42.2M) 개가 캐시 읽기(cache reads)였습니다. 이 세션은 31k 토큰의 컨텍스트 쓰기(context write)로 시작되었고, 그 이후의 모든 호출은 해당 접두사(prefix)를 다시 읽어 들인 뒤 점진적으로 추가했습니다. 프롬프트 크기가 31k, 32k, 39k, 43k, 44k, 46k, 47k, 51k, 54k로 계단식으로 상승하는 것을 볼 수 있습니다. 새로운 컨텍스트가 추가될 때 쓰기(writes)가 발생했습니다. 그 외의 모든 곳에서는 읽기(reads)가 지배적이었습니다. 이것은 단순한 숫자가 아니라 토폴로지(topology, 위상)입니다.

토폴로지가 드러내는 네 가지 패턴

세션을 하나의 형태(shape)로 볼 수 있게 되면, 네 가지 아키텍처 패턴이 명확하게 읽힙니다.

프롬프트 점진적 축적 (Prompt Accretion): 계속해서 커지기만 하는 시스템 프롬프트

첫 번째 패턴은 점진적으로 축적되며 결코 가지치기(pruned)되지 않는 프롬프트입니다. 시스템 프롬프트가 800 토큰으로 시작합니다. 누군가 규칙을 추가하고, 그다음 도구 설명(tool description)을 추가하고, 보안 주의 사항을 추가하고, 그다음에는 아무도 이유를 기억하지 못하는 예외 케이스(edge case)를 추가합니다. 결국 모든 호출은 수천 토큰의 지침을 실어 나르게 되며, 어느 부분이 여전히 중요한지 아무도 모르게 됩니다.

4월 29일의 세션은 조용한 예시입니다. 728개의 메시지에 걸쳐 255개의 별도 캐시 쓰기(cache-write) 이벤트가 발생했으며, 이는 대략 세 번의 턴마다 한 번꼴로 쓰기가 발생한 것입니다. 이 세션은 전체적으로 여전히 55배의 읽기 대비 쓰기 비율(read-to-write ratio)을 유지했습니다. 집계된 비율은 워크플로우가 건강하다고 말합니다. 하지만 쓰기 분포는 프롬프트가 과정 내내 계속 변이(mutating)했음을 말해줍니다. 경제적 효율성과 아키텍처 드리프트(architectural drift)는 동일한 세션 내에 공존할 수 있습니다.

보편적 컨텍스트 블록 (Universal context blocks): 잘못된 작업에 부착된 동일한 번들

두 번째 패턴은 너무 광범위하게 부착된 재사용 가능한 컨텍스트 블록입니다. 하나의 커다란 "표준" 프롬프트 번들이 코딩 작업, 제목 생성, 분류, 한 줄 편집, 그리고 작은 판단 작업에까지 결과적으로 모두 사용됩니다.

긴 코딩 작업의 경우, 해당 컨텍스트 (context)가 제 역할을 다할 수도 있습니다. 하지만 아주 작은 유틸리티 작업의 경우에는 그렇지 않습니다. 중요한 질문은 캐시 (cache)가 이를 재사용하느냐가 아니라, 이 작업에 애초에 해당 컨텍스트를 제공했어야 했느냐 하는 것입니다.

서브 에이전트 발산 (Sub-agent divergence): 캐시 접두사 (cache prefix)를 파편화하는 하위 에이전트들

세 번째 패턴은 작업을 위임함에 따라 프롬프트 (prompt) 형태가 변하는 부모-자식 루프 (parent-child loop)입니다. 외부에서 보면 워크플로 (workflow)는 하나의 작업처럼 보입니다. 하지만 캐시 계층 (cache layer)에서는 여러 개의 분리된 프롬프트 제품군 (prompt families)으로 나타납니다. 부모는 하나의 접두사 (prefix)를 쓰고 읽습니다. 각 서브 에이전트 (sub-agent)는 자신만의 접두사를 씁니다. 세션에는 여전히 재사용성이 존재하지만, 계보 (lineage)는 파편화됩니다.

이 패턴은 캡처된 데이터가 부모-자식 구조를 유지할 때만 나타납니다. paper는 모든 노드 (node)에 parent_hash를 기록하며, 이를 통해 저는 3,697개의 메시지를 하나의 트리 (tree)로 읽을 수 있었습니다. 즉, 408개의 대화 루트 (conversation roots)와 그로부터 파생된 3,289개의 자식 메시지가 있었으며, 가장 깊은 단일 스레드 (thread)는 495개의 메시지까지 이어졌습니다. 이 트리 구조가 없다면, 모든 메시지는 고립된 캐시 이벤트 (cache event)로 보일 것이며 부모-자식 간의 발산 (divergence)은 보이지 않을 것입니다.

컨텍스트 덤프 (Context dumps): 재사용성이 낮은 대규모 캐시 쓰기

네 번째 패턴은 125%의 캐시 쓰기 프리미엄 (cache-write premium)을 지불하면서도 재사용은 거의 얻지 못하는 짧은 세션입니다. 도구를 열고, 한 번의 턴 (turn)에 대량의 컨텍스트를 쏟아붓고, 한 가지 일을 수행한 뒤, 노트북을 닫는 식입니다.

제 데이터 중 가장 심각한 사례는 4월 21일의 Opus 세션이었습니다. 14개의 메시지, 87k 토큰 (tokens) 캐시 쓰기, 156k 토큰 읽기, 즉 1.8배의 읽기 대비 쓰기 비율 (read-to-write ratio)을 기록했습니다. 비교를 위해 4월 29일 세션을 보면 55배를 기록했습니다. 자신이 쓴 양의 채 두 배도 되지 않는 양을 다시 읽는 세션은, 복리 효과 (compounding benefit)를 거의 얻지 못하면서 프리미엄 가격을 지불하고 있는 것입니다. 이는 개별적으로는 비용이 작아 보일 수 있지만, 팀 전체가 습관적으로 행할 경우 총합적으로는 큰 비용이 발생하는 워크플로 (workflow) 선택입니다.

이것이 실무에서 의미하는 바

이 네 가지 패턴은 단순한 진단이 아닙니다. 각 패턴은 구체적인 변화를 가리키고 있습니다.

만약 프롬프트가 점진적으로 누적되어 비대해지는 것을 발견한다면, 가지치기(prune)를 하세요. 캡처된 세션 중 가장 긴 시스템 프롬프트(system prompts)를 불러와 규칙 하나하나를 검토하십시오. 누구도 정당성을 입증할 수 없는 내용은 모두 제거해야 합니다. 프롬프트를 변경할 때마다 첫 번째 요청은 여전히 캐시 쓰기 프리미엄(cache-write premium) 비용을 지불해야 하므로, 더 작고 안정적인 접두사(prefix)를 유지하는 것이 비용 면에서 저렴하고 추론(reasoning)하기에도 더 쉽습니다.

만약 보편적인 컨텍스트 블록(universal context blocks)을 발견한다면, 작업의 형태(shape)에 따라 분리하세요. 아주 작은 유틸리티 작업이 코딩 에이전트(coding agent)의 전체 서문(preamble)을 상속받아서는 안 됩니다. 프레임워크는 "캐시가 얼마나 많은 컨텍스트를 흡수할 수 있는가"가 아니라, "이 호출이 성공하는 데 필요한 최소한의 컨텍스트는 무엇인가"가 되어야 합니다.

만약 하위 에이전트 간의 발산(sub-agent divergence)을 발견한다면, 루프 전반에 걸쳐 프롬프트를 정규화(normalize)하세요. 부모와 자식 에이전트가 모두 공유하는 하나의 안정적인 접두사(prefix)를 선택한 다음, 차이점들을 더 작은 꼬리(tail) 부분으로 추가하십시오. 이렇게 하면 트리(tree) 전체에서 캐시를 계속 사용할 수 있으며, 부모 에이전트가 자식 에이전트가 반환될 때마다 매번 컨텍스트를 다시 구축할 필요가 없습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0