Wdrażanie skonteneryzowanego agenta w Agent Runtime

1. Przegląd

Agent Runtime (wcześniej Agent Engine) to zarządzane środowisko wykonawcze przeznaczone do skutecznego wdrażania, uruchamiania i skalowania agentów AI. Domyślnie platforma automatycznie łączy kod źródłowy i zależności podczas procesu wdrażania.

Zbiory zadań w firmach często wymagają jednak pełnej kontroli nad środowiskiem wykonawczym. Aby to umożliwić, środowisko wykonawcze agenta udostępnia funkcję Bring Your Own Container(BYOC), która pozwala wdrażać wstępnie utworzone niestandardowe obrazy kontenerów.

To ćwiczenie przedstawia kompleksowy proces konteneryzacji agenta utworzonego za pomocą pakietu Google Agent Development Kit (ADK), konfigurowania niezbędnych uprawnień Google Cloud i wdrażania go w środowisku wykonawczym agenta przy użyciu pakietu Python SDK lub Terraform.

W tym laboratorium dowiesz się, jak:

  1. Tworzenie agenta w Pythonie za pomocą pakietu Google Agent Development Kit (ADK).
  2. Umieszczenie agenta w aplikacji FastAPI.
  3. Konteneryzacja aplikacji za pomocą Dockera.
  4. Konfigurowanie uprawnień Google Cloud.
  5. wdrażanie i testowanie skonteneryzowanego agenta w środowisku wykonawczym agentów;

Przepływ kompilacji i wdrażania

Poniższy diagram ilustruje przepływ pracy kroków kompilacji i wdrażania, które wykonasz ręcznie w tym module:

Schemat procesu CI/CD

Wymagania

  • projekt Google Cloud z włączonymi płatnościami;
  • Dostęp do Cloud Shell (zalecane) lub lokalnego środowiska programistycznego z zainstalowanymi narzędziami gclouddocker.
  • Podstawowa znajomość języka Python i technologii Docker.

2. Konfiguracja środowiska

Zanim zaczniesz, musisz włączyć niezbędne interfejsy API i skonfigurować środowisko.

Krok 1. Otwórz Cloud Shell

W prawym górnym rogu konsoli Google Cloud kliknij przycisk Aktywuj Cloud Shell.

Cloud Shell

Krok 2. Skonfiguruj zmienne środowiskowe

W Cloud Shell ustaw identyfikator projektu i zdefiniuj kluczowe zmienne środowiskowe używane w trakcie tych ćwiczeń z programowania. Zastąp "YOUR_PROJECT_ID" identyfikatorem Twojego projektu Google Cloud:

gcloud config set project "YOUR_PROJECT_ID"
export PROJECT_ID=$(gcloud config get-value project)
export LOCATION="us-central1"
export MODEL="gemini-3.1-flash-lite"
export MODEL_REGION="global"

Te zmienne konfigurują ustawienia wdrożenia docelowego:

  • PROJECT_ID: unikalny identyfikator projektu Google Cloud, w którym będą się znajdować wszystkie zasoby Gemini Enterprise Agent Platform i Artifact Registry.
  • LOCATION: region geograficzny (np. us-central1), w którym znajdują się Twoje repozytoria i zadania wykonywane w czasie działania.
  • MODEL: wersja modelu Gemini (np. gemini-3.1-flash-lite) załadowana przez kontekst agenta.
  • MODEL_REGION: region punktu końcowego modelu. Ustaw tutaj wartość "global", aby wywoływać model Gemini z globalnych punktów końcowych.

Krok 3. Włącz interfejsy API

Włącz wymagane Google Cloud APIs:

gcloud services enable \
    aiplatform.googleapis.com \
    cloudbuild.googleapis.com \
    compute.googleapis.com \
    artifactregistry.googleapis.com \
    storage.googleapis.com

Krok 4. Zainstaluj pakiet SDK

Zainstaluj pakiet Vertex AI SDK z obsługą Agent Engine i ADK:

pip install --upgrade "google-cloud-aiplatform[agent_engines,adk]>=1.144"

3. Konfigurowanie plików źródłowych

W tym kroku utworzysz strukturę i kod agenta.

Omówienie struktury katalogu

Po ukończeniu tego ćwiczenia Twoje pliki będą uporządkowane w tej hierarchii obszaru roboczego:

weather-agent-byoc/
├── Dockerfile                  # Container definition
├── deploy_byoc.py              # Python SDK deployment script
├── main.py                     # FastAPI server wrapper
├── query_agent.py              # Verify / query script
├── requirements.txt            # Python dependencies

├── weather_agent/              # Agent source module
   ├── __init__.py             # Package declaration
   ├── agent.py                # Agent & mock tools logic
   └── config.json             # Environment config variables

└── terraform/                  # Terraform configuration files
    ├── main.tf
    ├── outputs.tf
    ├── providers.tf
    ├── terraform.tfvars
    └── variables.tf

Krok 1. Utwórz katalogi

Zacznij od katalogu głównego i utwórz strukturę obszaru roboczego:

cd ~
mkdir -p weather-agent-byoc/weather_agent
cd weather-agent-byoc

Krok 2. Utwórz plik konfiguracyjny

Uruchom w Cloud Shell to polecenie, aby zapisać parametry konfiguracji bezpośrednio w weather_agent/config.json. To polecenie automatycznie zastępuje zmienne wartościami środowiska:

cat <<EOF > weather_agent/config.json
{
    "PROJECT_ID": "${PROJECT_ID}",
    "LOCATION": "${LOCATION}",
    "MODEL": "${MODEL}",
    "MODEL_REGION": "${MODEL_REGION}"
}
EOF

Krok 3. Zdefiniuj agenta

Uruchom ten skrypt, aby zapisać konfigurację agenta i logikę narzędzia testowego w weather_agent/agent.py:

cat << 'EOF' > weather_agent/agent.py
import json
import random
from google.adk.agents import Agent
from google.adk.models.google_llm import Gemini
from functools import cached_property
from google.genai import Client

# Load config
llm_config = json.load(open("weather_agent/config.json"))
PROJECT_ID = llm_config["PROJECT_ID"]
MODEL = llm_config["MODEL"]
MODEL_REGION = llm_config["MODEL_REGION"]

# Override Gemini class for global endpoint compatibility
class GlobalGemini(Gemini):
  @cached_property
  def api_client(self) -> Client:
    return Client(vertexai=True, location="global")

# Define Tool
def get_temperature(place: str) -> str:
    '''Returns the current temperature of a given place.

    Args:
        place: The name of the city or location.

    Returns:
        str: A string describing the temperature.
    '''
    temp = random.randint(-10, 40)
    return f"The current temperature in {place} is {temp}°C."

# Initialize LLM
llm_model = GlobalGemini(model=MODEL) if MODEL_REGION == "global" else Gemini(model=MODEL)

# Initialize Agent
root_agent = Agent(
    model=llm_model,
    name='weather_agent',
    description='An agent that provides temperature information for locations.',
    instruction='You are a helpful assistant that can provide the current temperature for any given place using the get_temperature tool.',
    tools=[get_temperature],
)
EOF

Utwórz pusty plik __init__.py, aby przekształcić folder weather_agent w pakiet Pythona:

touch weather_agent/__init__.py

Krok 4. Utwórz otokę FastAPI

Uruchom ten skrypt, aby zapisać konfigurację punktu wejścia serwera FastAPI w main.py:

cat << 'EOF' > main.py
import inspect
import json
import logging
import os
from typing import Any, Dict, Optional
import uvicorn
import vertexai
from weather_agent.agent import root_agent
from fastapi import FastAPI, encoders, responses, Request
from vertexai import agent_engines

app = FastAPI()

config_json = json.load(open("weather_agent/config.json"))
PROJECT_ID = config_json["PROJECT_ID"]
LOCATION = config_json["LOCATION"]
MODEL_REGION = config_json["MODEL_REGION"]

vertexai.init(project=PROJECT_ID, location=MODEL_REGION)
adk_app = agent_engines.AdkApp(agent=root_agent)

def _encode_chunk_to_json(chunk):
  try:
    json_chunk = encoders.jsonable_encoder(chunk)
    return json.dumps(json_chunk) + "\n"
  except Exception:
    logging.exception("Failed to encode chunk")
    return None

async def json_generator(output):
  async for chunk in output:
    encoded_chunk = _encode_chunk_to_json(chunk)
    if encoded_chunk is None:
      break
    yield encoded_chunk

async def _invoke_callable_or_raise(invocation_callable, invocation_payload):
  if inspect.iscoroutinefunction(invocation_callable):
    return await invocation_callable(**invocation_payload)
  else:
    return invocation_callable(**invocation_payload)

@app.post("/api/reasoning_engine")
async def query(request: Request) -> responses.JSONResponse:
    request_json = await request.json()
    class_method = request_json.get("class_method")
    input_val = request_json.get("input")
    method = getattr(adk_app, class_method)
    output = await _invoke_callable_or_raise(method, input_val or {})
    try:
      json_serialized_content = encoders.jsonable_encoder({"output": output})
    except ValueError as encoding_error:
      logging.exception("Failed to encode response")
      raise encoding_error
    return responses.JSONResponse(content=json_serialized_content)

@app.post("/api/stream_reasoning_engine")
async def stream_query(request: Request) -> responses.StreamingResponse:
    request_json = await request.json()
    class_method = request_json.get("class_method")
    input_val = request_json.get("input")
    method = getattr(adk_app, class_method)
    output = await _invoke_callable_or_raise(method, input_val or {})
    return responses.StreamingResponse(
        content=json_generator(output),
        media_type="application/json",
    )

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

Krok 5. Określ zależności

Zapisz wymagane zależności Pythona w requirements.txt:

cat << 'EOF' > requirements.txt
fastapi
uvicorn
vertexai
google-cloud-aiplatform[agent_engines,adk]>=1.144
pydantic
EOF

4. Konteneryzacja

Teraz określ, jak agent będzie pakowany w kontenerze.

Krok 1. Utwórz plik Dockerfile

Utwórz plik Dockerfile w katalogu głównym projektu, aby określić sposób tworzenia aplikacji FastAPI:

cat << 'EOF' > Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY weather_agent/ /app/weather_agent/
COPY main.py .
COPY requirements.txt .
RUN pip install -r requirements.txt

CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port $PORT"]
EOF

5. Konfigurowanie Artifact Registry i Cloud Build

Aby przechowywać obraz kontenera i przekazywać go, musisz mieć repozytorium i odpowiednie uprawnienia.

Krok 1. Utwórz repozytorium

Zdefiniuj nazwę repozytorium i utwórz repozytorium Dockera w Artifact Registry, używając zmiennych środowiskowych zdefiniowanych podczas konfiguracji:

export REPOSITORY_NAME="agents-repo"

gcloud artifacts repositories create $REPOSITORY_NAME \
    --project=$PROJECT_ID \
    --repository-format=docker \
    --location=$LOCATION \
    --description="Docker repository for Agents"

Krok 2. Skonfiguruj uprawnienia konta usługi

Przyznaj domyślnemu kontu usługi Compute uprawnienia do przesyłania obrazów do Artifact Registry.

Najpierw uzyskaj numer projektu:

export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")

Przyznaj role:

# Allow pushing to Artifact Registry
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
    --role="roles/artifactregistry.writer" \
    --condition=None

# Allow Cloud Build to read storage objects
gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
    --role="roles/storage.objectViewer" \
    --condition=None

Krok 3. Przyznaj uprawnienia agentom usług

Przyznaj agentom usług AI Platform i Reasoning Engine uprawnienia do odczytu Artifact Registry:

gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
    --role="roles/artifactregistry.reader"  --condition=None

gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com" \
    --role="roles/artifactregistry.reader"  --condition=None

Krok 4. Skompiluj i prześlij obraz

Za pomocą Cloud Build utwórz obraz kontenera i przenieś go:

gcloud builds submit \
    --project=$PROJECT_ID \
    --region=$LOCATION \
    --tag $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/weather-agent-image:latest \
    .

6. Wdrażanie agenta za pomocą pakietu SDK

Po skonfigurowaniu uprawnień możesz wdrożyć kontener niestandardowy.

Krok 1. Wdróż agenta BYOC

Aby wdrożyć kontener hostowany w rejestrze w środowisku wykonawczym agenta, utwórz plik Pythona deploy_byoc.py w katalogu głównym projektu:

cat << 'EOF' > deploy_byoc.py
import json
import os
import vertexai
from google.cloud import aiplatform

config = json.load(open("weather_agent/config.json"))
PROJECT_ID = config["PROJECT_ID"]
LOCATION = config["LOCATION"]
REPOSITORY_NAME = "agents-repo"

vertexai.init(project=PROJECT_ID, location=LOCATION)
client = vertexai.Client(project=PROJECT_ID, location=LOCATION)

image_uri = f"{LOCATION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY_NAME}/weather-agent-image:latest"

print(f"Deploying custom container agent from {image_uri}...")
remote_agent = client.agent_engines.create(
    config={
        "display_name": "byoc_weather_agent",
        "description": "BYOC weather agent from custom container",
        "container_spec": {
            "image_uri": image_uri
        },
        "class_methods": [
            # For convenience to interact with the agent through the Python SDK
            # https://docs.cloud.google.com/gemini-enterprise-agent-platform/scale/runtime/use-an-adk-agent#supported-operations
            {"api_mode": "", "name": "get_session"},
            {"api_mode": "", "name": "list_sessions"},
            {"api_mode": "", "name": "create_session"},
            {"api_mode": "", "name": "delete_session"},
            {"api_mode": "async", "name": "async_get_session"},
            {"api_mode": "async", "name": "async_list_sessions"},
            {"api_mode": "async", "name": "async_create_session"},
            {"api_mode": "async", "name": "async_delete_session"},
            {"api_mode": "async", "name": "async_add_session_to_memory"},
            {"api_mode": "async", "name": "async_search_memory"},
            {"api_mode": "stream", "name": "stream_query"},
            {"api_mode": "async_stream", "name": "async_stream_query"},
            {"api_mode": "async_stream", "name": "streaming_agent_run_with_events"},
        ],
        "agent_framework": "google-adk",
    },
)

print(f"Agent successfully deployed!")
print(f"Resource Name: {remote_agent.api_resource.name}")

# Save resource name for testing
with open("agent_resource_name.txt", "w") as f:
    f.write(remote_agent.api_resource.name)
EOF

Uruchom skrypt wdrażania, aby wdrożyć agenta w środowisku wykonawczym agentów:

python3 deploy_byoc.py

7. Wdrażanie agenta za pomocą Terraform

Możesz też wdrożyć tego samego agenta w kontenerze za pomocą Terraform. Jest to zalecane w środowiskach produkcyjnych do zarządzania infrastrukturą jako kodem.

Krok 1. Przejdź do katalogu Terraform

Utwórz w katalogu głównym projektu katalog terraform i przejdź do niego:

mkdir -p terraform
cd terraform

Krok 2. Utwórz konfigurację dostawców

Aby zapisać mapowanie dostawców w providers.tf, uruchom ten skrypt:

cat << 'EOF' > providers.tf
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 5.28.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.location
}
EOF

Krok 3. Utwórz definicję zmiennych

Wpisz blok opisu danych wejściowych w variables.tf:

cat << 'EOF' > variables.tf
variable "project_id" {
  type        = string
  description = "The Google Cloud Project ID"
}

variable "location" {
  type        = string
  description = "The region to deploy the reasoning engine"
  default     = "us-central1"
}

variable "repository_name" {
  type        = string
  description = "The Artifact Registry repository name"
  default     = "agents-repo"
}

variable "image_tag" {
  type        = string
  description = "The tag of the container image to deploy"
  default     = "latest"
}
EOF

Krok 4. Utwórz konfigurację główną

Wpisz główne parametry definicji zasobów w main.tf:

cat << 'EOF' > main.tf
locals {
  class_methods = [
    {"api_mode" = "", "name" = "get_session"},
    {"api_mode" = "", "name" = "list_sessions"},
    {"api_mode" = "", "name" = "create_session"},
    {"api_mode" = "", "name" = "delete_session"},
    {"api_mode" = "async", "name" = "async_get_session"},
    {"api_mode" = "async", "name" = "async_list_sessions"},
    {"api_mode" = "async", "name" = "async_create_session"},
    {"api_mode" = "async", "name" = "async_delete_session"},
    {"api_mode" = "async", "name" = "async_add_session_to_memory"},
    {"api_mode" = "async", "name" = "async_search_memory"},
    {"api_mode" = "stream", "name" = "stream_query"},
    {"api_mode" = "async_stream", "name" = "async_stream_query"},
    {"api_mode" = "async_stream", "name" = "streaming_agent_run_with_events"}
  ]
}

# define the resource with the BYOC configuration, set agent_framework to "google-adk" to enable interactive features on the console.
resource "google_vertex_ai_reasoning_engine" "byoc_weather_agent" {
  display_name = "byoc_weather_agent_tf"
  description  = "BYOC weather agent deployed via Terraform"
  project      = var.project_id
  location     = var.location

  spec {
    class_methods = jsonencode(local.class_methods)
    agent_framework = "google-adk"
    container_spec {
      image_uri = "${var.location}-docker.pkg.dev/${var.project_id}/${var.repository_name}/weather-agent-image:${var.image_tag}"
    }
  }
}
EOF

Krok 5. Utwórz definicję danych wyjściowych

Zapisz blok wyjściowy w outputs.tf:

cat << 'EOF' > outputs.tf
output "reasoning_engine_id" {
  value       = google_vertex_ai_reasoning_engine.byoc_weather_agent.id
  description = "The ID of the deployed reasoning engine"
}

output "reasoning_engine_resource_name" {
  value       = google_vertex_ai_reasoning_engine.byoc_weather_agent.id
  description = "The resource name of the deployed reasoning engine"
}
EOF

Krok 6. Utwórz plik wartości zmiennych (tfvars)

Wdrażaj dynamicznie bez edytowania symboli zastępczych, przekazując zmienne środowiskowe bezpośrednio do terraform.tfvars:

cat <<EOF > terraform.tfvars
project_id      = "${PROJECT_ID}"
location        = "${LOCATION}"
repository_name = "agents-repo"
image_tag       = "latest"
EOF

Krok 7. Inicjowanie i stosowanie

Zainicjuj Terraform i zastosuj konfigurację:

terraform init
terraform apply

Gdy pojawi się odpowiedni komunikat, potwierdź zastosowanie, wpisując yes.

Po zakończeniu Terraform wyświetli nazwę zasobu. Przechwyć go programowo do agent_resource_name.txt i wróć do folderu głównego:

terraform output -raw reasoning_engine_resource_name > ../agent_resource_name.txt
cd ..

8. Zapytaj agenta

Sprawdź, czy agent jest uruchomiony i odpowiada.

Krok 1. Utwórz skrypt zapytania

Napisz skrypt weryfikacyjny w query_agent.py, używając dynamicznego sprawdzania konfiguracji, aby pobrać współrzędne geograficzne:

cat << 'EOF' > query_agent.py
import json
import os
import requests
from google import auth as google_auth
from google.auth.transport import requests as google_requests

# Load config coordinates directly
config_json = json.load(open("weather_agent/config.json"))
LOCATION = config_json["LOCATION"]
PROJECT_ID = config_json["PROJECT_ID"]

# Load agent resource name
with open("agent_resource_name.txt", "r") as f:
    agent_resource_name = f.read().strip()

def get_identity_token():
    credentials, _ = google_auth.default()
    auth_request = google_requests.Request()
    credentials.refresh(auth_request)
    return credentials.token

# Access the agent at the fastapi endpoint that was specified in main.py
url = f"https://{LOCATION}-aiplatform.googleapis.com/reasoningEngines/v1/{agent_resource_name}/api/api/stream_reasoning_engine"

payload = {
    "class_method": "async_stream_query",
    "input": {
        "user_id": "codelab_test_user",
        "message": "What is the temperature in Tokyo?",
    },
}

print(f"Sending query to {url}...")
response = requests.post(
    url,
    headers={
        "Content-Type": "application/json",
        "Authorization": f"Bearer {get_identity_token()}",
    },
    data=json.dumps(payload),
    stream=True,
)

for chunk in response.iter_content(chunk_size=8192):
    if chunk:
        print(chunk.decode('utf-8'))
EOF

Uruchom skrypt zapytania:

python3 query_agent.py

Powinny się wyświetlić dane wyjściowe przesyłane strumieniowo z agenta, w tym symulowana temperatura w Tokio.

Krok 2. Korzystanie z konsoli

  1. Aby przefiltrować listę agentów, przejdź do wdrożonego agenta, wybierając Platforma agentów > Agenci > Wdrożenia.

Zdjęcie agenta

  1. Na panelu agenta kliknij Playground (Piaskownica).

Panel agenta

  1. Utwórz nową sesję i wpisz zapytanie, aby sprawdzić, czy agent odpowiada na prośby zgodnie z instrukcjami.

Interakcja z agentem

9. Czyszczenie

Aby uniknąć opłat, wyczyść utworzone zasoby.

Jeśli wdrożenie zostało przeprowadzone za pomocą Terraform, przejdź do katalogu terraform i wykonaj działanie niszczące:

cd ~/weather-agent-byoc/terraform
terraform destroy
cd ..

Jeśli wdrożono agenta za pomocą pakietu SDK, utwórz skrypt, który go usunie:

cat << 'EOF' > delete_agent.py
import json
import os
import vertexai
from google.cloud import aiplatform

config = json.load(open("weather_agent/config.json"))
PROJECT_ID = config["PROJECT_ID"]
LOCATION = config["LOCATION"]

vertexai.init(project=PROJECT_ID, location=LOCATION)
client = vertexai.Client(project=PROJECT_ID, location=LOCATION)

with open("agent_resource_name.txt", "r") as f:
    agent_resource_name = f.read().strip()

# 1. Delete the Agent
# Note: We retrieve the list first to ensure we delete the ones created in this session
try:
    page_size = 100
    reasoning_engines = client.agent_engines.list()
    for engine in reasoning_engines:
        if agent_resource_name in engine.api_resource.name:
            print(f"Deleting Reasoning Engine: {engine.api_resource.name}")
            engine.delete(force=True)
except Exception as e:
    print(f"Error deleting reasoning engines: {e}")
EOF

Uruchom skrypt, aby usunąć agenta:

python3 delete_agent.py

Aby wyczyścić pozostałe zasoby, wróć do katalogu głównego i uruchom w Cloud Shell te polecenia:

cd ~

# 1. Delete the Artifact Registry Repository
gcloud artifacts repositories delete $REPOSITORY_NAME --location=$LOCATION --quiet

# 2. Clean up files (Optional)
rm -rf ~/weather-agent-byoc

10. Podsumowanie

Gratulacje! Udało Ci się skonteneryzować i wdrożyć agenta AI w środowisku wykonawczym agenta za pomocą BYOC.

Dowiedziałeś(-aś) się, jak:

  • Użyj ADK, aby zdefiniować agenta i zawrzeć go w FastAPI.
  • Utwórz plik Dockerfile i skompiluj obrazy za pomocą Cloud Build.
  • Zarządzaj uprawnieniami środowiska wykonawczego agenta.
  • Wdróż kontener niestandardowy za pomocą pakietu SDK PythonaTerraform.
  • Przetestuj wdrożonego agenta i zadaj mu pytania.