소개
AI 모델은 애플리케이션이 호출할 때마다 일반적으로 새로운 응답을 생성합니다. 모델이 방금 처리한 요청과 완전히 동일한 요청이라도 이 작업에는 시간이 걸리고 모델 사용량이 발생합니다. 캐시는 일정 시간 동안 재사용할 수 있는 응답을 저장하므로, 동일한 요청을 다시 모델에 보내지 않고 처리할 수 있습니다.
캐싱은 재사용해도 안전할 때만 유용합니다. 공개된 고정 FAQ 질문은 모든 호출자에게 같은 답변을 제공해도 되므로 적합한 대상입니다. 반면 개인화된 지원 프롬프트는 적합하지 않습니다. 속도를 높이기 위해 서로 다른 고객을 하나의 공유 캐시 키로 묶어서는 안 됩니다. AI Gateway 의 기본 캐시 키에는 provider, endpoint, model, provider credential 및 전체 request body 가 포함되어 이 실습을 보호합니다. body 가 조금이라도 바뀌면 다른 항목으로 저장됩니다.
이 실습에서는 5 분의 캐시 수명을 가진 일회성 인증 gateway 하나를 만듭니다. 작은 공개 Workers AI 질문을 보내 캐시 MISS를 확인하고, 동일한 요청을 반복해 HIT임을 입증한 다음 질문을 변경해 다시 MISS가 발생하는지 확인합니다. 마지막으로 최신 응답이 필요할 때 기존 캐시 응답을 우회하고, gateway 로그에서 요청이 모델에 도달했는지 확인합니다.
이 과정을 직접 시작했다면 먼저 Connect LabEx to Your Cloudflare Account를 완료합니다. 이 실습에서는 LabEx VM terminal, Wrangler device authorization, learning-account 확인 및 명시적 account ID 사용 방법을 다룹니다. 또한 이 실습에서는 별도의 gateway 와 upstream authorization 경계를 재사용하므로 Route Inference Through a Gateway를 먼저 완료합니다.
이 실습에서는 Cloudflare 가 호스팅하는 @cf/meta/llama-3.3-70b-instruct-fp8-fast 모델과 Standard Workers AI billing 을 사용합니다. Workers Paid, Unified Billing 및 외부 provider account 는 필요하지 않습니다. 모델에 도달하는 요청은 3 개뿐이어야 하며, 동일한 요청을 반복할 때는 캐시에서 응답이 반환되어야 합니다. 공유 일일 Workers AI 할당량을 사용할 수 없으면 반복해서 재시도하지 말고 중단합니다.
설정 과정에서 Node.js 22.22.0 과 project-local Wrangler 4.132.0 을 /home/labex/project/ai-gateway-cache에 설치합니다. 독립적인 읽기 전용 평가를 준비하지만 Wrangler 를 인증하거나 cloud resource 를 생성하거나 모델 트래픽을 보내지는 않습니다. 실습이 끝나면 LabEx 가 임시 VM 을 삭제하지만, VM 삭제만으로는 cloud resource 를 제거할 수 없으므로 로그아웃하기 전에 gateway 와 token 을 직접 삭제합니다.
VM 인증 및 캐시 실험 이름 지정
이 단계에서는 새 VM 을 learning account 에 연결하고, 일회성 gateway 와 token 에 사용할 이름을 생성합니다.
캐시는 공유 인프라이므로 범위를 신중하게 정해야 합니다. 이 실습에서는 고유한 이름의 gateway 하나와 합성된 공개 질문만 사용합니다. 무작위 접미사를 붙이면 같은 learning account 의 다른 gateway 와 실험이 충돌하지 않습니다.
준비된 project 디렉터리로 이동하고, 고정된 CLI 버전을 확인한 다음 이 VM 을 인증합니다.
cd /home/labex/project/ai-gateway-cache
npx wrangler --version
npx wrangler login --device --browser=false --scopes account:read user:read ai:write
표시된 링크를 열고 코드를 입력한 다음, 사용할 learning account 를 인증합니다. 구조화된 identity 정보를 확인합니다.
npx wrangler whoami --json
Wrangler 4.132.0 과 loggedIn: true가 표시되어야 합니다. 아래의 YOUR_ACCOUNT_ID를 사용할 account 에 표시된 실제 32 자 ID 로 바꿉니다.
GATEWAY_ID="labex-c09-g03-$(openssl rand -hex 6)"
TOKEN_NAME="$GATEWAY_ID-token"
cat > .labex/state.json <<JSON
{
"accountId": "YOUR_ACCOUNT_ID",
"gatewayId": "$GATEWAY_ID",
"tokenName": "$TOKEN_NAME"
}
JSON
cat .labex/state.json
이러한 비밀이 아닌 식별자는 로컬 inventory 에 저장됩니다. 이후의 모든 조회, 확인 및 정리 작업이 이 실습의 resource 만 대상으로 삼도록 하기 위해서입니다.
짧은 캐시 수명을 가진 인증 Gateway 생성
이 단계에서는 gateway 를 만들고 캐시된 응답의 time to live, 즉 TTL 을 5 분으로 설정합니다. TTL 은 항목이 오래된 것으로 간주되어 모델에서 새로 가져오기 전까지 재사용할 수 있는 최대 시간입니다.
Cloudflare Dashboard 를 열고 AI → AI Gateway → Create gateway → Custom gateway를 선택합니다. 저장한 gatewayId를 gateway 이름으로 사용합니다. request logging 과 gateway authentication 은 켜 둡니다. Cache responses를 활성화하고 TTL 을 정확히 300초로 설정합니다. rate limits, spend limits 및 retries 는 끄고 Workers AI billing 은 Standard로 유지합니다.

생성한 후 breadcrumb 에서 고유한 gateway ID 를 확인합니다. 짧은 TTL 은 이 실습을 반복하기에는 충분하지만 예시 응답이 불필요하게 오래 남는 것은 방지합니다.
Create an AI Gateway authentication token을 선택합니다. 저장한 tokenName을 사용하고, 사용할 learning account 만 포함한 다음 정확히 다음 권한을 설정합니다.
- AI Gateway — Run: 인증된 gateway 에 진입하는 권한입니다.
- AI Gateway — Edit: 캐시 증거를 읽고 이 일회성 gateway 를 삭제하는 권한입니다.
Workers AI permission 은 추가하지 않습니다. Wrangler 가 별도의 단기 upstream credential 을 제공합니다. account 와 permission 을 확인한 후 token 을 만들고, 한 번만 표시되는 값을 출력하지 않은 상태로 저장합니다.
bash -c '
while :; do
read -ersp "Paste the AI Gateway token: " GATEWAY_TOKEN
printf "\n"
[ -n "$GATEWAY_TOKEN" ] && break
printf "Token cannot be empty; paste it again.\n" >&2
done
umask 077
printf "%s" "$GATEWAY_TOKEN" > .labex/gateway-token
unset GATEWAY_TOKEN
chmod 600 .labex/gateway-token
'
인증된 management API 를 통해 정확한 캐시 설정을 확인합니다.
ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
-H "Authorization: Bearer $GATEWAY_TOKEN" \
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s),g=b.result||{};console.log(JSON.stringify({success:b.success,id:g.id,collect_logs:g.collect_logs,authentication:g.authentication,cache_ttl:g.cache_ttl},null,2))})'
unset GATEWAY_TOKEN
저장한 ID, collect_logs: true, authentication: true 및 cache_ttl: 300이 표시되어야 합니다.
첫 번째 공개 FAQ 요청 보내기
이 단계에서는 모든 학습자가 재사용해도 안전한 작은 공개 질문을 보냅니다. 새 gateway 에는 이전 항목이 없으므로 첫 번째 조건을 충족하는 요청은 캐시 MISS가 되어야 합니다. miss 는 AI Gateway 가 요청을 Workers AI 로 전달한 후 성공한 응답을 저장했다는 뜻입니다.
기본 캐시 키에는 upstream credential 이 포함됩니다. 네 번의 요청이 하나의 제어된 키를 사용하도록 이 VM 의 현재 Wrangler credential 을 안전하게 저장합니다. 이 파일은 짧은 실습 동안만 사용하는 것으로, production secret 관리 방식이 아닙니다.
umask 077
npx wrangler auth token --json \
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))' \
> .labex/upstream-token
chmod 600 .labex/upstream-token
첫 번째 요청을 보내고 두 credential 을 출력하지 않은 채 response headers, body 및 HTTP status 를 저장합니다.
ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
METADATA='{"lab":"g03-cache","case":"public-faq","synthetic":true}'
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(cat .labex/upstream-token)
STATUS=$(curl --http1.1 -sS -D .labex/first-headers.txt \
-o .labex/first-response.json -w '%{http_code}' \
-H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
-H "Authorization: Bearer $UPSTREAM_TOKEN" \
-H "cf-aig-metadata: $METADATA" \
-H 'Content-Type: application/json' \
--data '{"prompt":"In one short sentence, what does an AI gateway do?","max_tokens":32}' \
"https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/first-status.txt
awk 'BEGIN{IGNORECASE=1} /^cf-aig-cache-status:/ {gsub("\r","",$2); print toupper($2)}' .labex/first-headers.txt \
| tail -1 | tee .labex/first-cache-status.txt
node -e 'const b=require("./.labex/first-response.json"); console.log(b.result?.response ?? b.result)'
HTTP 200, 캐시 상태 MISS 및 짧은 생성 응답이 표시되어야 합니다. request body 에는 고객 데이터가 없으므로 이 응답은 일시적으로 재사용해도 안전합니다.
동일한 요청을 반복해 캐시 적중 확인
이 단계에서는 동일한 provider, endpoint, model, credential 및 request body 를 사용해 요청을 정확히 반복합니다. 따라서 AI Gateway 는 이전 단계에서 만든 항목을 재사용할 수 있습니다. 캐시 HIT는 새로 모델을 생성하지 않고 gateway cache 에서 응답이 반환되었다는 뜻입니다.
캐시 저장은 비동기 방식이므로 첫 번째 응답이 성공한 뒤 몇 초 기다렸다가 반복합니다.
sleep 5
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(cat .labex/upstream-token)
METADATA='{"lab":"g03-cache","case":"public-faq","synthetic":true}'
STATUS=$(curl --http1.1 -sS -D .labex/repeat-headers.txt \
-o .labex/repeat-response.json -w '%{http_code}' \
-H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
-H "Authorization: Bearer $UPSTREAM_TOKEN" \
-H "cf-aig-metadata: $METADATA" \
-H 'Content-Type: application/json' \
--data '{"prompt":"In one short sentence, what does an AI gateway do?","max_tokens":32}' \
"https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/repeat-status.txt
awk 'BEGIN{IGNORECASE=1} /^cf-aig-cache-status:/ {gsub("\r","",$2); print toupper($2)}' .labex/repeat-headers.txt \
| tail -1 | tee .labex/repeat-cache-status.txt
cmp -s .labex/first-response.json .labex/repeat-response.json \
&& echo 'response bytes match the cached source'
HTTP 200과 HIT가 표시되어야 합니다. 두 응답의 byte 가 일치하는 것은 유용한 추가 확인이지만, HIT response header 와 Dashboard 의 캐시 로그가 확정적인 증거입니다. AI Gateway 의 캐시 저장은 비동기이며 휘발성이므로 두 요청을 동시에 보내지 않습니다. 순차적으로 반복했는데도 여전히 miss 이면 몇 초 기다린 후 이 블록을 그대로 한 번만 다시 실행합니다.
Dashboard 에서 gateway 의 Logs 보기를 엽니다. 두 public-faq 요청을 찾아 cache indicator, duration 및 token usage 를 비교합니다. 한 행에는 모델이 처리한 miss 가, 다른 행에는 캐시된 hit 가 표시되어야 합니다.

질문을 변경해 새로운 miss 확인
이 단계에서는 prompt 만 변경합니다. 전체 request body 가 기본 캐시 키에 포함되므로 새 질문에는 이전 응답이 반환되지 않아야 합니다.
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(cat .labex/upstream-token)
METADATA='{"lab":"g03-cache","case":"changed-question","synthetic":true}'
STATUS=$(curl --http1.1 -sS -D .labex/changed-headers.txt \
-o .labex/changed-response.json -w '%{http_code}' \
-H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
-H "Authorization: Bearer $UPSTREAM_TOKEN" \
-H "cf-aig-metadata: $METADATA" \
-H 'Content-Type: application/json' \
--data '{"prompt":"In one short sentence, name one benefit of an AI gateway.","max_tokens":32}' \
"https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/changed-status.txt
awk 'BEGIN{IGNORECASE=1} /^cf-aig-cache-status:/ {gsub("\r","",$2); print toupper($2)}' .labex/changed-headers.txt \
| tail -1 | tee .labex/changed-cache-status.txt
node -e 'const b=require("./.labex/changed-response.json"); console.log(b.result?.response ?? b.result)'
HTTP 200과 MISS가 표시되어야 합니다. 이러한 정확한 일치 방식은 의미적 유사성보다 의도적으로 더 엄격합니다. 서로 관련 있어 보이는 두 질문도 body 가 다르면 서로 다른 캐시 항목을 사용합니다.
개인화된 prompt 에 support-answer와 같은 하나의 공유 키를 사용하도록 기본 키를 바꾸지 않습니다. 사용자 지정 키는 해당 키로 묶인 모든 요청이 동일한 응답을 받을 권한이 있을 때만 안전합니다.
최신 응답이 필요할 때 캐시 우회
이 단계에서는 원래 질문으로 돌아가 캐시된 응답을 명시적으로 건너뜁니다. Bypass는 유효한 캐시 항목이 있어도“지금 provider 에 요청한다”는 뜻입니다. 애플리케이션이 특정 요청에 대해 최신 출력을 필요로 할 때 유용합니다.
cf-aig-skip-cache: true header 는 현재 요청에만 적용됩니다. 다른 호출자의 요청에 대한 gateway cache 를 비활성화하지 않습니다.
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(cat .labex/upstream-token)
METADATA='{"lab":"g03-cache","case":"fresh-bypass","synthetic":true}'
STATUS=$(curl --http1.1 -sS -D .labex/bypass-headers.txt \
-o .labex/bypass-response.json -w '%{http_code}' \
-H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
-H "Authorization: Bearer $UPSTREAM_TOKEN" \
-H "cf-aig-metadata: $METADATA" \
-H 'cf-aig-skip-cache: true' \
-H 'Content-Type: application/json' \
--data '{"prompt":"In one short sentence, what does an AI gateway do?","max_tokens":32}' \
"https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA
printf '%s\n' "$STATUS" | tee .labex/bypass-status.txt
awk 'BEGIN{IGNORECASE=1} /^cf-aig-cache-status:/ {gsub("\r","",$2); print toupper($2)}' .labex/bypass-headers.txt \
| tail -1 | tee .labex/bypass-cache-status.txt
node -e 'const b=require("./.labex/bypass-response.json"); console.log(b.result?.response ?? b.result)'
HTTP 200이 표시되고 HIT가 아니어야 합니다. 현재 gateway 응답에 따라 header 에 bypass 가 표시되거나 단순히 hit 가 아닌 상태로 남을 수 있습니다. 확정적인 확인 방법은 gateway 로그에서 fresh-bypass의 cached: false를 확인하는 것입니다.
Dashboard 에서 Logs로 돌아가 fresh-bypass 요청을 엽니다. 이 요청을 캐시된 public-faq 행과 비교합니다. 요청별 bypass 가 gateway 기본 설정을 덮어썼기 때문에 동일한 질문이 Workers AI 에 도달했습니다.

일회성 Gateway 삭제
이 단계에서는 management credential 로 gateway 가 실제로 삭제되었는지 확인할 수 있는 동안 gateway 를 제거합니다. 소유한 이 gateway 를 삭제하면 단기 cache namespace 와 로그도 함께 삭제됩니다.
ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -X DELETE \
-H "Authorization: Bearer $GATEWAY_TOKEN" \
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s);if(!b.success)process.exit(1);console.log("gateway deletion accepted")})'
unset GATEWAY_TOKEN
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
-H "Authorization: Bearer $GATEWAY_TOKEN" \
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways" \
> .labex/gateways-after-delete.json
unset GATEWAY_TOKEN
node -e 'const b=require("./.labex/gateways-after-delete.json"),id=process.argv[1],found=(b.result||[]).some(g=>g.id===id);console.log("gateway absent:",!found);if(found)process.exit(1)' "$GATEWAY_ID"
gateway absent: true가 표시되어야 합니다. 이 인증된 inventory 확인은 로그아웃이나 네트워크 오류로 페이지를 불러오지 못한 것과 실제 삭제를 구분합니다.
Token 삭제 및 로그아웃
이 단계에서는 남아 있는 cloud credential 을 폐기하고, 임시 token 사본을 모두 삭제한 다음 VM 연결을 해제합니다.
Cloudflare Dashboard 에서 My Profile → API Tokens를 엽니다. 저장한 정확한 tokenName을 찾아 Actions를 열고 Delete를 선택합니다. 확인 내용을 검토한 후 해당 token 만 삭제합니다. gateway 삭제가 이미 확인되었으므로 지금 폐기해도 안전합니다.
gateway 및 upstream token 파일을 삭제한 다음 별도로 인증된 Wrangler 세션을 종료합니다.
shred -u .labex/gateway-token .labex/upstream-token
npx wrangler logout
npx wrangler whoami --json || true
test ! -e .labex/gateway-token -a ! -e .labex/upstream-token \
&& echo "local token files removed"
loggedIn: false와 local token files removed가 표시되어야 합니다. Dashboard session 은 별개이므로 로그인 상태가 유지됩니다. 실습이 끝나면 LabEx 가 이 임시 VM 을 저장하지 않고 삭제합니다.
요약
안전한 공개 질문 하나에 대해 짧은 AI Gateway response cache 를 설정했습니다. 첫 번째 요청은 MISS가 되었고, 동일한 요청을 반복하자 HIT가 되었으며, 입력을 변경하자 별도의 캐시 항목이 생성되었습니다. 그런 다음 최신 응답이 필요할 때 요청별 bypass 를 사용하고, 로그에서 캐시된 사본이 아니라 모델이 요청을 처리했는지 확인했습니다.
다음 실습에서는 트래픽 제어를 추가합니다. 요청이 들어오는 빈도를 제한하는 것과 gateway 가 사용할 수 있는 모델 사용량을 제한하는 것의 차이를 배우면서, 테스트 양과 비용은 의도적으로 작게 유지합니다.



