Lab práctico · Semana 8: Cumplimiento normativo e IA en Google Cloud

Llamar a Gemini en Agent Platform con REST y con el SDK

⏱ 45-60 minDificultad: básicaApartados: 2.51.3

Qué vas a construir

Nada que desplegar: vas a llamar a un modelo Gemini de Gemini Enterprise Agent Platform (antes Vertex AI) desde Cloud Shell, primero con la API REST y después con el Google Gen AI SDK para Python, vas a leer cuántos tokens consume cada llamada para estimar el coste, y vas a probar una respuesta con grounding with Google Search.

flowchart LR
  CS["Cloud Shell (tu usuario, ADC)"] -->|"generateContent"| EP["aiplatform.googleapis.com (location: global)"]
  EP --> M["Gemini 2.5 Flash"]
  M -->|"opcional: herramienta googleSearch"| GS["Google Search"]
  M -->|"texto + usageMetadata"| CS

Antes de empezar

  • Proyecto con facturación (lab-01-cuenta-y-presupuesto). Con el crédito gratuito el coste es despreciable.
  • En Cloud Shell ya estás autenticado; el SDK usa Application Default Credentials (ADC).
export PROJECT_ID=$(gcloud config get-value project)
export LOCATION=global
export MODEL_ID=gemini-2.5-flash
export API_ENDPOINT=https://aiplatform.googleapis.com

gcloud services enable aiplatform.googleapis.com

La API se llama ahora Agent Platform API, pero su nombre de servicio sigue siendo aiplatform.googleapis.com. Usamos la ubicación global, la que recomienda la guía de inicio; si tu caso exige residencia del dato, se usa un endpoint regional (p. ej. https://europe-west1-aiplatform.googleapis.com con LOCATION=europe-west1) siempre que el modelo esté disponible allí. Consulta la página de ubicaciones de Agent Platform antes de elegir.

Los identificadores de modelo cambian con frecuencia. Si gemini-2.5-flash ya no estuviera disponible, busca en Model Garden (consola: Agent Platform → Model Garden) el Flash vigente y cambia MODEL_ID.

Paso 1: primera llamada con REST

Construimos la URL con la forma projects/PROYECTO/locations/UBICACIÓN/publishers/google/models/MODELO:generateContent y nos autenticamos con un token OAuth de tu usuario.

cat > prompt.json <<'EOF'
{
  "contents": [{
    "role": "user",
    "parts": [{ "text": "Explica en tres frases qué es VPC Service Controls y para qué sirve, en español." }]
  }],
  "generationConfig": { "temperature": 0.2, "maxOutputTokens": 2048 }
}
EOF

curl -s -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  "${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/${MODEL_ID}:generateContent" \
  -d @prompt.json > respuesta.json

jq -r '.candidates[0].content.parts[0].text' respuesta.json
jq '.usageMetadata' respuesta.json

El límite de 2.048 tokens de salida es holgado a propósito: en los modelos con razonamiento, los tokens de «pensamiento» también consumen ese presupuesto y, si lo ajustas demasiado, la respuesta puede salir cortada o vacía.

usageMetadata muestra promptTokenCount (entrada), candidatesTokenCount (salida), thoughtsTokenCount (tokens de razonamiento interno, que se cobran como salida en los modelos que «piensan») y totalTokenCount.

Si recibes un error 403 de permisos, comprueba que eres Owner o que tienes roles/aiplatform.user. Si recibes un 404 del modelo, cambia MODEL_ID como se explica arriba.

Paso 2: calcular el coste de la llamada

Con los precios de Gemini 2.5 Flash vigentes en septiembre de 2026 (unos 0,30 USD por millón de tokens de entrada y 2,50 USD por millón de salida, según la página de precios), calcula el coste con jq:

jq '.usageMetadata as $u |
  (($u.promptTokenCount // 0) * 0.30 / 1000000) +
  ((($u.candidatesTokenCount // 0) + ($u.thoughtsTokenCount // 0)) * 2.50 / 1000000)' respuesta.json

Obtendrás algo del orden de milésimas de céntimo. Multiplícalo por el volumen previsto de una aplicación real (p. ej. 50.000 conversaciones al día) para entender por qué el coste por token es un requisito de diseño: modelo más pequeño (Flash-Lite), prompts más cortos, context caching, respuestas más breves o procesamiento por lotes con descuento.

También puedes contar tokens antes de llamar, sin generar respuesta:

curl -s -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  "${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/${MODEL_ID}:countTokens" \
  -d '{"contents":[{"role":"user","parts":[{"text":"¿Cuántos tokens tiene esta frase?"}]}]}'

Paso 3: la misma llamada con el Google Gen AI SDK

El SDK recomendado es google-genai. Se configura con variables de entorno; GOOGLE_GENAI_USE_ENTERPRISE=True le indica que use Agent Platform con tu proyecto (en documentación anterior verás GOOGLE_GENAI_USE_VERTEXAI).

python3 -m venv ~/venv-lab16 && source ~/venv-lab16/bin/activate
pip install --quiet --upgrade google-genai

export GOOGLE_CLOUD_PROJECT=$PROJECT_ID
export GOOGLE_CLOUD_LOCATION=global
export GOOGLE_GENAI_USE_ENTERPRISE=True

cat > llamada.py <<'EOF'
import os
from google import genai
from google.genai.types import GenerateContentConfig, HttpOptions

client = genai.Client(http_options=HttpOptions(api_version="v1"))
resp = client.models.generate_content(
    model=os.environ.get("MODEL_ID", "gemini-2.5-flash"),
    contents="Dame tres criterios para elegir entre RAG y fine-tuning. Responde en español y en viñetas.",
    config=GenerateContentConfig(
        temperature=0.2,
        max_output_tokens=2048,
        system_instruction="Eres un arquitecto de Google Cloud. Sé conciso.",
    ),
)
print(resp.text)
print(resp.usage_metadata)
EOF

python llamada.py

Fíjate en system_instruction: fija el comportamiento del modelo para toda la conversación. En una aplicación real es donde se definen tono, límites y formato.

Pregunta algo reciente que el modelo no puede saber por su entrenamiento, primero sin y luego con la herramienta de búsqueda:

cat > grounding.py <<'EOF'
import os
from google import genai
from google.genai.types import GenerateContentConfig, GoogleSearch, HttpOptions, Tool

client = genai.Client(http_options=HttpOptions(api_version="v1"))
pregunta = "¿Cuáles son las últimas novedades publicadas sobre Gemini Enterprise Agent Platform? Cita fuentes."
modelo = os.environ.get("MODEL_ID", "gemini-2.5-flash")

sin = client.models.generate_content(model=modelo, contents=pregunta)
print("=== SIN GROUNDING ===\n", sin.text)

con = client.models.generate_content(
    model=modelo,
    contents=pregunta,
    config=GenerateContentConfig(tools=[Tool(google_search=GoogleSearch())]),
)
print("\n=== CON GROUNDING ===\n", con.text)
meta = con.candidates[0].grounding_metadata
if meta and meta.grounding_chunks:
    print("\nFuentes:")
    for c in meta.grounding_chunks:
        if c.web:
            print("-", c.web.title, c.web.uri)
print("\nConsultas de búsqueda:", meta.web_search_queries if meta else None)
EOF

python grounding.py

La respuesta con grounding incluye metadatos de fuentes y las consultas que el modelo lanzó. Esto es lo que buscan los requisitos de «respuestas verificables» o «reducir alucinaciones» en los casos de estudio. Recuerda que el grounding con Google Search se factura por consulta a partir de un cupo gratuito mensual; unas pocas pruebas no cuestan nada apreciable.

Paso 5 (opcional): explorar en la consola

  • Agent Platform → Agent Studio: repite el prompt en el editor visual, cambia la temperatura y activa el grounding con un clic. Busca la opción para obtener el código equivalente del prompt (REST o SDK) y compárala con lo que has escrito.
  • Agent Platform → Model Garden: localiza Gemini, modelos de terceros y modelos abiertos como Gemma; observa las opciones de despliegue (API gestionada, endpoint propio, GKE).

Comprueba que funciona

  • El paso 1 imprime un texto en español y un bloque usageMetadata con recuentos de tokens.
  • El cálculo del paso 2 da un coste inferior a 0,001 USD por llamada.
  • En el paso 4, la versión con grounding muestra una lista de fuentes con URL y la versión sin grounding no.
  • En Billing → Reports, filtrando por el servicio de Agent Platform, verás el gasto al día siguiente (los informes no son en tiempo real).

Limpieza

No has creado recursos persistentes. Borra los ficheros locales y, si quieres, desactiva la API:

deactivate 2>/dev/null; rm -rf ~/venv-lab16 prompt.json respuesta.json llamada.py grounding.py
gcloud services disable aiplatform.googleapis.com --force

Desactivar la API es opcional; con ella activa no se cobra nada si no la llamas.

Preguntas para pensar como arquitecto

Una aplicación hará 2 millones de llamadas al mes con prompts de 3.000 tokens y respuestas de 300. ¿Qué palancas de coste propondrías?

Calcular primero: 6.000 millones de tokens de entrada y 600 millones de salida al mes. Palancas: elegir el modelo más pequeño que cumpla la calidad (Flash-Lite frente a Flash frente a Pro), reducir el prompt (instrucciones más cortas, recuperar menos fragmentos en RAG), context caching para la parte fija del prompt, limitar maxOutputTokens y el razonamiento, usar batch con descuento para lo que no sea interactivo y valorar Provisioned Throughput si el volumen es alto y estable.

¿Por qué el lab usa tu usuario y no una cuenta de servicio? ¿Qué cambiarías en producción?

En Cloud Shell ADC usa tus credenciales, lo cómodo para aprender. En producción la aplicación (Cloud Run, GKE) correría con una cuenta de servicio dedicada con roles/aiplatform.user (o el mínimo necesario), sin claves, y el proyecto estaría dentro de un perímetro de VPC Service Controls, con Model Armor filtrando prompts y respuestas.

¿Cuándo usarías grounding con Google Search y cuándo con Agent Search?

Google Search para información pública y reciente (noticias, datos generales). Agent Search (o RAG Engine) para información privada de la empresa (manuales, políticas, catálogo), respetando permisos y sin exponer los datos a la web. Muchos casos combinan ambos.

El equipo legal exige que los prompts con datos de clientes europeos se procesen en la UE. ¿Qué cambia?

Pasar de la ubicación global a un endpoint regional de la UE donde el modelo esté disponible, restringir ubicaciones con la política de organización, desidentificar PII con Sensitive Data Protection o Model Armor antes de enviar el prompt si no es necesaria, y revisar en la documentación de Agent Platform los compromisos de residencia y retención de datos del modelo elegido.


Volver al módulo