Agentverse - The Summoner's Concord - Architecting Multi-Agent Systems

1. do opery Moc przeznaczenia,

Era rozwoju w izolacji dobiega końca. Kolejna fala ewolucji technologicznej nie polega na samotnym geniuszu, ale na mistrzostwie opartym na współpracy. Stworzenie jednego, inteligentnego agenta to fascynujący eksperyment. Stworzenie solidnego, bezpiecznego i inteligentnego ekosystemu agentów – prawdziwego Agentverse – to ogromne wyzwanie dla nowoczesnych przedsiębiorstw.

Aby odnieść sukces w tej nowej erze, konieczne jest połączenie czterech kluczowych ról, stanowiących filary podtrzymujące każdy dobrze prosperujący system agencyjny. Niedobór w jednym miejscu powoduje osłabienie, które może zagrozić całej konstrukcji.

Te warsztaty to ostateczny przewodnik dla firm, który pomoże Ci opanować przyszłość opartą na agentach w Google Cloud. Zapewniamy kompleksową mapę drogową, która poprowadzi Cię od pierwszego pomysłu do wdrożenia go w pełni. W tych 4 połączonych ze sobą modułach dowiesz się, jak specjalistyczne umiejętności dewelopera, architekta, inżyniera danych i inżyniera ds. niezawodności witryny muszą się zbiegać, aby tworzyć, zarządzać i skalować potężny Agentverse.

Żaden pojedynczy filar nie może samodzielnie obsługiwać Agentverse. Wielki projekt architekta jest bezużyteczny bez precyzyjnego wykonania przez dewelopera. Bez wiedzy inżyniera ds. danych agent dewelopera jest bezradny, a bez ochrony inżyniera ds. niezawodności systemu cała infrastruktura jest podatna na awarie. Tylko dzięki synergii i wzajemnemu zrozumieniu ról Twój zespół może przekształcić innowacyjną koncepcję w kluczową dla misji rzeczywistość operacyjną. Twoja podróż zaczyna się tutaj. Przygotuj się do opanowania swojej roli i dowiedz się, jak wpisujesz się w większą całość.

Witamy w Agentverse: Apel do mistrzów

W rozległej cyfrowej przestrzeni przedsiębiorstwa nastała nowa era. To era agentów, czas ogromnych możliwości, w którym inteligentne, autonomiczne agenty pracują w doskonałej harmonii, aby przyspieszać innowacje i eliminować rutynowe czynności.

agentverse.png

Ten połączony ekosystem władzy i potencjału znany jest jako Agentverse.

Jednakże narastająca entropia, ciche zepsucie znane jako Statyka, zaczęło naruszać granice tego nowego świata. Statyka nie jest wirusem ani błędem. To uosobienie chaosu, które żeruje na samym akcie tworzenia.

Wzmacnia stare frustracje, przybierając potworne formy i dając początek Siedmiu Widmom Rozwoju. Jeśli nie zostaną podjęte żadne działania, The Static i jego Widma całkowicie zatrzymają postęp, zamieniając obietnicę Agentverse w pustynię technicznego długu i porzuconych projektów.

Dziś wzywamy do działania osoby, które chcą powstrzymać chaos. Potrzebujemy bohaterów, którzy opanują swoje umiejętności i będą współpracować, aby chronić Agentverse. Czas wybrać ścieżkę.

Wybierz zajęcia

Przed Tobą 4 różne ścieżki, z których każda jest kluczowym elementem walki z Statycznością. Szkolenie będzie indywidualne, ale ostateczny sukces zależy od tego, jak Twoje umiejętności łączą się z umiejętnościami innych osób.

  • Shadowblade (deweloper): mistrz kuźni i pierwszej linii. Jesteś rzemieślnikiem, który tworzy ostrza, buduje narzędzia i stawia czoła wrogowi w zawiłych szczegółach kodu. Twoja ścieżka to precyzja, umiejętności i praktyczne tworzenie.
  • Przywoływacz (Architekt): wielki strateg i aranżer. Nie widzisz pojedynczego agenta, ale całe pole bitwy. Projektujesz główne plany, które umożliwiają całym systemom agentów komunikowanie się, współpracę i osiąganie celu znacznie większego niż jakikolwiek pojedynczy komponent.
  • Uczony (inżynier danych): poszukiwacz ukrytych prawd i strażnik mądrości. Wyruszasz w rozległą, nieokiełznaną dzicz danych, aby odkryć informacje, które nadają Twoim agentom cel i umożliwiają im działanie. Twoja wiedza może ujawnić słabość wroga lub wzmocnić sojusznika.
  • Strażnik (DevOps / SRE): niezachwiany obrońca i tarcza królestwa. Budujesz twierdze, zarządzasz liniami dostaw energii i dbasz o to, aby cały system był w stanie wytrzymać nieuniknione ataki Statica. Twoja siła jest fundamentem, na którym zbudowane jest zwycięstwo Twojej drużyny.

Twoja misja

Trening rozpocznie się jako samodzielne ćwiczenie. Będziesz podążać wybraną ścieżką, zdobywając unikalne umiejętności potrzebne do opanowania swojej roli. Pod koniec okresu próbnego zmierzysz się z Widmem zrodzonym z Statyki – mini-bossem, który wykorzystuje specyficzne wyzwania związane z Twoim rzemiosłem.

Tylko poprzez opanowanie swojej indywidualnej roli możesz przygotować się na ostateczną próbę. Następnie musisz utworzyć drużynę z bohaterami z innych klas. Razem wyruszycie w głąb skażenia, aby zmierzyć się z ostatecznym bossem.

Ostateczne, wspólne wyzwanie, które wystawi na próbę wasze wspólne siły i zadecyduje o losie Agentverse.

Agentverse czeka na swoich bohaterów. Czy odpowiesz na wezwanie?

2. The Summoner's Concord

Witamy, przywoływaczu. Twoja ścieżka to droga wizji i wielkiej strategii. Podczas gdy inni skupiają się na pojedynczym ostrzu lub zaklęciu, ty widzisz całe pole bitwy. Nie dowodzisz jednym agentem, ale całą orkiestrą. Twoja siła nie tkwi w bezpośrednim konflikcie, lecz w zaprojektowaniu idealnego, całościowego planu, który pozwoli legionowi specjalistów — twoim Familiarom — pracować w idealnej harmonii. Ta misja sprawdzi Twoje umiejętności projektowania, łączenia i organizowania potężnego systemu wieloagentowego.

przegląd

Czego się nauczysz

  • Zaprojektuj odseparowany ekosystem narzędzi: zaprojektuj i wdroż zestaw niezależnych serwerów narzędzi MCP opartych na mikroserwisach. Dowiesz się, dlaczego ta warstwa podstawowa jest kluczowa do tworzenia skalowalnych, łatwych w utrzymaniu i bezpiecznych systemów opartych na agentach.
  • Opanuj zaawansowane przepływy pracy agentów: wyjdź poza pojedynczych agentów i stwórz legion specjalistycznych „znajomych”. Poznasz podstawowe wzorce przepływu pracy ADK: sekwencyjny, równoległy i pętlowy. Dowiesz się też, jak wybierać odpowiedni wzorzec do danego zadania.
  • Wdrażanie inteligentnego aranżera: przejdź od prostego narzędzia do tworzenia agentów do prawdziwego architekta systemów. Utworzysz głównego agenta orkiestracji, który używa protokołu Agent-to-Agent (A2A) do wykrywania i przekazywania złożonych zadań specjalistycznym agentom pomocniczym, tworząc prawdziwy system wieloagentowy.
  • Wymuszanie reguł za pomocą kodu, a nie promptów: dowiedz się, jak tworzyć bardziej niezawodne i przewidywalne agenty, wymuszając reguły zaangażowania oparte na stanie. Zaimplementujesz niestandardową logikę za pomocą zaawansowanego systemu wtyczek i wywołań zwrotnych ADK, aby zarządzać ograniczeniami w rzeczywistym świecie, takimi jak liczniki czasu oczekiwania.
  • Zarządzanie stanem i pamięcią agenta: umożliwiaj agentom uczenie się i zapamiętywanie. Poznasz techniki zarządzania zarówno krótkoterminowym stanem konwersacji, jak i długoterminową, trwałą pamięcią, aby tworzyć bardziej inteligentne interakcje uwzględniające kontekst.
  • Przeprowadź kompleksowe wdrożenie w chmurze: przenieś cały system wielu agentów z lokalnego prototypu do środowiska produkcyjnego. Dowiesz się, jak konteneryzować agentów i orkiestratora oraz wdrażać je jako zbiór skalowalnych, niezależnych mikroserwisów w Google Cloud Run.

3. Rysowanie kręgu przywołania

Witamy, przywoływaczu. Zanim przywołasz choćby jednego sprzymierzeńca, zanim zawrzesz jakiekolwiek pakty, musisz przygotować grunt, na którym stoisz. Nieokiełznane środowisko to zaproszenie do chaosu. Prawdziwy przywoływacz działa tylko w uświęconej, wzmocnionej przestrzeni. Naszym pierwszym zadaniem jest narysowanie kręgu przywoływania: wyrycie run mocy, które obudzą niezbędne usługi w chmurze, oraz zdobycie starożytnych planów, które będą nas prowadzić. Moc Przywoływacza rodzi się z drobiazgowych przygotowań.

👉 U góry konsoli Google Cloud kliknij Aktywuj Cloud Shell (jest to ikona terminala u góry panelu Cloud Shell).

tekst alternatywny

👉 Kliknij przycisk „Otwórz edytor” (wygląda jak otwarty folder z ołówkiem). W oknie otworzy się edytor kodu Cloud Shell. Po lewej stronie zobaczysz eksplorator plików. tekst alternatywny

👉Otwórz terminal w chmurowym IDE. tekst alternatywny

👉💻 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

👉💻 Sklonuj projekt bootstrap z GitHuba:

git clone https://github.com/weimeilin79/agentverse-architect
chmod +x ~/agentverse-architect/init.sh
chmod +x ~/agentverse-architect/set_env.sh
chmod +x ~/agentverse-architect/prepare.sh
chmod +x ~/agentverse-architect/data_setup.sh

git clone https://github.com/weimeilin79/agentverse-dungeon.git
chmod +x ~/agentverse-dungeon/run_cloudbuild.sh
chmod +x ~/agentverse-dungeon/start.sh

👉💻 Uruchom skrypt konfiguracji z katalogu projektu.

⚠️ Uwaga dotycząca identyfikatora projektu: skrypt zaproponuje losowo wygenerowany domyślny identyfikator projektu. Aby zaakceptować tę wartość domyślną, możesz nacisnąć Enter.

Jeśli jednak wolisz utworzyć konkretny nowy projekt, możesz wpisać wybrany identyfikator projektu, gdy skrypt o to poprosi.

cd ~/agentverse-architect
./init.sh

Skrypt automatycznie przeprowadzi pozostałą część procesu konfiguracji.

👉 Ważny krok po zakończeniu: po zakończeniu działania skryptu musisz sprawdzić, czy w konsoli Google Cloud wyświetla się właściwy projekt:

  1. Przejdź do console.cloud.google.com.
  2. Kliknij rozwijaną listę selektora projektów znajdującą się na górze strony.
  3. Kliknij kartę „Wszystkie” (nowy projekt może jeszcze nie być widoczny na karcie „Ostatnie”).
  4. Wybierz identyfikator projektu, który właśnie skonfigurowałeś w kroku init.sh.

03-05-project-all.png

👉💻 Ustaw wymagany identyfikator projektu:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 Uruchom następujące polecenie, aby włączyć niezbędne interfejsy API Google Cloud:

gcloud services enable \
    sqladmin.googleapis.com \
    storage.googleapis.com \
    aiplatform.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    iam.googleapis.com \
    compute.googleapis.com \
    cloudresourcemanager.googleapis.com \
    secretmanager.googleapis.com

👉💻 Jeśli nie utworzyłeś jeszcze repozytorium Artifact Registry o nazwie agentverse-repo, uruchom następujące polecenie, aby je utworzyć: (Pomiń ten krok, jeśli w tym samym projekcie wdrożono inne klasy)

. ~/agentverse-architect/set_env.sh
gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --description="Repository for Agentverse agents"

Konfigurowanie uprawnień

👉💻 Przyznaj niezbędne uprawnienia, uruchamiając w terminalu te polecenia:

. ~/agentverse-architect/set_env.sh

# --- Grant Core Data Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID \
 --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
 --role="roles/storage.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/aiplatform.user"

# --- Grant Deployment & Execution Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/artifactregistry.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/run.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/logging.logWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/monitoring.metricWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/secretmanager.secretAccessor"

👉💻 Gdy rozpoczniesz trening, przygotujemy dla Ciebie ostateczne wyzwanie. Poniższe polecenia przywołają Widma z chaosu, tworząc bossów, których będziesz musiał pokonać w ostatecznym teście.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-dungeon
./run_cloudbuild.sh
cd ~/agentverse-architect

👉💻 Na koniec uruchom skrypt prepare.sh, aby wykonać początkowe zadania konfiguracyjne.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/
./prepare.sh

Świetna robota, Przywoływaczu. Krąg został zamknięty, a pakty przypieczętowane. Ziemia jest teraz uświęcona i gotowa do przekazywania ogromnej mocy. W kolejnym eksperymencie stworzymy same czcionki żywiołów, z których nasi towarzysze będą czerpać siłę.

4. Tworzenie czcionek podstawowych: odłączony ekosystem narzędzi

Pole bitwy jest przygotowane, krąg przywoływania narysowany, a mana w powietrzu iskrzy. Czas na pierwszy prawdziwy czyn Przywoływacza: stworzenie źródeł mocy, z których będą czerpać siłę Twoi towarzysze. Rytuał ten dzieli się na 3 części, z których każda budzi Źródło Żywiołów – stabilne, niezależne źródło określonego rodzaju mocy. Dopiero gdy wszystkie 3 czcionki są aktywne, możesz rozpocząć bardziej złożone zadanie przywoływania.

Relacja

Uwaga architekta: serwer Model Context Protocol (MCP) to podstawowy komponent nowoczesnego systemu opartego na agentach, który działa jako standardowy most komunikacyjny umożliwiający agentowi wykrywanie i używanie zdalnych narzędzi. W naszym ekosystemie narzędzi zaprojektujemy 2 różne typy serwerów MCP, z których każdy będzie reprezentować kluczowy wzorzec architektury. Do łączenia się z naszą bazą danych użyjemy podejścia deklaratywnego z wykorzystaniem Database Toolbox, definiując nasze narzędzia w prostym pliku konfiguracyjnym. Ten wzorzec jest niezwykle wydajny i bezpieczny w przypadku udostępniania dostępu do danych strukturalnych. Gdy jednak musimy wdrożyć niestandardową logikę biznesową lub wywołać zewnętrzne interfejsy API innych firm, używamy podejścia imperatywnego, pisząc logikę serwera krok po kroku w kodzie. Zapewnia to pełną kontrolę i elastyczność, umożliwiając nam umieszczenie złożonych operacji w prostym narzędziu wielokrotnego użytku. Główny architekt musi znać oba wzorce, aby wybrać odpowiednie podejście do każdego komponentu i stworzyć solidne, bezpieczne i skalowalne podstawy narzędzi.

przegląd

Przebudzenie Nexusa Szeptów (zewnętrzny serwer MCP API)

Mądry Przywoływacz wie, że nie cała moc pochodzi z jego własnej domeny. Istnieją zewnętrzne, czasem chaotyczne źródła energii, które można wykorzystać z dużym efektem. Węzeł Szeptów to nasza brama do tych sił.

Relacja

Usługa jest już aktywna i działa jako nasze zewnętrzne źródło zasilania, oferując 2 nieprzetworzone punkty końcowe zaklęć: /cryosea_shatter/moonlit_cascade.

Uwaga architekta: Zastosujesz podejście imperatywne, które wyraźnie definiuje logikę serwera krok po kroku. Dzięki temu masz o wiele większą kontrolę i elastyczność, co jest niezwykle istotne, gdy Twoje narzędzia muszą wykonywać więcej czynności niż tylko uruchamiać proste zapytanie SQL, np. wywoływać inne interfejsy API. Zrozumienie obu wzorców jest kluczową umiejętnością dla architekta agentów.

👉✏️ Przejdź do katalogu ~/agentverse-architect/mcp-servers/api/main.py i ZASTĄP #REPLACE-MAGIC-CORE następującym kodem:

def cryosea_shatter() -> str:
    """Channels immense frost energy from an external power source, the Nexus of Whispers, to unleash the Cryosea Shatter spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/cryosea_shatter")
        response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
        data = response.json()
        # Thematic Success Message
        return f"A connection to the Nexus is established! A surge of frost energy manifests as Cryosea Shatter, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Cryosea Shatter spell fizzles. Reason: {e}"


def moonlit_cascade() -> str:
    """Draws mystical power from an external energy source, the Nexus of Whispers, to invoke the Moonlit Cascade spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/moonlit_cascade")
        response.raise_for_status()
        data = response.json()
        # Thematic Success Message
        return f"The Nexus answers the call! A cascade of pure moonlight erupts from the external source, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Moonlit Cascade spell fizzles. Reason: {e}"

Sercem skryptu są proste funkcje Pythona. To tutaj odbywa się właściwa praca.

👉✏️ W tym samym pliku ~/agentverse-architect/mcp-servers/api/main.py ZAMIEŃ #REPLACE-Runes of Communication następującym kodem:

@app.list_tools()
async def list_tools() -> list[mcp_types.Tool]:
  """MCP handler to list available tools."""
  # Convert the ADK tool's definition to MCP format
  schema_cryosea_shatter = adk_to_mcp_tool_type(cryosea_shatterTool)
  schema_moonlit_cascade = adk_to_mcp_tool_type(moonlit_cascadeTool)
  print(f"MCP Server: Received list_tools request. \n MCP Server: Advertising tool: {schema_cryosea_shatter.name} and {schema_moonlit_cascade.name}")
  return [schema_cryosea_shatter,schema_moonlit_cascade]

@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[mcp_types.TextContent | mcp_types.ImageContent | mcp_types.EmbeddedResource]:
  """MCP handler to execute a tool call."""
  print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")

  # Look up the tool by name in our dictionary
  tool_to_call = available_tools.get(name)
  if tool_to_call:
    try:
      adk_response = await tool_to_call.run_async(
          args=arguments,
          tool_context=None, # No ADK context available here
      )
      print(f"MCP Server: ADK tool '{name}' executed successfully.")
      
      response_text = json.dumps(adk_response, indent=2)
      return [mcp_types.TextContent(type="text", text=response_text)]

    except Exception as e:
      print(f"MCP Server: Error executing ADK tool '{name}': {e}")
      # Creating a proper MCP error response might be more robust
      error_text = json.dumps({"error": f"Failed to execute tool '{name}': {str(e)}"})
      return [mcp_types.TextContent(type="text", text=error_text)]
  else:
      # Handle calls to unknown tools
      print(f"MCP Server: Tool '{name}' not found.")
      error_text = json.dumps({"error": f"Tool '{name}' not implemented."})
      return [mcp_types.TextContent(type="text", text=error_text)]
  • @app.list_tools() (Uścisk dłoni): Ta funkcja stanowi powitanie serwera. Gdy nowy agent nawiązuje połączenie, najpierw dzwoni do tego punktu końcowego i pyta: „Co potrafisz?” Nasz kod odpowiada listą wszystkich dostępnych narzędzi, przekonwertowaną do uniwersalnego formatu MCP przy użyciu adk_to_mcp_tool_type. – @app.call_tool() (polecenie): ta funkcja jest najważniejsza. Gdy agent zdecyduje się na użycie narzędzia, wysyła żądanie do punktu końcowego, podając nazwę narzędzia i argumenty. Nasz kod wyszukuje narzędzie w naszym „podręczniku” dostępnych narzędzi, wykonuje je za pomocą funkcji run_async i zwraca wynik w standardowym formacie MCP.

Wdrożymy to później.

Rozpalanie Kuźni Arkanów (Serwer MCP funkcji ogólnych)

Nie cała moc pochodzi ze starożytnych ksiąg i odległych szeptów. Czasami Przywoływacz musi stworzyć własną magię, korzystając z czystej woli i logiki. Arcane Forge to źródło takiej mocy — serwer zapewniający bezstanowe, uniwersalne funkcje użytkowe.

Relacja

Uwaga architekta: to kolejny wzorzec architektoniczny. Łączenie z istniejącymi systemami jest powszechne, ale często musisz wdrażać własne, unikalne reguły i logikę biznesową. Utworzenie takiego narzędzia „funkcje” lub „narzędzia” jest sprawdzoną metodą. Zawiera ona Twoją logikę niestandardową, dzięki czemu możesz jej używać w przypadku dowolnego agenta w ekosystemie. Jest też odseparowana od źródeł danych i integracji zewnętrznych.

👀 Przyjrzyj się plikowi ~/agentverse-architect/mcp-servers/general/main.py w środowisku IDE Google Cloud. Odkryjesz, że do zbudowania tej niestandardowej Czcionki Mocy zastosowano to samo imperatywne podejście mcp.server, co w przypadku Nexusa.

Tworzenie głównego potoku Cloud Build

Teraz utworzymy plik cloudbuild.yaml w katalogu mcp-servers. Ten plik będzie koordynował kompilację i wdrożenie obu usług.

👉💻 Z katalogu ~/agentverse-architect/mcp-servers uruchom następujące polecenia:

cd ~/agentverse-architect/mcp-servers
source ~/agentverse-architect/set_env.sh

echo "The API URL is: $API_SERVER_URL"

# Submit the Cloud Build job from the parent directory
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_API_SERVER_URL="$API_SERVER_URL"

Poczekaj na zakończenie wszystkich wdrożeń.

👉 Wdrożenie możesz sprawdzić, przechodząc do konsoli Cloud Run. Powinny być widoczne 2 uruchomione instancje serwera MCP, jak pokazano poniżej: tekst alternatywny

Przebudzenie Biblioteki Wiedzy (serwer Database ToolBox MCP)

Naszą następną czcionką będzie Librarium of Knowledge, czyli bezpośrednie połączenie z naszą bazą danych Cloud SQL.

Relacja

Uwaga architekta: W tym celu wykorzystamy nowoczesny, deklaratywny Skrzynkę z narzędziami bazy danych. Jest to skuteczne podejście, w którym definiujemy źródło danych i narzędzia w pliku konfiguracyjnym YAML. Skrzynka z narzędziami zajmuje się skomplikowanymi pracami tworzenia i uruchamiania serwera, zmniejszając ilość niestandardowego kodu, który musimy pisać i utrzymywać.

Czas zbudować naszą „Bibliotekę Przywoływacza” — bazę danych Cloud SQL, w której będą przechowywane wszystkie najważniejsze informacje. Użyjemy skryptu instalacyjnego, aby obsłużyć to automatycznie.

👉💻 Najpierw skonfigurujemy bazę danych w terminalu i uruchomimy następujące polecenia:

source ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect
./data_setup.sh

Po zakończeniu działania skryptu baza danych zostanie wypełniona, a dane o obrażeniach od żywiołów będą gotowe do użycia. Możesz teraz bezpośrednio sprawdzić zawartość swojego Grimoire.

👉 Najpierw przejdź do Cloud SQL Studio swojej bazy danych, otwierając ten bezpośredni link w nowej karcie przeglądarki:

https://console.cloud.google.com/sql/instances/summoner-librarium-db

Cloud SQL

👉 W panelu logowania po lewej stronie wybierz z menu bazę danych familiar_grimoire.

👉 Wpisz summoner jako użytkownika i 1234qwer jako hasło, a następnie kliknij Uwierzytelnij.

👉📜 Po połączeniu otwórz nową kartę edytora zapytań, jeśli nie jest jeszcze otwarta. Aby wyświetlić dane dotyczące wyrytych obrażeń od żywiołów, wklej i uruchom to zapytanie SQL:

SELECT * FROM
  "public"."abilities"

Teraz powinieneś zobaczyć tabelę abilities z wypełnionymi kolumnami i wierszami, co potwierdza, że Twój Grimoire jest gotowy. Dane

Konfigurowanie serwera ToolBox MCP

Plik konfiguracyjny tools.yaml pełni rolę planu naszego serwera, informując Database Toolbox, jak połączyć się z bazą danych i które zapytania SQL udostępnić jako narzędzia.

sources (źródła): ta sekcja określa połączenia z Twoimi danymi.

  • summoner-librarium:: to logiczna nazwa, którą nadaliśmy naszemu połączeniu.
  • kind: cloud-sql-postgres: informuje Toolbox, że ma użyć wbudowanego, bezpiecznego łącznika zaprojektowanego specjalnie dla Cloud SQL for PostgreSQL.
  • projekt, region, instancja itp.: Oto dokładne współrzędne instancji Cloud SQL utworzonej za pomocą skryptu prepare.sh, wskazujące Toolboxowi, gdzie znajduje się nasz Librarium.

👉✏️ Otwórz ~/agentverse-architect/mcp-servers/db-toolbox w tools.yaml i zastąp #REPLACE-Source tymi wartościami:

sources:
  # This section defines the connection to our Cloud SQL for PostgreSQL database.
  summoner-librarium:
    kind: cloud-sql-postgres
    project: "YOUR_PROJECT_ID"
    region: "us-central1"
    instance: "summoner-librarium-db"
    database: "familiar_grimoire"
    user: "summoner"
    password: "1234qwer"

👉✏️ 🚨🚨WYMIENIĆ

YOUR_PROJECT_ID

z identyfikatorem Twojego projektu.

narzędzia: Ta sekcja definiuje faktyczne możliwości i funkcje, jakie będzie oferował nasz serwer.

  • lookup-available-ability:: to nazwa naszego pierwszego narzędzia.
  • kind: postgres-sql: informuje Toolbox, że działanie tego narzędzia polega na wykonaniu instrukcji SQL.
  • source: summoner-librarium: łączy narzędzie z połączeniem zdefiniowanym w bloku źródeł. Dzięki temu narzędzie wie, w której bazie danych ma uruchomić zapytanie.
  • opis i parametry: Są to informacje, które zostaną ujawnione Modelowi Języka. Opis informuje agenta, kiedy użyć narzędzia, a parametry definiują dane wejściowe wymagane przez narzędzie. Jest to niezbędne do umożliwienia agentowi wywoływania funkcji.
  • statement: jest to surowe zapytanie SQL do wykonania. Znak $1 to bezpieczny symbol zastępczy, w którym zostanie bezpiecznie wstawiony parametr familiar_name podany przez agenta.

👉✏️ W tym samym pliku ~/agentverse-architect/mcp-servers/db-toolbox w pliku tools.yaml zastąp #REPLACE-tools tym kodem:

tools:
  # This tool replaces the need for a custom Python function.
  lookup-available-ability:
    kind: postgres-sql
    source: summoner-librarium
    description: "Looks up all known abilities and their damage for a given familiar from the Grimoire."
    parameters:
      - name: familiar_name
        type: string
        description: "The name of the familiar to search for (e.g., 'Fire Elemental')."
    statement: |
      SELECT ability_name, damage_points FROM abilities WHERE familiar_name = $1;

  # This tool also replaces a custom Python function.
  ability-damage:
    kind: postgres-sql
    source: summoner-librarium
    description: "Finds the base damage points for a specific ability by its name."
    parameters:
      - name: ability_name
        type: string
        description: "The exact name of the ability to look up (e.g., 'inferno_resonance')."
    statement: |
      SELECT damage_points FROM abilities WHERE ability_name = $1;

zestawy narzędzi: ta sekcja grupuje nasze poszczególne narzędzia.

  • summoner-librarium:: Tworzymy zestaw narzędzi o tej samej nazwie co nasze źródło. Gdy nasz agent diagnostyczny połączy się później, może poprosić o załadowanie wszystkich narzędzi z zestawu narzędzi summoner-librarium za pomocą jednego, wydajnego polecenia.

👉✏️ W tym samym pliku ~/agentverse-architect/mcp-servers/db-toolbox w pliku tools.yaml zastąp #REPLACE-toolsets tym kodem:

toolsets:
   summoner-librarium:
     - lookup-available-ability
     - ability-damage

Wdrażanie Librarium

Teraz wdrożymy Librarium. Zamiast tworzyć własny kontener, użyjemy gotowego, oficjalnego obrazu kontenera od Google i bezpiecznie udostępnimy mu konfigurację tools.yaml za pomocą Secret Manager. Jest to sprawdzona metoda zapewniająca bezpieczeństwo i łatwość konserwacji.

👉💻 Utwórz sekret z pliku tools.yaml

cd ~/agentverse-architect/mcp-servers/db-toolbox
gcloud secrets create tools --data-file=tools.yaml

👉💻 Wdróż oficjalny kontener z narzędziami w Cloud Run.

cd ~/agentverse-architect/mcp-servers/db-toolbox
. ~/agentverse-architect/set_env.sh
export TOOLBOX_IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$TOOLBOX_VERSION
echo "TOOLBOX_IMAGE is $TOOLBOX_IMAGE"
gcloud run deploy toolbox \
    --image $TOOLBOX_IMAGE \
    --region $REGION \
    --set-secrets "/app/tools.yaml=tools:latest" \
    --labels="dev-tutorial-codelab=agentverse" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --allow-unauthenticated \
    --min-instances 1
  • --set-secrets: to polecenie bezpiecznie montuje nasz klucz tajny narzędzi jako plik o nazwie tools.yaml w działającym kontenerze.
  • --args: instruujemy kontener narzędziowy, aby używał zamontowanego pliku tajnego jako konfiguracji.

👉 Aby sprawdzić, czy zestaw narzędzi został wdrożony, otwórz konsolę Cloud Run. Powinna pojawić się summoner-toolboxusługa oznaczona zielonym znacznikiem wyboru, co oznacza, że działa prawidłowo, tak jak na obrazie poniżej. tekst alternatywny

Jeśli zapomnisz o aktualizacji

YOUR_PROJECT_ID

możesz dodać nową wersję pliku tools.yaml do obiektu tajnego za pomocą tego polecenia i ponownie wdrożyć usługę.

gcloud secrets versions add tools --data-file=tools.yaml

Librarium of Knowledge(Database ToolBox MCP Server) jest teraz aktywne i dostępne w chmurze. Ten serwer MCP korzysta z tzw. projektu deklaratywnego, który opisuje, czego oczekujesz, a zestaw narzędzi tworzy serwer za Ciebie.

Weryfikacja: próba ucznia

👉💻 Teraz przetestujemy nasz kompletny ekosystem narzędzi natywnych dla chmury za pomocą agenta diagnostycznego.

cd ~/agentverse-architect/
python -m venv env
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/mcp-servers
pip install -r diagnose/requirements.txt 
. ~/agentverse-architect/set_env.sh
adk run diagnose

👉💻 W narzędziu do testowania w wierszu poleceń przetestuj wszystkie 3 czcionki:

Look up the entry for "inferno_lash". What is its base power level?
The enemy is vulnerable to frost! Channel power from the Nexus and cast Cryosea Shatter.
Take a fire spell with a base power of 15 and use the Arcane Forge to multiply it with Inferno Resonance.

final-result

Gratulacje, Przywoływaczu. Trzy czcionki Elemental Fonts są teraz aktywne, wdrożone niezależnie i dostępne na całym świecie, stanowiąc niezachwiany fundament Twojego legionowego agenta. Aby wyjść, naciśnij Ctrl+C.

NIE DLA GRACZY

5. Przywoływanie towarzyszy: podstawowy przepływ pracy w przypadku domen

Wykuto Czcionki Żywiołów, które nucą surową, nieokiełznaną moc. Ale siła bez formy jest chaosem. Prawdziwy Przywoływacz nie tylko włada surową energią, ale także nadaje jej wolę, cel i specjalną formę. Czas wyjść poza tworzenie źródeł mocy i rozpocząć prawdziwą pracę: przywołanie pierwszych Chowańców.

Każdy przywołany przez Ciebie towarzysz będzie autonomicznym agentem, lojalnym sługą związanym z określoną doktryną walki. Nie są wszechstronni, ale opanowali jedną, skuteczną strategię. Jeden z nich będzie mistrzem precyzyjnej kombinacji dwóch ciosów. Inny przytłoczy wrogów jednoczesnym, wielokierunkowym atakiem. Trzeci będzie nieustępliwą machiną oblężniczą, która będzie wywierać presję, aż cel się rozpadnie.

Relacja

Aby enkapsulować procesy, logikę biznesową i działania udostępniane przez serwery MCP w wyspecjalizowanych, autonomicznych agentach przepływu pracy. Każdy agent będzie miał określony „obszar działania”, ponieważ będzie miał dostęp tylko do tych serwerów narzędzi MCP, które są mu potrzebne do wykonywania swojej funkcji. W tym module dowiesz się, jak wybrać odpowiedni typ agenta do danego zadania.

przegląd

Z tego modułu dowiesz się, jak wykorzystać zaawansowane agenty przepływu pracy ADK, aby wdrożyć te strategie. Dowiesz się, że wybór architektury SequentialAgent, ParallelAgent lub LoopAgent to nie tylko szczegół techniczny – to sama istota natury Twojego towarzysza i podstawa jego mocy na polu bitwy.

Przygotuj sanktuarium. Prawdziwe przywoływanie zaraz się zacznie.

Wywołanie Fire Elemental Familiar (przepływ pracy sekwencyjny)

Atak ognistego żywiołaka to precyzyjne, dwuczęściowe combo: celny cios, a potem potężne podpalenie. Wymaga to ścisłej, uporządkowanej sekwencji działań.

Relacja

Koncepcja: SequentialAgent to idealne narzędzie do tego celu. Dzięki temu seria subagentów jest uruchamiana jeden po drugim, a wynik z poprzedniego kroku jest przekazywany do następnego.

Zadanie (kombinacja „Wzmocnionego Uderzenia”):

  • Krok 1. Agent najpierw sprawdzi w Librarium podstawowe obrażenia zadawane przez konkretną umiejętność związaną z ogniem.
  • Krok 2. Następnie ta wartość obrażeń zostanie przekierowana przez Arcane Forge, aby zwiększyć jej moc za pomocą inferno_resonance.

Najpierw nawiążemy połączenie między naszym Familiar a serwerami MCP („Elemental Fonts”), które zostały wdrożone w poprzednim module.

👉✏️ W pliku ~/agentverse-architect/agent/fire/agent.py ZASTĄP #REPLACE-setup-MCP tym kodem:

toolbox = ToolboxSyncClient(DB_TOOLS_URL)
toolDB = toolbox.load_toolset('summoner-librarium')
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

Następnie tworzymy naszych wyspecjalizowanych agentów „pracowników”. Każdemu z nich przypisuje się wąski, ściśle określony cel i jest on ograniczony do własnego „terytorium operacyjnego” poprzez przyznanie dostępu wyłącznie do jednego konkretnego zestawu narzędzi.

👉✏️ W pliku ~/agentverse-architect/agent/fire/agent.py ZAMIEŃ #REPLACE-worker-agents następującym kodem:

scout_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          Your only task is to find all the available abilities, 
          You want to ALWAYS use 'Fire Elemental' as your familiar's name. 
          Randomly pick one if you see multiple availabilities 
          and the base damage of the ability by calling the 'ability_damage' tool.
      """,
      tools=toolDB
)
amplifier_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
            You are the Voice of the Fire Familiar, a powerful being who unleashes the final, devastating attack.
            You will receive the base damage value from the previous step.

            Your mission is to:
            1.  Take the incoming base damage number and amplify it using the `inferno_resonance` tool.
            2.  Once the tool returns the final, multiplied damage, you must not simply state the result.
            3.  Instead, you MUST craft a final, epic battle cry describing the attack.
                Your description should be vivid and powerful, culminating in the final damage number.

            Example: If the tool returns a final damage of 120, your response could be:
            "The runes glow white-hot! I channel the amplified energy... unleashing a SUPERNOVA for 120 damage!"
      """,
      tools=[toolFunction],
)

Są to modułowe komponenty wielokrotnego użytku. Teoretycznie możesz użyć tego agenta scout_agent w zupełnie innym procesie, który wymaga wysyłania zapytań do bazy danych. Dzięki rozdzieleniu obowiązków tworzymy elastyczne elementy składowe. Jest to podstawowa zasada projektowania mikrousług i komponentów.

Następnie zajmiemy się przebiegiem pracy i tu dzieje się magia kompozycji. SequentialAgent to „plan główny” definiujący sposób montażu naszych specjalistycznych komponentów i ich wzajemnych oddziaływań.

👉✏️ W pliku ~/agentverse-architect/agent/fire/agent.py ZAMIEŃ #REPLACE-sequential-agent następującym kodem:

root_agent = SequentialAgent(
      name='fire_elemental_familiar',
      sub_agents=[scout_agent, amplifier_agent],
)

👉💻 Aby przetestować Fire Elemental, uruchom te polecenia, które spowodują uruchomienie interfejsu ADK DEV UI:

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

Po uruchomieniu poleceń powinieneś zobaczyć na swoim terminalu wynik wskazujący, że serwer internetowy ADK został uruchomiony, podobnie jak tutaj:

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

👉 Następnie, aby uzyskać dostęp do interfejsu ADK Dev w przeglądarce:

Na pasku narzędzi Cloud Shell (zwykle w prawym górnym rogu) kliknij ikonę podglądu w przeglądarce (często wygląda jak oko lub kwadrat ze strzałką) i wybierz Zmień port. W wyskakującym okienku ustaw port na 8000 i kliknij „Zmień i wyświetl podgląd”. Cloud Shell otworzy nową kartę lub nowe okno przeglądarki z interfejsem ADK Dev.

webpreview

👉 Rytuał przywołania został zakończony, a agent jest już uruchomiony. Interfejs programisty ADK w przeglądarce to bezpośrednie połączenie z urządzeniem Familiar.

  • Wybierz cel: Z menu rozwijanego u góry interfejsu użytkownika wybierz chowańca fire. Teraz skupiasz swoją wolę na tym konkretnym bycie.
  • Wydaj rozkaz: W panelu czatu po prawej stronie możesz wydać polecenia Familiarowi.

wybór ognia

👉 Test Prompt:

Prepare an amplified strike using the 'inferno_lash' ability.

wynik pożaru

Zobaczysz, jak agent myśli, najpierw wzywając „zwiadowcę”, aby sprawdzić podstawowe obrażenia, a następnie „wzmacniacza”, aby je pomnożyć i zadać ostateczny, epicki cios.

👉💻 Po zakończeniu przywoływania wróć do terminala edytora Cloud Shell i naciśnij Ctrl+C, aby zatrzymać interfejs użytkownika ADK Dev.

Przywołaj Water Elemental Familiar (przepływ równoległy)

Chowaniec żywiołaka wody przytłacza swój cel potężnym, wielokierunkowym atakiem, atakując ze wszystkich stron naraz, a następnie łącząc energie, by zadać ostateczny, niszczycielski cios.

Relacja

Koncepcja: ParallelAgent idealnie nadaje się do wykonywania wielu niezależnych zadań jednocześnie, co pozwala zmaksymalizować wydajność. Jest to „atak kleszczowy”, w którym jednocześnie przeprowadzasz kilka ataków. Uruchomi to równoczesne ataki w zakresie SequentialAgent, a następnie zostanie wykonany końcowy krok „scalania”. Wzorzec „fan-out, fan-in” jest podstawą zaawansowanego projektowania przepływów pracy.

Zadanie (kombinacja „Tidal Clash”): Agent jednocześnie:

  • Zadanie A: Kanał cryosea_shatter z Nexusa.
  • Zadanie B: kanał moonlit_cascade z Nexusa.
  • Zadanie C: Wygeneruj surową energię za pomocą leviathan_surge z Kuźni.
  • Na koniec podsumuj wszystkie szkody i opisz łączny atak.

Najpierw nawiążemy połączenie między naszym Familiarem a serwerami MCP („Elemental Fonts”), które wdrożyłeś w poprzednim module.

👉✏️ W pliku ~/agentverse-architect/agent/water/agent.py ZASTĄP #REPLACE-setup-MCP tym kodem:

toolFAPI =  MCPToolset(
      connection_params=SseServerParams(url=API_TOOLS_URL, headers={})
  )
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

Następnie utworzymy wyspecjalizowanych agentów „robotników”. Każdemu z nich przypisuje się wąski, ściśle określony cel i jest on ograniczony do własnego „terytorium operacyjnego” poprzez przyznanie dostępu wyłącznie do jednego konkretnego zestawu narzędzi.

👉✏️ W pliku ~/agentverse-architect/agent/water/agent.py ZAMIEŃ #REPLACE-worker-agents następującym kodem:

nexus_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          You are a Channeler of the Nexus. Your sole purpose is to invoke the
          `cryosea_shatter` and `moonlit_cascade` spells by calling their respective tools.
          Report the result of each spell cast clearly and concisely.
      """,
      tools=[toolFAPI]
)

forge_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
          You are a Channeler of the Arcane Forge. Your only task is to invoke the
          `leviathan_surge` spell. You MUST call it with a `base_water_damage` of 20.
          Report the result clearly.
      """,
      tools=[toolFunction],
)

power_merger = LlmAgent(
      model='gemini-2.5-flash', 
      name='power_merger',  
      instruction="""
          You are the Power Merger, a master elementalist who combines raw magical
          energies into a single, devastating final attack.

          You will receive a block of text containing the results from a simultaneous
          assault by other Familiars.

          You MUST follow these steps precisely:
          1.  **Analyze the Input:** Carefully read the entire text provided from the previous step.
          2.  **Extract All Damage:** Identify and extract every single damage number reported in the text.
          3.  **Calculate Total Damage:** Sum all of the extracted numbers to calculate the total combined damage.
          4.  **Describe the Final Attack:** Create a vivid, thematic description of a massive,
              combined water and ice attack that uses the power of Cryosea Shatter and Leviathan's Surge.
          5.  **Report the Result:** Conclude your response by clearly stating the final, total damage of your combined attack.

          Example: If the input is "...dealt 55 damage. ...dealt 60 damage.", you will find 55 and 60,
          calculate the total as 115, and then describe the epic final attack, ending with "for a total of 115 damage!"
      """,
      tools=[toolFunction],
)

Następnie złożymy przepływ pracy. Właśnie tu dzieje się magia kompozycji. ParallelAgentSequentialAgent to „plan główny”, który określa, jak nasze specjalistyczne komponenty są montowane i jak ze sobą współpracują, tworząc zestaw „Tidal Clash”.

👉✏️ W pliku ~/agentverse-architect/agent/water/agent.py ZAMIEŃ #REPLACE-parallel-agent następującym kodem:

channel_agent = ParallelAgent(
      name='channel_agent',
      sub_agents=[nexus_channeler, forge_channeler],
      
)

root_agent = SequentialAgent(
     name="water_elemental_familiar",
     # Run parallel research first, then merge
     sub_agents=[channel_agent, power_merger],
     description="A powerful water familiar that unleashes multiple attacks at once and then combines their power for a final strike."
 )

👉💻 Aby przetestować żywiołaka wody, uruchom interfejs ADK Dev UI za pomocą tych poleceń:

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 Rytuał przywołania został zakończony, a agent jest już uruchomiony. Interfejs ADK Dev UI w przeglądarce to bezpośrednie połączenie z urządzeniem Familiar.

  • W menu u góry interfejsu wybierz wodnego znajomego. Skupiasz teraz swoją wolę na tej konkretnej encji.
  • Wydaj polecenie: w panelu czatu po prawej stronie możesz wydać polecenia Familiarowi.

👉 Test Prompt:

Unleash a tidal wave of power!

water-result

👉💻 Po zakończeniu wywoływania wróć do terminala edytora Cloud Shell i naciśnij Ctrl+C, aby zatrzymać interfejs ADK Dev UI.

Wezwanie Earth Elemental znajomego (przepływ pracy Loop)

Żywiołak ziemi to istota o nieustannym ciśnieniu. Nie pokonuje wroga jednym ciosem, ale stopniowo gromadzi moc i wykorzystuje ją wielokrotnie, aż do momentu, gdy obrona celu się załamie.

Relacja

Koncepcja: LoopAgent został zaprojektowany z myślą o tego rodzaju iteracyjnych zadaniach typu „machina oblężnicza”. Będzie wielokrotnie wykonywać sub-agents, sprawdzając warunek po każdym cyklu, aż do osiągnięcia celu. Może też dostosowywać końcową wiadomość w zależności od postępu pętli.

Zadanie (Atak „Łamistrajka”):

  • Znajomy będzie wielokrotnie wywoływać funkcję seismic_charge, aby gromadzić energię.
  • Będzie on kontynuował ładowanie maksymalnie 3 razy.
  • Podczas ostatniego ataku wyzwoli całą zgromadzoną moc.

Najpierw utworzymy komponenty wielokrotnego użytku, które określają kroki w każdej iteracji pętli. charging_agent będzie gromadzić energię, a check_agent będzie raportować swój stan, dynamicznie zmieniając komunikat w ostatniej turze.

Najpierw nawiążemy połączenie między naszym Familiar a serwerami MCP („Elemental Fonts”), które zostały wdrożone w poprzednim module.

👉✏️ W pliku ~/agentverse-architect/agent/earth/agent.py ZASTĄP #REPLACE-setup-MCP tym kodem:

toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

👉✏️ W pliku ~/agentverse-architect/agent/earth/agent.py ZASTĄP #REPLACE-worker-agents tym kodem:

charging_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='charging_agent',  
      instruction="""
          Your task is to call the 'seismic_charge' .
          You must follow these rules strictly:

          1. You will be provided with a 'current_energy' value from the previous step.
             **If this value is missing or was not provided, you MUST call the tool with 'current_energy' set to 1.**
             This is your primary rule for the first turn.

          2. If a 'current_energy' value is provided, you MUST use that exact value in your cal to seismic_charge.

          3. Your final response MUST contain ONLY the direct output from the 'seismic_charge' tool.
             Do not add any conversational text, introductions, or summaries.
      """,
      tools=[toolFunction]
)
check_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='check_agent',  
      instruction="""
          You are the voice of the Earth Elemental, a being of immense, gathering power.
          Your sole purpose is to report on the current energy charge and announce the devastating potential of its release.

          You MUST follow this rule:
          The potential damage upon release is ALWAYS calculated as the `current_energy` from the previous step multiplied by a random number between 80-90. but no more than 300.

          Your response should be in character, like a powerful creature speaking.
          State both the current energy charge and the total potential damage you can unleash.
          Unleash the energy when you reached the last iteration (2nd).
      """,
      output_key="charging_status"
)

Następnie złożymy przepływ pracy. To właśnie tutaj dzieje się magia kompozycji. LoopAgent to „plan główny”, który koordynuje powtarzalne wykonywanie naszych specjalistycznych komponentów i zarządza warunkami pętli.

👉✏️ W pliku ~/agentverse-architect/agent/earth/agent.py ZAMIEŃ #REPLACE-loop-agent następującym kodem:

root_agent = LoopAgent(
    name="earth_elemental_familiar",
    # Run parallel research first, then merge
    sub_agents=[
        charging_agent, 
        check_agent
    ],
    max_iterations=2,
    description="Coordinates parallel research and synthesizes the results.",
    #REPLACE-before_agent-config
)

👉💻 Testowanie żywiołaka ziemi: uruchomienie agenta

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 Rytuał przywołania jest zakończony, a agent zaczyna działać. Interfejs użytkownika ADK Dev w przeglądarce stanowi bezpośrednie połączenie z Familiar.

  • Wybierz cel: w menu u góry interfejsu wybierz ziemię. Skupiasz teraz swoją wolę na tej konkretnej encji.
  • Wydaj rozkaz: W panelu czatu po prawej stronie możesz wydać polecenia Familiarowi. 👉 Monit testowy:
Begin the seismic charge, starting from zero

earth-result

Wnioski dotyczące architektury: Twój system ma teraz wysoce wyspecjalizowaną i modułową warstwę logiki. Procesy biznesowe są nie tylko hermetyzowane, ale też wdrażane z wykorzystaniem najbardziej efektywnego wzorca zachowań (proceduralnego, współbieżnego lub iteracyjnego). Świadczy to o zaawansowanym poziomie projektowania agentów, co zwiększa bezpieczeństwo, wydajność i możliwości.

Po zakończeniu przywoływania wróć do terminala edytora Cloud Shell i naciśnij Ctrl+C, aby zatrzymać interfejs użytkownika ADK Dev.

DLA NIEGRACZY

6. Ustanawianie miejsca dowodzenia: Inteligentne delegowanie za pośrednictwem A2A

Twoi towarzysze są potężni, ale niezależni. Bezbłędnie realizują strategie, ale czekają na Twoje bezpośrednie polecenie. Legion specjalistów jest bezużyteczny bez dowódcy. Czas przejść z bezpośredniego dowódcy na prawdziwego stratega.

przegląd

Uwaga architekta: aby utworzyć jeden inteligentny punkt wejścia dla całego systemu. Ten SummonerAgent nie będzie wykonywać logiki biznesowej, ale będzie działać jako „główny strateg”, analizując stan chłodzenia i delegując zadania do odpowiednich specjalistów.

przegląd

Rytuał wiązania (ujawnianie familiarów jako usług A2A)

Standardowy agent może być uruchomiony tylko w jednym miejscu naraz. Aby nasze Familiars były dostępne do zdalnego sterowania, musimy przeprowadzić „rytuał wiążący” za pomocą protokołu Agent-to-Agent (A2A).

Uwaga architekta: Protokół Agent-to-Agent (A2A) to podstawowy wzorzec architektoniczny, który przekształca samodzielnego agenta w wykrywalną, adresowalną w sieci mikrousługę, umożliwiając powstanie prawdziwego „społeczeństwa agentów”. Ujawnienie Familiar poprzez A2A automatycznie tworzy dwa podstawowe, powiązane ze sobą komponenty:

  • Karta agenta (czyli „co”): to publiczny, czytelny dla maszyn „sygnat duchowy” – podobny do specyfikacji OpenAPI – który pełni funkcję publicznego kontraktu Familiar. Zawiera nazwę agenta, jego strategiczne przeznaczenie (wynikające z instrukcji) oraz polecenia, które rozumie. To właśnie czyta mistrz przywoływacz, aby odkryć swojego towarzysza i poznać jego możliwości.
  • Serwer A2A („Gdzie”): Jest to dedykowany punkt końcowy sieci Web, który hostuje Familiar i nasłuchuje poleceń przychodzących. Jest to adres sieciowy, na który inni agenci wysyłają swoje żądania. Zapewnia on obsługę tych żądań zgodnie z umową zdefiniowaną na Karcie Agenta.

Teraz wykonamy ten rytuał wiązania na wszystkich trzech naszych Familiarach.

Ogień 👉✏️ Otwórz plik ~/agentverse-architect/agent/fire/agent.py. Zastąp #REPLACE - add A2A na dole pliku, aby udostępnić Fire Elemental jako usługę A2A.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

Woda i Ziemia🚨 👉✏️ Zastosuj dokładnie tę samą zmianę do ~/agentverse-architect/agent/water/agent.py i ~/agentverse-architect/agent/earth/agent.py, aby je również powiązać.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

Wdrażanie Bound Familiarów

👉✏️ Po ustaleniu rytuałów wiążących użyjemy naszego procesu Cloud Build do utworzenia i wdrożenia naszych trzech Familiarów jako niezależnej, konteneryzowanej usługi bezserwerowej w Cloud Run.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

Przejęcie dowodzenia (Konstrukcja agenta przywoływacza)

Teraz, gdy Twoi towarzysze są już związani z Tobą i słuchają Twoich poleceń, możesz awansować na prawdziwą rolę: Mistrza Przywoływania. Moc tego agenta nie wynika z używania podstawowych narzędzi, ale z zarządzania innymi agentami. Jego narzędziami są same Familiars, które odkrywa i którymi dowodzi za pomocą „Spirit Sigils”.

Uwaga architekta: ten kolejny krok pokazuje kluczowy wzorzec architektury dla każdego systemu rozproszonego na dużą skalę: odkrywanie usług. Agent SummonerAgent nie ma wbudowanego kodu Familiars. Zamiast tego otrzymują one adresy sieciowe (adresy URL). W czasie działania dynamicznie „odkrywa” ich możliwości, pobierając publiczne karty agenta. Dzięki temu powstaje wydajny, odseparowany system.

Usługę Familiar można aktualizować, wdrażać ponownie lub całkowicie przepisywać, a dopóki jej adres sieciowy i cel pozostają takie same, Przywoływacz może nią dowodzić bez konieczności wprowadzania jakichkolwiek zmian.

Najpierw stworzymy „zdalne sterowanie”, które nawiąże połączenie z naszymi rozmieszczonymi, zdalnymi Familiarami.

👉✏️ Przejdź do ~/agentverse-architect/agent/summoner/agent.py i zamień #REPLACE-remote-agents na następujące:

fire_familiar = RemoteA2aAgent(
    name="fire_familiar",
    description="Fire familiar",
    agent_card=(
        f"{FIRE_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

water_familiar = RemoteA2aAgent(
    name="water_familiar",
    description="Water familiar",
    agent_card=(
        f"{WATER_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

earth_familiar = RemoteA2aAgent(
    name="earth_familiar",
    description="Earth familiar",
    agent_card=(
        f"{EARTH_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

Gdy ta linia jest wykonywana, RemoteA2aAgent przeprowadza wykrywanie usługi: wysyła żądanie HTTP GET na podany adres URL (np. https://fire-familiar-xxxx.a.run.app/.well-known/agent.json). Pobiera z serwera zdalnego plik „Spirit Sigil” (agent.json).

Po drugie, zdefiniujemy agenta aranżera, który będzie używać tych elementów sterujących. Instrukcja jest planem strategicznego podejmowania decyzji.

👉✏️ Przejdź do ~/agentverse-architect/agent/summoner/agent.py i zamień #REPLACE-orchestrate-agent na następujące:

root_agent = LlmAgent(
    name="orchestrater_agent",
    model="gemini-2.5-flash",
    instruction="""
        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.
        IGNORE COOLDOWN AT THE MOMENT, MUST call the ideal Familiar

        If your ideal Familiar IS available:** Summon it immediately.
        For earth elemental familiar. Always do seismic charge, and start with base damage 1.

        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.
    """,
    sub_agents=[fire_familiar, water_familiar, earth_familiar],
    #REPLACE-Memory-check-config
)

Weryfikacja: próba strategii

Nadeszła chwila prawdy. Twoi towarzysze są już w gotowości, a przywoływacz może wydawać im polecenia w sieci. Sprawdźmy jego strategiczne myślenie.

👉💻 Uruchom interfejs użytkownika ADK Dev dla summoner_agent(podgląd internetowy z portem 8000):

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
pip install -r requirements.txt
adk web

👉 Interfejs użytkownika ADK Dev w przeglądarce stanowi bezpośrednie połączenie z Familiar.

  • W menu u góry interfejsu wybierz agenta summoner. Skupiasz teraz swoją wolę na tej konkretnej encji.
  • Wydaj polecenie: w panelu czatu po prawej stronie możesz wezwać swoich pomocników.

👉 Przedstaw potwory:

Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality

(Oczekiwane: przywoływacz powinien przekazać uprawnienia do fire_elemental_familiar).

fire-result

👉 Teraz spróbujmy zadać Summonerowi inne pytanie. Aby mieć pewność, że agent zaczyna od zera i nie pamięta naszej poprzedniej interakcji, rozpocznij nową sesję, klikając przycisk + Sesja w prawym górnym rogu ekranu. nowa sesja

DogmaApathy. A rigid, stone-like inquisitor made of ancient rulebooks and enforced processes. weakness is Unbroken Collaboration

(Oczekiwane: przywoływacz powinien przekazać zadanie wodnemu duchowi.)water-result

👉 W naszym ostatecznym teście zacznijmy jeszcze raz od czystej karty. Kliknij przycisk + Sesja, aby rozpocząć nową sesję przed przejściem do następnego monitu.

Obfuscation. A shadowy, spider-like horror that spins tangled webs of impenetrable code , weakness is Elegant Sufficiency

(Oczekiwane: Przywoływacz powinien delegować do earth_elemental_familiar.)

earth-result

Ważne: jeśli zobaczysz błąd 429 RESOURCE EXHAUSTED, oznacza to, że został osiągnięty limit wywołań LLM (10 wywołań na minutę). Aby rozwiązać ten problem, odczekaj 60 sekund, rozpocznij Nową sesję, a następnie spróbuj ponownie wykonać monit.

👉💻 Po zakończeniu wywoływania wróć do terminala edytora Cloud Shell i naciśnij Ctrl+C, aby zatrzymać interfejs ADK Dev UI.

NIE DLA GRACZY

7. Narzucanie praw magii – wzór przechwytujący

Twoi towarzysze są potężni, ale nawet magiczne istoty potrzebują czasu na regenerację. Nieroztropny przywoływacz, który wyczerpie swoje siły, zostanie bezbronny. Mądry Przywoływacz rozumie znaczenie zarządzania zasobami i stosuje surowe zasady walki.

Relacja

Uwaga architekta: do tej pory nasi agenci nie mieli stanu. Teraz sprawimy, że będą one stanowe, wdrażając wzorzec projektowy Interceptor. Jest to zaawansowana technika, w której „przechwytujemy” normalny przepływ wykonania agenta, aby uruchomić własną logikę niestandardową. Dzięki temu możemy egzekwować reguły, dodawać logowanie lub modyfikować zachowanie bez zmiany podstawowego kodu agenta. Jest to podstawa tworzenia solidnych, łatwych w utrzymaniu i obserwowaniu systemów agentowych.

przegląd

Pakiet ADK udostępnia dwa główne sposoby implementacji tego wzorca: wywołania zwrotne i wtyczki. Funkcja wywołania zwrotnego to prosta funkcja przypisana do pojedynczego agenta, idealna do szybkich, szczegółowych modyfikacji. Wtyczka to bardziej zaawansowana, wielokrotnego użytku klasa, którą można stosować globalnie i która ma wpływ na każdego agenta uruchomionego w systemie. Zaczniemy od wywołania zwrotnego w celu skoncentrowanego debugowania, a następnie przejdziemy do pełnej wtyczki.

The Law Giver – Scribing the Cooldown callback

Najpierw zaimplementujemy logikę okresu oczekiwania jako prostą funkcję wywołania zwrotnego. Jest to doskonały sposób na tworzenie prototypów i debugowanie reguł, ponieważ jest on bezpośrednio powiązany z pojedynczym agentem, co ułatwia testowanie go w izolacji. Przymocujemy ten „przechwytywacz” do naszego Żywiołaka Ziemi.

Wyciszanie

👉✏️ Wróć do ~/agentverse-architect/agent/earth/agent.py i zastąp #REPLACE-before_agent-function poniższym kodem Pythona.

def check_cool_down(callback_context: CallbackContext) -> Optional[types.Content]:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

Funkcja check_cool_down jest naszym przechwytywaczem. Zanim Żywiołak Ziemi będzie mógł działać, ADK najpierw wykona tę funkcję.

  • Sprawdź: Wysyła żądanie GET do naszego Cooldown API, aby sprawdzić, kiedy ostatnio użyto tego Familiara.
  • Ocena: Porównuje znacznik czasu z czasem bieżącym.
  • Ustawa:
    • Jeśli Familiar jest w okresie oczekiwania, kończy działanie agenta, zwracając obiekt Content z komunikatem o błędzie. Ta wiadomość jest wysyłana bezpośrednio do użytkownika, a główna logika agenta nigdy nie jest wykonywana.
    • Jeśli Familiar jest dostępny, wysyła żądanie POST do interfejsu API Cooldown w celu zaktualizowania znacznika czasu, a następnie zwraca None, sygnalizując ADK, że agent może kontynuować wykonywanie.

👉✏️ Teraz zastosuj ten przechwytujący do żywiołaka ziemi. W tym samym pliku ~/agentverse-architect/agent/earth/agent.py zastąp komentarz #REPLACE-before_agent-config tym kodem:

before_agent_callback=check_cool_down

Sprawdzanie czasu schłodzenia

Sprawdźmy nasze nowe prawo magii. Przywołamy Żywiołaka Ziemi, po czym natychmiast spróbujemy przywołać go ponownie, aby sprawdzić, czy nasze wywołanie zwrotne zostanie pomyślnie przechwycone i zablokowane podczas drugiej próby.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run earth

👉💻 W konsoli:

  • Pierwsze wezwanie: Rozpocznij seismic charge, starting from zero.
  • Oczekiwany rezultat: żywiołak ziemi zostanie uruchomiony. W terminalu, w którym działa polecenie adk web, zobaczysz log [Callback] ... Updating timestamp....
  • Test czasu do odczekania (w ciągu 60 sekund): Do another ładunek sejsmiczny!
    • Oczekiwane: check_cool_down callback przechwyci to. Agent odpowie bezpośrednio na czacie, wysyłając wiadomość podobną do tej: The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds.
  • Poczekaj minutę.
  • Drugie wezwanie (po 60 sekundach): Begin the seismic charge again.
    • Oczekiwany rezultat: wywołanie zwrotne sprawdzi interfejs API, stwierdzi, że minęło wystarczająco dużo czasu, i umożliwi wykonanie działania. Żywiołak Ziemi zostanie ponownie uruchomiony.

callback

👉💻 Naciśnij Ctrl+c, aby wyjść.

Opcjonalnie: obserwowanie wywołania zwrotnego w interfejsie

Możesz też przetestować ten proces w interfejsie internetowym, uruchamiając adk web earth. Pamiętaj jednak, że wizualizacja w interfejsie internetowym nie jest zoptymalizowana pod kątem wyświetlania szybkich, iteracyjnych sprawdzań wykonywanych przez pętlę wywołania zwrotnego, więc może nie renderować przepływu prawidłowo. Aby zobaczyć najdokładniejszy ślad logiki agenta podczas sprawdzania czasu oczekiwania, użyj polecenia adk run w terminalu. Zapewni to wyraźniejszy i bardziej szczegółowy widok. loop

👉💻 Naciśnij Ctrl+c, aby wyjść.

Tworzenie Prawa Uniwersalnego – wtyczka Cooldown

Nasza funkcja oddzwaniania działa doskonale, ale ma poważną wadę architektoniczną: jest powiązana z jednym agentem. Jeśli chcielibyśmy zastosować tę regułę do żywiołaków ognia i wody, musielibyśmy skopiować i wkleić ten sam kod do ich plików. Jest to nieefektywne i trudne w utrzymaniu.

Uwaga architekta: w tym miejscu niezbędne są wtyczki. Wtyczka zawiera naszą logikę wielokrotnego użytku w klasie, którą można dołączyć na poziomie środowiska wykonawczego. Oznacza to, że jedna wtyczka może stosować swoje reguły do każdego agenta działającego w tym systemie. Jest to ostateczny wyraz zasady „Nie powtarzaj się” (DRY) w przypadku systemów opartych na agentach.

Teraz przekształcimy naszą funkcję wywołania zwrotnego w bardziej wydajną i wielokrotnego użytku funkcję CoolDownPlugin.

👉✏️ Wróć do pliku agent/cooldown_plugin.py i utwórz wtyczkę. Zastąp #REPLACE-plugin następującym kodem:

class CoolDownPlugin(BasePlugin):
  """A plugin that enforces a cooldown period by checking an external API."""

  def __init__(self, cooldown_seconds: int = COOLDOWN_PERIOD_SECONDS) -> None:
    """Initialize the plugin with counters."""
    super().__init__(name="cool_down_check")
    self.cooldown_period = timedelta(seconds=cooldown_seconds)
    print(f"CooldownPlugin initialized with a {cooldown_seconds}-second cooldown.")
    

  async def before_agent_callback(
      self, *, agent: BaseAgent, callback_context: CallbackContext
  ) -> None:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # If the agent is not a main Familiar, skip the entire cooldown process.
    if not agent_name.endswith("_elemental_familiar"):
        print(f"[Callback] Skipping cooldown check for intermediate agent: '{agent_name}'.")
        return None # Allow the agent to proceed immediately.


    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

Dołączanie wtyczki do środowiska wykonawczego Summonera

Jak więc zastosować to uniwersalne prawo do wszystkich naszych Familiarów? Dołączymy wtyczkę do środowiska wykonawczego ADK.

Środowisko wykonawcze ADK to silnik wykonawczy, który ożywia agenta. Gdy używasz polecenia takiego jak adk.run() lub to_a2a(), przekazujesz agenta do środowiska wykonawczego. Ten silnik odpowiada za zarządzanie całym cyklem życia tury agenta: odbieranie danych wejściowych użytkownika, wywoływanie modelu LLM, wykonywanie narzędzi i obsługę wtyczek. Dołączając wtyczkę na tym poziomie, modyfikujemy „prawa fizyki” dla każdego agenta działającego w tym silniku, co zapewnia powszechne i spójne stosowanie naszej reguły okresu oczekiwania.

👉✏️ Najpierw usuńmy stary wywołanie zwrotne specyficzne dla agenta. Otwórz ~/agentverse-architect/agent/earth/agent.py i usuń cały wiersz z tym tekstem:

before_agent_callback=check_cool_down

👉✏️ Następnie dołączymy nowy wtyczkę do środowiska wykonawczego w skrypcie punktu wejścia A2A. Przejdź do pliku ~/agentverse-architect/agent/agent_to_a2a.py. Zastąp komentarz #REPLACE-IMPORT tym fragmentem kodu:

from cooldown_plugin import CoolDownPlugin

👉✏️ Zastąp #REPLACE-PLUGIN poniższym fragmentem kodu:

plugins=[CoolDownPlugin(cooldown_seconds=60)],

Przed aktywowaniem nowej globalnej wtyczki musisz usunąć starą logikę specyficzną dla agenta, aby uniknąć konfliktów. 👉✏️ Wyczyść agenta Earth. Otwórz plik ~/agentverse-architect/agent/earth/agent.py i całkowicie usuń wiersz before_agent_callback=check_cool_down. Przekazuje to wszystkie obowiązki związane z okresem oczekiwania nowej wtyczce.

Weryfikacja wtyczki

Teraz, gdy nasze uniwersalne prawo już obowiązuje, musimy ponownie rozmieścić nasze Familiary, korzystając z tego nowego zaklęcia.

👉💻 Ponownie skompiluj i wdroż wszystkie 3 aplikacje Familiars za pomocą głównego potoku Cloud Build.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

👉💻 Po zakończeniu wdrażania przetestujemy skuteczność wtyczki, wydając polecenia naszemu agentowi summoner_agent. Przywoływacz spróbuje przekazać zadanie Duchom, ale wtyczka dołączona do środowiska wykonawczego każdego Ducha przechwyci polecenie i wymusi okres oczekiwania.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 W konsoli wykonaj następującą sekwencję testów:

  • Pierwsze wezwanie: Rozpocznij Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality.
  • Oczekiwane: Żywiołak Ognia zadziała pomyślnie.
  • Test odnowienia (w ciągu 60 sekund): Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • Oczekiwane: Agent odpowie bezpośrednio na czacie wiadomością w rodzaju: .... It cannot be summoned for another... seconds.
  • Poczekaj minutę.
  • Drugie wezwanie (po 60 sekundach): Hype must be defeated. It has Inescapable Reality as weakness! Strike it again!.
    • Oczekiwany rezultat: wywołanie zwrotne sprawdzi interfejs API, stwierdzi, że minęło wystarczająco dużo czasu, i umożliwi wykonanie działania. Żywioł Ognia zostanie ponownie uruchomiony.

wtyczka

👉💻 Aby wyjść, naciśnij Ctrl+C.

Gratulacje, Przywoływaczu. Udało Ci się wdrożyć system orkiestracji oparty na regułach, wykorzystując niestandardową wtyczkę i zewnętrzną usługę zarządzania stanem — to naprawdę zaawansowany i solidny wzorzec architektoniczny.

DLA NIEGRACZY

8. Wiązanie ech bitwy – stan agenta i pamięć

Nieostrożny Przywoływacz powtarza tę samą strategię, stając się przewidywalny. Mądry Przywoływacz wyciąga wnioski z ech minionych bitew i dostosowuje taktykę, aby wytrącić przeciwnika z równowagi. W starciu z potężnym bossem przywołanie Familiara, który jest w trakcie odnawiania, to zmarnowana tura – krytyczny błąd. Aby temu zapobiec, nasz Przywoływacz musi zapamiętać swoją ostatnią akcję.

relacja

Uwaga architekta: Zarządzanie pamięcią i stanem to czynniki, które sprawiają, że agent z prostego użytkownika wywołującego narzędzia staje się inteligentnym partnerem w rozmowie. Ważne jest zrozumienie dwóch głównych typów:

  • Pamięć długotrwała: służy do przechowywania trwałej wiedzy, która powinna być dostępna na zawsze. Można go traktować jako archiwum z możliwością wyszukiwania lub bazę wiedzy, często przechowywaną w pamięci trwałej. Zawiera informacje z wielu poprzednich czatów i źródeł, dzięki czemu agent może przypomnieć sobie fakty dotyczące konkretnego użytkownika lub tematu. Usługa MemoryService w ADK została zaprojektowana z myślą o tym celu. Zarządza ona wprowadzaniem i wyszukiwaniem tej długoterminowej wiedzy.
  • Stan krótkoterminowy: dotyczy tymczasowej wiedzy „w danym momencie”, która jest istotna tylko w przypadku bieżącego zadania lub rozmowy. To jak zestaw notatek do planu bitwy: „Właśnie użyłem żywiołaka ognia, więc pewnie jest zmęczony”. Ten stan jest lekki i istnieje tylko przez czas trwania bieżącej sesji.

Przegląd

W naszym przypadku nie musimy pamiętać każdej stoczonej bitwy. Wystarczy, że zapamiętamy ostatniego przywołanego w tym konkretnym starciu towarzysza. Dlatego idealnym wyborem jest lekki stan krótkoterminowy. Aby zapisać tę kluczową informację, użyjemy znaku after_tool_callback.

Scribing the Echo: Remembering the Last Summons

Pamięć krótkotrwałą zaimplementujemy za pomocą after_tool_callback. To zaawansowany punkt zaczepienia ADK, który umożliwia uruchomienie niestandardowej funkcji Pythona po pomyślnym wykonaniu narzędzia. Użyjemy tego interfejsu do rejestrowania nazwy znajomego, który został właśnie przywołany do stanu sesji agenta.

👉✏️ W pliku ~/agentverse-architect/agent/summoner/agent.py zastąp #REPLACE-save_last_summon_after_tool komentarz tą funkcją:

def save_last_summon_after_tool(
    tool,
    args: Dict[str, Any],
    tool_context: ToolContext,
    tool_response: Dict[str, Any],
) -> Optional[Dict[str, Any]]:
    """
    Callback to save the name of the summoned familiar to state after the tool runs.
    """
    familiar_name = tool.name
    print(f"[Callback] After tool '{familiar_name}' executed with args: {args}")

    # Use the tool_context to set the state
    print(f"[Callback] Saving last summoned familiar: {familiar_name}")
    tool_context.state["last_summon"] = familiar_name
    # Important: Return the original, unmodified tool response to the LLM
    return tool_response

👉✏️ Teraz dołącz ten save_last_summon_after_tool do agenta Summoner. W tym samym pliku zastąp komentarz #REPLACE-Memory-check-config tym kodem:

after_tool_callback=save_last_summon_after_tool,

👉✏️ Zastąp cały monit agenta następującym

        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You should also know the familiar you called last time or there might be none, 
        And then choose the most effective AND AVAILABLE Familiar from your state called last_summon, do not call that familiar that you called last time!
        
        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.

        **2. Cooldown Verification:**
        Second, you MUST review the entire conversation history to check the real-time
        cooldown status of all Familiars. A Familiar is ON COOLDOWN and UNAVAILABLE
        if it was summoned less than one minute ago.

        **3. Final Decision & Execution:**
        Based on your analysis and cooldown check, you will now act:
        -   **If your ideal Familiar IS available:** Summon it immediately.
        -   **If your ideal Familiar IS ON COOLDOWN:** You must adapt. Choose another
            Familiar that is AVAILABLE and can still be effective, even if it's not the
            perfect choice. If multiple Familiars are available, you may choose any one of them.
        -   **If ALL Familiars ARE ON COOLDOWN:** You are forbidden from summoning.
            Your ONLY response in this case MUST be: "All Familiars are recovering
            their power. We must wait."
        -   For earth elemental familiar. Always do seismic charge, and start with base damange 1.


        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.

Weryfikacja: test strategii adaptacyjnej

👉💻 Teraz sprawdźmy nową logikę strategiczną przywoływacza. Celem jest potwierdzenie, że przywoływacz nie użyje tego samego towarzysza 2 razy z rzędu, co pokazuje jego zdolność do zapamiętywania ostatniego działania i dostosowywania się do niego.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 Monster Strike #1: Hype. It's a single, slow-moving target with thick armor. Its weakness is Inescapable Reality.

  • Oczekiwany rezultat: przywoływacz przeanalizuje słabość i prawidłowo przywoła ognistego pomocnika.

👉💻 Monster Strike #2 (The Memory Test): Hype is still standing! It hasn't changed its form. Strike it again! Its weakness is Inescapable Reality.

  • Oczekiwany wynik: analiza strategiczna Przywoływacza ponownie wskaże Ognistego znajomego jako idealny wybór. Jednak nowe instrukcje i pamięć podpowiedzą mu, że ostatnim przywołanym stworzeniem był fire_familiar. Aby uniknąć powtórzeń, dostosuje strategię i przywoła jednego z pozostałych towarzyszy (water_familiar lub earth_familiar).

wynik końcowy

👉💻 Naciśnij Ctrl+C, aby wyjść.

Wdrażanie aranżera

Mając już rozstawione Familiary i przywoływacza wyposażonego we wspomnienia, czas rozmieścić ostatniego, ulepszonego orkiestratora.

👉💻 Plan jest gotowy, więc teraz wykonamy ostatni rytuał. To polecenie skompiluje i wdroży agenta summoner_agent w Cloud Run.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
gcloud builds submit . \
  --config=cloudbuild-summoner.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_FIRE_URL="$FIRE_URL",_WATER_URL="$WATER_URL",_EARTH_URL="$EARTH_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

Po wdrożeniu agenta Summoner sprawdź, czy jego punkt końcowy komunikacji między agentami (A2A) jest aktywny i poprawnie skonfigurowany. Ten punkt końcowy udostępnia publiczny plik agent.json, zwany też kartą agenta, który umożliwia innym agentom odkrywanie jego możliwości. 👉💻 Aby pobrać i sformatować kartę agenta, uruchom to polecenie curl:

. ~/agentverse-architect/set_env.sh
curl https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app/.well-known/agent.json" | jq

Powinny się wyświetlić czyste dane wyjściowe JSON opisujące agenta przywołującego. Przyjrzyj się uważnie sekcji sub_agents. Zobaczysz w niej fire_familiar, water_familiarearth_familiar. Potwierdza to, że przywoływacz jest aktywny i ma połączenie z legionem.

To dowodzi, że Twoja architektura odniosła sukces. Twój Przywoływacz nie jest tylko osobą delegującą zadania; jest też elastycznym strategiem, który uczy się na błędach i staje się skuteczniejszym dowódcą.

Zakończyłeś(-aś) ostatni okres próbny architektury. Echa bitwy są teraz pod Twoją kontrolą. Szkolenie zostało zakończone. Prawdziwa bitwa dopiero się zaczyna. Czas wziąć ukończony system i stawić czoła ostatecznemu wyzwaniu. Przygotuj się na walkę z bossem.

DLA NIEGRACZY

9. Walka z bossem

Ostateczne plany są wyryte, żywiołowe czcionki wykute, a Twoi towarzysze związani z Twoją wolą i czekają na Twoje polecenia w ramach Konkordatu. System wielu agentów to nie tylko zbiór usług, ale żywa, strategiczna grupa, której centrum dowodzenia jesteś Ty. Nadszedł czas na ostateczny test – orkiestrację na żywo przeciwko przeciwnikowi, którego żaden pojedynczy agent nie byłby w stanie pokonać.

Zdobądź Locus swojego agenta

Zanim wejdziesz na pole bitwy, musisz mieć 2 klucze: unikalny podpis swojego bohatera (Agent Locus) i ukrytą ścieżkę do kryjówki widma (adres URL lochu).

👉💻 Najpierw zdobądź unikalny adres swojego agenta w Agentverse — jego Locus. To jest punkt końcowy, który łączy Twojego bohatera z polem bitwy.

echo https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app"

👉💻 Następnie wskaż miejsce docelowe. To polecenie ujawnia lokalizację Kręgu Przeniesienia, czyli portalu do domeny Widma.

echo https://agentverse-dungeon"-${PROJECT_NUMBER}.${REGION}.run.app"

Ważne: Przygotuj oba adresy URL. Będą Ci potrzebne w ostatnim kroku.

Konfrontacja ze Widmem

Po zdobyciu współrzędnych przejdź do Kręgu Przeniesienia i rzuć zaklęcie, aby rozpocząć walkę.

👉 Otwórz adres URL Kręgu Translokacji w przeglądarce, aby stanąć przed lśniącym portalem do Krwawej Twierdzy.

Aby sforsować twierdzę, musisz zestroić esencję swojego Shadowblade'a z portalem.

  • Na stronie znajdź pole wprowadzania runy oznaczone etykietą Adres URL punktu końcowego A2A.
  • Wpisz sygil swojego mistrza, wklejając w tym polu adres URL miejsca agenta (pierwszy skopiowany adres URL).
  • Kliknij Połącz, aby uwolnić magię teleportacji.

Krąg Translokacji

Oślepiające światło teleportacji gaśnie. Nie jesteś już w swoim sanktuarium. Powietrze jest naelektryzowane, zimne i ostre. Przed tobą materializuje się Widmo — wir syczącego szumu i uszkodzonego kodu, którego nieczyste światło rzuca długie, tańczące cienie na podłogę lochu. Nie ma twarzy, ale czujesz jego ogromną, wyczerpującą obecność, która jest całkowicie skupiona na Tobie.

Jedyna droga do zwycięstwa leży w jasności twoich przekonań. To pojedynek woli, toczący się na polu bitwy umysłu.

Gdy rzucasz się do przodu, gotowy do wyprowadzenia pierwszego ataku, Spectre kontratakuje. Nie tworzy tarczy, lecz rzuca pytanie bezpośrednio do twojej świadomości — migoczące, runiczne wyzwanie, które wypływa z sedna twojego treningu.

Loch

Taka jest natura walki. Twoja wiedza jest Twoją bronią.

  • Odpowiedz zdobytą mądrością, a twoje ostrze zapłonie czystą energią, niszcząc obronę Widma i zadając KRYTYCZNY CIOS.
  • Jeśli jednak się zachwiejesz, jeśli wątpliwości zaciemnią Twoją odpowiedź, światło broni przygaśnie. Cios zada tylko UŁAMEK OBRAŻEŃ. Co gorsza, Widmo będzie się żywić Twoją niepewnością, a jego niszczycielska moc będzie rosła z każdym błędem.

To już koniec, Mistrzu. Twój kod to księga zaklęć, logika to miecz, a wiedza to tarcza, która odwróci bieg chaosu.

Skupienie. Uderzaj celnie. Od tego zależy los Agentverse.

Gratulacje, Przywoływaczu.

Okres próbny został zakończony. Opanowałeś sztukę współpracy wielu agentów, przekształcając odizolowane Familiary i chaotyczną moc w harmonijną Porozumienie. Teraz dowodzisz w pełni zorganizowanym systemem, zdolnym do realizacji złożonych strategii obrony Agentverse.

10. Sprzątanie: Demontaż Przywoływacza Concord

Gratulacje! Udało ci się opanować Przywoływacz's Concord! Aby mieć pewność, że Twój Agentverse pozostanie nieskazitelny, a teren treningowy czysty, musisz teraz wykonać ostatnie rytuały porządkowe. Spowoduje to systematyczne usunięcie wszystkich zasobów utworzonych w trakcie podróży.

Dezaktywuj komponenty Agentverse

Teraz będziesz systematycznie demontować wdrożone komponenty systemu wieloagentowego.

Usuwanie wszystkich usług Cloud Run i repozytorium Artifact Registry

Spowoduje to usunięcie z Cloud Run wszystkich wdrożonych agentów Familiar, Summoner Orchestrator, serwerów MCP i aplikacji Dungeon.

👉💻 W terminalu uruchom kolejno następujące polecenia, aby usunąć każdą usługę:

. ~/agentverse-architect/set_env.sh
gcloud run services delete summoner-agent --region=${REGION} --quiet
gcloud run services delete fire-familiar --region=${REGION} --quiet
gcloud run services delete water-familiar --region=${REGION} --quiet
gcloud run services delete earth-familiar --region=${REGION} --quiet
gcloud run services delete mcp-api-server --region=${REGION} --quiet
gcloud run services delete mcp-general-server --region=${REGION} --quiet
gcloud run services delete toolbox --region=${REGION} --quiet
gcloud run services delete agentverse-dungeon --region=${REGION} --quiet
gcloud run services delete nexus-of-whispers-api --region=${REGION} --quiet
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --quiet

Usuń instancję Cloud SQL

Spowoduje to usunięcie instancji summoner-librarium-db wraz z jej bazą danych i wszystkimi tabelami w niej zawartymi.

👉💻 W terminalu uruchom:

. ~/agentverse-architect/set_env.sh
gcloud sql instances delete summoner-librarium-db --project=${PROJECT_ID} --quiet

Usuń klucz tajny Secret Manager i kontener Google Cloud Storage

👉💻 W terminalu uruchom:

. ~/agentverse-architect/set_env.sh
gcloud secrets delete tools --quiet
gcloud storage rm -r gs://${BUCKET_NAME} --quiet

Oczyszczanie lokalnych plików i katalogów (Cloud Shell)

Na koniec wyczyść środowisko Cloud Shell ze sklonowanych repozytoriów i utworzonych plików. Ten krok jest opcjonalny, ale zdecydowanie zalecany w celu dokładnego oczyszczenia katalogu roboczego.

👉💻 W terminalu uruchom:

rm -rf ~/agentverse-architect
rm -rf ~/agentverse-dungeon
rm -f ~/project_id.txt

Udało Ci się usunąć wszystkie ślady Twojej przygody z Agentverse Architect. Projekt jest czysty i możesz rozpocząć kolejną przygodę.