Tworzenie agentów stanowych i spersonalizowanych za pomocą pakietu ADK

1. Wprowadzenie

tytuł

Problem „złotej rybki”

Wyobraź sobie, że zatrudniasz biuro podróży, które ma zaplanować Twoje wymarzone wakacje w Tokio. Użyj agenta sesji, aby zobaczyć, jak działa „Problem ze złotą rybką”.

Wchodzisz do biura i mówisz:

„Dzień dobry, Chcę zaplanować 2-dniową wycieczkę do Tokio. Interesują mnie miejsca historyczne i sushi”.

Agent odpowiada z entuzjazmem:

„Świetnie! Zaplanowałem wizytę w Pałacu Cesarskim i kolację sushi w Sukiyabashi Jiro”.

Uśmiechasz się i mówisz:

„Brzmi świetnie! Czy możesz przesłać mi plan podróży?”

Agent patrzy na Ciebie z pustym wzrokiem i pyta:

„Dzień dobry, W czym mogę Ci dzisiaj pomóc zaplanować przejazd?”.

To jest „problem złotej rybki”. Bez pamięci każda interakcja jest jak czysta karta. Agent ma odpowiednią wiedzę – wie, jak planować podróże – ale brakuje mu ciągłości. Aby agent AI był naprawdę przydatny, musi pamiętać.

Twoja dzisiejsza misja

Podczas tych warsztatów rozwiążesz problem złotej rybki, tworząc biuro podróży, które zapamiętuje, uczy się i dostosowuje. Przejdziesz przez 6 poziomów pamięci agenta, tworząc system, który zachowuje się mniej jak chatbot, a bardziej jak osobisty asystent.

Poziom

Pomysł

„Supermoc”

Poziom 1

Sesja i stan

prowadzenie rozmowy bez zapominania,

Poziom 2

Stan wielu agentów

udostępnianie notatek członkom zespołu,

Poziom 3

Trwałość

pamiętanie o Tobie nawet po ponownym uruchomieniu systemu;

Poziom 4

Wywołania zwrotne

Aktualizowanie pamięci całkowicie autonomicznie

Poziom 5

Narzędzia niestandardowe

Odczytywanie i zapisywanie ustrukturyzowanych profili użytkowników

Poziom 6

Multimodalna pamięć

„Widzenie” i zapamiętywanie zdjęć oraz filmów

Stos pamięci ADK

Zanim zaczniemy pisać kod, zapoznajmy się z narzędziami, których będziemy używać. Pakiet Google Agent Development Kit (ADK) zapewnia ustrukturyzowany sposób obsługi pamięci:

  1. Sesja: kontener rozmowy. Zawiera historię tego, co zostało powiedziane.
  2. Stan: „notatnik” z parami klucz-wartość dołączony do sesji. Agenty używają tego do przechowywania konkretnych faktów (np. destination="Tokyo").
  3. MemoryService: długoterminowe przechowywanie danych. To tutaj przechowujemy rzeczy na zawsze, takie jak preferencje użytkownika czy przeanalizowane dokumenty.

2. Skonfiguruj

Aby zasilać naszych agentów AI, potrzebujemy 2 rzeczy: projektu Google Cloud, który stanowi podstawę,

Część 1. Włącz konto rozliczeniowe

Aby uruchomić tego ćwiczenia, potrzebujesz konta rozliczeniowego z pewnymi środkami. Aby rozpocząć, użyj środków z banera u góry tego ćwiczenia. Jeśli masz już połączenie z kontem rozliczeniowym, możesz pominąć ten krok.

Część 2. Otwórz środowisko

  1. 👉 Kliknij ten link, aby przejść bezpośrednio do edytora Cloud Shell.
  2. 👉 Jeśli w którymś momencie pojawi się prośba o autoryzację, kliknij Autoryzuj, aby przejść dalej. Kliknij, aby uwierzytelnić się w Cloud Shell
  3. 👉 Jeśli terminal nie pojawia się u dołu ekranu, otwórz go:
    • Kliknij Wyświetl.
    • Kliknij Terminal.Otwieranie nowego terminala w edytorze Cloud Shell
  4. 👉💻 W terminalu sprawdź, czy uwierzytelnianie zostało już przeprowadzone, a projekt jest ustawiony na Twój identyfikator projektu, używając tego polecenia:
    gcloud auth list
    
  5. 👉💻 Sklonuj projekt bootstrap z GitHuba:
    git clone https://github.com/cuppibla/memory_agent_starter
    
    
  6. 👉💻 Uruchom skrypt konfiguracyjny z katalogu projektu.
    cd ~/memory_agent_starter
    ./init.sh
    
    Skrypt automatycznie zajmie się resztą procesu konfiguracji.
  7. 👉💻 Ustaw wymagany identyfikator projektu:
    gcloud config set project $(cat ~/project_id.txt) --quiet
    

Część 3. Konfigurowanie uprawnień

  1. 👉💻 Włącz wymagane interfejsy API za pomocą tego polecenia. Może to potrwać kilka minut.
    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        servicenetworking.googleapis.com \
        run.googleapis.com \
        aiplatform.googleapis.com \
        compute.googleapis.com
    
  2. 👉💻 Przyznaj wymagane uprawnienia, uruchamiając w terminalu te polecenia:
    . ~/memory_agent_starter/set_env.sh
    

Zwróć uwagę, że został utworzony plik .env. Wyświetlą się informacje o projekcie.

3. Podstawy – sesja i stan

stanowy

Koncepcja: kontekst jest najważniejszy

Najbardziej podstawową formą pamięci jest pamięć sesji. Dzięki temu agent wie, że „to” w zdaniu „Chcę to kupić” odnosi się do buta, o którym była mowa 10 sekund wcześniej.

W ADK zarządzamy tym za pomocą obiektu Session.

  • Podejście bezstanowe: tworzenie nowej sesji dla każdej wiadomości.
  • Podejście stanowe: tworzenie jednej sesji i ponowne jej używanie w całej rozmowie.

Krok 1. Sprawdź agenta

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

Otwórz pokój ~/memory_agent_starter/01_session_agent/agent.py.

👉 Znajdź komentarz # TODO: Create a root agent w funkcji agent.py.

Zastąp cały ten wiersz tym kodem:

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]
)

Instrukcja nakazuje LLM zapamiętywanie, ale kod musi zapewniać możliwość zapamiętywania.

Krok 2. Dwa scenariusze

Otwórz pokój ~/memory_agent_starter/01_session_agent/main.py.

👉 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

Otwórz plik ~/memory_agent_starter/01_session_agent/main.py i znajdź komentarz # TODO: Create a runner with in memorysession service w funkcji main.py.

Zastąp cały ten wiersz tym kodem:

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

👉 Znajdź komentarz # TODO: create a different session to test w funkcji main.py.

Zastąp cały ten wiersz tym kodem:

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

Sprawdź

Mamy 2 funkcje, które pokazują różnicę między pamięcią „złotej rybki” i „słonia”.

Scenariusz 1. Stanowy (sesja współdzielona)

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, ...)

Scenariusz 2. Bezstanowy (nowa sesja za każdym razem)

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, ...)

Krok 3. Uruchom agenta

Zobaczmy, jak to działa. Uruchom skrypt:

👉💻 W wierszu poleceń uruchom to polecenie:

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

Obserwuj scenariusz 1: agent zapamiętuje Twoje preferencje z pierwszej wiadomości i dostosowuje plan w drugiej wiadomości.

Obserwacja scenariusza 2: w drugiej turze („czy pamiętasz, co mi się podobało w jedzeniu?”) agent nie radzi sobie z odpowiedzią, ponieważ jest to nowa sesja. Oznacza to, że nie wie, o co chodzi.

Kluczowy wniosek

Zasada nr 1 dotycząca pamięci: zawsze używaj ponownie session.id, aby zachować kontekst rozmowy. Obiekt Session to bufor pamięci krótkotrwałej agenta.

4. Zespół – stan z wieloma agentami

jedzenie

Koncepcja: „Głuchy telefon”

Gdy wiele agentów współpracuje ze sobą, przypominają współpracowników, którzy przekazują sobie nawzajem folder z plikami. Jeśli jeden agent zapisze notatkę w folderze, następny agent powinien móc ją odczytać.

W ADK ten „folder” to stan.

  • State to słownik ({"key": "value"}), który znajduje się w sesji.
  • Każdy agent w sesji może odczytywać i zapisywać dane w sesji.

Krok 1. Przeanalizuj przepływ pracy

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

👉 W pliku ~/memory_agent_starter/02_multi_agent/agent.py znajdź komentarz # TODO: foodie agent.

Zastąp cały ten wiersz tym kodem:

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']
)

👉 Znajdź komentarz # TODO: transportation agent w funkcji agent.py.

Zastąp cały ten wiersz tym kodem:

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}.
    """,
)

👉 Znajdź komentarz # TODO: root_agent w funkcji agent.py.

Zastąp cały ten wiersz tym kodem:

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."
)

Terą mamy 2 agenty działające sekwencyjnie:

  1. Agent dla smakoszy: znajduje restaurację.
  2. Agent ds. transportu: podaje wskazówki dojazdu do tej restauracji.

Magiczne przekazanie: zwróć uwagę, jak foodie_agent przekazuje pałeczkę 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": Odpowiedź agenta Foodie została zapisana.
  2. {destination}: Agent transportowy automatycznie odczytuje tę odpowiedź.

(Nie musisz nic robić) Krok 2. Orkiestrator

Otwórz pokój 02_multi_agent/main.py.

Używamy SequentialAgent, aby uruchamiać je w odpowiedniej kolejności.

# 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, ...)

Użytkownik wysyła 1 prompt:

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

Agenty współpracują, aby odpowiedzieć na pytanie.

Krok 3. Uruchom zespół

👉💻 W terminalu Cloud Shell uruchom przepływ pracy Agentic Workflows:

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

Co się dzieje?

  1. Agent ds. jedzenia: znajduje „Jin Sho” (lub podobne miejsce).
  2. ADK: zapisuje „Jin Sho” w state['destination'].
  3. Agent ds. transportu: otrzymuje w instrukcji nazwę „Jin Sho”.
  4. Wynik: „Aby dotrzeć do Jin Sho ze stacji Caltrain, idź University Ave…”

Kluczowy wniosek

Zasada pamięci nr 2: używaj stanu do przekazywania ustrukturyzowanych informacji między agentami. Użyj output_key, aby pisać, i {placeholders}, aby czytać.

5. The Reboot - Persistence

stanowy

Koncepcja: „Problem z ponownym uruchomieniem”

Do tej pory nasza pamięć była InMemory. Jeśli zatrzymasz skrypt i uruchomisz go ponownie, agent zapomni wszystko. To jak komputer, który czyści dysk twardy za każdym razem, gdy go wyłączasz.

Aby rozwiązać ten problem, potrzebujemy trwałości. Zamieniamy InMemorySessionService na DatabaseSessionService.

Krok 1. Przełączenie bazy danych

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

👉 W pliku ~/memory_agent_starter/03_persistent_agent/main.py znajdź komentarz # TODO: Configuration for Persistent Sessions.

Zastąp cały ten wiersz tym kodem:

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}"

Teraz każda sesja i każde zdarzenie są zapisywane w pliku SQLite.

Krok 2. Pobieranie danych z różnych sesji

Trwałość pozwala nie tylko na wznawianie rozmowy, ale też na wyciąganie wniosków z poprzednich.

W tym samym pliku ~/memory_agent_starter/03_persistent_agent/main.py znajdź element testowania 3: Cross-Session Retrieval (Przypadek testowy 3: pobieranie danych z różnych sesji).

👉 Znajdź komentarz # TODO: retrieve the previous session manually

Zastąp cały ten wiersz tym kodem:

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

👉 Znajdź komentarz # TODO: Extract content from the OLD session w funkcji main.py.

Zastąp cały ten wiersz tym kodem:

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

👉 Znajdź komentarz # TODO: Manually inject the context to the query w funkcji main.py.

Zastąp cały ten wiersz tym kodem:

    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?
    """

Symuluje to powrót użytkownika po kilku miesiącach. Tylko dzięki bazie danych możesz odzyskać tę starą historię.

Krok 3. Przetrwanie ponownego uruchomienia

👉💻 W terminalu uruchom skrypt:

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

Zostanie utworzony plik ~/memory_agent_starter/trip_planner.db. Wypróbuj to: uruchom skrypt dwukrotnie.

  • Przy drugim uruchomieniu poszukaj komunikatu „Resumed existing session” (Wznowiono istniejącą sesję).
  • Agent zapamięta kontekst z pierwszego uruchomienia, ponieważ wczyta go z pliku bazy danych.

Kluczowy wniosek

Zasada nr 3 dotycząca pamięci: w środowisku produkcyjnym używaj DatabaseSessionService. Dzięki temu rozmowy użytkowników nie są tracone po ponownym uruchomieniu serwera i możliwa jest długoterminowa analiza historii.

6. Szpieg – wywołania zwrotne

stanowy

Czasami musisz automatycznie aktualizować pamięć na podstawie tego, co robi agent, a nie tylko tego, co mówi. Chcesz mieć „szpiega”, który obserwuje agenta i robi notatki.

W ADK ten szpieg to wywołanie zwrotne. adk_callback

  • after_tool_callback: funkcja, która jest uruchamiana za każdym razem, gdy agent działa.
  • ToolContext: sposób na zapisanie stanu z poziomu tej funkcji.

Krok 1. Logika

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

👉 W pliku ~/memory_agent_starter/04_stateful_agent/agent.py znajdź komentarz # TODO: Implement call back logic.

Zastąp cały ten wiersz tym kodem:

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

👉 W tym samym pliku znajdź komentarz # TODO: add callback to root agent w funkcji 04_stateful_agent/agent.py.

Zastąp cały ten wiersz tym kodem:

    after_tool_callback=save_activity_type_callback,

Instrukcja dynamiczna: instrukcja agenta jest teraz funkcją, a nie ciągiem znaków. Zmienia się w zależności od stanu.

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.
    """

Krok 3. Przetestuj szpiega

👉💻 W terminalu uruchom skrypt, kopiując i wklejając to polecenie:

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

Po uruchomieniu tego agenta zobaczysz pętlę.

  1. Tura 1. Pytasz o muzeum. Szpieg ustawia last_activity="CULTURAL".
  2. Tura 2. Pytasz o inne muzeum.
  3. Aktualizacja instrukcji dla agenta: „CULTURAL is BANNED”.
  4. Pracownik obsługi klienta: „Nie dam rady pójść do kolejnego muzeum. Może park?

Obserwuj logi konsoli pod kątem [CALLBACK] i [STATE UPDATE]. Możesz obserwować, jak pamięć zmienia się w czasie rzeczywistym podczas pracy agenta.

Kluczowy wniosek

Zasada pamięci nr 4: używaj wywołań zwrotnych do automatyzacji zarządzania stanem. Agent tworzy własny kontekst, po prostu wykonując swoją pracę.

7. Magazyn plików – narzędzia niestandardowe

Koncepcja: „uporządkowane zapamiętane informacje”

stanowy

Do tej pory „pamięć” była dziennikiem czatu lub prostą parą klucz-wartość. Co jednak, jeśli musisz zapamiętać złożony profil użytkownika, np. diet: vegan, budget: high, pets: [cat, dog]?

W tym celu traktujemy pamięć jako narzędzie. Agent wyraźnie decyduje, kiedy otworzyć magazyn plików (odczyt), a kiedy złożyć raport (zapis). diagram narzędzi niestandardowych

Krok 1. Narzędzia

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

👉 W tym pliku: ~/memory_agent_starter/05_profile_agent/tools.py.

Musimy wdrożyć te 2 konkretne narzędzia:

  1. save_user_preferences: zapisuje dane w bazie danych.
  2. recall_user_preferences: odczytuje dane z bazy danych.

Znajdź komentarz # TODO: implement save_user_preferences tools w funkcji ~/memory_agent_starter/05_profile_agent/tools.py.

Zastąp cały ten wiersz tym kodem:

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())}"

👉 Znajdź komentarz # TODO: implement recall_user_preferences tools w funkcji 05/tools.py.

Zastąp cały ten wiersz tym kodem:

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

Instrukcja wymusza przepływ pracy:

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

Krok 2. Wykonanie

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

Otwórz pokój ~/memory_agent_starter/05_profile_agent/main.py.

W odróżnieniu od poprzednich modułów, w których ADK automatycznie obsługiwał stan, tutaj kontrolę sprawuje Agent.

  • Decyduje się na sprawdzenie recall_user_preferences na początku.
  • Wybiera, że zadzwoni do save_user_preferences, gdy powiesz „Jestem weganinem”.

Krok 3. Utwórz profil

👉💻 Uruchom skrypt:

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

Wypróbuj ten schemat rozmowy:

  1. „Cześć, zaplanuj kolację”. -> Agent sprawdza bazę danych i nic nie znajduje. pyta o preferencje,
  2. „Jestem weganinem”. -> Agent zapisuje „weganizm” w bazie danych.
  3. Uruchom ponownie skrypt.
  4. „Cześć, zaplanuj kolację”. -> Agent sprawdza bazę danych, widzi „weganin” i natychmiast sugeruje restaurację wegańską.

Kluczowy wniosek

Zasada pamięci nr 5: w przypadku złożonych, uporządkowanych danych udostępnij agentowi narzędzia do odczytu i zapisu. Pozwól LLM zarządzać własną długoterminową pamięcią masową.

8. Mózg – pamięć multimodalna

stanowy

Koncepcja: „Doświadczenie człowieka”

Ludzie zapamiętują nie tylko tekst. Pamiętamy klimat zdjęcia, brzmienie głosu, emocje, które wywołuje film.

Bank zapamiętanych informacji Vertex AI umożliwia agentowi obsługę pamięci multimodalnej. Może przetwarzać obrazy, filmy i dźwięk, „rozumieć” je i później pobierać.

Krok 1. Konfiguracja

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

👉 Otwórz 06_multimodal_agent/main.py. Znajdź komentarz # TODO: Configure Memory Bank Topic.

Zastąp cały ten wiersz tym kodem:

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""",
        )
    ),
]

Znajdź komentarz # TODO: Configure Memory Bank Customization.

Zastąp cały ten wiersz tym kodem:

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"
    },
}

Krok 2. Przetwarzanie świata

W test_trip_planner wysyłamy:

  1. wiadomość tekstowa („Cześć”),
  2. Obraz (punkt orientacyjny)
  3. Film (Morze Śródziemne)
  4. klip audio (notatka głosowa o Gaecie),

Znajdź komentarz # TODO create session service and memory service w funkcji 6_multimodal_agent/main.py.

Zastąp cały ten wiersz tym kodem:

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
)

👉 W tym samym pliku 06_multimodal_agent/main.py znajdź komentarz # TODO: create memory from session.

Zastąp cały ten wiersz tym kodem:

    await memory_service.add_session_to_memory(final_session_state)

To jest magiczna linia. Wysyła wszystkie te multimedia do Vertex AI, która je przetwarza i indeksuje.

Krok 3. Pobieranie

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając polecenie:

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

Agent ma PreloadMemoryTool.

tools=[PreloadMemoryTool(), budget_tool]

Po rozpoczęciu nowej sesji narzędzie to automatycznie wyszukuje w banku pamięci odpowiednie wcześniejsze doświadczenia i wprowadza je do kontekstu.

Krok 4. Uruchom Brain

👉💻 W terminalu Cloud Shell uruchom skrypt (uwaga: wymaga to projektu Google Cloud z włączoną usługą Vertex AI):

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

Obejrzyj film o ostatnim kroku weryfikacji:

„Na podstawie udostępnionego wcześniej obrazu, filmu ORAZ dźwięku…”

Agent odpowie:

„Powinieneś odwiedzić Gaetę! Pokazałeś mi film z Morzem Śródziemnym i klip audio, w którym powiedziałeś, że uwielbiasz Gaetę”.

Połączyła ona różne typy multimediów z przeszłości.

Kluczowy wniosek

Zasada 6 dotycząca pamięci: aby uzyskać najlepsze wyniki, używaj banku zapamiętanych informacji Vertex AI. Łączy tekst, obrazy i filmy w jedną bazę wiedzy, którą można przeszukiwać.

9. Podsumowanie

Udało Ci się przejść od zapominalskiej złotej rybki do multimodalnego słonia.

Utworzone przez Ciebie

Funkcja

Agent sesji

Krótkoterminowa pamięć konwersacyjna

Multi-Agent

Współdzielona pamięć zespołu

Agent trwały

Historia długoterminowa

Agent stanowy

Dynamiczna, samoczynnie aktualizująca się pamięć

Agent profilu

Pamięć uporządkowanych danych

Agent multimodalny

pamięć sensoryczna podobna do ludzkiej,

Zaufanie opiera się na pamięci. Wdrażając te wzorce, tworzysz agentów, którzy szanują czas i historię użytkownika, co prowadzi do głębszych i skuteczniejszych interakcji.

Zacznij tworzyć spersonalizowanych agentów już dziś.