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

1. Wprowadzenie

tytuł

Problem „złotej rybki”

Załóżmy, że zatrudniasz agenta turystycznego, aby 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:

„Cześć! Chcę zaplanować 2-dniową wycieczkę do Tokio. Interesują mnie zabytki i sushi”.

Pracownik obsługi klienta z entuzjazmem odpowiada:

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

Uśmiechasz się i mówisz:

„Brzmi idealnie. Czy możesz przesłać mi plan podróży?

Pracownik patrzy na Ciebie bez wyrazu i pyta:

„Cześć! W czym mogę Ci dziś pomóc w planowaniu podróży?

To jest „problem złotej rybki”. Bez pamięci każda interakcja jest czystą kartą. Sztuczna inteligencja jest dostępna – agent wie, jak planować wycieczki – ale brakuje ciągłości. Aby agent AI był naprawdę przydatny, musi pamiętać.

Twoja misja na dziś

Podczas tych warsztatów rozwiążesz problem ze złotą rybką, tworząc agenta turystycznego, który zapamiętuje, uczy się i dostosowuje. Przejdziesz przez 6 poziomów pamięci agenta, tworząc system, który będzie działać bardziej jak osobisty asystent niż czatbot.

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ść

zapamiętywanie Cię nawet po ponownym uruchomieniu systemu;

Poziom 4

Wywołania zwrotne

Aktualizowanie pamięci w pełni autonomicznie

Poziom 5

Narzędzia niestandardowe

Odczytywanie i zapisywanie strukturalnych profili użytkowników

Poziom 6

Multimodal Memory

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

Stos pamięci ADK

Zanim napiszemy kod, poznajmy narzędzia, których będziemy używać. Pakiet Google Agent Development Kit (ADK) zapewnia ustrukturyzowany sposób zarządzania pamięcią:

  1. Sesja: kontener rozmowy. Zawiera historię tego, co zostało powiedziane.
  2. Stan: „notatnik” z parą klucz-wartość dołączony do sesji. Agenty używają tego do przechowywania konkretnych faktów (np. destination="Tokyo").
  3. MemoryService: długoterminowa pamięć masowa. Przechowujemy w niej na stałe różne informacje, np. preferencje użytkowników czy przeanalizowane dokumenty.

2. Skonfiguruj

Aby obsługiwać naszych agentów AI, potrzebujemy dwóch rzeczy: projektu Google Cloud, który będzie stanowić podstawę.

Część 1. Włączanie konta rozliczeniowego

  • Aby odebrać konto rozliczeniowe z 5 dolarami środków, musisz je mieć wdrożone. Zaloguj się na konto Gmail.

Część 2. Środowisko otwarte

  1. 👉 Kliknij ten link, aby przejść bezpośrednio do edytora Cloud Shell
  2. 👉 Jeśli w dowolnym momencie pojawi się prośba o autoryzację, kliknij Autoryzuj, aby kontynuować. 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 TerminalOtwieranie nowego terminala w edytorze Cloud Shell.
  4. 👉💻 W terminalu sprawdź, czy użytkownik jest już uwierzytelniony i czy projekt jest ustawiony na 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 konfiguracji z katalogu projektu.
    cd ~/memory_agent_starter
    ./init.sh
    
    Skrypt automatycznie przeprowadzi 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 niezbędne uprawnienia, uruchamiając w terminalu te polecenia:
    . ~/memory_agent_starter/set_env.sh
    

Zwróć uwagę, że utworzyliśmy dla Ciebie plik .env. Wyświetlą się informacje o Twoim 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ę kupić to” odnosi się do butów, o których mówiliśmy 10 sekund temu.

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

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

Krok 1. Sprawdź agenta

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając to 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 mówi LLM, że ma zapamiętać, 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 to polecenie:

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

Otwórz ~/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
    )

Przetestuj

Mamy 2 funkcje, które pokazują różnicę między pamięcią „złotej rybki” a pamięcią „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 („do you remember what I liked about the food?”) agent całkowicie zawodzi, ponieważ jest to nowa sesja. Oznacza to: „Nie wiem, o czym mówisz”.

Kluczowy wniosek

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

4. Zespół – stan wielu agentów

jedzenie

Koncepcja: „Głuchy telefon”

Gdy wielu agentów pracuje razem, przypomina to współpracowników przekazujących sobie nawzajem folder z plikami. Jeśli jeden agent zapisze notatkę w folderze, następny agent powinien mieć możliwość jej odczytania.

W ADK ten „folder” to stan.

  • State to słownik ({"key": "value"}) znajdujący się w sesji.
  • Każdy agent w sesji może odczytywać i zapisywać dane w tym pliku.

Krok 1. Sprawdź przepływ pracy

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając to 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."
)

Obecnie mamy 2 agenty działające w sekwencji:

  1. Foodie Agent: znajduje restaurację.
  2. Agent ds. transportu: podaje wskazówki dojazdu do 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ź Foodie Agenta jest zapisywana w efektywny sposób.
  2. {destination}: Pracownik obsługi klienta ds. transportu odczytuje tę odpowiedź automatycznie.

(Nie wymaga działania) Krok 2. Koordynator

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 jedną prośbę:

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

Agenci współpracują ze sobą, aby na nie odpowiedzieć.

Krok 3. Uruchom zespół

👉💻 W terminalu Cloud Shell wykonaj przepływ pracy z wieloma agentami:

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

Co się dzieje?

  1. Foodie Agent: znajduje „Jin Sho” (lub podobne).
  2. ADK: zapisuje „Jin Sho” w state['destination'].
  3. Agent transportowy: otrzymuje w instrukcji imię „Jin Sho”.
  4. Wynik: „Aby dostać się do Jin Sho ze stacji Caltrain, idź wzdłuż University Ave…”.

Kluczowy wniosek

Reguła 2 dotycząca pamięci: używaj stanu do przekazywania uporządkowanych informacji między agentami. Używaj output_key do pisania i {placeholders} do czytania.

5. The Reboot - Persistence

stanowy

Koncepcja: „Problem z ponownym uruchomieniem”

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

Aby to naprawić, potrzebujemy trwałości. Zamieniamy InMemorySessionService na DatabaseSessionService.

Krok 1. Przełączanie bazy danych

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając to 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ść umożliwia nie tylko wznowienie rozmowy, ale też uczenie się na podstawie poprzednich rozmów.

tym samym pliku~/memory_agent_starter/03_persistent_agent/main.py znajdź 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 w bazie danych możesz pobrać 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

Spowoduje to utworzenie pliku ~/memory_agent_starter/trip_planner.db. Wypróbuj to: uruchom skrypt 2 razy.

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

Kluczowy wniosek

Reguła 3 dotycząca pamięci: w środowisku produkcyjnym używaj DatabaseSessionService. Dzięki temu rozmowy użytkowników przetrwają ponowne uruchomienie serwera i umożliwią długoterminową analizę historii.

6. The Spy - Callbacks

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 tym szpiegiem jest Callback. adk_callback

  • after_tool_callback: funkcja, która jest uruchamiana za każdym razem, gdy agent pracuje.
  • ToolContext: sposób zapisywania danych w obiekcie State z poziomu tej funkcji.

Krok 1. Logika

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając to 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 urządzenie Spy

👉💻 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. Prosisz o muzeum. Szpieg ustawia last_activity="CULTURAL".
  2. Tura 2. Prosisz o kolejne muzeum.
  3. Aktualizacje instrukcji agenta: „CULTURAL is BANNED”.
  4. Agent mówi: „Nie mogę iść do kolejnego muzeum. A może park?”

Sprawdź w logach konsoli, czy nie ma komunikatów [CALLBACK][STATE UPDATE]. Pamięć zmienia się w czasie rzeczywistym w miarę pracy agenta.

Kluczowy wniosek

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

7. Magazyn plików – narzędzia niestandardowe

Koncepcja: „pamięć strukturalna”

stanowy

Do tej pory „Pamięć” była dziennikiem czatu lub prostą parą klucz-wartość. Ale co zrobić, 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ć szafę na dokumenty (odczyt), a kiedy złożyć raport (zapis). schemat narzędzi niestandardowych,

Krok 1. Narzędzia

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając to 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 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 to 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 zarządzał stanem, w tym przypadku kontrolę sprawuje Agent.

  • Na początku wybiera połączenie z recall_user_preferences.
  • Wybiera połączenie z save_user_preferences, gdy powiesz „Jestem weganem”.

Krok 3. Tworzenie profilu

👉💻 Uruchom skrypt:

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

Wypróbuj ten przebieg rozmowy:

  1. „Cześć, zaplanuj kolację”. -> Agent sprawdza bazę danych i nic nie znajduje. Prosi o określenie preferencji.
  2. „Jestem weganką”. -> Agent zapisuje w bazie danych słowo „vegan”.
  3. Uruchom skrypt ponownie.
  4. „Cześć, zaplanuj kolację”. -> Agent sprawdza bazę danych, widzi „wegańska” i od razu proponuje wegańską restaurację.

Kluczowy wniosek

Reguła 5 dotycząca pamięci: w przypadku złożonych, uporządkowanych danych udostępnij agentowi narzędzia do odczytu i zapisu. Pozwól modelowi LLM zarządzać własnym długoterminowym miejscem na dane.

8. Mózg – pamięć multimodalna

stanowy

Koncepcja: „Ludzkie doświadczenie”

Ludzie zapamiętują więcej niż tylko tekst. Pamiętamy klimat zdjęcia, dźwięk głosu czy emocje, jakie wywołuje film.

Bank pamięci Vertex AI umożliwia agentowi obsługę pamięci multimodalnej. Może ona przetwarzać obrazy, filmy i pliki audio, „rozumieć” je i później je wyszukiwać.

Krok 1. Konfiguracja

👉💻 W terminalu Cloud Shell otwórz plik w edytorze Cloud Shell, uruchamiając to 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. Wchłanianie świata

W test_trip_planner wysyłamy:

  1. SMS („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. Odzyskiwanie

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

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

Agent ma PreloadMemoryTool.

tools=[PreloadMemoryTool(), budget_tool]

Gdy rozpoczyna się nowa sesja, to narzędzie automatycznie wyszukuje w Banku pamięci odpowiednie wcześniejsze doświadczenia i wstawia 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 ostatni etap weryfikacji:

„Na podstawie zdjęcia, filmu i dźwięku, które wcześniej Ci udostępniłem(-am)...”

Pracownik obsługi klienta odpowie:

„Powinieneś odwiedzić Gaetę! Pokazano mi film z Morzem Śródziemnym i klip audio, w którym mówisz, że kochasz Gaetę”.

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

Kluczowy wniosek

Zasada 6 dotycząca pamięci: aby w pełni wykorzystać możliwości pamięci, używaj banku pamięci Vertex AI. Łączy tekst, obrazy i filmy w jedną bazę danych, w której można wyszukiwać informacje.

9. Podsumowanie

Przeszedłeś(-aś) drogę od zapominalskiej złotej rybki do wielozadaniowego słonia.

Utworzone przez Ciebie

Funkcja

Agent sesji

Pamięć krótkotrwała rozmowy

Multi-Agent

Wspólna pamięć zespołu

Persistent Agent

Historia długoterminowa

Agent stanowy

Dynamiczna, automatycznie aktualizowana pamięć

Profile Agent

Pamięć danych strukturalnych

Agent multimodalny

Pamięć sensoryczna podobna do ludzkiej

Zaufanie opiera się na pamięci. Wdrażając te wzorce, możesz tworzyć 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ś.