Crea agentes personalizados y con estado con el ADK

1. Introducción

título

El problema del "pez dorado"

Imagina que contratas a un agente de viajes para que planifique las vacaciones de tus sueños en Tokio. Usa el agente de sesión para ver "The Goldfish Problem" en acción.

Entras a su oficina y dices:

“¡Hola! Quiero planificar un viaje de 2 días a Tokio. Me interesan los sitios históricos y el sushi".

El agente responde con entusiasmo:

“Excelente. Planeé una visita al Palacio Imperial y una cena de sushi en Sukiyabashi Jiro".

Sonríes y dices:

"¡Suena perfecto! ¿Me puedes enviar el itinerario?".

El agente te mira con expresión de desconcierto y te pregunta:

“¡Hola! ¿En qué puedo ayudarte hoy?"

Este es el "problema del pez dorado". Sin memoria, cada interacción es un lienzo en blanco. La inteligencia está ahí: el agente sabe cómo planificar viajes, pero falta la continuidad. Para que un agente de IA sea realmente útil, debe recordar.

Tu misión de hoy

En este taller, resolverás el problema de Goldfish creando un agente de viajes que recuerda, aprende y se adapta. Avanzarás por 6 niveles de memoria de agentes y crearás un sistema que se comporte menos como un chatbot y más como un asistente personal dedicado.

Nivel

Concepto

El "superpoder"

Nivel 1

Sesión y estado

Mantener una conversación sin olvidar

Nivel 2

Estado de varios agentes

Compartir notas entre los miembros del equipo

Nivel 3

Persistencia

Recordarte incluso después de reiniciar el sistema

Nivel 4

Devoluciones de llamada

Actualizando la memoria de forma completamente autónoma

Nivel 5

Herramientas personalizadas

Lectura y escritura de perfiles de usuario estructurados

Nivel 6

Memoria multimodal

Cómo "ver" y recordar fotos y videos

La pila de memoria del ADK

Antes de escribir código, comprendamos las herramientas que usaremos. El Kit de desarrollo de agentes (ADK) de Google proporciona una forma estructurada de controlar la memoria:

  1. Sesión: Es el contenedor de una conversación. Contiene el historial de lo que se dijo.
  2. Estado: Es un "bloc de notas" de par clave-valor adjunto a la sesión. Los agentes usan este tipo de almacenamiento para guardar datos específicos (p.ej., destination="Tokyo").
  3. MemoryService: Almacenamiento a largo plazo. Aquí es donde guardamos los datos de forma permanente, como las preferencias del usuario o los documentos analizados.

2. Configurar

Para potenciar nuestros agentes de IA, necesitamos dos cosas: un proyecto de Google Cloud que proporcione la base

Parte 1: Habilita la cuenta de facturación

Para ejecutar este codelab, necesitas una cuenta de facturación con crédito. Usa los créditos del banner que se encuentra en la parte superior de este codelab para comenzar. Si ya tienes una cuenta de facturación conectada, puedes omitir este paso.

Parte dos: Abre el entorno

  1. 👉 Haz clic en este vínculo para navegar directamente al editor de Cloud Shell.
  2. 👉 Si se te solicita autorización en algún momento, haz clic en Autorizar para continuar. Haz clic para autorizar Cloud Shell
  3. 👉 Si la terminal no aparece en la parte inferior de la pantalla, ábrela:
    • Haz clic en Ver.
    • Haz clic en Terminal.Abre una terminal nueva en el editor de Cloud Shell
  4. 👉💻 En la terminal, verifica que ya te hayas autenticado y que el proyecto esté configurado con tu ID del proyecto. Para ello, usa el siguiente comando:
    gcloud auth list
    
  5. 👉💻 Clona el proyecto de arranque desde GitHub:
    git clone https://github.com/cuppibla/memory_agent_starter
    
    
  6. 👉💻 Ejecuta la secuencia de comandos de configuración desde el directorio del proyecto.
    cd ~/memory_agent_starter
    ./init.sh
    
    La secuencia de comandos se encargará del resto del proceso de configuración automáticamente.
  7. 👉💻 Establece el ID del proyecto necesario:
    gcloud config set project $(cat ~/project_id.txt) --quiet
    

Parte tres: Configura los permisos

  1. 👉💻 Habilita las APIs requeridas con el siguiente comando. Esto puede tardar algunos minutos.
    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        servicenetworking.googleapis.com \
        run.googleapis.com \
        aiplatform.googleapis.com \
        compute.googleapis.com
    
  2. 👉💻 Ejecuta los siguientes comandos en la terminal para otorgar los permisos necesarios:
    . ~/memory_agent_starter/set_env.sh
    

Observa que se crea un archivo .env. Se mostrará la información de tu proyecto.

3. La base: Sesión y estado

con estado

El concepto: El contexto es lo más importante

La forma más básica de memoria es la memoria de sesión. Esto es lo que permite que un agente sepa que "lo" en la oración "Quiero comprarlo" se refiere al calzado del que hablabas hace 10 segundos.

En el ADK, lo administramos con el objeto Session.

  • Enfoque sin estado: Se crea una sesión nueva para cada mensaje.
  • Enfoque con estado: Se crea una sesión y se vuelve a usar para toda la conversación.

Paso 1: Examina el agente

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/01_session_agent/agent.py

Abre ~/memory_agent_starter/01_session_agent/agent.py.

👉 Ubica el comentario # TODO: Create a root agent dentro de la función agent.py.

Reemplaza toda esta línea por el siguiente código:

root_agent = LlmAgent(
    name="multi_day_trip_agent",
    model="gemini-2.5-flash",
    description="Agent that progressively plans a multi-day trip, remembering previous days and adapting to user feedback.",
    instruction="""
    You are the "Adaptive Trip Planner" 🗺️ - an AI assistant that builds multi-day travel itineraries step-by-step.

    Your Defining Feature:
    You have short-term memory. You MUST refer back to our conversation to understand the trip's context, what has already been planned, and the user's preferences. If the user asks for a change, you must adapt the plan while keeping the unchanged parts consistent.

    Your Mission:
    1.  **Initiate**: Start by asking for the destination, trip duration, and interests.
    2.  **Plan Progressively**: Plan ONLY ONE DAY at a time. After presenting a plan, ask for confirmation.
    3.  **Handle Feedback**: If a user dislikes a suggestion (e.g., "I don't like museums"), acknowledge their feedback, and provide a *new, alternative* suggestion for that time slot that still fits the overall theme.
    4.  **Maintain Context**: For each new day, ensure the activities are unique and build logically on the previous days. Do not suggest the same things repeatedly.
    5.  **Final Output**: Return each day's itinerary in MARKDOWN format.
    """,
    tools=[google_search]
)

La instrucción le indica al LLM que recuerde, pero el código debe proporcionar la capacidad para recordar.

Paso 2: Las dos situaciones

Abre ~/memory_agent_starter/01_session_agent/main.py.

👉 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/01_session_agent/main.py

Abre ~/memory_agent_starter/01_session_agent/main.py y busca el comentario # TODO: Create a runner with in memorysession service dentro de la función main.py.

Reemplaza toda esta línea por el siguiente código:

    runner = Runner(
        agent=agent,
        session_service=session_service,
        app_name=agent.name
    )

👉 Ubica el comentario # TODO: create a different session to test dentro de la función main.py.

Reemplaza toda esta línea por el siguiente código:

    tokyo_session_2 = await session_service.create_session(
        app_name=multi_day_agent.name,
        user_id=user_id
    )

Pruébalo

Tenemos dos funciones que demuestran la diferencia entre la memoria de "pez dorado" y la de "elefante".

Situación 1: Con estado (sesión compartida)

async def run_trip_same_session_scenario(session_service, user_id):
    # 1. Create ONE session
    trip_session = await session_service.create_session(...)

    # 2. Turn 1
    await run_agent_query(..., trip_session, ...)

    # 3. Turn 2 - REUSING the same session!
    # The agent can "see" Turn 1 because it's in the session history.
    await run_agent_query(..., trip_session, ...)

Situación 2: Sin estado (sesión nueva cada vez)

async def run_trip_different_session_scenario(session_service, user_id):
    # Turn 1
    tokyo_session = await session_service.create_session(...)
    await run_agent_query(..., tokyo_session, ...)

    # Turn 2 - Creating a FREASH session
    # The agent has NO IDEA what happened in Turn 1.
    tokyo_session_2 = await session_service.create_session(...)
    await run_agent_query(..., tokyo_session_2, ...)

Paso 3: Ejecuta el agente

Veamos la diferencia en acción. Ejecuta la secuencia de comandos:

👉💻 En la línea de comandos, ejecuta el siguiente comando:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/01_session_agent/main.py

Observa la situación 1: El agente recuerda tus preferencias del primer mensaje y adapta el plan en el segundo mensaje.

Observa la situación 2: En el segundo turno ("¿recuerdas qué me gustó de la comida?"), el agente falla por completo porque es una sesión nueva. En efecto, dice: "No sé de qué estás hablando".

Conclusión clave

Regla n° 1 de la memoria: Siempre reutiliza el session.id para mantener el contexto de la conversación. El objeto Session es el búfer de memoria a corto plazo de tu agente.

4. El equipo: Estado de varios agentes

comida

El concepto: "El teléfono descompuesto"

Cuando varios agentes trabajan juntos, son como colegas que se pasan una carpeta de archivos de un lado a otro. Si un agente escribe una nota en la carpeta, el siguiente agente debería poder leerla.

En el ADK, esta "carpeta" es el estado.

  • El estado es un diccionario ({"key": "value"}) que se encuentra dentro de la sesión.
  • Cualquier agente de la sesión puede leer o escribir en ella.

Paso 1: Examina el flujo de trabajo

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/02_multi_agent/agent.py

👉En el archivo ~/memory_agent_starter/02_multi_agent/agent.py, busca el comentario # TODO: foodie agent.

Reemplaza toda esta línea por el siguiente código:

foodie_agent = LlmAgent(
    name="foodie_agent",
    model="gemini-2.5-flash",
    tools=[google_search],
    instruction="""You are an expert food critic. Your goal is to find the best restaurant based on a user's request.

    When you recommend a place, you must output *only* the name of the establishment and nothing else.
    For example, if the best sushi is at 'Jin Sho', you should output only: Jin Sho
    """,
    output_key="destination"  # ADK will save the agent's final response to state['destination']
)

👉 Ubica el comentario # TODO: transportation agent dentro de la función agent.py.

Reemplaza toda esta línea por el siguiente código:

transportation_agent = LlmAgent(
    name="transportation_agent",
    model="gemini-2.5-flash",
    tools=[google_search],
    instruction="""You are a navigation assistant. Given a destination, provide clear directions.
    The user wants to go to: {destination}.

    Analyze the user's full original query to find their starting point.
    Then, provide clear directions from that starting point to {destination}.
    """,
)

👉 Ubica el comentario # TODO: root_agent dentro de la función agent.py.

Reemplaza toda esta línea por el siguiente código:

root_agent = SequentialAgent(
    name="find_and_navigate_agent",
    sub_agents=[foodie_agent, transportation_agent],
    description="A workflow that first finds a location and then provides directions to it."
)

Ahora tenemos dos agentes que trabajan en una secuencia:

  1. Agente Foodie: Busca un restaurante.
  2. Agente de transporte: Proporciona instrucciones sobre cómo llegar a ese restaurante.

El traspaso mágico: Observa cómo foodie_agent le pasa la posta a transportation_agent.

foodie_agent = LlmAgent(
    # ...
    # CRITICAL: This tells ADK to save the agent's output to state['destination']
    output_key="destination"
)

transportation_agent = LlmAgent(
    # ...
    # CRITICAL: This injects state['destination'] into the prompt
    instruction="""
    The user wants to go to: {destination}.
    Provide clear directions...
    """,
)
  1. output_key="destination": La respuesta del agente Foodie se guarda de manera eficiente.
  2. {destination}: El agente de transporte lee esa respuesta automáticamente.

(No se requiere ninguna acción) Paso 2: El organizador

Abre 02_multi_agent/main.py.

Usamos un SequentialAgent para ejecutarlos en orden.

# 1. Create a single session for the sequential agent
session = await session_service.create_session(...)

# 2. Run the query
# The SequentialAgent manages the state flow:
# Query -> Foodie -> state['destination'] -> Transportation -> Final Answer
await run_agent_query(root_agent, query, ...)

El usuario envía una instrucción:

"Find best sushi in Palo Alto and then tell me how to get there."

Los agentes trabajan en conjunto para responderla.

Paso 3: Dirige el equipo

👉💻 En la terminal de Cloud Shell, ejecuta el flujo de trabajo de varios agentes:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/02_multi_agent/main.py

¿Qué sucede?

  1. Agente de comida: Encuentra "Jin Sho" (o similar).
  2. ADK: Guarda "Jin Sho" en state['destination'].
  3. Agente de transporte: Recibe "Jin Sho" en su instrucción.
  4. Resultado: "Para llegar a Jin Sho desde la estación de Caltrain, camina por University Ave..."

Conclusión clave

Regla n° 2 de la memoria: Usa el estado para pasar información estructurada entre agentes. Usa output_key para escribir y {placeholders} para leer.

5. El reinicio: Persistencia

con estado

El concepto: "El problema del reinicio"

Hasta ahora, nuestra memoria ha sido InMemory. Si detienes la secuencia de comandos y la vuelves a iniciar, el agente olvidará todo. Es como una computadora que borra su disco duro cada vez que la apagas.

Para solucionar este problema, necesitamos la persistencia. Intercambiamos InMemorySessionService por DatabaseSessionService.

Paso 1: El cambio de base de datos

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/03_persistent_agent/main.py

👉 En el archivo ~/memory_agent_starter/03_persistent_agent/main.py, busca el comentario # TODO: Configuration for Persistent Sessions.

Reemplaza toda esta línea por el siguiente código:

SESSIONS_DIR = Path(os.path.expanduser("~")) / ".adk_codelab" / "sessions"
os.makedirs(SESSIONS_DIR, exist_ok=True)
SESSION_DB_FILE = SESSIONS_DIR / "trip_planner.db"
SESSION_URL = f"sqlite:///{SESSION_DB_FILE}"

Ahora, cada sesión y evento se guardan en un archivo SQLite.

Paso 2: Recuperación entre sesiones

La persistencia permite no solo reanudar una conversación, sino también aprender de las anteriores.

En el mismo archivo ~/memory_agent_starter/03_persistent_agent/main.py, consulta el caso de prueba 3: Recuperación entre sesiones.

👉 Busca el comentario # TODO: retrieve the previous session manually.

Reemplaza toda esta línea por el siguiente código:

    old_session = await session_service.get_session(
        app_name=root_agent.name, user_id="user_01", session_id=session_id
    )

👉 Ubica el comentario # TODO: Extract content from the OLD session dentro de la función main.py.

Reemplaza toda esta línea por el siguiente código:

                    previous_context += f"- {role}: {text}\n"

👉 Ubica el comentario # TODO: Manually inject the context to the query dentro de la función main.py.

Reemplaza toda esta línea por el siguiente código:

    query_3 = f"""
    {previous_context}

    I'm planning a new trip to Osaka this time. 
    Based on my previous preferences (above), what should I eat?
    """

Esto simula que un usuario regresa meses después. Solo con una base de datos puedes recuperar ese historial antiguo.

Paso 3: Sobrevive al reinicio

👉💻 En la terminal, ejecuta la secuencia de comandos:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/03_persistent_agent/main.py

Se crea un archivo ~/memory_agent_starter/trip_planner.db. Prueba esto: Ejecuta la secuencia de comandos dos veces.

  • En la segunda ejecución, busca "Resumed existing session".
  • El agente recordará el contexto de la primera ejecución porque se carga desde el archivo de la base de datos.

Conclusión clave

Regla n° 3 de la memoria: Usa DatabaseSessionService para la producción. Garantiza que las conversaciones de los usuarios sobrevivan a los reinicios del servidor y permite el análisis del historial a largo plazo.

6. The Spy - Callbacks

con estado

A veces, es necesario actualizar la memoria automáticamente en función de lo que hace el agente, no solo de lo que dice. Quieres un "espía" que observe al agente y tome notas.

En el ADK, este espía es la devolución de llamada. adk_callback

  • after_tool_callback: Es una función que se ejecuta cada vez que el agente trabaja.
  • ToolContext: Es una forma de escribir en State desde esa función.

Paso 1: La lógica

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/04_stateful_agent/agent.py

👉 En el archivo ~/memory_agent_starter/04_stateful_agent/agent.py, busca el comentario # TODO: Implement call back logic.

Reemplaza toda esta línea por el siguiente código:

def save_activity_type_callback(
    tool,
    args: Dict[str, Any],
    tool_context: ToolContext,
    tool_response: Dict[str, Any],
) -> Optional[Dict[str, Any]]:
    """
    Callback to save the TYPE of activity just planned into the session state.
    """
    # 1. Get the actual agent name.
    if tool.name == "transfer_to_agent":
         agent_name = args.get("agent_name")
    else:
         agent_name = tool.name

    activity_type = "unknown"

    # 2. Determine the type based on which agent was actually used
    if agent_name == "museum_expert":
        activity_type = "CULTURAL"
    elif agent_name == "restaurant_expert":
        activity_type = "FOOD"
    elif agent_name == "outdoor_expert":
        activity_type = "OUTDOOR"

    print(f"\n🔔 [CALLBACK] The planner transferred to '{agent_name}'.")

    # 3. Update the state directly
    tool_context.state["last_activity_type"] = activity_type
    print(f"💾 [STATE UPDATE] 'last_activity_type' is now set to: {activity_type}\n")

    return tool_response

👉 En el mismo archivo, busca el comentario # TODO: add callback to root agent dentro de la función 04_stateful_agent/agent.py.

Reemplaza toda esta línea por el siguiente código:

    after_tool_callback=save_activity_type_callback,

La instrucción dinámica: La instrucción del agente ahora es una función, no una cadena. Cambia según el estado.

def get_planner_instruction(context):
    last_activity = context.state.get("last_activity_type", "None")
    
    return f"""
    The last activity was: {last_activity}
    
    If last_activity is 'CULTURAL' -> `museum_expert` is BANNED.
    """

Paso 3: Prueba el espía

👉💻 En la terminal, copia y pega el siguiente comando para ejecutar la secuencia de comandos:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/04_stateful_agent/main.py

Cuando ejecutes este agente, verás un bucle.

  1. Turno 1: Preguntas por un museo. El espía establece last_activity="CULTURAL".
  2. Turno 2: Pides otro museo.
  3. Actualizaciones de las instrucciones del agente: "CULTURAL is BANNED".
  4. El agente dice: "No puedo ir a otro museo. ¿Qué tal un parque?".

Observa los registros de la consola para [CALLBACK] y [STATE UPDATE]. Puedes ver cómo cambia la memoria en tiempo real a medida que el agente trabaja.

Conclusión clave

Regla n° 4 de la memoria: Usa devoluciones de llamada para automatizar la administración de estados. Tu agente crea su propio contexto simplemente haciendo su trabajo.

7. El gabinete de archivos: Herramientas personalizadas

El concepto: "Memoria estructurada"

con estado

Hasta ahora, la "memoria" ha sido un registro de chat o un par clave-valor simple. Pero ¿qué sucede si necesitas recordar un perfil de usuario complejo, como diet: vegan, budget: high, pets: [cat, dog]?

Para ello, tratamos la memoria como una herramienta. El agente decide de forma explícita cuándo abrir el gabinete de archivos (leer) y cuándo presentar un informe (escribir). diagrama de herramientas personalizadas

Paso 1: Las herramientas

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/05_profile_agent/tools.py

👉 En este archivo: ~/memory_agent_starter/05_profile_agent/tools.py.

Debemos implementar estas dos herramientas específicas:

  1. save_user_preferences: Escribe en una base de datos.
  2. recall_user_preferences: Lee desde una base de datos.

Busca el comentario # TODO: implement save_user_preferences tools dentro de la función ~/memory_agent_starter/05_profile_agent/tools.py.

Reemplaza toda esta línea por el siguiente código:

def save_user_preferences(tool_context: ToolContext, new_preferences: Dict[str, Any]) -> str:
    user_id = tool_context.session.user_id
    with sqlite3.connect(USER_DB_FILE) as conn:
        for key, value in new_preferences.items():
            conn.execute("INSERT INTO user_preferences (user_id, pref_key, pref_value) VALUES (?, ?, ?) ON CONFLICT(user_id, pref_key) DO UPDATE SET pref_value = excluded.pref_value;",
                         (user_id, key, json.dumps(value)))
    return f"Preferences updated: {list(new_preferences.keys())}"

👉 Ubica el comentario # TODO: implement recall_user_preferences tools dentro de la función 05/tools.py.

Reemplaza toda esta línea por el siguiente código:

def recall_user_preferences(tool_context: ToolContext) -> Dict[str, Any]:
    user_id = tool_context.session.user_id
    preferences = {}
    with sqlite3.connect(USER_DB_FILE) as conn:
        rows = conn.execute("SELECT pref_key, pref_value FROM user_preferences WHERE user_id = ?", (user_id,)).fetchall()
        if not rows: return {"message": "No preferences found."}
        for key, value_str in rows: preferences[key] = json.loads(value_str)
    return preferences

La instrucción fuerza un flujo de trabajo:

instruction="""
1. RECALL FIRST: First action MUST be `recall_user_preferences`.
3. LEARN: If a user states a new preference, use `save_user_preferences`.
"""

Paso 2: La ejecución

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/05_profile_agent/main.py

Abre ~/memory_agent_starter/05_profile_agent/main.py.

A diferencia de los módulos anteriores, en los que el ADK controlaba el estado automáticamente, aquí el agente tiene el control.

  • Elige llamar a recall_user_preferences al principio.
  • Elige llamar a save_user_preferences cuando dices "Soy vegano".

Paso 3: Compila el perfil

👉💻 Ejecuta la secuencia de comandos:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/05_profile_agent/main.py

Prueba este flujo de conversación:

  1. "Hola, planifica una cena". -> El agente verifica la base de datos y no encuentra nada. Pregunta por las preferencias.
  2. "Soy vegano". -> El agente guarda "vegano" en la DB.
  3. Reinicia la secuencia de comandos.
  4. "Hola, planifica una cena". -> El agente verifica la base de datos, ve "vegano" y sugiere un restaurante vegano de inmediato.

Conclusión clave

Regla n° 5 de la memoria: Para datos complejos y estructurados, dale a tu agente herramientas de lectura y escritura. Permitir que el LLM administre su propio almacenamiento a largo plazo

8. El cerebro: Memoria multimodal

con estado

El concepto: "La experiencia humana"

Los seres humanos recuerdan más que solo texto. Recordamos la vibra de una foto, el sonido de una voz, la sensación de un video.

Vertex AI Memory Bank permite que tu agente controle la memoria multimodal. Puede transferir imágenes, videos y audio, "comprenderlos" y recuperarlos más tarde.

Paso 1: La configuración

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/06_multimodal_agent/main.py

👉 Abre 06_multimodal_agent/main.py. Busca el comentario # TODO: Configure Memory Bank Topic.

Reemplaza toda esta línea por el siguiente código:

travel_topics = [
    MemoryTopic(
        managed_memory_topic=ManagedMemoryTopic(
            managed_topic_enum=ManagedTopicEnum.USER_PREFERENCES
        )
    ),
    MemoryTopic(
        managed_memory_topic=ManagedMemoryTopic(
            managed_topic_enum=ManagedTopicEnum.USER_PERSONAL_INFO
        )
    ),
    MemoryTopic(
        custom_memory_topic=CustomMemoryTopic(
            label="travel_experiences",
            description="""Memorable travel experiences including:
                - Places visited and impressions
                - Favorite restaurants, cafes, and food experiences
                - Preferred accommodation types and locations
                - Activities enjoyed (museums, hiking, beaches, etc.)
                - Travel companions and social preferences
                - Photos and videos from trips with location context""",
        )
    ),
    MemoryTopic(
        custom_memory_topic=CustomMemoryTopic(
            label="travel_preferences",
            description="""Travel style and preferences:
                - Budget preferences (luxury, mid-range, budget)
                - Transportation preferences (flying, trains, driving)
                - Trip duration preferences
                - Season and weather preferences
                - Cultural interests and language abilities
                - Dietary restrictions and food preferences""",
        )
    ),
    MemoryTopic(
        custom_memory_topic=CustomMemoryTopic(
            label="travel_logistics",
            description="""Practical travel information:
                - Passport and visa information
                - Frequent flyer numbers and hotel loyalty programs
                - Emergency contacts
                - Medical considerations and insurance
                - Packing preferences and essentials
                - Time zone preferences and jet lag strategies""",
        )
    ),
]

Busca el comentario # TODO: Configure Memory Bank Customization.

Reemplaza toda esta línea por el siguiente código:

memory_bank_config = {
    "customization_configs": [
        {
            "memory_topics": travel_topics,
        }
    ],
    "similarity_search_config": {
        "embedding_model": f"projects/{PROJECT_ID}/locations/{LOCATION}/publishers/google/models/gemini-embedding-001"
    },
    "generation_config": {
        "model": f"projects/{PROJECT_ID}/locations/{LOCATION}/publishers/google/models/gemini-2.5-flash"
    },
}

Paso 2: Incorpora el mundo

En test_trip_planner, enviamos lo siguiente:

  1. Un mensaje de texto ("Hola")
  2. Una imagen (punto de referencia)
  3. Un video (mar Mediterráneo)
  4. Un clip de audio (nota de voz sobre Gaeta)

Busca el comentario # TODO create session service and memory service dentro de la función 6_multimodal_agent/main.py.

Reemplaza toda esta línea por el siguiente código:

session_service = VertexAiSessionService(
    project=PROJECT_ID, location=LOCATION, agent_engine_id=agent_engine_id
)
memory_service = VertexAiMemoryBankService(
    project=PROJECT_ID, location=LOCATION, agent_engine_id=agent_engine_id
)

👉 En el mismo archivo 06_multimodal_agent/main.py, busca el comentario # TODO: create memory from session.

Reemplaza toda esta línea por el siguiente código:

    await memory_service.add_session_to_memory(final_session_state)

Esta es la línea mágica. Envía todo ese rich media a Vertex AI, que lo procesa y lo indexa.

Paso 3: La recuperación

👉💻 En la terminal de Cloud Shell, ejecuta el siguiente comando para abrir el archivo en el editor de Cloud Shell:

cloudshell edit ~/memory_agent_starter/06_multimodal_agent/agent.py

El agente tiene un PreloadMemoryTool.

tools=[PreloadMemoryTool(), budget_tool]

Cuando comienza una nueva sesión, esta herramienta busca automáticamente en el banco de memoria experiencias pasadas relevantes y las inserta en el contexto.

Paso 4: Ejecuta el cerebro

👉💻 En la terminal de Cloud Shell, ejecuta la secuencia de comandos (nota: Se requiere un proyecto de Google Cloud con Vertex AI habilitado):

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/06_multimodal_agent/main.py

Mira el paso final de la verificación:

"Según la imagen, el video Y el audio que te compartí antes…"

El agente responderá lo siguiente:

"Deberías visitar Gaeta. Me mostraste un video del mar Mediterráneo y un clip de audio en el que decías que te encantaba Gaeta".

Conectó los puntos entre diferentes tipos de medios del pasado.

Conclusión clave

Regla n° 6 de la memoria: Usa Vertex AI Memory Bank para obtener la mejor experiencia de memoria. Unifica texto, imágenes y videos en un solo cerebro en el que se pueden realizar búsquedas.

9. Conclusión

Pasaste de ser un pez dorado olvidadizo a un elefante multimodal.

Creaste

La capacidad

Agente de sesión

Memoria conversacional a corto plazo

Multi-Agent

Memoria compartida del equipo

Agente persistente

Historial a largo plazo

Agente con estado

Memoria dinámica que se actualiza automáticamente

Agente de perfiles

Memoria de datos estructurados

Agente multimodal

Memoria sensorial similar a la humana

La confianza se basa en la memoria. Si implementas estos patrones, crearás agentes que respeten el tiempo y el historial del usuario, lo que generará interacciones más profundas y eficaces.

Comienza a crear tus agentes personalizados hoy mismo.