Cómo implementar una app de frontend de Gradio que llama a un agente de ADK de backend, ambos ejecutándose en Cloud Run

1. Introducción

Descripción general

En este codelab, implementarás un agente del ADK en Cloud Run como un servicio de backend y, luego, implementarás un frontend de Gradio para el agente del ADK como un segundo servicio de Cloud Run. En este codelab, se muestra cómo solicitar autenticación a tu servicio de agente del ADK y realizar llamadas autenticadas a este desde el servicio de frontend de Gradio.

Qué aprenderás

  • Cómo implementar un agente del ADK en Cloud Run
  • Cómo implementar una app de Gradio en Cloud Run
  • Cómo realizar llamadas autenticadas entre servicios en Cloud Run

2. Habilita las APIs

Primero, configura tu proyecto de Google Cloud.

gcloud config set project <YOUR_PROJECT_ID>

Para confirmar tu proyecto de Google Cloud, ejecuta el siguiente comando:

gcloud config get-value project

En este codelab, se deben habilitar las siguientes APIs:

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

3. Configuración y requisitos

En esta sección, crearás un par de cuentas de servicio y les otorgarás los roles de IAM adecuados. Cada servicio de Cloud Run tendrá su propia cuenta de servicio.

Primero, establece las variables de entorno para este codelab que se usarán durante todo el proceso.

export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION=<YOUR_REGION>

export SERVICE_ACCOUNT_ADK="adk-agent-cr"
export SERVICE_ACCOUNT_ADDRESS_ADK=$SERVICE_ACCOUNT_ADK@$PROJECT_ID.iam.gserviceaccount.com

export SERVICE_ACCOUNT_GRADIO="adk-agent-gradio"
export SERVICE_ACCOUNT_ADDRESS_GRADIO=$SERVICE_ACCOUNT_GRADIO@$PROJECT_ID.iam.gserviceaccount.com

export AGENT_APP_NAME="multi_tool_agent"

A continuación, crea la cuenta de servicio para el agente del ADK.

gcloud iam service-accounts create $SERVICE_ACCOUNT_ADK \
--display-name="Service account for adk agent on cloud run"

Otorga a la cuenta de servicio del ADK el rol de "Usuario de Vertex AI".

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS_ADK" \
  --role="roles/aiplatform.user"

Ahora, crea la cuenta de servicio para el frontend de Gradio

gcloud iam service-accounts create $SERVICE_ACCOUNT_GRADIO \
  --display-name="Service account for gradio frontend cloud run"

Además, otorga al frontend de Gradio el rol de invocador de Cloud Run, que le permitirá llamar al agente del ADK alojado en Cloud Run.

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS_GRADIO" \
  --role="roles/run.invoker"

4. Crea una app del ADK

En el siguiente paso, crearás el código para la aplicación de inicio rápido del ADK.

Nota: Al final del lab, la estructura de archivos debería verse de la siguiente manera:

- codelab-gradio-adk  <-- you'll deploy the ADK agent from here
  - gradio-frontend
    - app.py
    - requirements.txt
  - multi_tool_agent  <-- you'll deploy the gradio app from here
    - __init__.py
    - agent.py
    - requirements.txt

Primero, crea un directorio para el codelab general

mkdir codelab-gradio-adk
cd codelab-gradio-adk

Ahora, crea un directorio para el servicio del agente del ADK.

mkdir multi_tool_agent && cd multi_tool_agent

Crea un archivo __init__.py con el siguiente contenido:

from . import agent

Crea un archivo requirements.txt:

google-adk

Crea un archivo llamado agent.py.

import datetime
from zoneinfo import ZoneInfo
from google.adk.agents import Agent

def get_weather(city: str) -> dict:
    """Retrieves the current weather report for a specified city.

    Args:
        city (str): The name of the city for which to retrieve the weather report.

    Returns:
        dict: status and result or error msg.
    """
    if city.lower() == "new york":
        return {
            "status": "success",
            "report": (
                "The weather in New York is sunny with a temperature of 25 degrees"
                " Celsius (77 degrees Fahrenheit)."
            ),
        }
    else:
        return {
            "status": "error",
            "error_message": f"Weather information for '{city}' is not available.",
        }


def get_current_time(city: str) -> dict:
    """Returns the current time in a specified city.

    Args:
        city (str): The name of the city for which to retrieve the current time.

    Returns:
        dict: status and result or error msg.
    """

    if city.lower() == "new york":
        tz_identifier = "America/New_York"
    else:
        return {
            "status": "error",
            "error_message": (
                f"Sorry, I don't have timezone information for {city}."
            ),
        }

    tz = ZoneInfo(tz_identifier)
    now = datetime.datetime.now(tz)
    report = (
        f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}'
    )
    return {"status": "success", "report": report}


root_agent = Agent(
    name="weather_time_agent",
    model="gemini-2.5-flash",
    description=(
        "Agent to answer questions about the time and weather in a city."
    ),
    instruction=(
        "You are a helpful agent who can answer user questions about the time and weather in a city."
    ),
    tools=[get_weather, get_current_time],
)

5. Implementa el agente del ADK

En esta sección, implementarás el agente del ADK en Cloud Run. Luego, verificarás que la implementación haya funcionado con la IU web para desarrolladores que proporciona el ADK. Por último, necesitarás llamadas autenticadas a este servicio.

Navega a la carpeta principal.

NOTA: El código del agente del ADK debe incluir la carpeta multi_tool_agent como carpeta raíz.

cd ..

Primero, crea el servicio de Cloud Run:

NOTA: El parámetro --with_ui es opcional para realizar pruebas con la IU de desarrollo, como se muestra en un paso próximo:

NOTA: El comando -- te permite pasar marcas de línea de comandos al comando gcloud run deploy subyacente.

NOTA: uvx --from ejecuta un comando del paquete google-adk. uvx creará un entorno virtual temporal, instalará google-adk en él, ejecutará el comando especificado y, luego, destruirá el entorno.

uvx --from google-adk \
adk deploy cloud_run \
    --project=$PROJECT_ID \
    --region=$REGION \
    --service_name=adk-agent-cr \
    --with_ui \
    ./multi_tool_agent \
    -- \
    --service-account=$SERVICE_ACCOUNT_ADDRESS_ADK \
    --allow-unauthenticated

A continuación, guarda la URL como una variable de entorno que usarás en la segunda parte de este codelab.

AGENT_SERVICE_URL=$(gcloud run services describe adk-agent-cr --region $REGION --format 'value(status.url)')

Ahora, prueba el agente

Abre la URL del servicio en tu navegador web y pregunta tell me about the weather in new york. Deberías ver una respuesta similar a "El clima en Nueva York es soleado con una temperatura de 25 grados Celsius (77 grados Fahrenheit)".

Por último, protege el agente

Ahora, aseguraremos el acceso al agente. En la siguiente sección, implementarás un servicio de Cloud Run que realiza una llamada autenticada a este servicio de backend.

gcloud run services remove-iam-policy-binding adk-agent-cr \
  --member="allUsers" \
  --role="roles/run.invoker" \
  --region=$REGION

6. Implementa un frontend de Gradio

En este paso, crearás una interfaz de usuario de Gradio para tu agente de ADK.

Nota: Puedes tener la app de Gradio en el mismo servicio que el agente del ADK. En este codelab, se proporcionan 2 servicios separados para mostrar cómo realizar llamadas autenticadas de servicio a servicio en Cloud Run.

Primero, crea una app junto a la carpeta multi_tool_agent.

mkdir gradio-frontend && cd gradio-frontend

A continuación, crea un archivo requirements.txt que contenga lo siguiente:

gradio
requests
google-auth

Ahora, crea un archivo app.py

import gradio as gr
import requests
import json
import uuid
import os
import google.auth.transport.requests
import google.oauth2.id_token

# https://weather-time-service2-392295011265.us-west4.run.app
BASE_URL = os.environ.get("AGENT_SERVICE_URL")

# multi_tool_agent
APP_NAME = os.environ.get("AGENT_APP_NAME")

# Generate a unique user ID for each session of the Gradio app
USER_ID = f"gradio-user-{uuid.uuid4()}"

# API Endpoints
CREATE_SESSION_URL = f"{BASE_URL}/apps/{APP_NAME}/users/{USER_ID}/sessions"
RUN_SSE_URL = f"{BASE_URL}/run_sse"

def get_id_token():
    """Get an ID token to authenticate with the other Cloud Run service."""
    audience = BASE_URL
    request = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(request, audience)
    return id_token

def create_session() -> str | None:
    """Creates a new session and returns the session ID."""
    try:
        id_token = get_id_token()
        headers = {"Authorization": f"Bearer {id_token}"}
        response = requests.post(CREATE_SESSION_URL, headers=headers)
        response.raise_for_status()
        return response.json().get("id")
    except Exception as e:
        print(f"Error creating session: {e}")
        return None

def query_agent(prompt: str):
    """Sends a prompt to the agent and returns the streamed response."""
    session_id = create_session()
    if not session_id:
        return "Error: Could not create a session."

    id_token = get_id_token()
    headers = {
        "Content-Type": "application/json",
        "Accept": "text/event-stream",
        "Authorization": f"Bearer {id_token}",
    }
    payload = {
        "app_name": APP_NAME,
        "user_id": USER_ID,
        "session_id": session_id,
        "new_message": {"role": "user", "parts": [{"text": prompt}]},
        "streaming": True
    }

    full_response = ""
    try:
        with requests.post(RUN_SSE_URL, headers=headers, json=payload, stream=True) as response:
            response.raise_for_status()
            for chunk in response.iter_lines():
                if chunk and chunk.decode('utf-8').startswith('data:'):
                    json_data = chunk.decode('utf-8')[len('data:'):].strip()
                    try:
                        data = json.loads(json_data)
                        text = data.get("content", {}).get("parts", [{}])[0].get("text", "")
                        if text:
                            full_response = text
                    except json.JSONDecodeError:
                        pass # Ignore chunks that are not valid JSON
        return full_response
    except requests.exceptions.RequestException as e:
        return f"An error occurred: {e}"

iface = gr.Interface(
    fn=query_agent,
    inputs=gr.Textbox(lines=2, placeholder="e.g., What's the weather in new york?"),
    outputs="text",
    title="Weather and Time Agent",
    description="Ask a question about the weather or time in a specific location.",
)

if __name__ == "__main__":
    iface.launch()

7. Implementa y prueba tu app de Gradio

En este paso, implementarás la app de Gradio de frontend en Cloud Run.

Asegúrate de estar en el directorio de la app de Gradio.

pwd

Deberías ver codelab-gradio-adk/gradio-frontend

Ahora implementa tu app de Gradio.

Nota: Si bien este servicio de frontend de Gradio es un sitio web disponible públicamente, el servicio de backend requiere autenticación. Para ilustrar por qué podrías querer hacer esto, podrías agregar la autenticación de usuarios (p.ej., Firebase Auth) a este servicio de frontend y, luego, permitir que solo los usuarios que accedieron realicen llamadas al servicio de backend.

gcloud run deploy my-adk-gradio-frontend \
--source . \
--region $REGION \
--allow-unauthenticated \
--set-env-vars AGENT_SERVICE_URL=$AGENT_SERVICE_URL,AGENT_APP_NAME=$AGENT_APP_NAME \
--service-account=$SERVICE_ACCOUNT_ADDRESS_GRADIO

Una vez que se implemente, pregúntale a what's the weather in new york? y deberías obtener una respuesta similar a The weather in New York is sunny with a temperature of 25 degrees Celsius (77 degrees Fahrenheit)..

8. ¡Felicitaciones!

¡Felicitaciones por completar el codelab!

Te recomendamos que revises la documentación sobre el alojamiento de apps y agentes basados en IA.

Temas abordados

  • Cómo implementar un agente del ADK en Cloud Run
  • Cómo implementar una app de Gradio en Cloud Run
  • Cómo realizar llamadas autenticadas entre servicios en Cloud Run

9. Limpia

Para evitar cargos involuntarios, por ejemplo, si los servicios de Cloud Run se invocan de forma accidental más veces que tu asignación mensual de invocaciones de Cloud Run en el nivel gratuito, puedes borrar el servicio de Cloud Run que creaste en el paso 6.

Para borrar los servicios de Cloud Run, ve a la consola de Cloud Run en https://console.cloud.google.com/run y borra los servicios my-adk-gradio-frontend y adk-agent-cr.

Para borrar todo el proyecto, ve a Administrar recursos, selecciona el proyecto que creaste en el paso 2 y elige Borrar. Si borras el proyecto, deberás cambiar de proyecto en el SDK de Cloud. Para ver la lista de todos los proyectos disponibles, ejecuta gcloud projects list.