컨텍스트 캐싱(Context caching)
컨텍스트 캐싱(Context caching)
일반적인 AI 워크플로에서는 같은 입력 토큰을 모델에 반복해서 전달할 수 있어요. Gemini API는 두 가지 캐싱 메커니즘을 제공해요:
- 암시적 캐싱(Implicit caching, Gemini 2.5 이상 모델에서 자동 활성화, 비용 절감 보장 없음)
- 명시적 캐싱(Explicit caching, 대부분의 모델에서 수동 활성화 가능, 비용 절감 보장)
명시적 캐싱은 비용 절감을 보장하고 싶지만 약간의 추가 개발 작업이 필요한 경우 유용해요.
출처: 원문
본문
암시적 캐싱(Implicit caching)
암시적 캐싱은 모든 Gemini 2.5 이상 모델에서 기본적으로 활성화돼요. 요청이 캐시에 적중하면 비용 절감 효과가 자동으로 전달돼요. 이를 활성화하기 위해 해야 할 일은 없어요. 컨텍스트 캐싱의 최소 입력 토큰 수는 각 모델에 대해 다음 표에 나열돼 있어요:
| 모델 | 최소 토큰 한도 |
|---|---|
| Gemini 3.8 Flash | 4,096 |
| Gemini 3.7 Flash | 4,096 |
| Gemini 3.6 Flash | 4,096 |
| Gemini 3.5 Flash | 4,096 |
| Gemini 3.1 Pro Preview | 4,096 |
| Gemini 2.5 Flash | 2,048 |
| Gemini 2.5 Pro | 2,048 |
암시적 캐시 적중 가능성을 높이려면:
- 프롬프트 앞부분에 크고 공통된 콘텐츠를 배치해 보세요.
- 짧은 시간 안에 비슷한 프리픽스를 가진 요청을 보내 보세요.
응답 객체의 usage_metadata 필드에서 캐시 적중 토큰 수를 확인할 수 있어요.
명시적 캐싱(Explicit caching)
Beta: 명시적 컨텍스트 캐싱은 현재 Beta 상태예요. 엔드포인트와 SDK 메서드는 v1beta에서 사용할 수 있어요.
Gemini API의 명시적 캐싱 기능을 사용하면 일부 콘텐츠를 모델에 한 번 전달하고, 입력 토큰을 캐시한 다음, 이후 요청에서 캐시된 토큰을 참조할 수 있어요. 일정 볼륨 이상에서는 캐시된 토큰을 사용하는 것이 같은 토큰 코퍼스를 반복해서 전달하는 것보다 저렴해요.
토큰 세트를 캐시할 때 캐시가 자동으로 삭제되기 전에 얼마 동안 유지할지 정할 수 있어요. 이 캐시 지속 시간을 time to live(TTL)라고 해요. 설정하지 않으면 TTL 기본값은 1시간이에요. 캐싱 비용은 입력 토큰 크기와 토큰을 보관할 기간에 따라 달라져요.
이 섹션은 Get started 가이드에 표시된 대로 Gemini SDK를 설치하고(또는 curl 설치) API 키를 구성했다고 가정해요.
캐시를 사용한 콘텐츠 생성
Python
다음 예시는 캐시된 시스템 지침과 비디오 파일을 사용해 콘텐츠를 생성하는 방법을 보여줘요.
비디오(Videos)
import os
import pathlib
import requests
import time
from google import genai
from google.genai import types
client = genai.Client()
# Download a test video file and save it locally
url = 'https://storage.googleapis.com/generativeai-downloads/data/SherlockJr._10min.mp4'
path_to_video_file = pathlib.Path('SherlockJr._10min.mp4')
if not path_to_video_file.exists():
path_to_video_file.write_bytes(requests.get(url).content)
# Upload the video using the Files API
video_file = client.files.upload(file=path_to_video_file)
# Wait for the file to finish processing
while video_file.state.name == 'PROCESSING':
time.sleep(2.5)
video_file = client.files.get(name=video_file.name)
print(f'Video processing complete: {video_file.uri}')
model='models/gemini-3.8-flash'
# Create a cache with a 5 minute TTL (300 seconds)
cache = client.caches.create(
model=model,
config=types.CreateCachedContentConfig(
display_name='sherlock jr movie', # used to identify the cache
system_instruction=(
'You are an expert video analyzer, and your job is to answer '
'the user\'s query based on the video file you have access to.'
),
contents=[video_file],
ttl="300s",
)
)
response = client.models.generate_content(
model = model,
contents= (
'Introduce different characters in the movie by describing '
'their personality, looks, and names. Also list the timestamps '
'they were introduced for the first time.'),
config=types.GenerateContentConfig(cached_content=cache.name)
)
print(response.usage_metadata)
print(response.text)
from google import genai
from google.genai import types
import io
import httpx
client = genai.Client()
long_context_pdf_path = "https://sma.nasa.gov/SignificantIncidents/assets/a11_missionreport.pdf"
# Retrieve and upload the PDF using the File API
doc_io = io.BytesIO(httpx.get(long_context_pdf_path).content)
document = client.files.upload(
file=doc_io,
config=dict(mime_type='application/pdf')
)
model_name = "gemini-3.8-flash"
system_instruction = "You are an expert analyzing transcripts."
# Create a cached content object
cache = client.caches.create(
model=model_name,
config=types.CreateCachedContentConfig(
system_instruction=system_instruction,
contents=[document],
)
)
print(f'{cache=}')
response = client.models.generate_content(
model=model_name,
contents="Please summarize this transcript",
config=types.GenerateContentConfig(
cached_content=cache.name
)
)
print(f'{response.usage_metadata=}')
print('\n\n', response.text)
JavaScript
다음 예시는 캐시된 시스템 지침과 텍스트 파일을 사용해 콘텐츠를 생성하는 방법을 보여줘요.
import {
GoogleGenAI,
createUserContent,
createPartFromUri,
} from "@google/genai";
const ai = new GoogleGenAI({ apiKey: "YOUR_API_KEY" });
async function main() {
const doc = await ai.files.upload({
file: "path/to/file.txt",
config: { mimeType: "text/plain" },
});
console.log("Uploaded file name:", doc.name);
const modelName = "gemini-3.8-flash";
const cache = await ai.caches.create({
model: modelName,
config: {
contents: createUserContent(createPartFromUri(doc.uri, doc.mimeType)),
systemInstruction: "You are an expert analyzing transcripts.",
},
});
console.log("Cache created:", cache);
const response = await ai.models.generateContent({
model: modelName,
contents: "Please summarize this transcript",
config: { cachedContent: cache.name },
});
console.log("Response text:", response.text);
}
await main();
Go
다음 예시는 캐시를 사용해 콘텐츠를 생성하는 방법을 보여줘요.
package main
import (
"context"
"fmt"
"log"
"google.golang.org/genai"
)
func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: "YOUR_API_KEY"
Backend: genai.BackendGeminiAPI,
})
if err != nil {
log.Fatal(err)
}
modelName := "gemini-3.8-flash"
document, err := client.Files.UploadFromPath(
ctx,
"media/a11.txt",
&genai.UploadFileConfig{
MIMEType: "text/plain",
},
)
if err != nil {
log.Fatal(err)
}
parts := []*genai.Part{
genai.NewPartFromURI(document.URI, document.MIMEType),
}
contents := []*genai.Content{
genai.NewContentFromParts(parts, genai.RoleUser),
}
cache, err := client.Caches.Create(ctx, modelName, &genai.CreateCachedContentConfig{
Contents: contents,
SystemInstruction: genai.NewContentFromText(
"You are an expert analyzing transcripts.", genai.RoleUser,
),
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Cache created:")
fmt.Println(cache)
// Use the cache for generating content.
response, err := client.Models.GenerateContent(
ctx,
modelName,
genai.Text("Please summarize this transcript"),
&genai.GenerateContentConfig{
CachedContent: cache.Name,
},
)
if err != nil {
log.Fatal(err)
}
printResponse(response) // helper for printing response parts
}
REST
다음 예시는 캐시를 만들고 이를 사용해 콘텐츠를 생성하는 방법을 보여줘요.
비디오(Videos)
wget https://storage.googleapis.com/generativeai-downloads/data/a11.txt
echo '{
"model": "models/gemini-3.8-flash",
"contents":[
{
"parts":[
{
"inline_data": {
"mime_type":"text/plain",
"data": "'$(base64 $B64FLAGS a11.txt)'"
}
}
],
"role": "user"
}
],
"systemInstruction": {
"parts": [
{
"text": "You are an expert at analyzing transcripts."
}
]
},
"ttl": "300s"
}' > request.json
curl -X POST "https://generativelanguage.googleapis.com/v1beta/cachedContents?key=$GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d @request.json \
> cache.json
CACHE_NAME=$(cat cache.json | grep '"name":' | cut -d '"' -f 4 | head -n 1)
curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent?key=$GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"contents": [
{
"parts":[{
"text": "Please summarize this transcript"
}],
"role": "user"
},
],
"cachedContent": "'$CACHE_NAME'"
}'
DOC_URL="https://sma.nasa.gov/SignificantIncidents/assets/a11_missionreport.pdf"
DISPLAY_NAME="A11_Mission_Report"
SYSTEM_INSTRUCTION="You are an expert at analyzing transcripts."
PROMPT="Please summarize this transcript"
MODEL="models/gemini-3.8-flash"
TTL="300s"
# Download the PDF
wget -O "${DISPLAY_NAME}.pdf" "${DOC_URL}"
MIME_TYPE=$(file -b --mime-type "${DISPLAY_NAME}.pdf")
NUM_BYTES=$(wc -c < "${DISPLAY_NAME}.pdf")
echo "MIME_TYPE: ${MIME_TYPE}"
echo "NUM_BYTES: ${NUM_BYTES}"
tmp_header_file=upload-header.tmp
# Initial resumable request defining metadata.
# The upload url is in the response headers dump them to a file.
curl "${BASE_URL}/upload/v1beta/files?key=${GOOGLE_API_KEY}" \
-D upload-header.tmp \
-H "X-Goog-Upload-Protocol: resumable" \
-H "X-Goog-Upload-Command: start" \
-H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \
-H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \
-H "Content-Type: application/json" \
-d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null
upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file}"
# Upload the actual bytes.
curl "${upload_url}" \
-H "Content-Length: ${NUM_BYTES}" \
-H "X-Goog-Upload-Offset: 0" \
-H "X-Goog-Upload-Command: upload, finalize" \
--data-binary "@${DISPLAY_NAME}.pdf" 2> /dev/null > file_info.json
file_uri=$(jq ".file.uri" file_info.json)
echo "file_uri: ${file_uri}"
# Clean up the downloaded PDF
rm "${DISPLAY_NAME}.pdf"
# Create the cached content request
echo '{
"model": "'$MODEL'",
"contents":[
{
"parts":[
{"file_data": {"mime_type": "'$MIME_TYPE'", "file_uri": '$file_uri'}}
],
"role": "user"
}
],
"system_instruction": {
"parts": [
{
"text": "'$SYSTEM_INSTRUCTION'"
}
],
"role": "system"
},
"ttl": "'$TTL'"
}' > request.json
# Send the cached content request
curl -X POST "${BASE_URL}/v1beta/cachedContents?key=$GOOGLE_API_KEY" \
-H 'Content-Type: application/json' \
-d @request.json \
> cache.json
CACHE_NAME=$(cat cache.json | grep '"name":' | cut -d '"' -f 4 | head -n 1)
echo "CACHE_NAME: ${CACHE_NAME}"
# Send the generateContent request using the cached content
curl -X POST "${BASE_URL}/${MODEL}:generateContent?key=$GOOGLE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"contents": [
{
"parts":[{
"text": "'$PROMPT'"
}],
"role": "user"
}
],
"cachedContent": "'$CACHE_NAME'"
}' > response.json
cat response.json
echo jq ".candidates[].content.parts[].text" response.json
캐시 나열(List caches)
캐시된 콘텐츠를 검색하거나 보는 것은 불가능하지만, 캐시 메타데이터(name, model, display_name, usage_metadata, create_time, update_time, expire_time)는 가져올 수 있어요.
Python
모든 업로드된 캐시의 메타데이터를 나열하려면 CachedContent.list()를 사용해요:
for cache in client.caches.list():
print(cache)
하나의 캐시 객체의 메타데이터를 가져오려면 이름을 알고 있을 때 get을 사용해요:
client.caches.get(name=name)
JavaScript
모든 업로드된 캐시의 메타데이터를 나열하려면 GoogleGenAI.caches.list()를 사용해요:
console.log("My caches:");
const pager = await ai.caches.list({ config: { pageSize: 10 } });
let page = pager.page;
while (true) {
for (const c of page) {
console.log(" ", c.name);
}
if (!pager.hasNextPage()) break;
page = await pager.nextPage();
}
Go
다음 예시는 모든 캐시를 나열해요.
caches, err := client.Caches.All(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("Listing all caches:")
for _, item := range caches {
fmt.Println(" ", item.Name)
}
다음 예시는 페이지 크기 2로 캐시를 나열해요.
page, err := client.Caches.List(ctx, &genai.ListCachedContentsConfig{PageSize: 2})
if err != nil {
log.Fatal(err)
}
pageIndex := 1
for {
fmt.Printf("Listing caches (page %d):\n", pageIndex)
for _, item := range page.Items {
fmt.Println(" ", item.Name)
}
if page.NextPageToken == "" {
break
}
page, err = page.Next(ctx)
if err == genai.ErrPageDone {
break
} else if err != nil {
return err
}
pageIndex++
}
REST
curl "https://generativelanguage.googleapis.com/v1beta/cachedContents?key=$GEMINI_API_KEY"
캐시 업데이트(Update a cache)
캐시에 새 ttl 또는 expire_time을 설정할 수 있어요. 캐시의 다른 것은 변경할 수 없어요.
Python
다음 예시는 client.caches.update()로 캐시의 ttl을 업데이트하는 방법을 보여줘요.
from google import genai
from google.genai import types
client.caches.update(
name = cache.name,
config = types.UpdateCachedContentConfig(
ttl='300s'
)
)
만료 시간을 설정하려면 datetime 객체 또는 ISO 형식의 datetime 문자열(dt.isoformat() — 예: 2025-01-27T16:02:36.473528+00:00)을 받아요. 시간에는 반드시 시간대가 포함되어야 해요(datetime.utcnow()는 시간대를 붙이지 않고, datetime.now(datetime.timezone.utc)는 시간대를 붙여요).
from google import genai
from google.genai import types
import datetime
# You must use a time zone-aware time.
in10min = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=10)
client.caches.update(
name = cache.name,
config = types.UpdateCachedContentConfig(
expire_time=in10min
)
)
JavaScript
다음 예시는 GoogleGenAI.caches.update()로 캐시의 ttl을 업데이트하는 방법을 보여줘요.
const ttl = `${2 * 3600}s`; // 2 hours in seconds
const updatedCache = await ai.caches.update({
name: cache.name,
config: { ttl },
});
console.log("After update (TTL):", updatedCache);
Go
다음 예시는 캐시의 TTL을 업데이트하는 방법을 보여줘요.
// Update the TTL (2 hours).
cache, err = client.Caches.Update(ctx, cache.Name, &genai.UpdateCachedContentConfig{
TTL: 7200 * time.Second,
})
if err != nil {
log.Fatal(err)
}
fmt.Println("After update:")
fmt.Println(cache)
REST
다음 예시는 캐시의 ttl을 업데이트하는 방법을 보여줘요.
curl -X PATCH "https://generativelanguage.googleapis.com/v1beta/$CACHE_NAME?key=$GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"ttl": "600s"}'
캐시 삭제(Delete a cache)
캐싱 서비스는 캐시에서 콘텐츠를 수동으로 제거하기 위한 삭제 작업을 제공해요. 다음 예시는 캐시를 삭제하는 방법을 보여줘요:
Python
client.caches.delete(cache.name)
JavaScript
await ai.caches.delete({ name: cache.name });
Go
_, err = client.Caches.Delete(ctx, cache.Name, &genai.DeleteCachedContentConfig{})
if err != nil {
log.Fatal(err)
}
fmt.Println("Cache deleted:", cache.Name)
REST
curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/$CACHE_NAME?key=$GEMINI_API_KEY"
OpenAI 라이브러리로 명시적 캐싱
OpenAI 라이브러리를 사용한다면 extra_body의 cached_content 속성으로 명시적 캐싱을 활성화할 수 있어요.
명시적 캐싱을 사용해야 할 때
컨텍스트 캐싱은 상당한 초기 컨텍스트가 더 짧은 요청들에 의해 반복적으로 참조되는 시나리오에 특히 잘 맞아요. 다음과 같은 사용 사례에 컨텍스트 캐싱을 고려해 보세요:
- 광범위한 시스템 지침이 있는 챗봇
- 긴 비디오 파일의 반복적 분석
- 대규모 문서 세트에 대한 반복 쿼리
- 빈번한 코드 저장소 분석 또는 버그 수정
명시적 캐싱이 비용을 줄이는 방법
컨텍스트 캐싱은 비용을 줄이기 위해 설계된 유료 기능이에요. 청구는 다음 요소에 기반해요:
- 캐시 토큰 수: 캐시된 입력 토큰 수로, 이후 프롬프트에 포함될 때 할인된 요율로 청구돼요.
- 저장 기간: 캐시된 토큰이 저장되는 시간(TTL)으로, 캐시 토큰 수의 TTL 기간에 따라 청구돼요. TTL에는 최소·최대 경계가 없어요.
- 기타 요소: 캐시되지 않은 입력 토큰과 출력 토큰 같은 다른 요금도 적용돼요.
최신 가격 세부 정보는 Gemini API pricing 페이지를 참고하세요. 토큰 계산 방법은 Token 가이드를 참고하세요.
추가 고려 사항
컨텍스트 캐싱을 사용할 때 다음을 고려하세요:
- 컨텍스트 캐싱의 최소 입력 토큰 수는 모델별로 달라요. 최대는 해당 모델의 최대치와 같아요. (토큰 계산에 대한 자세한 내용은 Token 가이드를 참고하세요.)
- 모델은 캐시된 토큰과 일반 입력 토큰을 구분하지 않아요. 캐시된 콘텐츠는 프롬프트의 프리픽스예요.
- 컨텍스트 캐싱에는 특별한 요금 또는 사용 한도가 없어요.
GenerateContent의 표준 요금 한도가 적용되며, 토큰 한도에는 캐시된 토큰이 포함돼요. - 캐시된 토큰 수는 캐시 서비스의 create, get, list 작업과 캐시를 사용할 때
GenerateContent의usage_metadata에 반환돼요.