GPT-4o가 80% 빨라졌다고 생각했지만, 실제로는 프롬프트 캐싱 때문이었다
요약
LLM 벤치마크에서 성능 향상을 과대 해석하는 경향에 대한 경고입니다. 실제 빠른 속도나 낮은 비용은 모델 개선이 아닌, 프롬프트 접두사(prefix)가 일치하여 캐시가 작동했기 때문일 가능성이 높습니다. 따라서 정확한 분석을 위해서는 `cached_tokens`와 같은 사용량 필드를 반드시 로깅해야 합니다.
핵심 포인트
- LLM 벤치마크의 속도 개선은 모델 최적화보다 프롬프트 캐싱 때문인 경우가 많다.
- 에이전트 워크플로우는 기본적으로 캐시를 유발하도록 설계되어 있어, 비용과 지연 시간에 영향을 준다.
- 정확한 분석을 위해 `usage.prompt_tokens_details.cached_tokens`와 같은 사용량 필드를 로깅해야 한다.
놀라운 성능을 보여주는 벤치마크에 속았습니다.
동일한 에이전트 워크플로우. 동일한 모델. 동일한 코드 경로를 사용했습니다.
두 번째 실행은 극적으로 빨랐습니다.
저의 첫 반응은 우리 대부분의 엔지니어들이 느끼는 어리석은 작은 도파민 분출과 같았습니다: '좋아, 무언가를 최적화했어.'
하지만 그렇지 않았습니다.
프롬프트 접두사(prompt prefix)가 일치했고, 캐시가 작동했으며, 저의 '모델 개선'은 대부분 재사용에 불과했습니다.
이것은 나중에 생각하면 당연하게 들립니다. 하지만 많은 LLM 벤치마크 게시물들이 여전히 이 점을 놓칩니다. 사람들은 동일한 에이전트를 두 번 실행하고, 지연 시간(latency)이 떨어지면, 갑자기 GPT-4o나 Claude 또는 Gemini가 더 빠르거나, 저렴하거나, 안정적이라고 생각합니다.
대부분의 경우 벤치마크는 그저 '워밍업'된 것일 뿐입니다.
만약 n8n, Make, Zapier, OpenClaw 또는 자체 Python 워커에서 에이전트를 구축한다면, 요청의 많은 부분이 호출 간에 동일하게 유지되기 때문에 이 점을 놓치기가 훨씬 쉽습니다.
벤치마크가 좋아 보였던 것은 사용량을 확인하기 전까지였다
에이전트 워크로드는 기본적으로 프롬프트 캐싱을 유발하도록 설계되어 있습니다.
일반적인 요청에는 다음 내용들이 포함됩니다:
- 대규모 시스템 프롬프트(system prompt)
- 툴 스키마(tool schemas)
- 예시(examples)
- 대화 기록(conversation history)
- 플래너/크리틱 프롬프트(planner / critic prompts)
- 구조화된 출력 스키마(structured output schemas)
사용자의 최신 메시지는 종종 요청에서 가장 작은 부분입니다.
비용이 많이 드는 부분은 '골격(scaffolding)'입니다.
따라서 두 번째 실행이 훨씬 빨라진다고 해서, 모델이 개선되었다고 자동적으로 의미하지 않습니다. 이는 제공업체가 크고 안정적인 접두사 부분을 재사용했다는 것을 의미할 때가 많습니다.
프로덕션 환경에서는 이것이 좋습니다.
하지만 벤치마킹을 할 때는 완전히 거짓말을 할 수 있습니다.
의미 있는 숫자를 원한다면 로깅해야 할 것들
캐시 관련 사용량 필드를 로깅하지 않는다면, 추측하는 것입니다.
중요한 필드는 다음과 같습니다:
| 제공업체 | 확인할 내용 |
|---|---|
| OpenAI 프롬프트 캐싱 | usage.prompt_tokens_details.cached_tokens |
| ... | |
| OpenAI가 가장 쉬운 예시입니다. |
프롬프트 캐싱은 지원되는 모델에서 기본적으로 활성화됩니다. 1,024 토큰을 초과하는 프롬프트에 대해 작동하며, 응답에는 캐시에서 제공된 프롬프트 토큰 수가 표시됩니다.
예시 응답 형태:
{
만약 `cached_tokens`가 첫 번째 실행에서는 `0`에서 두 번째 실행에서는 `1920`으로 증가했다면, 당신은 마법 같은 최적화를 발견한 것이 아닙니다.
당신이 발견한 것은 접두사(prefix)가 일치한다는 사실입니다.
그것이 이야기의 전부입니다.
## 두 번째 실행도 저렴해 보이는 이유
캐싱은 지연 시간(latency)과 비용 모두에 영향을 미치기 때문입니다.
OpenAI는 이 점을 명확히 했습니다. 지원되는 모델에서 캐시된 입력(cached input)은 캐시되지 않은 입력(uncached input)보다 저렴합니다.
Google 역시 Vertex AI에서 발생하는 암묵적인 캐시 히트(implicit cache hits)에 대해서도 큰 할인을 받을 수 있다고 말합니다.
따라서 누군가 다음과 같이 말한다면:
> Gemini 2.5 Pro의 비용이 우리 파이프라인에서 훨씬 저렴해졌다.
제가 가장 먼저 던지는 질문은 다음이 아닙니다:
> 모델에 무엇이 바뀌었나요?
오히려 이것입니다:
> `usage.total_cached_tokens`를 기록했나요?
만약 답이 '아니요'라면, 가격 책정 이야기는 불완전합니다.
## 간단한 Python 예시: 캐시 필드를 로깅하거나 벤치마크를 신뢰하지 마세요
다음은 최소한의 OpenAI 호환 예제입니다.
```python
from openai import OpenAI
import time
import json
...
만약 두 번째 호출이 더 빠르고 cached_tokens가 급증한다면, 그 결과는 웜 캐시(warm-cache) 동작입니다.
순수한 모델 속도가 아닙니다.
curl을 사용한다면, 같은 규칙이 적용됩니다
이를 포착하기 위해 전체 벤치마크 하네스(benchmark harness)가 필요하지 않습니다.
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
...
이것을 두 번 실행해 보세요.
캐시된 토큰 필드가 나타나거나 증가하는지 확인하세요.
단 한 단계만으로도 수많은 가짜 벤치마크 자신감에서 벗어날 수 있습니다.
Anthropic과 Gemini 역시 똑같이 속일 수 있습니다
이것은 OpenAI만의 문제가 아닙니다.
Anthropic
Anthropic은 cache_control을 통해 프롬프트 캐싱을 지원합니다. 캐시 수명(Cache lifetime)은 보통 5분 정도입니다.
from anthropic import Anthropic
client = Anthropic()
...
이는 후속 요청이 캐시 가능한 접두사(cacheable prefix)가 변경되지 않았다면 훨씬 빠르게 보일 수 있다는 의미입니다.
또한 짜증나는 타이밍의 엣지 케이스(timing edge case)도 있습니다. 스트리밍 응답이 몇 분 걸린다면, 실수로 캐시 창(cache window)을 벗어나서 벤치마크가 무작위적이라고 생각할 수 있습니다.
무작위적인 것이 아닙니다. 당신의 타이밍 측정만 부실한 것입니다.
Gemini
Gemini 2.5+ 모델 역시 암시적인 캐싱 동작(implicit caching behavior)을 가집니다.
따라서 두 번째 호출이 더 빠를 수는 있습니다.
하지만 이것이 Gemini가 사용자의 워크플로우를 '학습했다'는 의미는 아닙니다.
Vertex AI를 사용하고 있다면, 캐시된 토큰 필드(cached token fields)를 검사해 보세요. 만약 이를 로깅하지 않는다면, 벤치마크가 변경된 주요 이유를 놓치고 있는 것입니다.
OpenRouter가 실제보다 벤치마크를 더 깨끗하게 보이게 할 수 있다
이것은 OpenRouter를 통해 벤치마킹하는 경우 중요합니다.
OpenRouter는 캐시된 요청(cached request) 이후에 '스티키 라우팅(sticky routing)'을 사용하기 때문에, 동일한 모델과 대화에 대한 후속 요청들이 같은 제공업체 측 캐시(provider-side cache)를 계속 이용할 수 있습니다.
이는 프로덕션 환경에서는 유용합니다.
하지만 엉성한 벤치마킹에는 좋지 않습니다. 왜냐하면 라우터가 벤치마크가 '따뜻하게' 유지되도록 도와주기 때문입니다.
예시 페이로드:
{
"model": "openai/gpt-4o",
"messages": [
...
만약 후속 호출에서 성능 향상이 나타난다면, 모델 자체가 개선된 것인지 아니면 OpenRouter가 계속 같은 따뜻한 제공업체로 보내준 것인지를 물어봐야 합니다.
이것들은 매우 다른 설명입니다.
n8n이 요청이 모델에 도달하기도 전에 승리를 조작할 수 있다
이 부분이 사람들이 가장 듣기 싫어하는 내용입니다.
때로는 모델 자체가 빨라지지 않았습니다.
때로는 사용자의 워크플로우가 더 짧아졌을 뿐입니다.
n8n에서는 '중복 제거(Remove Duplicates)'와 같은 노드들이 여러 실행에 걸쳐 실제로 LLM에 도달하는 항목의 수를 줄일 수 있습니다.
따라서 벤치마크 이야기는 다음과 같이 전개됩니다:
- n8n이 중복된 항목을 필터링했습니다.
- GPT-4o나 Claude로 가는 요청 수가 줄었습니다.
- 후속 실행들이 더 빠르고 저렴해 보였습니다.
- 모두가 모델의 공로로 돌렸습니다.
이것은 모델 개선이 아닙니다.
이것은 상류(upstream)에서 중복을 제거한 것입니다.
만약 재시도(retries), 필터, 또는 배치 처리 동작(batching behavior)이 실행 간에 변경되는 경우, Make나 Zapier, 또는 사용자 지정 큐에서도 같은 일이 발생할 수 있습니다.
나의 현재 벤치마크 규칙: 콜드와 웜을 분리하거나 아예 발표하지 않는다
이것이 가장 간단한 해결책입니다.
만약 사용자의 벤치마크가 콜드(cold) 실행과 웜(warm) 실행을 분리하지 못한다면, 그것은 미완성입니다.
제가 현재 사용하는 체크리스트는 다음과 같습니다.
1. 모든 요청에 대해 캐시 메트릭을 로깅하라
최소한으로:
- OpenAI:
usage.prompt_tokens_details.cached_tokens - Gemini:
usage.total_cached_tokens또는cachedContentTokenCount - Anthropic: 응답 사용량 객체(response usage object) 내의 캐시 사용 필드
- OpenRouter: 라우팅/세션 동작
2. 완전히 렌더링된 프롬프트 해싱 (Hash the fully rendered prompt)
단순히 사용자 메시지만 버전 관리하지 마십시오.
템플릿화(templating)를 포함하여 다음 항목들을 모두 포함한 최종 요청 본문(final request body)을 해시해야 합니다:
- 시스템 프롬프트 (system prompt)
- 개발자 프롬프트 (developer prompt)
- 도구 정의 (tool definitions)
- 도구 순서 (tool order)
- 예제 (examples)
- 대화 기록 (conversation history)
- 응답 스키마 (response schema)
이 중 어느 하나라도 변경되면 캐시 동작(cache behavior)도 변경됩니다.
3. 콜드 및 웜 상태를 분리하여 벤치마크 수행 (Benchmark cold and warm separately)
1가지 세트는 고유한 접두사(unique prefixes)로 실행하고,
다른 한 가지 세트는 안정적인 접두사(stable prefixes)로 실행하십시오.
솔직하게 라벨을 지정해야 합니다:
- 콜드 스타트 지연 시간 (cold-start latency)
- 웜 캐시 지연 시간 (warm-cache latency)
이 두 가지를 평균 내어 하나의 허울 좋은 수치(vanity number)로 만들지 마십시오.
4. 타이밍 창(timing window) 제어하기
캐시 TTL(Time To Live)이 중요합니다.
벤치마크가 캐시 만료 기간을 넘나들게 되면, 측정 수치 역시 불안정해집니다.
5. 워크플로우가 실제 모델 호출을 줄이지 않았는지 확인 (Verify the workflow didn’t reduce actual model calls)
비용이나 지연 시간 측면에서 이점을 자랑하기 전에 다음 사항들을 반드시 확인하십시오:
- 중복 제거 노드(dedupe node)가 항목을 제거하지 않았는지
- 재시도 로직(retry logic)이 요청 횟수를 변경하지 않았는지
- 배치 처리 계층(batching layer)이 호출 볼륨을 변경하지 않았는지
- 라우터의 고정성(router stickiness)이 실제 경로를 숨기지 않았는지
실용적인 벤치마크 하네스 패턴 (A practical benchmark harness pattern)
이는 에이전트 팀에게 추천하는 형태입니다.
import hashlib
import json
import time
...
이것이 모든 벤치마킹 문제를 해결해 주지는 못할 것입니다.
하지만 따뜻한 캐시 히트(warm cache hit)를 모델의 혁신적인 돌파구로 오인하는 것을 막아줄 수는 있습니다.
짜증 나는 진실: 프롬프트 캐싱은 좋지만, 가짜 벤치마크 이야기는 아니다 (The annoying truth: prompt caching is good, fake benchmark stories are not)
프롬프트 캐싱(Prompt caching)은 속임수가 아닙니다.
이는 실제 에이전트 워크로드에 가장 좋은 기능 중 하나입니다.
만약 장기간 운영되는 자동화 작업(long-lived automations), 코딩 에이전트, 지원 봇 또는 다단계 워크플로우를 실행한다면, 큰 안정적인 접두사(big stable prefixes)가 재사용되기를 절대적으로 원합니다.
그것은 실제 프로덕션에서의 이점입니다.
실수하는 부분은 모델 품질, 순수한 속도, 또는 제공업체 가격을 측정했다고 주장하면서, 실제로 측정한 것은 캐시 친화성(cache friendliness)이었다는 점입니다.
이들은 서로 다른 것입니다.
이것을 알아차리면, 많은 벤치마크 게시물이 수상할 정도로 마법처럼 보이기 시작합니다.
- 두 번째 실행은 항상 더 빠르다
- 거대 에이전트가 세 번째 턴 이후에 “더 똑똑해진다”
- Claude가 다중 턴 평가기에서 갑자기 더 저렴해진다
- Gemini가 몇 번의 호출 후에 “안정화된다”
그럴 수도 있습니다.
하지만 보통 지루한 답변이 승리합니다.
프리픽스(prefix)가 일치했다.
라우터(router)는 계속 붙어 있었다.
워크플로우가 중복을 제거했다.
이것이 에이전트를 구축하는 팀에게 더 중요한 이유
심각한 자동화를 구축하고 있다면, 벤치마크 극장이 아니라 예측 가능한 동작이 필요합니다.
이것이 제가 Standard Compute의 방식에 매력을 느끼는 한 가지 이유입니다.
Standard Compute는 OpenAI와 호환되는 API를 통해 월별 고정 요금으로 무제한 AI 컴퓨팅을 제공합니다. 따라서 n8n, Make, Zapier, OpenClaw 또는 사용자 지정 워커에서 에이전트를 실행하더라도, 토큰당 비용에 대한 불안감 없이 동일한 SDK 패턴을 유지할 수 있습니다.
그것이 정직한 벤치마킹의 필요성을 없애는 것은 아닙니다.
단지 반복적인 에이전트 호출로 인한 모든 토큰 급증에 집착하는 대신, 실제 워크플로우 성능을 최적화할 수 있다는 의미입니다.
많은 장문 컨텍스트(long-context), 다단계 자동화를 실행하는 팀에게는 그 트레이드오프가 매우 합리적입니다.
핵심 요약
캐시 필드를 확인하지 않고 반복적인 LLM 호출을 벤치마크한다면, 당신의 수치는 아마도 거짓말하고 있을 것입니다.
사용량 필드를 기록하세요.
콜드(cold)와 웜(warm)을 분리하세요.
전체 프롬프트를 해시하세요.
워크플로우 계층을 확인하세요.
그런 다음 그 수치를 공개하세요.
그 외의 것은 단지 벤치마크 팬픽션일 뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기