서버리스 AI: Cloud Run으로 Gemma 삽입

1. 소개

이 Codelab에서는 GPU를 사용하여 Cloud Run에 강력한 다국어 텍스트 삽입 모델인 EmbeddingGemma를 배포하는 방법을 알아봅니다. 그런 다음 이 배포된 서비스를 사용하여 시맨틱 검색 애플리케이션의 임베딩을 생성합니다.

텍스트를 생성하는 기존 대규모 언어 모델 (LLM)과 달리 임베딩 모델은 텍스트를 숫자 벡터로 변환합니다. 이러한 벡터는 사용자의 질문과 가장 관련성이 높은 문서를 찾을 수 있는 검색 증강 생성 (RAG) 시스템을 빌드하는 데 중요합니다.

실습할 내용

  • Ollama를 사용하여 EmbeddingGemma 모델을 컨테이너화합니다.
  • GPU 가속을 사용하여 Cloud Run에 컨테이너를 배포합니다.
  • 샘플 텍스트의 임베딩을 생성하여 배포된 모델을 테스트합니다.
  • 배포된 서비스를 사용하여 경량 시맨틱 검색 시스템을 빌드합니다.

필요한 항목

  • 결제가 사용 설정된 Google Cloud 프로젝트.
  • Docker 및 명령줄에 관한 기본 지식

2. 시작하기 전에

프로젝트 설정

  1. 아직 Google 계정이 없다면 Google 계정을 만들어야 합니다.
    • 직장 또는 학교 계정 대신 개인 계정을 사용하세요. 직장 및 학교 계정에는 이 실습에 필요한 API를 사용 설정하지 못하도록 하는 제한이 있을 수 있습니다.
  2. Google Cloud 콘솔에 로그인합니다.
  3. Cloud 콘솔에서 결제를 사용 설정합니다.
    • 이 실습을 완료하는 데 드는 Cloud 리소스 비용은 미화 1달러 미만입니다.
    • 이 실습이 끝나면 단계에 따라 리소스를 삭제하여 추가 요금이 발생하지 않도록 할 수 있습니다.
    • 신규 사용자는 미화$300 상당의 무료 체험판을 사용할 수 있습니다.
  4. 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다.
    • 프로젝트 할당량에 관한 오류가 표시되면 기존 프로젝트를 재사용하거나 기존 프로젝트를 삭제하여 새 프로젝트를 만드세요.

Cloud Shell 시작

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

  1. Google Cloud 콘솔 상단에서 Cloud Shell 활성화를 클릭합니다.
  2. Cloud Shell에 연결되면 인증을 확인합니다.
    gcloud auth list
    
  3. 프로젝트가 선택되었는지 확인합니다.
    gcloud config get project
    
  4. 필요한 경우 설정합니다.
    gcloud config set project <YOUR_PROJECT_ID>
    

API 사용 설정

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

gcloud services enable \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com

3. 모델 컨테이너화

EmbeddingGemma를 서버리스로 실행하려면 컨테이너로 패키징해야 합니다. LLM을 실행하기 위한 경량 프레임워크인 OllamaDocker를 사용합니다.

Dockerfile 만들기

Cloud Shell에서 프로젝트의 새 디렉터리를 만들고 해당 디렉터리로 이동합니다.

mkdir embedding-gemma-codelab
cd embedding-gemma-codelab

다음 콘텐츠로 Dockerfile라는 파일을 만듭니다.

FROM ollama/ollama:latest

# Listen on all interfaces, port 8080
ENV OLLAMA_HOST=0.0.0.0:8080

# Store model weight files in /models
ENV OLLAMA_MODELS=/models

# Reduce logging verbosity
ENV OLLAMA_DEBUG=false

# Never unload model weights from the GPU
ENV OLLAMA_KEEP_ALIVE=-1

# Store the model weights in the container image
ENV MODEL=embeddinggemma:latest
RUN ollama serve & sleep 5 && ollama pull $MODEL

# Start Ollama
ENTRYPOINT ["ollama", "serve"]

이 Dockerfile은 다음을 수행합니다.

  1. 공식 Ollama 기본 이미지에서 시작합니다.
  2. 포트 8080 (Cloud Run의 기본값)에서 수신 대기하도록 Ollama를 구성합니다.
  3. RUN 명령어는 ollama 서버를 시작하고 빌드 프로세스 중에 embeddinggemma 모델을 다운로드하여 이미지에 포함합니다.
  4. 후속 요청의 속도를 높이기 위해 모델이 GPU 메모리에 로드된 상태를 유지하도록 OLLAMA_KEEP_ALIVE=-1를 설정합니다.

4. 빌드 및 배포

Cloud Run 소스 배포를 사용하여 단일 단계로 컨테이너를 빌드하고 배포합니다. 이 명령어는 Cloud Build를 사용하여 이미지를 빌드하고, Artifact Registry에 저장하고, Cloud Run에 배포합니다.

다음 명령어를 실행하여 배포합니다.

gcloud run deploy embedding-gemma \
  --source . \
  --region europe-west1 \
  --concurrency 4 \
  --cpu 8 \
  --set-env-vars OLLAMA_NUM_PARALLEL=4 \
  --gpu 1 \
  --gpu-type nvidia-l4 \
  --max-instances 1 \
  --memory 32Gi \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --no-gpu-zonal-redundancy \
  --timeout=600 \
  --labels dev-tutorial=codelab-embedding-gemma

구성 이해

  • --source .은 현재 디렉터리를 빌드의 소스로 지정합니다.
  • --region europe-west1 Cloud Run에서 GPU를 지원하는 리전을 사용합니다.
  • --concurrency 4은 환경 변수 OLLAMA_NUM_PARALLEL의 값과 일치하도록 설정됩니다.
  • --gpu-type nvidia-l4가 포함된 --gpu 1는 서비스의 모든 Cloud Run 인스턴스에 NVIDIA L4 GPU 1개를 할당합니다.
  • --max-instances 1은 확장할 최대 인스턴스 수를 지정합니다. 프로젝트의 NVIDIA L4 GPU 할당량보다 작거나 같아야 합니다.
  • --no-allow-unauthenticated는 서비스에 대해 인증되지 않은 액세스를 제한합니다. 서비스를 비공개로 유지하면 서비스 간 통신에 Cloud Run에서 기본 제공하는 Identity and Access Management (IAM) 인증을 사용할 수 있습니다.
  • GPU를 사용 설정하려면 --no-cpu-throttling가 필요합니다.
  • --no-gpu-zonal-redundancy는 영역 장애 조치 요구사항과 사용 가능한 할당량에 따라 영역 중복 옵션을 설정합니다.

지역 고려사항

Cloud Run의 GPU는 특정 리전에서 사용할 수 있습니다. 지원되는 리전은 문서에서 확인할 수 있습니다.

배포 출력

몇 분 후 배포가 완료되고 다음과 같은 메시지가 표시됩니다.

Service [embedding-gemma] revision [embedding-gemma-12345-abc] has been deployed and is serving 100 percent of traffic.
Service URL: https://embedding-gemma-123456789012.europe-west1.run.app

5. 배포 테스트

--no-allow-unauthenticated로 서비스를 배포했으므로 공개 URL을 간단히 curl할 수는 없습니다. 먼저 서비스에 액세스하고 요청에서 인증 토큰을 사용할 권한을 부여해야 합니다.

  1. 사용자 계정에 서비스 호출 권한을 부여합니다.
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member=user:$(gcloud config get-value account) \
        --role='roles/run.invoker'
    
  2. 요청에서 사용할 수 있도록 Google Cloud 사용자 인증 정보와 프로젝트 번호를 환경 변수에 저장합니다.
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
  3. 다음 명령어를 실행하여 '샘플 텍스트'의 삽입을 생성합니다.
    curl -X POST "https://embedding-gemma-$PROJECT_NUMBER.europe-west1.run.app/api/embed" \
        -H "Authorization: Bearer $ID_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
            "model": "embeddinggemma",
            "input": "Sample text"
        }'
    

embedding 필드에 벡터 (긴 숫자 목록)가 포함된 JSON 응답이 표시됩니다. 이는 서버리스 GPU 지원 삽입 모델이 작동하고 있음을 확인해 줍니다.

대답은 다음과 같습니다. EmbeddingGemma 컬 출력

Python 클라이언트

Python을 사용하여 서비스와 상호작용할 수도 있습니다. test_client.py이라는 파일을 만듭니다.

import urllib.request
import urllib.parse
import json
import os

# 1. Setup the URL and Payload
url = f"https://embedding-gemma-{os.environ['PROJECT_NUMBER']}.europe-west1.run.app/api/embed"
payload = {
    "model": "embeddinggemma",
    "input": "Sample text"
}

# 2. Create the Request object
# Note: Providing 'data' automatically makes this a POST request
req = urllib.request.Request(
    url,
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['ID_TOKEN']}",
        "Content-Type": "application/json"
    }
)

# 3. Execute and print the response
response = urllib.request.urlopen(req)
result = json.loads(response.read().decode("utf-8"))
print(result)

에이전트 실행:

python test_client.py

6. 시맨틱 검색 애플리케이션 빌드

이제 작동하는 임베딩 서비스가 있으므로 간단한 시맨틱 검색 애플리케이션을 빌드해 보겠습니다. 생성된 임베딩을 사용하여 지정된 질문과 가장 관련성이 높은 문서를 찾습니다.

종속 항목

chromadb를 벡터 데이터베이스로 사용하고 ollama 클라이언트 라이브러리를 사용합니다.

uv init semantic-search --description "Semantic Search Application"
cd semantic-search
uv add chromadb ollama

검색 애플리케이션 만들기

다음 코드를 사용하여 semantic_search.py 파일을 만듭니다.

import ollama
import chromadb
import os

# 1. Define our knowledge base
documents = [
    "Poland is a country located in Central Europe.",
    "The capital and largest city of Poland is Warsaw.",
    "Poland's official language is Polish, which is a West Slavic language.",
    "Marie Curie, the pioneering scientist who conducted groundbreaking research on radioactivity, was born in Warsaw, Poland.",
    "Poland is famous for its traditional dish called pierogi, which are filled dumplings.",
    "The Białowieża Forest in Poland is one of the last and largest remaining parts of the immense primeval forest that once stretched across the European Plain.",
]

print("Initializing Vector Database...")
client = chromadb.Client()
collection = client.create_collection(name="docs")

# Configure the client to point to our Cloud Run proxy
ollama_client = ollama.Client(
    host=f"https://embedding-gemma-{os.environ['PROJECT_NUMBER']}.europe-west1.run.app",
    headers={'Authorization': 'Bearer ' + os.environ['ID_TOKEN']}
)

print("Generating embeddings and indexing documents...")
# 2. Store each document in the vector database
for i, d in enumerate(documents):
    # This calls our Cloud Run service to get the embedding
    response = ollama_client.embed(model="embeddinggemma", input=d)
    embeddings = response["embeddings"]
    collection.add(ids=[str(i)], embeddings=embeddings, documents=[d])

print("Indexing complete.\n")

# 3. Perform a Semantic Search
question = "What is Poland's official language?"
print(f"Query: {question}")

# Generate an embedding for the question
response = ollama_client.embed(model="embeddinggemma", input=question)

# Query the database for the most similar document
results = collection.query(
    query_embeddings=[response["embeddings"][0]],
    n_results=1
)

best_match = results["documents"][0][0]
print(f"Best Match Document: {best_match}")

애플리케이션 실행

스크립트를 실행합니다.

uv run semantic_search.py

다음과 비슷한 출력이 표시됩니다.

Initializing Vector Database...
Generating embeddings and indexing documents...
Indexing complete.

Query: What is Poland's official language?
Best Match Document: Poland's official language is Polish, which is a West Slavic language.

이 스크립트는 RAG 시스템의 핵심을 보여줍니다. 서버리스 EmbeddingGemma 서비스를 사용하여 문서와 질문을 모두 벡터로 변환하여 사용자의 질문에 답변하는 데 필요한 정확한 정보를 찾을 수 있습니다.

7. 삭제

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

Cloud Run 서비스 삭제

gcloud run services delete embedding-gemma --region europe-west1 --quiet

컨테이너 이미지 삭제

gcloud artifacts docker images delete \
    europe-west1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/cloud-run-source-deploy/embedding-gemma \
    --quiet

8. 축하합니다

축하합니다. GPU를 사용하여 Cloud RunEmbeddingGemma를 성공적으로 배포하고 이를 사용하여 시맨틱 검색 애플리케이션을 구동했습니다.

이제 텍스트 의미를 이해해야 하는 AI 애플리케이션을 빌드하기 위한 확장 가능한 서버리스 기반이 마련되었습니다.

학습한 내용

  • Docker로 Ollama 모델을 컨테이너화하는 방법
  • GPU 지원 서비스를 Cloud Run에 배포하는 방법
  • 배포된 모델을 시맨틱 검색 (RAG)에 사용하는 방법

다음 단계

  • Gemma 제품군의 다른 모델을 살펴보세요.
  • Cloud Run GPU 자세히 알아보기
  • 다른 Cloud Run Codelab 살펴보기
  • 이 검색 단계를 생성 모델에 연결하여 전체 RAG 파이프라인을 빌드합니다.

참조 문서