1. Descripción general
El panorama de la IA y la tecnología avanza más rápido de lo que cualquiera puede seguir. Todos los días se lanzan nuevos modelos, documentos y productos. Un agente de resúmenes que recupera los titulares del día, escribe resúmenes concisos y genera un PDF todas las mañanas resolvería ese problema, pero antes, crear uno significaba elegir un framework, definir herramientas en Python, escribir un bucle de orquestación, empaquetar un contenedor y realizar la implementación en Cloud Run. Todo eso antes de que el agente realizara una sola solicitud web.
Los agentes administrados en la API de Gemini cambian la ecuación. Escribes dos archivos de configuración de Markdown y una secuencia de comandos de renderizador prediseñada, realizas una llamada a la API y se inicia un entorno de pruebas real de Ubuntu, navegas por la Web, escribes tus resúmenes y generas un PDF. No hay contenedores. No hay implementación. No se requiere código de organización.
En este codelab, compilarás exactamente ese agente: desde una función vacía hasta un resumen diario funcional, un concepto a la vez.
Qué compilarás
- Crea y ejecuta tu primer agente administrado en una zona de pruebas de Linux real
- Personaliza el agente con instrucciones detalladas
- Descarga el resultado en PDF del agente
- Continúa la conversación para definir mejor el resumen sin volver a recuperar la Web.
- Guarda la configuración del agente y, luego, invócalo por ID en ejecuciones futuras
Requisitos
- Python 3.10 o versiones posteriores
- Una clave de API de Gemini con la facturación habilitada: aistudio.google.com/api-keys
- Aproximadamente USD 1 de crédito de API (cada ejecución completa cuesta entre USD 0.30 y USD 1.30)
2. ¿Qué son los agentes administrados en la API de Gemini?
Tres niveles de sistemas de IA
Antes de profundizar en el código, aquí se explica dónde encajan los agentes administrados en relación con las dos alternativas:
Nivel | De qué se trata | ¿Quién administra la infraestructura? |
LLM estándar | Tú le das una instrucción y ella responde con texto. Sin manos, sin memoria y sin Internet. | N/A: No puede hacer nada por sí solo. |
Agente autoalojado | Conectas ADK/LangChain/AutoGen + Docker + herramientas + memoria. | Tú: Todo (o una plataforma administrada como Agent Engine) |
Agente administrado | Le das un objetivo. Google aprovisiona una zona de pruebas segura. El agente escribe código, lo ejecuta, lee errores, busca en la Web y corrige errores de forma autónoma. | Google: todo |
Este codelab trata sobre la tercera fila. Proporcionas archivos de configuración y tareas. Google se encarga de todo lo demás.
Qué compilarías con el ADK y Cloud Run
Para compilar un agente de resumen de noticias que navegue por la Web, ejecute Python y genere un PDF, necesitarías todo esto con ADK y Cloud Run:
# agent.py: define tools and wire up the agent
from google.adk.agents import LlmAgent
from google.adk.tools import google_search, built_in_code_execution
agent = LlmAgent(
name="digest-agent",
model=MODEL,
instruction=AGENTS_MD, # your editorial voice and rules
tools=[google_search, built_in_code_execution],
)
# app.py: serve the agent over HTTP
from google.adk.runners import FastApiRunner
runner = FastApiRunner(agent=agent)
app = runner.app
# pdf_tool.py: custom tool, install reportlab, render PDF
# scraper.py: custom tool, fetch each news source
# streaming.py: wire agent events to your SSE endpoint
# Dockerfile: package everything
FROM python:3.12
COPY . /app
RUN pip install google-adk reportlab requests
CMD ["uvicorn", "app:app", "--host", "0.0.0.0"]
# Deploy to Cloud Run
gcloud run deploy digest-agent \
--image gcr.io/your-project/digest-agent \
--set-secrets GEMINI_API_KEY=gemini-key:latest \
--memory 2Gi
Esto es antes de que el agente se haya ejecutado una vez. Aún eres propietario del aislamiento de la zona de pruebas (por lo que el agente no puede dañar tu servidor), la instalación de paquetes, la administración de estados entre llamadas a herramientas y la infraestructura de transmisión para enviar eventos a un cliente.
Con qué reemplazan los agentes administrados
from google import genai
client = genai.Client()
stream = client.interactions.create(
agent="antigravity-preview-05-2026",
input="",
stream=True,
environment={
"type": "remote",
"sources": [ # your config files, mounted at startup
{
"type": "inline",
"target": ".agents/AGENTS.md",
"content": AGENTS_MD,
},
{
"type": "inline",
"target": ".agents/skills/digest-pdf/SKILL.md",
"content": SKILL_MD,
},
{
"type": "inline",
"target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
"content": GENERATE_PDF_PY,
},
],
},
)
Requisitos de ADK y Cloud Run | Qué tareas realizan los agentes administrados por ti |
Imagen de contenedor + Dockerfile + CI/CD | Zona de pruebas de Ubuntu completamente administrada (Python 3.12, Node 22, 4 CPU / 16 GB de RAM) |
Implementación y ajuste de escala de Cloud Run | Se aprovisiona por interacción y vence automáticamente después de 7 días de inactividad. |
Aislamiento de zona de pruebas | Aislamiento por interacción |
Herramienta de PDF personalizada + | El agente instala paquetes dentro de la zona de pruebas |
Infraestructura de transmisión de SSE |
|
Definiciones de herramientas en Python | Herramientas integradas: navegación web, ejecución de código y sistema de archivos |
Administración de estados entre llamadas a herramientas | Integrado en el bucle de razonamiento del agente |
Escribes archivos de configuración (AGENTS.md, SKILL.md, una secuencia de comandos prediseñada) y realizas una llamada a la API. Google se encarga de todo lo demás.
Cómo funciona la zona de pruebas
interactions.create() call
│
▼
Google provisions Ubuntu sandbox (Python 3.12, Node 22, 4 CPU / 16 GB RAM)
│
▼
Agent reasoning loop:
plan → fetch URLs → run Python → write files → reason → repeat
│
▼
Events stream back in real time: tool calls, text chunks, completion
│
▼
interaction.completed → environment_id + interaction_id
El entorno de pruebas persiste durante 7 días de inactividad. Puedes reanudarlo con environment_id para refinar el resultado, ejecutar tareas de seguimiento o bifurcarlo en un agente guardado con nombre.
3. Configurar
Opción A: Cloud Shell (recomendada)
Haz clic en el siguiente botón para abrir este codelab en Google Cloud Shell. Todas las dependencias están preinstaladas.
Opción B: Configuración local
git clone https://github.com/Saoussen-CH/tech-digest-managed-agent.git
cd tech-digest-managed-agent
Instala uv si es necesario:
curl -LsSf https://astral.sh/uv/install.sh | sh
Configura tu clave de API
cp .env.example .env
cloudshell edit .env
Configura tu llave:
GEMINI_API_KEY=your-key-here
Instala dependencias
uv sync
4. Realiza tu primera llamada al agente
Abre el archivo de inicio
cloudshell edit run_digest.py
run_digest() tiene un TODO para completar ahora y tres más para el siguiente paso. Ya hay dos asistentes completados previamente arriba:
load_source(path): Lee un archivo de.agents/en relación con la secuencia de comandos. La usarás en el próximo ejercicio para activar el comentario editorial, la guía en PDF y el procesador en la zona de pruebas.run_stream(stream): Procesa el flujo de eventos y devuelve(environment_id, interaction_id). No es necesario que escribas el bucle de eventos por tu cuenta.
Qué agregar
TODO 1: Reemplaza pass por (por ahora, ignora los comentarios TODO 3 y 4, ya que son para el siguiente paso):
from google import genai
client = genai.Client()
stream = client.interactions.create(
agent=BASE_AGENT,
input="Fetch the Hacker News front page and list the top 5 stories.",
stream=True,
environment="remote",
)
environment_id, interaction_id = run_stream(stream)
print(f"\nDone. environment_id={environment_id}")
Qué hace cada parte
genai.Client() lee GEMINI_API_KEY del entorno. Todo lo demás pasa por este cliente.
interactions.create() es la llamada principal. Cuatro parámetros hacen que funcione:
agent=BASE_AGENT: Selecciona el agente de Antigravity (antigravity-preview-05-2026), un agente administrado de uso general potenciado por Gemini 3.5 Flash. Incluye tres herramientas integradas habilitadas de forma predeterminada:code_execution(ejecuta Bash, Python y Node.js),google_searchyurl_context(recupera y lee páginas web). Las herramientas del sistema de archivos (read_file,write_file,list_files) se habilitan automáticamente cuando pasas el parámetroenvironment. Una llamada aprovisiona un entorno de Ubuntu completamente administrado con Python 3.12, Node.js 22, git, pip y curl preinstalados. No hay contenedor para compilar ni implementación para ejecutar.input: Es la tarea de esta ejecución. El agente navega por Hacker News y razona sobre los resultados.environment="remote": Aprovisiona una zona de pruebas de Cloud nueva para esta interacción.stream=True: Devuelve un iterable de eventos en lugar de bloquearse. Sin él, la llamada espera entre 30 y 90 segundos y devuelve toda la salida de una vez comointeraction.output_text. Con la transmisión, ves el motivo del agente y actúas a medida que sucede. La transmisión no es una función avanzada aquí: es el valor predeterminado correcto, ya que una caja negra de 90 segundos no te da ninguna señal sobre si el agente está funcionando o atascado.
Lo que acabas de aprovisionar: Cada llamada a interactions.create() inicia una zona de pruebas dedicada:
Componente | Especificación |
Sistema operativo | Entorno aislado de Ubuntu Linux |
Entornos de ejecución preinstalados | Python 3.12, Node.js 22 y Bash |
Procesamiento | 4 núcleos de CPU y 16 GB de RAM |
Administración del contexto | La autocompactación se activa con alrededor de 135 000 tokens. |
Redes | Acceso web saliente a través del proxy de salida |
El agente puede instalar cualquier paquete con pip o npm, leer y escribir archivos, y realizar solicitudes web salientes. Nunca se manipulan tu máquina ni tus credenciales.
environment_id es un identificador de la zona de pruebas que acaba de ejecutarse. Después de interaction.completed, el entorno de pruebas no se apaga, sino que permanece activo hasta por 7 días. El environment_id es la forma de volver a ella. Pásalo a una segunda llamada a interactions.create() y el agente se reanudará en el mismo sistema de archivos, con los mismos archivos y paquetes instalados, como si nunca se hubiera ido. El siguiente paso lo usa para descargar el PDF sin volver a ejecutar el agente, y el paso posterior lo usa para continuar la conversación.
interaction_id es un identificador del turno de conversación que acaba de completarse. Pásalo como previous_interaction_id en la siguiente llamada, y el agente tendrá memoria completa de lo que dijo y realizó en este turno.
Verificar
uv run python run_digest.py
Deberías ver el resultado en vivo a medida que el agente trabaja:
[agent started]
[tool] run_code
Here are the top 5 stories currently on the Hacker News front page, retrieved via the official Hacker News API:
1. **Qwen 3.6 27B is the sweet spot for local development** — 471 points
2. **.self: A new top-level domain designed to support self-hosting** — 116 points
...
Done. environment_id=e3de58774073f75a6ef42924c6ce2e88
La API devuelve un environment_id real incluso con environment="remote". Se ejecutó la zona de pruebas. Lo que falta es la configuración: no hay voz, no hay habilidad, no hay generador de PDF. El agente solo imprimió historias como texto y se detuvo. En el siguiente paso, se agregarán esos elementos.
Cada línea de resultado se asigna a un evento de run_stream():
| Qué es | Qué imprime |
| El agente recupera una URL |
|
| Agente que ejecuta código en la zona de pruebas |
|
| El agente busca en la Web. |
|
| Herramientas de archivos y otras |
|
| El agente está escribiendo texto. | se transmite directamente a stdout |
5. Personaliza el agente
El agente no tenía instrucciones: no tenía voz, no tenía habilidad y no tenía generador de PDF. En este paso, cargarás los archivos de configuración de .agents/ y los activarás en el entorno de pruebas.
Qué cambiar
Realiza cuatro cambios en run_digest.py:
TODO 2: Debajo de load_source(), agrega las tres constantes a nivel del módulo (se encuentran fuera de run_digest(), en la parte superior del archivo):
AGENTS_MD = load_source(".agents/AGENTS.md")
SKILL_MD = load_source(".agents/skills/digest-pdf/SKILL.md")
GENERATE_PDF_PY = load_source(".agents/skills/digest-pdf/scripts/generate_pdf.py")
Abre cada archivo para ver lo que cargas: AGENTS.md establece el comentario editorial y las reglas del flujo de trabajo; SKILL.md es la guía paso a paso en formato PDF; generate_pdf.py es el renderizador prediseñado que ejecutará el agente.
Ahora, realiza dos cambios más dentro de run_digest():
TODO 3: Cambia environment de "remote" al diccionario de fuentes y establece input en "":
environment={
"type": "remote",
"sources": [
{
"type": "inline",
"target": ".agents/AGENTS.md",
"content": AGENTS_MD,
},
{
"type": "inline",
"target": ".agents/skills/digest-pdf/SKILL.md",
"content": SKILL_MD,
},
{
"type": "inline",
"target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
"content": GENERATE_PDF_PY,
},
],
},
TODO 4: Agrega estas líneas justo después de print(f"\nDone. environment_id={environment_id}"):
set_key(".env", "ENVIRONMENT_ID", environment_id)
set_key(".env", "INTERACTION_ID", interaction_id)
(set_key ya se importó en la parte superior de run_digest.py).
Esto escribe ambos IDs en .env durante esta ejecución, por lo que el siguiente paso puede descargar el PDF sin volver a ejecutar el agente.
Qué hace cada fuente
Cada fuente es un archivo activado en el sistema de archivos de la zona de pruebas al inicio, antes de que se ejecute el agente. Las rutas de target coinciden con las ubicaciones en las que se espera que se encuentren los arneses antigravedad:
.agents/
├── AGENTS.md ← auto-loaded as global instructions
└── skills/
└── digest-pdf/
├── SKILL.md ← auto-discovered and registered as a skill
└── scripts/
└── generate_pdf.py ← pre-built renderer the agent can run
Ruta de acceso | Variable | Qué hace el arnés con el cable |
|
| Se cargan automáticamente como instrucciones persistentes: comentario editorial, flujo de trabajo y reglas de ejecución |
|
| Se descubre y registra automáticamente como una habilidad con nombre; el agente la invoca por su nombre. |
|
| Renderizador de PDF compilado previamente: El agente escribe |
Verificar
uv run python run_digest.py
La ejecución ahora tarda de 1 a 3 minutos. Deberías ver que el agente lee los archivos de configuración, escribe resúmenes y guarda el PDF:
[agent started]
[tool] read_file (/.agents/skills/digest-pdf/SKILL.md)
[tool] list_files (/.agents/skills/digest-pdf/scripts)
[tool] read_file (/.agents/skills/digest-pdf/scripts/generate_pdf.py)
[tool] run_code
[tool] write_file (/workspace/summaries.json)
[tool] run_code
[tool] delete_file (/tmp/test_scrape.py)
I have successfully generated today's tech news digest and saved the formatted document to /workspace/digest.pdf.
Done. environment_id=4129ffd75574e308748e9425d7ec828f
environment_id ahora es un valor real: el entorno de pruebas se ejecutó con tus archivos de configuración y el agente creó digest.pdf. En el siguiente paso, se descargará.
6. Descargue el PDF.
El agente escribió digest.pdf en /workspace/digest.pdf dentro de la zona de pruebas. La instantánea del entorno está disponible como un archivo tar a través de la API de Gemini Files.
Instala requests si es necesario:
uv pip install requests
Qué completar
Abre download_pdf.py. Tiene dos TODOs.
TODO 1: Completa la llamada a requests.get():
r = requests.get(
f"https://generativelanguage.googleapis.com/v1beta/files/environment-{environment_id}:download",
params={"alt": "media"},
headers={"x-goog-api-key": api_key},
allow_redirects=True,
)
r.raise_for_status()
La URL dirige a la instantánea del entorno aislado. params={"alt": "media"} devuelve bytes sin procesar en lugar de metadatos. Tu GEMINI_API_KEY existente también autentica la API de Files.
TODO 2: Busca y extrae el PDF del archivo tar:
member = next(m for m in tar.getmembers() if m.name.endswith("workspace/digest.pdf"))
tar.extract(member, path=tmp, filter="data")
El prefijo de la ruta de acceso de tar varía entre las ejecuciones, por lo que se recomienda buscar por sufijo en lugar de codificar la ruta de acceso exacta. filter="data" suprime la advertencia de obsolescencia de Python 3.13 sobre la extracción de archivos tar no seguros.
Verificar
uv run python download_pdf.py
Saved digest.pdf (48,231 bytes)
Abre digest.pdf en el mismo directorio. Contiene el resumen con formato que el agente generó a partir de páginas web en vivo.
7. Continúa la conversación
Ya tienes digest.pdf. Si solo querías el archivo, ya terminaste. Este paso se trata de algo diferente: pedirle al agente que cambie el resumen sin volver a recuperar la Web.
La zona de pruebas sigue activa. El agente aún tiene /workspace/digest.pdf y recuerda cada historia que resumió. Una segunda llamada a interactions.create() envía un mensaje de seguimiento al mismo entorno de pruebas. Aquí le pides que agregue una nota de "Por qué es importante" debajo de cada historia, y actualiza el PDF en su lugar, sin volver a recuperar ni resumir.
Qué completar
Abre refine_digest.py. Tiene tres tareas pendientes.
TODOs 1 y 2: Completa los dos parámetros de varias turnos dentro de interactions.create():
environment=environment_id,
previous_interaction_id=interaction_id,
environment=environment_id reanuda el mismo entorno de pruebas con sus archivos y paquetes. previous_interaction_id=interaction_id le proporciona al agente su historial de conversaciones. No cambia nada más desde la primera llamada.
TODO 3: Persiste el nuevo interaction_id en .env después del bucle de eventos:
set_key(".env", "INTERACTION_ID", interaction_id)
Cada llamada a interactions.create() produce un nuevo interaction_id. Volver a escribirlo significa que la próxima ejecución pasará este refinamiento como previous_interaction_id, y las encadenaciones se activarán correctamente. El ID de zona de pruebas nunca cambia, por lo que no es necesario actualizar ENVIRONMENT_ID.
Los dos parámetros que hacen que funcione el chat de varios turnos
ID | Qué conserva | Analogía |
| Archivos, paquetes instalados, estado del sistema: todo en el sistema de archivos de Linux | Mantener el mismo escritorio de oficina entre reuniones |
| Historial de conversaciones: Lo que el agente dijo e hizo en turnos anteriores | Recordar lo que se habló en la última reunión |
Puedes pasar cualquiera de los IDs de forma independiente:
- Solo en
environment_id: Reutiliza archivos y paquetes, pero inicia una conversación nueva. Es útil para una tarea nueva en el mismo espacio de trabajo. - Solo
previous_interaction_id: Continúa el contexto de la conversación, pero en un sandbox nuevo (los archivos desaparecieron). - Ambos: Continuidad completa, que es lo que usa este paso.
Sin environment_id: Zona de pruebas en blanco, sin PDF. Sin previous_interaction_id: No hay contexto, el agente no puede refinar una sección específica.
Verificar
uv run python refine_digest.py
La transmisión debe ser rápida, ya que el agente no vuelve a recuperar nada. Después de que finalice, haz lo siguiente:
Refinement done.
Saved digest_v2.pdf (52,418 bytes)
Abre digest_v2.pdf y compáralo con digest.pdf. Cada historia ahora debería tener una línea de "Por qué es importante" agregada.
8. Cómo conservar la configuración de un agente administrado
Hasta ahora, cada llamada pasó AGENTS.md, SKILL.md y generate_pdf.py de forma intercalada. Eso funciona, pero tu código de llamada transporta el contenido completo del archivo en cada ejecución. agents.create() incorpora la configuración en un agente con nombre guardado del lado de Google. La siguiente invocación solo pasa el ID del agente:
Inline calls: send sources on every call
Named agent: bake once → invoke by ID, no sources
Qué completar
Abre save_agent.py. Tiene una tarea pendiente (TODO 1).
Observa que las constantes se importan directamente desde run_digest.py (sin duplicación):
from run_digest import BASE_AGENT, AGENTS_MD, SKILL_MD, GENERATE_PDF_PY
TODO 1: Completa la llamada a agents.create():
agent = client.agents.create(
id="my-digest",
base_agent=BASE_AGENT,
description="Daily tech digest with editorial voice and PDF generation.",
base_environment={
"type": "remote",
"sources": [
{
"type": "inline",
"target": ".agents/AGENTS.md",
"content": AGENTS_MD,
},
{
"type": "inline",
"target": ".agents/skills/digest-pdf/SKILL.md",
"content": SKILL_MD,
},
{
"type": "inline",
"target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
"content": GENERATE_PDF_PY,
},
],
},
)
base_environment (no environment) es la diferencia clave con la llamada intercalada del paso anterior: las fuentes se almacenan del lado de Google y se activan automáticamente en cada invocación futura. Ejecútalo una vez, no en cada ejecución del resumen.
Verifica y guarda el agente
uv run python save_agent.py
Saved: my-digest
my-digest: Daily tech digest with editorial voice and PDF generation.
Invoca el agente guardado
Abre invoke_agent.py. Llama al agente guardado por ID sin fuentes:
stream = client.interactions.create(
agent="my-digest",
input="",
stream=True,
environment="remote",
)
Compara esto con la llamada intercalada: agent=BASE_AGENT se reemplaza por "my-digest", y el bloque environment completo con tres fuentes intercaladas se reemplaza por environment="remote". La configuración ya está integrada en el sistema de Google.
Verifica: Invoca el agente guardado
uv run python invoke_agent.py
Deberías ver la misma transmisión en vivo que la ejecución intercalada, pero la llamada no contiene archivos fuente. Después de la ejecución, se actualizan ENVIRONMENT_ID y INTERACTION_ID en .env para que puedas continuar con refine_digest.py como antes.
[agent started]
[tool] read_file
[tool] write_file
[tool] run_code
I have successfully created today's tech news digest.
Done. environment_id=9a1c3e02-...
9. Limpieza
El sandbox vence automáticamente después de 7 días de inactividad. No hay servidores para detener. No hay contenedores para borrar.
Si guardaste una configuración del agente, bórrala:
uv run python delete_agent.py
10. Resumen
Compilaste un agente administrado desde cero, un concepto a la vez. A continuación, se explica lo que enseñó cada ejercicio:
Ejercicio | Concepto | API de Key |
Realiza tu primera llamada | Aprovisiona un sandbox de Linux real y transmite sus eventos en vivo |
|
Personaliza el agente | Se montan los archivos de configuración y se conservan los IDs en |
|
Descargue el PDF. | Descarga el PDF sin volver a ejecutar el agente | API de Gemini Files |
Continúa la conversación | Continúa la conversación sin volver a buscar en la Web |
|
Persiste la configuración del agente | Persiste la configuración del agente; invoca por ID, no se necesitan fuentes |
|
Patrones de clave
- Una llamada, una zona de pruebas:
interactions.create()controla toda la infraestructura (no hay contenedores para implementar ni paquetes para instalar de forma local). - Transmisión progresiva:
stream=Trueconvierte un cuadro negro de 90 segundos en un feed en vivo de llamadas a herramientas y fragmentos de texto - Fuentes intercaladas: Se montan
AGENTS.md,SKILL.mdy secuencias de comandos prediseñadas en el entorno de pruebas sin ningún paso de carga o implementación. - Detección automática de arneses: Los archivos colocados en
.agents/se detectan automáticamente (no se requiere configuración del SDK). - Estado bidimensional:
environment_idhace un seguimiento de los archivos y paquetes;previous_interaction_idhace un seguimiento del contexto de la conversación; cualquiera de los dos se puede pasar de forma independiente - Descarga de instantáneas: El entorno es un archivo tar del sistema de archivos completo, al que se puede acceder a través de la API de Gemini Files.
- Agentes con nombre:
agents.create()incorpora la configuración de forma permanente; las llamadas futuras solo pasan el ID del agente yenvironment="remote", sin fuentes.
ADK + Cloud Run vs. agentes administrados: la diferencia en un vistazo
Función | ADK y Cloud Run | Agentes administrados en la API de Gemini |
Aprovisiona una zona de pruebas |
|
|
Define herramientas | Funciones de Python registradas en el agente | Integradas: navegación web, ejecución de código, sistema de archivos |
Instalar paquetes |
| El agente ejecuta |
Eventos de transmisión | Infraestructura de SSE personalizada |
|
Cómo continuar una sesión | Base de datos de sesión + inserción de contexto |
|
Archivos de configuración | Codificado de forma rígida en el agente o insertado en el inicio | Se montó con |
Infraestructura para administrar | Contenedor, Cloud Run, IAM, secretos | Ninguno |