BigQuery의 컨텍스트 캐싱: 빅데이터를 위한 빠르고 비용 효율적이며 근거가 있는 생성형 AI

1. 소개

BigQuery의 생성형 AI 함수를 사용하면 SQL을 사용하여 대규모 언어 모델 (LLM)을 통해 데이터에 대해 추론할 수 있습니다. 데이터를 이동하지 않고도 수백만 개의 행에 걸쳐 감정을 분석하고, 요약을 생성하고, 이미지에 캡션을 추가할 수 있습니다.

하지만 정확하고 신뢰할 수 있는 결과를 얻기 위해 프롬프트에 정책, 매뉴얼, 동영상과 같은 방대한 양의 컨텍스트가 필요한 경우에는 어떻게 해야 할까요?

Gemini 컨텍스트 캐싱은 이러한 대규모 컨텍스트를 캐시에 저장하여 이 문제를 해결합니다. 후속 프롬프트는 매번 전체 콘텐츠를 처리하는 대신 캐시를 참조하여 지연 시간을 줄이고 입력 토큰에 최대 90% 할인을 제공합니다.

이 Codelab에서는 명시적 컨텍스트 캐싱을 사용하여 BigQuery의 대규모 정적 반품 정책 문서에 대해 고객 반품 요청을 분석하는 '세부사항' 반품 정책 검사기를 빌드합니다.

BigQuery 컨텍스트 캐시 워크플로 (이미지 업데이트 예정)

실습할 내용

  • BigQuery 데이터 세트를 만들고 샘플 고객 반품 요청으로 채웁니다.
  • Cloud Storage에 저장된 반품 정책 문서를 가리키는 Gemini Enterprise Agent Platform (이전 명칭: Vertex AI)에서 컨텍스트 캐시를 만듭니다.
  • 캐시를 참조하는 AI.GENERATE를 사용하여 쿼리를 실행하여 행별로 요청을 효율적으로 평가합니다.

필요한 항목

  • 웹브라우저(예: Chrome)
  • 결제가 사용 설정된 Google Cloud 프로젝트
  • Google Cloud Shell 액세스

이 Codelab은 초보자를 포함한 모든 수준의 개발자를 대상으로 합니다.

이 Codelab에서 만든 리소스의 비용은 2달러 미만이어야 합니다.

예상 소요 시간: 이 Codelab을 완료하는 데 약 30분이 소요됩니다.

2. 시작하기 전에

Google Cloud 프로젝트 만들기

  1. Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
  2. Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

Cloud Shell 시작

Cloud Shell은 Google Cloud에서 실행되는 명령줄 환경으로, 필요한 도구가 미리 로드되어 제공됩니다.

  1. Google Cloud 콘솔 상단에서 Cloud Shell 활성화를 클릭합니다. Cloud Shell 이미지 활성화
  2. Cloud Shell에 연결되면 인증을 확인합니다.
    gcloud auth list
    
  3. 프로젝트가 구성되어 있는지 확인합니다.
    gcloud config get project
    
  4. 프로젝트가 예상대로 설정되지 않은 경우 설정합니다.
    gcloud config set project <YOUR_PROJECT_ID>
    

프로젝트 ID 및 위치 설정

다음 명령어를 실행하여 활성 Google Cloud 프로젝트 ID를 가져오고 기본 위치를 설정하여 이 Codelab 전체에서 사용할 환경 변수로 설정합니다.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export LOCATION="us-central1"

API 사용 설정

이 명령어를 실행하여 필요한 API를 사용 설정합니다.

gcloud services enable \
 bigquery.googleapis.com \
 aiplatform.googleapis.com

3. BigQuery 데이터 준비

컨텍스트 캐싱을 테스트하려면 쿼리를 실행할 데이터 세트와 샘플 고객 반품 요청으로 채워진 테이블이 필요합니다.

1. 데이터 세트 만들기

Cloud Shell에서 다음 명령어를 실행하여 caching_demo라는 BigQuery 데이터 세트를 만듭니다.

bq mk --dataset $PROJECT_ID:caching_demo

2. 테이블 만들기 및 채우기

다음 명령어를 실행하여 return_requests라는 이름의 테이블을 만들고 샘플 고객 반품 요청을 삽입합니다.

bq query \
  --use_legacy_sql=false \
  "CREATE OR REPLACE TABLE \`caching_demo.return_requests\` AS
SELECT
  10001 AS return_id,
  'P-1001' AS purchase_id,
  'I bought this jacket on Black Friday but it was too small.' AS return_comment,
  DATE('2025-11-28') AS purchase_date,
  DATE('2025-12-05') AS return_date,
  'ApexWear' AS product_brand,
  'Gold' AS customer_tier
UNION ALL
  SELECT
  10002 AS return_id,
  'P-1002' AS purchase_id,
  'The item arrived broken, I want a refund. I don\'t have photos because I threw it away.' AS return_comment,
  DATE('2026-04-01') AS purchase_date,
  DATE('2026-04-02') AS return_date,
  'GenericBrand' AS product_brand,
  'Standard' AS customer_tier
UNION ALL
  SELECT
  10003 AS return_id,
  'P-1003' AS purchase_id,
  'I bought this ApexWear jacket, took the tags off to wear it once, but it doesn\'t fit well.' AS return_comment,
  DATE('2026-02-15') AS purchase_date,
  DATE('2026-02-20') AS return_date,
  'ApexWear' AS product_brand,
  'Standard' AS customer_tier
UNION ALL
  SELECT
  10004 AS return_id,
  'P-1004' AS purchase_id,
  'This was a holiday gift but doesn\'t fit.' AS return_comment,
  DATE('2025-12-20') AS purchase_date,
  DATE('2026-01-28') AS return_date,
  'StyleCorp' AS product_brand,
  'Standard' AS customer_tier
UNION ALL
  SELECT
  10005 AS return_id,
  'P-1005' AS purchase_id,
  'I realized this doesn\'t fit' AS return_comment,
  DATE('2026-02-01') AS purchase_date,
  DATE('2026-03-15') AS return_date,
  'ApexWear' AS product_brand,
  'Gold' AS customer_tier;"

다음과 같은 성공 메시지가 표시됩니다.

Created your-project-id.caching_demo.return_requests

이제 캐시를 만들 준비가 되었습니다.

4. 컨텍스트 캐시 만들기

curl를 사용하여 Gemini Enterprise 에이전트 플랫폼 (이전 명칭: Vertex AI) 모델 엔드포인트에 대한 REST 호출을 사용하여 캐시를 만듭니다.

Cloud Shell에서 다음 명령어를 실행하여 새 스토리지 버킷을 만듭니다. 이는 캐시할 파일을 저장하는 데 사용됩니다.

gcloud storage buckets create gs://${PROJECT_ID}-caching-demo --location=${LOCATION}

다음으로 새로 만든 버킷에 샘플 정책 문서를 복사합니다.

gcloud storage cp gs://sample-data-and-media/context_caching_demo/return_policy.md gs://${PROJECT_ID}-caching-demo/

이제 다음 명령어를 실행하여 새로 스테이징된 정책 문서를 참조하는 캐시를 만듭니다 (완료하는 데 1분 정도 걸릴 수 있음).

curl -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  "https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/cachedContents" \
  -d '{
    "model": "projects/'"${PROJECT_ID}"'/locations/'"${LOCATION}"'/publishers/google/models/gemini-2.5-flash",
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "fileData": {
              "mimeType": "text/markdown",
              "fileUri": "gs://'"${PROJECT_ID}"'-caching-demo/return_policy.md"
            }
          }
        ]
      }
    ],
    "ttl": "3600s"
  }'

응답 JSON에 반환된 name를 확인합니다. projects/PROJECT_NUMBER/locations/LOCATION/cachedContents/CACHE_ID와 비슷합니다. 다음 단계에서 이 CACHE_ID이 필요합니다.

{
  "name": "projects/123456789012/locations/us-central1/cachedContents/123456789012345"
}

Cloud Shell에서 CACHE_ID를 환경 변수로 저장합니다.

export CACHE_ID="<YOUR_CACHE_ID>"

5. 캐시된 콘텐츠로 AI.GENERATE 실행

먼저 샘플 데이터가 올바르게 생성되었는지 확인해 보겠습니다. BigQuery 콘솔로 이동하여 caching_demo 데이터 세트를 찾고 return_requests 테이블을 클릭합니다.

미리보기 탭에 이전에 생성한 고객 반품 요청이 표시됩니다.

BigQuery의 return_requests 테이블 미리보기

이제 캐시가 생성되고 채워졌으므로 AI.GENERATE를 사용하여 해당 캐시 ID를 참조하는 것만으로 환불 요청을 평가할 수 있습니다.

변수를 수동으로 찾아 바꾸지 않으려면 Cloud Shell에서 다음 명령어를 실행하세요. 그러면 기존 환경 변수를 사용하여 SQL 쿼리가 동적으로 빌드되고 화면에 출력되므로 쉽게 복사할 수 있습니다.

cat << EOF > query.sql
WITH generated_returns AS (
  SELECT
    *,
    -- Call AI.GENERATE with the prompt, schema, and cache ID
    AI.GENERATE(
      -- Construct the prompt referencing the cached policy
      prompt => CONCAT(
        'Analyze this return request using the cached Return Policy. ',
        'Return Comment: "', return_comment, '". ',
        'Purchase Date: ', purchase_date, '. ',
        'Brand: ', product_brand, '. ',
        'Customer Tier: ', customer_tier, '. '
      ),
      -- Define the structured output schema
      output_schema => """
        eligible_for_refund STRING OPTIONS(description = 'True/False whether the request is eligible for a refund based on the policy'),
        refund_type STRING OPTIONS(description = 'Classify as Full, Store Credit, or None'),
        reason_citation STRING OPTIONS(description = 'Quote the specific rule from the policy applied to this decision')
      """,    
      -- Construct the endpoint string dynamically using variables
      endpoint => 'gemini-2.5-flash',
      
      -- Pass the cached content ID using bash interpolation for the literal
      model_params => JSON '{"cachedContent": "projects/$PROJECT_NUMBER/locations/$LOCATION/cachedContents/$CACHE_ID"}'
    ) AS results
  FROM \`caching_demo.return_requests\`
)
SELECT 
  *,
  -- Extract token usage metrics from the raw JSON response
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.prompt_token_count') AS INT64) AS prompt_token_count,
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.cached_content_token_count') AS INT64) AS cached_content_token_count,
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.candidates_token_count') AS INT64) AS output_token_count,
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.total_token_count') AS INT64) AS total_token_count,
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.thoughts_token_count') AS INT64) AS thoughts_token_count,
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.billable_prompt_usage.text_count') AS INT64) AS billable_prompt_text_count,
  CAST(JSON_EXTRACT_SCALAR(results.full_response, '$.usage_metadata.billable_cached_content_usage.text_count') AS INT64) AS billable_cached_text_count
  
FROM generated_returns;
EOF

cat query.sql

이제 터미널에서 SQL을 복사하고 브라우저에서 BigQuery 콘솔로 이동하여 쿼리 편집기 탭에서 쿼리를 실행합니다.

BigQuery의 return_requests 테이블 미리보기

이 함수 호출의 주요 인수는 다음과 같습니다.

  • prompt: 각 고객 행의 구체적인 정보를 포함합니다. 이 텍스트는 캐시에 이미 있는 대규모 반품 정책 문서에 효과적으로 추가됩니다.
  • output_schema: 모델의 응답에 예상되는 JSON 구조를 정의합니다.
  • endpoint: 생성에 사용되는 에이전트 플랫폼 AI 모델 엔드포인트 (이 경우 Gemini 2.5 Flash)를 지정합니다.
  • model_params: cachedContent 필드를 사용하여 생성된 캐시 ID를 전달하는 중요한 매개변수입니다.

저장된 정책에 따라 각 반품 요청을 분석한 결과가 표시됩니다. 오른쪽으로 스크롤하여 추출된 토큰 측정항목을 확인합니다.

모델 분석 및 토큰 수를 보여주는 쿼리 결과

표시되는 토큰 측정항목은 다음과 같습니다.

  • prompt_token_count: 입력 프롬프트에서 처리된 총 토큰 수 (캐시된 콘텐츠 포함)입니다.
  • cached_content_token_count: 캐시에서 제공된 토큰 수 (정적 반품 정책 문서를 나타냄)
  • output_token_count: 모델에서 응답에 생성한 토큰 수입니다.
  • total_token_count: 프롬프트 및 출력 토큰의 합계입니다.
  • billable_prompt_text_count: 캐시되지 않은 프롬프트 부분의 청구 가능한 문자 수입니다.
  • billable_cached_text_count: 캐시된 콘텐츠의 청구 가능한 문자 수입니다.

billable_prompt_text_count 열을 살펴보세요. 행당 수백 자만 표시되며 이는 고객의 구체적인 요청일 뿐입니다. 전체 반품 정책의 billable_cached_text_count은 30,000자를 초과합니다. 컨텍스트 캐싱이 없으면 모든 단일 행에 대해 전체 정책 문서를 처리하는 비용을 지불해야 합니다. 캐싱하면 대규모 문서에 대해 한 번만 비용을 지불하고 이후 행에서는 변경되는 작은 프롬프트 텍스트에 대해서만 비용이 청구됩니다.

따라서 일괄 작업의 비용을 대폭 절감할 수 있습니다.

6. 삭제

Google Cloud 계정에 지속적으로 비용이 청구되지 않도록 하려면 이 Codelab 중에 만든 리소스를 삭제하세요.

Cloud Shell에서 다음 명령어를 실행하여 BigQuery 데이터 세트와 테이블을 삭제합니다.

bq rm -r -f -d caching_demo

정책 문서용으로 생성된 스테이징 버킷을 삭제합니다.

gcloud storage rm --recursive gs://${PROJECT_ID}-caching-demo

마지막으로 이전에 저장한 변수를 사용하여 지속적인 스토리지 요금이 청구되지 않도록 컨텍스트 캐시를 삭제합니다.

curl -X DELETE \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  "https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/cachedContents/${CACHE_ID}"

7. 축하합니다

축하합니다. Agent Platform에서 컨텍스트 캐시를 만들고 BigQuery AI 함수에서 이를 참조하여 분석 속도를 높이는 동시에 입력 토큰 처리 비용을 절감했습니다.

학습한 내용

  • 반품 요청 분석을 위한 환경 테이블을 설정하는 방법
  • curl를 사용하여 에이전트 플랫폼 (Vertex AI) API를 호출하여 정적 문서 컨텍스트 캐시를 명시적으로 만드는 방법
  • 생성된 캐시 ID를 AI.GENERATE SQL 쿼리에서 사용하여 활성 프롬프트 전반에서 중복 입력 토큰을 삭제하는 방법

참조 문서