1. Przegląd
Nagłówek ADK 2 to 3 wzorce orkiestracji. W tym ćwiczeniu nauczysz się wszystkich 3 metod, tworząc po kolei aplikację Marathon Race Day Coach. Każdy poziom odpowiada na jedno pytanie, dodaje jeden pomysł i działa samodzielnie.
Czego się nauczysz
- Przepływy pracy w formie wykresów (filary 1) – gdy możesz narysować przepływ przed nadejściem danych wejściowych.
- Agenci współpracujący (Pillar 2) – gdy znasz zespół, ale prośba wybiera podzbiór, a wszystkie 3 tryby współpracy (
chat/task/single_turn) działają na żywo. - Dynamiczne przepływy pracy (filar 3) – gdy kształt pracy zależy od danych wejściowych.
- Jak wybrać – drzewo decyzyjne z 1 pytaniem i informacje o tym, jak powstają wzory.
Wspólny wątek
znana struktura → znany zespół lub podzbiór zmiennych → nieznany kształt → wybierz odpowiedni

Co utworzysz
Jedna z aplikacji – Marathon Race Day Coach – tworzyła po jednym poziomie, który można było przebiec. Każdy poziom to zwykły moduł Pythona, który uruchamiasz w terminalu. Od poziomu 5 wszystkie poniższe elementy są Twoje.
Obraz jest generowany na podstawie działającego kodu: każda linia ciągła została odczytana z Workflow.graph.edges. Pierwsza lekcja: części, które można narysować z wyprzedzeniem, to właśnie filar 1, a części, których nie można, to powód istnienia filarów 2 i 3.

Czego potrzebujesz
- Konto Google (w przypadku Colab) – nie wymaga konfiguracji lokalnej.
- około 50 minut (poziomy L4 są długie – zaplanuj je);
- Jeden z 2 sposobów na dostęp do modelu Gemini. Wybierz ścieżkę – wykonaj jeden krok konfiguracji i pomijaj pozostałe:
🎓 Warsztaty | 🏠 Na wynos | |
Kto | Uczestniczysz w warsztatach na żywo, a prowadzący przekazał Ci link do wykorzystania środków. | Wszyscy pozostali, w tym uczestnicy warsztatów, po ich zakończeniu |
Wymagania | link do roszczenia i konto Google, które może utworzyć projekt w chmurze | bezpłatny klucz interfejsu API AI Studio; |
Działa na | Vertex AI w projekcie, za który opłaty są naliczane na podstawie środków na warsztaty | Google AI Studio |
Koszt | Objęte środkami | Poziom bezpłatny |
Krok konfiguracji | Konfiguracja warsztatu (następny krok) | Konfiguracja w domu (krok następny) |
Wszystko od prologu jest identyczne w obu przypadkach – ścieżka decyduje tylko o tym, z którym punktem końcowym modelu rozmawia notatnik.
2 sposoby śledzenia
Każdy krok poniżej odpowiada jednej komórce w notatniku Colab i jednemu folderowi w repozytorium GitHub. Wybierz jedną z tych opcji:
- ▶ Colab (zalecane): otwórz notatnik → uruchom komórki od góry do dołu.
- 💻 Lokalnie:
git clonerepozytorium,./setup_venv.sh, a następnie uruchom każdy poziom jako moduł (python -m ...) lub przejrzyj je wszystkie za pomocą./run.sh(adk web).
2. Konfiguracja warsztatów · Odbierz środki i przejdź na Vertex AI
Podczas warsztatów otrzymasz środki na Google Cloud. Odbierzesz go, utworzysz projekt, za który będziesz płacić, i skierujesz notatnik do Vertex AI zamiast do AI Studio. Jedna komórka wykonuje wszystkie czynności po zgłoszeniu roszczenia.
1. Odbierz środki (ok. 1 min)
- Otwórz link do odbioru udostępniony przez nauczyciela. Wygląda na to, że
https://me.developers.google.com/benefits/claim/your-workshop-name. - Zaloguj się i postępuj zgodnie z instrukcjami na stronie, aby zaakceptować środki.
- Zanotuj, którego konta Google używasz. Każdy z poniższych kroków musi zostać wykonany na tym samym koncie.
2. Otwórz notatnik i zainstaluj ADK 2 (~1 min)
Kliknij Otwórz w Colab ▶, a potem uruchom pierwszą komórkę kodu. Przypina dokładną wersję ADK 2, w której ten przewodnik został zweryfikowany, i wyświetla ✓ installed.
3. Uruchom komórkę „Workshop setup” (ok. 3 min)
To komórka o nazwie 🎓 Ścieżka A · Warsztaty. Uruchom go, a Colab poprosi Cię o autoryzację. Wybierz to samo konto Google, na którym właśnie odebrano środki, i zezwalaj na dostęp.
Wykonuje 4 czynności: tworzy projekt o nazwie adk-2-tutorial-XXXX na Twoim koncie, włącza w nim Vertex AI API, ustawia 4 zmienne środowiskowe, które odczytuje każda kolejna komórka, a następnie wykonuje połączenie testowe do Vertex i czeka na odpowiedź. Dzięki temu konfiguracja albo kończy się powodzeniem, albo informuje o przyczynie niepowodzenia, zamiast zawieść później na poziomie.
Oczekiwane dane wyjściowe – najważniejszy jest ostatni wiersz:
Signed in as: you@example.com
...
Successfully created GCP project 'adk-2-tutorial-4817'.
Successfully linked 'adk-2-tutorial-4817' to billing account '01ABCD-...'.
waiting for Vertex AI to come up on the new project... (10s)
waiting for Vertex AI to come up on the new project... (20s)
✅ Vertex AI on adk-2-tutorial-4817 · us-central1 · gemini-2.5-flash — answered a test call
4. Pomiń krok „Konfiguracja w domu”
Nie uruchamiaj komórki klucza AI Studio, ponieważ spowoduje to powrót do AI Studio i cofnięcie wprowadzonych zmian. (Komórka chroni przed tym i odmówi uruchomienia, ale lepszym rozwiązaniem jest po prostu jej pominięcie). Przejdź bezpośrednio do komórki Wspólne bloki.
5. Uruchom komórkę „Shared building blocks” (Wspólne elementy składowe).
Uruchom go raz. Definiuje schematy Pydantic i gotowe scenariusze maratonu, które są ponownie wykorzystywane na każdym poziomie od L2. Zobaczysz ✓ schemas + scenarios ready.
Po warsztatach
Środki i utworzony przez nie projekt nie będą dostępne bezterminowo. Aby po zakończeniu warsztatów nadal bezpłatnie uruchamiać te poziomy, wykonaj krok Konfiguracja do samodzielnego wykonania – bezpłatny klucz AI Studio, bez projektu w chmurze i bez rozliczeń. Zmienia się tylko ta jedna komórka.
Aby wcześniej usunąć projekt, otwórz konsolę Google Cloud, wybierz adk-2-tutorial-XXXX i usuń go. Żadne inne elementy tego laboratorium nie tworzą płatnych zasobów.
3. Konfiguracja w domu · klucz interfejsu API AI Studio
Wszystko na tej ścieżce działa na bezpłatnym kluczu interfejsu API Google AI Studio – nie wymaga projektu w chmurze Google Cloud, rozliczeń ani instalacji lokalnej. Cały ten krok zajmuje około 3 minut.
1. Otwórz notatnik.
Kliknij Otwórz w Colab ▶. Otworzy się notatnik z wprowadzeniem w formacie Markdown i jedną komórką do uruchomienia na każdym poziomie. Komórki są uruchamiane od góry do dołu, a każda z nich drukuje własne dane wyjściowe bezpośrednio pod nią.
2. Zainstaluj ADK 2 (~1 min)
Uruchom pierwszą komórkę z kodem. Określa dokładną wersję, w której te ćwiczenia zostały zweryfikowane:
%pip install -q "google-adk==2.3.0" python-dotenv pydantic nest_asyncio
Poczekaj na zakończenie procesu – zobaczysz ✓ installed. (Pierwsza instalacja trwa około 30–60 sekund, a potem jest zapisywana w pamięci podręcznej).
3. Uzyskaj klucz interfejsu Gemini API z AI Studio (ok. 1 min)
- Otwórz stronę aistudio.google.com/app/apikey w nowej karcie przeglądarki.
- Zaloguj się przy użyciu swojego konta Google.
- Kliknij Utwórz klucz interfejsu API (w prawym górnym rogu).
- Wybierz istniejący projekt Google lub pozwól mu utworzyć nowy.
- Skopiuj klucz – zaczyna się on od
AIza...i ma około 40 znaków.
4. Dodaj klucz do Colab (ok. 1 min)
Opcja A – Colab Secrets (zalecana; klucz pozostaje ukryty):
- Na pasku bocznym po lewej stronie w Colab kliknij ikonę klucza 🔑.
- Kliknij + Dodaj nowy tajny klucz.
- Ustaw Name (Nazwa) na
GOOGLE_API_KEY. - Wklej klucz w polu Wartość.
- Ustaw przełącznik Dostęp do notatnika w pozycji WŁ.
Opcja B – wklejanie po wyświetleniu prośby (szybkie): pomiń klucz tajny. Gdy uruchomisz następną komórkę, pojawi się ukryta prośba 🔑 Enter your Google AI Studio API key: – wklej i naciśnij Enter.
5. Uruchom komórkę klucza
Odczytuje on klucz tajny (lub wraca do prompta wklejonego), a następnie kieruje ADK do AI Studio (nie do Vertex AI):
import os
# 🏠 TAKE-HOME ONLY — if you ran the Workshop setup cell, skip this one.
if os.environ.get("GOOGLE_GENAI_USE_VERTEXAI") == "True":
raise SystemExit("✋ You're set up on the workshop path (Vertex AI). Skip this cell.")
# Google AI Studio API key — add GOOGLE_API_KEY in the 🔑 Secrets panel (or paste when prompted).
try:
from google.colab import userdata
key = userdata.get("GOOGLE_API_KEY")
except Exception:
import getpass
key = getpass.getpass("Enter your Google AI Studio API key: ")
os.environ["GOOGLE_API_KEY"] = "".join(key.split()) # drop any stray whitespace/newlines
os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "False" # use AI Studio, not Vertex AI
print("✅ API key set — using Google AI Studio.")
Oczekiwane dane wyjściowe: ✅ API key set — using Google AI Studio.
6. Uruchom komórkę „Shared building blocks” (Wspólne elementy składowe).
Uruchom komórkę Wspólne elementy składowe. Definiuje schematy Pydantic i gotowe scenariusze maratonu, które są ponownie wykorzystywane na każdym poziomie od L2. Zobaczysz ✓ schemas + scenarios ready.
Wszystko gotowe. 🎽 Zanim przejdziemy do L0, czyli wersji, którą wszyscy tworzą w pierwszej kolejności, zróbmy mały krok w bok.
4. Wprowadzenie · Dlaczego nie jeden duży prompt?
⚡ Zanim uruchomisz narzędzie, ustal JEDNĄ rzecz, na którą będziesz zwracać uwagę: skąd pochodzi każda konkretna liczba? To całe ćwiczenie – wszystko inne to tylko ozdoba.
Przed użyciem drabiny uruchom to, co ma ona zastąpić: jednego agenta, którego prompt obiecuje wszystko – pobieranie informacji o pogodzie, analizowanie trasy, odczytywanie dziennika treningowego, wyznaczanie trasy na podstawie warunków, generowanie planu.
Co zobaczysz: pewną, konkretną i dobrze sformatowaną strategię, której liczby są zmyślone. Podczas jednego z testów na żywo otworzył się z komunikatem „Pobrałem dzisiejsze dane pogodowe” i podał temperaturę 11°C, wiatr o prędkości 14,5 km/h oraz analizę dziennika treningowego, którego nigdy wcześniej nie widział. Nie ma tu interfejsu API pogodowego, danych o trasie ani logu – jedno nieprzejrzyste wywołanie modelu albo tworzy dane wejściowe, albo zabezpiecza je w taki sposób, że stają się bezużyteczne.
To choroba, która ma 4 objawy warte wymienienia:
- Nie możesz mu ufać – dane są wymyślone, ale brzmią naturalnie.
- Nie możesz go przetestować – routing w kroku 4 znajduje się w tekście, więc nie ma
if, które można by przetestować jednostkowo. - Nie możesz zamienić kroku – nie ma miejsca, w którym można by podłączyć prawdziwy interfejs API pogodowy.
- Za każdym razem płacisz za wszystko – 5 kroków, 1 duże wywołanie, bez buforowania części deterministycznej.
Utrzymaj to uczucie. Na kolejnych 9 poziomach te kroki są usuwane z promptu po kolei: funkcje pobierają (L1–L2a), instrukcja if kieruje (L2b), specjaliści dzielą pracę (L3a–L3b), a kod ogranicza kształt (L4a–L4b).

💻 Lokalne: python -m shared.prologue
5. L0 · Twój pierwszy agent ADK 2

⚡ W skrócie: agent to model + instrukcja + narzędzia, z których może korzystać; Runner wykonuje te działania. Wszystko powyżej tego poziomu to po prostu więcej agentów ułożonych w lepsze kształty.
Pytanie: czy model może odpowiadać na pytania i sięgać po prawdziwy kod, gdy ważne są obliczenia arytmetyczne?
Jeden pomysł – trzy części:
Agent– element, który wnioskuje (model Gemini + instrukcja).Runner– element, który wykonuje agenta w sesji i przesyła strumieniowo zdarzenia.- narzędzie – zwykła funkcja Pythona (
pace_splits), którą model decyduje się wywołać; ADK odczytuje sygnaturę i ciąg dokumentujący i przekazuje modelowi deklarację. Nie trzeba pisać schematu.
Po prologu następuje pierwsza poprawka: duży model językowy wykonujący w pamięci obliczenia tempa z łatwością się pomyli – pace_splits to deterministyczny kod w Pythonie, więc liczby w odpowiedzi są obliczane, a nie improwizowane.
▶ Colab: uruchom L0komórkę · 📁 GitHub: L0_first_agent/ · 💻 lokalnie: python -m L0_first_agent.agent

def pace_splits(target_finish: str) -> dict:
"""Convert a goal time like '3:30:00' into exact per-mile / per-km paces."""
... # deterministic Python — no LLM
pace_coach = Agent(
name="pace_coach", model=MODEL,
tools=[pace_splits], # the model may call it; ADK reads the signature
instruction="You are a friendly, concise marathon coach. ... If the runner "
"mentions a goal time, call pace_splits — never do arithmetic yourself.",
)
runner = Runner(node=pace_coach, session_service=InMemorySessionService(), auto_create_session=True)
async for event in runner.run_async(user_id="u1", session_id="s1", new_message=msg):
... # events carry the model's text
🔍 Markery: Agent(...) · tools=[pace_splits] · Runner(...). W danych wyjściowych wiersz 🔧 oznacza, że model w trakcie udzielania odpowiedzi postanowił wywołać Twój kod.
Co zobaczysz:
🔧 model called tool → pace_splits({'target_finish': '3:30:00'})
🔧 tool returned → {'per_mile': '8:00', 'per_km': '4:58', ...}
🧠 Coach: To finish in 3:30:00, you need an average pace of 8:00 per mile...
Linie oznaczone 🔧 to lekcja: w trakcie odpowiedzi model zdecydował się wywołać Twoją funkcję, a dokładny 8:00/mile w odpowiedzi pochodzi z Twojego kodu, a nie ze statystyk tokenów.
❓ Być może zastanawiasz się, czy model zawsze wywołuje narzędzie. Nie – decyduje o tym w przypadku każdego pytania. Zapytaj o coś, co nie zawiera liczb, a linie 🔧 znikną (w tym celu możesz skorzystać z platformy).
👀 Przeczytaj: pace_splits (zwykła funkcja) i wiersz tools=[pace_splits]. · ▶ Uruchom go. · ✏️ Zmiana: zadaj ogólne pytanie (bez czasu docelowego) – zauważ, że linie 🔧 znikają: model decyduje, kiedy warto wywołać narzędzie. Następnie przepisz instruction i uruchom ponownie – instrukcja to reszta programu.
6. L1 · Twój pierwszy przepływ pracy

⚡ TL;DR: zwykła funkcja i agent LLM to ten sam rodzaj węzła. Przewidywalna praca → funkcja (0 LLM, deterministyczna); rozumowanie → agent.
Pytanie: jak połączyć zwykły kod i LLM w jednym przepływie bez płacenia za wywołanie modelu w przypadku części, które są tylko kodem?
Jedna idea: w Workflow zarówno zwykła funkcja Pythona, jak i agent LLM są po prostu węzłami na tej samej liście edges.
START ──► fetch_conditions (function, 0 LLM) ──► advise (agent, 1 LLM)
▶ Colab: uruchom L1komórkę · 📁 GitHub: L1_graph_basics/ · 💻 lokalnie: python -m L1_graph_basics.workflow

Węzeł funkcji drukuje wygenerowane dane (bez wywołania modelu), a potem agent udziela porady, która odnosi się do otrzymanej temperatury i wiatru:
def fetch_conditions(node_input): # function node — 0 LLM
return Event(output=Conditions(temp_f=78, wind_mph=12, conditions="sunny").model_dump())
advise = Agent(name="advise", model=MODEL, mode="single_turn",
input_schema=Conditions, instruction="...give pacing + gear advice...")
workflow = Workflow(edges=[(START, fetch_conditions, advise)])
🔍 Znaczniki: jedna krotka krawędzi – (START, fetch_conditions, advise) – z funkcją Pythona w środku i input_schema= weryfikująca przekazanie.
Nowości w porównaniu z L0: Workflow(edges=[...]), START (gdzie wprowadzane są dane), węzeł funkcji zwracający Event(output=...) i input_schema=Conditions, dzięki czemu dane wyjściowe funkcji są weryfikowane pod kątem tego schematu, zanim zobaczy je agent (jako tekst JSON – input_schema weryfikuje granicę, nie przekazuje agentowi obiektu Pythona).
❓ Być może zastanawiasz się, czy kolejność „funkcja, a potem agent” jest wymagana. Nie – dowolne zamówienie, dowolna kombinacja, dowolna liczba. advise jest uruchamiana jako druga, ponieważ potrzebuje danych z fetch_conditions. Lekcją jest szlachectwo, a nie kolejność.
👀 Przeczytaj: fetch_conditions zwraca dane bez wywołania modelu; advise ma input_schema=Conditions. · ▶ Uruchom go. · ✏️ Zmiana: ustaw temp_f=30 w funkcji i uruchom ją ponownie – porada zostanie odwrócona, a funkcja nadal będzie kosztować 0 wywołań LLM.
7. L2a · Parallel fan-out + JoinNode (Pillar 1a)

⚡ TL;DR: rozdziel zadanie równolegle (bezpłatnie), poczekaj na wszystkie odpowiedzi, połącz je w pakiet i przekaż agentowi pełny obraz.
Pytanie: możesz narysować schemat przed otrzymaniem danych wejściowych. Zacznij od szkieletu: zbieraj dane równolegle, grupuj je i przekazuj jednemu agentowi.
Kształt:
START ──► fetch_weather ──┐
START ──► analyze_course ─┼─► JoinNode ─► strategy (1 agent)
START ──► pull_fitness ───┘ (bundles)
▶ Colab: uruchom L2akomórkę · 📁 GitHub: L2a_parallel_join/ · 💻 lokalnie: python -m L2a_parallel_join.workflow

🔍 Znaczniki: 3 krawędzie, które zaczynają się w punkcie START – to jest zwielokrotnienie wyjściowe – i punkt JoinNode, w którym się spotykają.
- Te 3 pobrania to funkcje, które działają równolegle i nie wymagają wywołań LLM.
JoinNodeczeka na wszystkie 3 odpowiedzi i łączy je w 1 ładunek z określonym typem (BundledRunData) z kluczem w postaci nazwy funkcji.- 1 agent
strategyodczytuje pakiet i zapisujeRaceStrategy.
Co zobaczysz: każde pobranie powoduje wyświetlenie sygnatury czasowej started / finished. Wszystkie 3 rozpoczynają się o 0,0 s, a zwielokrotnienie wyjściowe kończy się o 2,0 s – jest to najwolniejsze pobieranie, a nie 4,5 s, czyli suma ich czasów trwania. Ten zakres nakładania się to równoległość. (Łączny czas rzeczywisty wydrukowany na końcu wynosi około 8 sekund, ponieważ zawiera również wywołanie LLM agenta strategii – odczytaj sygnatury czasowe pobierania dla równoległego zgłoszenia, a nie dla całości).
💡 Nawiązanie do prologu: mega-prompt wymyślił pogodę. Temperatura jest tu pobierana za pomocą funkcji pobierania – prawdziwy kod, prawdziwy szew. Zastąp gotowy dyktat rzeczywistym interfejsem Weather API i nie wprowadzaj żadnych innych zmian.
❓ Być może zastanawiasz się, ile
JoinNode
muszę rozumieć? Jedno zdanie: czeka, aż wszystkie równoległe gałęzie zakończą działanie, pakuje wyniki w jeden słownik z kluczami w postaci nazw funkcji nadrzędnych i nie wykonuje żadnych obliczeń. Dzięki temu słownikowi router L2b może zapisywać node_input["fetch_weather"]["temp_f"].
👀 Odczyt: trzy krawędzie rozchodzą się od START; JoinNode łączy je w jeden wątek dla agenta. · ▶ Uruchom go i odczytaj sygnatury czasowe, a nie łączną liczbę. · ✏️ Zmiana: uśpij jedno pobieranie 3.0 – najpierw przewiduj nowy czas zakończenia zwielokrotnienia wyjściowego, a potem weryfikuj.
8. L2b · Dodaj deterministyczny router (Pillar 1b)

⚡ W skrócie: niezmieniony poziom 2a + zwykły if decyduje, który agent ma zostać uruchomiony. rozgałęzianie bez zadawania pytań modelowi.
Pytanie: plan powinien się różnić w zależności od tego, czy jest ciepło czy zimno. Jak rozgałęziać wątki bez proszenia modelu o podjęcie decyzji?
Kształt (L2a + router):
... JoinNode ─► route_by_weather ─► hot_strategy
(if-statement) ─► normal_strategy
─► cold_strategy
▶ Colab: uruchom L2b komórkę – spróbuj run("NORMAL") / run("COLD") · 📁 GitHub: L2b_router/ · 💻 lokalnie: python -m L2b_router.workflow COLD

def route_by_weather(node_input): # an if-statement, 0 LLM
temp = node_input["fetch_weather"]["temp_f"]
route = "HOT" if temp >= 70 else "COLD" if temp <= 40 else "NORMAL"
return Event(output=node_input, route=route)
(route_by_weather, {"HOT": hot_strategy, "NORMAL": normal_strategy, "COLD": cold_strategy})
🔍 Markery: Event(output=..., route=...) węzeł funkcji określający ścieżkę i krawędź słownika {"HOT": ..., "NORMAL": ..., "COLD": ...}, która mapuje nazwy na węzły.
Podsumowanie – 3 rodzaje pracy, 3 domy:
- Przewidywalna praca → funkcje (3 równoległe pobrania)
- Jasna reguła → routing ze wcześniej ustaloną ścieżką (
route_by_weathertoif-statement, a nie decyzja modelu) - Uzasadnienie → model (dokładnie jeden agent strategii)
Co zobaczysz: temp=78F -> route=HOT, a potem ustrukturyzowany RaceStrategy. Koszt netto: 1 wywołanie LLM.
⚠️ Jeśli dodasz czwartą gałąź,dodaj też do słownika tras wpis DEFAULT_ROUTE. Trasa, która nie pasuje do słownika, nie jest błędem – gałąź po prostu się kończy, a program kończy działanie z kodem 0 bez danych wyjściowych, co jest mylącym ślepym zaułkiem do debugowania.
❓ Być może zastanawiasz się: czy L2b to po prostu L2a z routerem? Tak – pobieranie i łączenie danych pozostają bez zmian i nadal jest to dokładnie 1 wywołanie LLM. Co się zmieniło: „zawsze ten sam agent” stało się „jeden z trzech, wybrany na podstawie danych”.
👀 Przeczytaj: route_by_weather – router jest if-statement, a nie agentem. · ▶ Uruchom run("COLD"). · ✏️ Zmiana: dodaj gałąź WINDY z czwartym agentem i przeczytaj DEFAULT_ROUTE ostrzeżenie powyżej zanim to zrobisz.
9. L3a · Collaborative agents: one flag, two worlds — Pillar 2

⚡ TL;DR: ten sam zespół, jedna flaga. chat przekazuje całą rozmowę jednemu specjaliście i nigdy nie wraca; single_turn zamienia każdego specjalistę w narzędzie – równoległy podzbiór, automatyczny powrót, jedna synteza.
Pytanie: znasz zespół, ale to prośba decyduje, którzy członkowie powinni odpowiedzieć. Jak pozwolić LLM wybrać podzbiór i uruchomić go jednocześnie?
Kształt: koordynator nadzorujący 6 specjalistów (medycznych, pogodowych, tempa, sprzętu, żywienia i zdrowia psychicznego). Na tym poziomie ten sam zespół wykonuje zadanie 2 razy – ten sam prompt koordynatora i tych samych 6 specjalistów. Jedyna różnica to jedna flaga w przypadku subagentów. Kontrast to lekcja.
▶ Colab: uruchom L3akomórkę · 📁 GitHub: L3a_collaborative/ · 💻 lokalnie: python -m L3a_collaborative.concierge --mode chat "What about fueling?"

🔍 Markery: mode="single_turn" w fabryce i w danych wyjściowych, TRANSFER → (uderzenie 1) w porównaniu z serią linii DISPATCH → z tą samą sygnaturą czasową (uderzenie 2).
Krok 1. Uruchom domyślny kod i obserwuj, jak zadanie kończy się niepowodzeniem.
Brak mode= → subagenci domyślnie mają wartość chat. Co zobaczysz:
TRANSFER → nutrition_specialist (transfer_to_agent — the only tool chat subagents provide)
Final speaker: nutrition_specialist
Koordynator nie ma narzędzi do przekazywania – podagenci na czacie przekazują mu tylko transfer_to_agent, czyli całą rozmowę do jednego specjalisty. Specjalista odpowiada użytkownikowi bezpośrednio i na tym kończy się działanie. Brak równoległego wysyłania. Bez możliwości zwrotu. Brak syntezy. Zadaj szerokie pytanie, a sytuacja się pogorszy: 6 specjalistów, 1 przekazanie.
To nie jest błąd – to tryb czatu wykonuje swoją pracę. Rozmowa należy do osoby, która ją prowadzi, dopóki nie zostanie wyraźnie przeniesiona na inną osobę. Prawidłowe w przypadku asystenta o otwartej architekturze, nieprawidłowe w przypadku kroku potoku.
Sekcja 2. Jedna flaga, dwa światy
Jedyna różnica: mode="single_turn" w przypadku każdego specjalisty. To samo pytanie, uruchom ponownie:
[t= 7.8s] DISPATCH → medical_specialist ← same timestamp =
[t= 7.8s] DISPATCH → weather_specialist one turn, many calls
[t=14.5s] ↩ medical_specialist replied ← replies land inside
[t=14.5s] ↩ weather_specialist replied one short window
🧠 Concierge (synthesized): <one answer>
ADK wstawia teraz 1 narzędzie do delegowania na specjalistę – nazwane na cześć podagenta i opisane przez jego description= (ten tekst jest odczytywany przez koordynatora podczas wybierania podzbioru; pomiń go, a będziesz kierować połączenia tylko na podstawie nazw). Koordynator wysyła kilka wywołań w jednej turze, ADK uruchamia je równolegle, każde z nich automatycznie zwraca wynik, a koordynator dokonuje syntezy.
Pytanie | Specjaliści, którzy strzelają |
„A co z tankowaniem?” | tylko odżywianie, |
„Boli mnie kolano na 18 mili” | tylko medyczne |
„Should I race today?” (Czy powinienem dziś startować w zawodach?) | medyczne + pogoda + tempo |
„Czy jest coś, czym powinienem się martwić?” | wszystkie 6 |
Dlaczego każdy specjalista otrzymuje pełne informacje: każdy single_turn podagent działa w osobnej, odizolowanej gałęzi sesji – nie widzi rozmowy ani innych podagentów. Nic nie jest otoczeniem: koordynator musi przekazywać cały SpecialistInput (pytanie + strategia + dane wykonawcy) oddzielnie do każdego wywołania równoległego.
💡 W ADK 2 jest to realizowane w ten sposób: model LLM wybiera podzbiór na potrzeby każdego żądania I uruchamia go równolegle – zadeklarowany za pomocą sub_agents + mode="single_turn". W wersji 1.x można było utworzyć ten sam kształt, umieszczając każdego specjalistę w AgentTool. Zmieniło się to, że teraz jest to deklaracja, a nie połączenie. (ParallelAgent to zawsze wszystkie, a transfer_to_agent to serial).
⚠️ Dwa ważne zastrzeżenia: (1) podzbiór jest wybierany przez model, więc jest on mniej deterministyczny niż router L2 z zakodowanymi na stałe regułami – dokładny podzbiór może się różnić w zależności od uruchomienia. (2) Czasami zobaczysz Error validating input: ... dla jednego specjalisty. Prawie nigdy nie jest to wynik specjalisty – output_schema wymusza to po stronie serwera. Jest to dane wejściowe: koordynator musi dosłownie odtworzyć całą zagnieżdżoną funkcję SpecialistInput w przypadku każdego wywołania równoległego, a czasami się myli. ADK zwraca błąd jako wynik działania tego narzędzia, koordynator odzyskuje dane, a synteza nadal jest wykonywana.
❓ Być może zastanawiasz się, czy
chat
tylko delegowanie w stylu 1.x – jeden agent naraz? Tak, to domyślne działanie w wersji 1.x, tylko teraz ma nazwę. Różnica w stosunku do single_turn jest trójwymiarowa: co ma koordynator (1 transfer_to_agent w porównaniu z 1 narzędziem na specjalistę), ilu specjalistów może pracować (1, który prowadzi rozmowę, w porównaniu z N pracujących równolegle) i czy kontrola jest przywracana (nigdy w porównaniu z automatycznym przywracaniem z wynikami). A co do kodu: gałąź if mode == w fabryce istnieje tylko po to, aby jeden zespół mógł być budowany na 2 sposoby w celu uzyskania tego kontrastu – prawdziwa aplikacja ma zakodowany jeden tryb, a if znika.
👀 Odczytaj: _specialist fabryka – parametr mode to cały poziom. · ▶ Uruchom oba bity. · ✏️ Zmiana: zapytanie „Boli mnie kolano na 18 mili” – najpierw przewiduj podzbiór, a potem sprawdzaj wiersze DISPATCH.
# The factory's mode parameter is THE variable this level teaches:
def _specialist(name, domain, focus, mode):
kwargs = {}
if mode == "single_turn": # the structured contract only makes sense for a TOOL
kwargs = dict(mode="single_turn",
input_schema=SpecialistInput, output_schema=SpecialistResponse)
return Agent(name=name, model=MODEL,
description=f"Marathon {domain} specialist. Consult for: {focus}.",
instruction=..., **kwargs)
race_concierge = Agent(name="race_concierge", model=MODEL,
sub_agents=[...six specialists...], # NOTE: no `mode` on the coordinator
instruction="...DECIDE which specialists are relevant... call them IN PARALLEL... SYNTHESIZE...")
10. L3b · Tryb zadania: rozmowa z linią mety – filar 2

⚡ W skrócie: tryb środkowy – rozmawiaj z użytkownikiem do momentu zebrania pól, a następnie automatycznie zwracaj zweryfikowany obiekt.
Pytanie: L3a pozostawił lukę. chat prowadzi całą rozmowę; single_turn nigdy nie rozmawia z użytkownikiem. Prawdziwa praca polega jednak na tym, co dzieje się pomiędzy tymi etapami: „rozmawiaj z użytkownikiem, DOPÓKI nie zbierzesz X – a potem wróć z zweryfikowanym obiektem”. Który to tryb?
Kształt:
race_desk (coordinator)
└─ gear_fitter (mode="task", output_schema=GearOrder)
▶ Colab: uruchom L3bkomórkę · 📁 GitHub: L3b_task_desk/ · 💻 lokalnie: python -m L3b_task_desk.desk


🔍 Markery: mode="task" + output_schema= na tym samym agencie, a w danych wyjściowych – ⏸ wstrzymanie i finish_task połączenie.
Co zobaczysz:
━━ TURN 1 ━━ user: 'I need shoes for the marathon.'
race_desk → delegate: gear_fitter
gear_fitter: What is your shoe size?
⏸ The run ENDED — but nothing failed. This is a PAUSED task.
━━ TURN 2 ━━ user: 'Size 9, wide.' (same session → resumes the task)
gear_fitter → finish_task (payload validates as GearOrder)
race_desk: Your order ... in size 9 Wide has been confirmed.
Wystąpiły 3 sytuacje, których nie można osiągnąć w trybie L3a:
- Uruchomienie zostało zatrzymane w trakcie zadania – zadanie zostało wstrzymane, a nie zawieszone ani nie zakończone niepowodzeniem. Agent zadał pytanie doprecyzowujące i pozostawił zadanie otwarte. (W
adk webwystarczy wpisać odpowiedź. Skrypty testowe potraktują ją jako drugą wiadomość w tej samej sesji). - Kolejna wiadomość wznowiła TĘ SAMĄ aktywność agenta – bez przekierowania ani ponownego delegowania. Sesja wie, kto czekał.
finish_taskzakończył – narzędzie wstrzyknięte przez ADK z powodumode="task". Aby zakończyć działanie, agent musi wywołać to narzędzie, a jego ładunek musi zostać zweryfikowany na podstawieoutput_schema. Rozmowa z wpisaną linią mety – sterowanie automatycznie wraca do koordynatora, a wynik jest dołączony.
Reguła jednego pytania dotycząca wyboru trybu
💡 „Czy użytkownik musi z nim rozmawiać i do kiedy?” czat = bezterminowo · zadanie = do momentu zebrania pól · pojedyncza tura = nigdy.
Tryb | Proces z udziałem człowieka | Równoległe? | Powrót do elementu nadrzędnego |
| pełna rozmowa, | nie | ręcznie (przez przeniesienie) |
| tylko pytania wyjaśniające; | nie | automatycznie (za pomocą |
| brak | yes | automatyczne (z wynikiem), |
mode jest przekazywana tylko subagentom, a nigdy koordynatorowi. Węzły przepływu pracy mają domyślnie wartość single_turn (dlatego pracownicy poziomu 1–2b nigdy nie musieli tego robić), a podagenci mają domyślnie wartość chat (dlatego pracownicy poziomu 3a musieli to robić).
⚠️ Zanim zaczniesz korzystać z tej funkcji, zapoznaj się z 2 uwagami dotyczącymi wersji: (1) task
jako statyczny węzeł wykresu zależy od wersji – w przypadku wersji 2.0.0b1–2.3.0 (wersja przypięta w tym ćwiczeniu) Workflow(...) zgłasza błąd podczas tworzenia; użyj dokładnie tego, co robi ten poziom (koordynator czatu z podagentami zadań), lub wyślij za pomocą ctx.run_node. Usunięto w wersji 2.5.0. (2) „Agenci zadań muszą być agentami liści” (nie mogą mieć własnych subagentów) to udokumentowane ograniczenie ADK, ale umowa, a nie zabezpieczenie w czasie działania: ani wersja 2.3.0, ani 2.5.0 nie powstrzymają Cię przed jego naruszeniem. Brak błędu nie oznacza, że masz pozwolenie.
💡 Więcej informacji: task agent osadzony w przepływie pracy z wykorzystaniem grafu (kształt 2.5.0+), z routingiem, który może zapętlić rozmowę, aby ponowić próbę: repozytorium towarzyszące 22_agent_in_workflow · pełny przewodnik po trybie: docs/agent-modes.md.
❓ Możesz się zastanawiać: co oznacza
task
kupić mi tego, czego nie mogą kupić pozostałe 2 osoby? Trzy rzeczy: automatyczny powrót (czat przejmuje rozmowę) · wpisana linia mety (ładunek finish_task musi być zgodny ze schematem – otrzymujesz dane, a nie transkrypcję) · wstrzymanie/wznowienie (⏸ to wstrzymane zadanie oczekujące na człowieka, a nie zawieszenie).
👀 Przeczytaj: gear_fitter – mode="task" + output_schema to cała umowa. · ▶ Uruchom go. · ✏️ Zmiana: run_desk("I need a hydration vest", "2 liters, medium") – pytanie wyjaśniające dostosowuje się, a linia mety pozostaje wpisana.
11. L4a · Równoległe zwielokrotnienie wyjściowe o rozmiarze dostosowanym do czasu działania (Pillar 3a)

⚡ W skrócie: szkielet nadal składa się z 3 statycznych kroków – dynamiczny ukrywa się wewnątrz środkowego, w którym szerokość jest określana przez dane w czasie działania.
⚠️ Uwaga: to najbardziej stromy stopień drabiny. Poprzedni poziom miał 44 linie, a ten ma około 120 – 3 agenty i 2 węzły przepływu pracy, bez żadnego wypełnienia. Poświęć na to około 15 minut i skup się na wierszu „Przeczytaj/uruchom/zmień” na końcu. Nie musisz za pierwszym razem przyswajać wszystkich wierszy.
Pytanie: forma pracy zależy od danych wejściowych. Nie możesz narysować wykresu z wyprzedzeniem. Zacznij od szerokości środowiska wykonawczego: pozwól LLM zdecydować, ile podrzędnych pytań ma zostać zadanych.
Kształt (jeden poziom):
START ─► decompose ─► research_topic (parallel_worker) ─► synthesize
│ │ │
└──┴──┴─ (flat: no children yet)
Pytanie otwarte jest dzielone na N podpytań – liczbę N wybiera LLM w czasie działania (3–7) – z których każde jest wyszukiwane równolegle, a następnie syntetyzowane w jedno podsumowanie.
▶ Colab: uruchom L4akomórkę · 📁 GitHub: L4a_flat_research/ · 💻 lokalnie: python -m L4a_flat_research.deep_research

🔍 Znaczniki – brak
dynamic=True
przełącznik. Dynamic to sposób pisania, a nie konfiguracja. Dwa markery i tylko dwa: @node(parallel_worker=True) (przyjmuje listę o rozmiarze określonym w czasie działania, uruchamia 1 proces roboczy na element) i ctx.run_node(...) (bezpośrednio planuje węzły kodu). Jeśli widzisz jedną z tych opcji, korzystasz z dynamicznego określania cen.
Co zobaczysz: dekompozytor drukuje np. 5 podpytań, które są badane równolegle, a następnie tworzone jest podsumowanie. Liczba różni się w każdym przebiegu – stały wykres nie mógłby tego zrobić.
Warto zwrócić uwagę na 2 flagi dotyczące pracownika:
rerun_on_resume=Truejest wymagany w każdym węźle, który wywołujectx.run_node– bez niego ADK zgłaszaValueError. Po wznowieniu musi ponownie wykonać węzeł wysyłający, aby odbudować utworzone przez niego węzły podrzędne, ponieważ nie znajdują się one na statycznym wykresie.retry_config=bounds how this FAILS. Pracownik równoległy anuluje wszystkie zadania równorzędne i ponownie zgłasza błąd, gdy jedno z zadań podrzędnych zakończy się niepowodzeniem. Oznacza to, że bez ponowienia próby pojedynczy przejściowy błąd 429 powoduje odrzucenie całego uruchomienia, w tym wszystkich wywołań, za które już zapłacono. Ponowna próba jest podejmowana w węźle wewnętrznym dla poszczególnych elementów, więc każda gałąź jest ponawiana niezależnie.
❓ Możesz się zastanawiać: skąd ADK „wie”, że jest to dynamiczne? Nie musi tego robić – nigdzie nie jest zadeklarowana. Decomposer tworzy listę w czasie działania, a węzeł roboczy równoległy dostosowuje swój rozmiar do otrzymanych danych. Dynamiczność jest właściwością napisanego przez Ciebie przepływu danych, a nie trybem, który został włączony.
👀 Przeczytaj: 2 flagi na research_topic – parallel_worker i rerun_on_resume. · ▶ Uruchom go. · ✏️ Zmiana: zastąpienie własnym pytaniem otwartym – N zmian, ponieważ dane wejściowe decydują o szerokości.
12. L4b · Add recursive spawning (Pillar 3b)

⚡ TL;DR: rekursja jest pisana, a nie podawana – proces roboczy wywołuje sam siebie za pomocą ctx.run_node, zwykłego kodu Pythona, więc hamulec też musi być napisany. To MAX_DEPTH.
Pytanie: jedno z odkryć badawczych może dotyczyć wąskiego podtematu, który warto zbadać osobno. Jak sprawić, aby gałąź generowała więcej równoległych zadań, i utrzymać ją w określonych granicach?
Kształt (obecnie rekurencyjny):
START ─► decompose ─► research_topic (parallel_worker, recursive) ─► synthesize
│ │ │
│ │ └─ research(q3) ─► maybe spawn children
│ └─── research(q2) ─► maybe spawn children
└────── research(q1) ─► maybe spawn children
▶ Colab: uruchom L4bkomórkę · 📁 GitHub: L4b_recursion/ · 💻 lokalnie: python -m L4b_recursion.deep_research

@node(parallel_worker=True, rerun_on_resume=True)
async def research_topic(ctx, node_input):
finding = coerce(await ctx.run_node(research_agent, node_input=...), ResearchFinding)
if finding.needs_deeper and finding.deeper_questions and depth < MAX_DEPTH: # boundary in CODE
children = await ctx.run_node(research_topic, node_input=deeper) # recursive fan-out
yield Event(output={..., "children": children})
🔍 Znaczniki: ctx.run_node(research_topic, ...) wewnątrzresearch_topic samego siebie – odwołanie do samego siebie jest rekurencją – i strażnik depth < MAX_DEPTH w wierszu powyżej.
Co zobaczysz: węzły wyszukiwania drukujące spawning N deeper – rekursja zachodząca na żywo – a następnie kształt drzewa czasu działania (np. 5 top-level + 10 recursive children). Drzewo różni się w każdym przebiegu.
⚠️ Zanim zwiększysz wartość: pułap rośnie szybko – MAX_DEPTH=3 w najgorszym przypadku zwiększa liczbę połączeń z ok. 30 do ok. 93. Na samym końcu uruchomienia możesz zobaczyć wiersz dziennika cancelling N leftover tasks: oznacza to, że ADK zamyka grupę zadań równoległych po zakończeniu działania. Nie jest szkodliwy i w zależności od konfiguracji logowania możesz go nigdy nie zobaczyć.
❓ Być może zastanawiasz się, czy dynamiczne reklamy w wyszukiwarce nie są domyślnie rekursywne. Nie – L4a jest w pełni dynamiczny i ma zero rekursji. Dynamic tylko przekazuje zwykły przepływ sterowania w Pythonie; L4b wybiera, aby pisać z nim rekurencję. A ponieważ Ty piszesz rekurencję, Ty musisz napisać jej granicę – w tym miejscu hasło „pozwól LLM kształtować pracę, zachowaj granice w kodzie” przestaje być sloganem.
👀 Przeczytaj: strażnik: if finding.needs_deeper and depth < MAX_DEPTH. · ▶ Uruchom go. · ✏️ Zmiana: ustaw MAX_DEPTH = 1 i uruchom ponownie – drzewo zostanie spłaszczone (a wykonanie będzie tańsze). Granica jest TWOJA, w kodzie.
13. L5 · Którego wzorca użyć?

⚡ W skrócie: wszystko zależy od jednego czynnika – kto wybiera następny krok: narysowany przez Ciebie wykres, LLM czy Twój kod.
Masz już wszystkie 3 rodzaje. To model, który sprawia, że są one przydatne: dopasuj wzorzec do kształtu problemu.
Oś: kto decyduje o tym, co będzie odtwarzane dalej?
Filar | Kto decyduje o tym, co będzie odtwarzane dalej | Wbudowane |
1. Wykres | wykres, który został narysowany, | L2a / L2b |
2. Współpraca | LLM | L3a / L3b |
3. Dynamiczne | kod Pythona w czasie działania, | L4a / L4b |
Krok 0. Czy w ogóle potrzebujesz wykresu?
ADK zawiera gotowe agenty przepływu pracy – SequentialAgent, ParallelAgent, LoopAgent. W przypadku zwykłego łańcucha agentów jest to najtańsza prawidłowa odpowiedź i nie ma grafu do złożenia. Możesz je pominąć, gdy potrzebujesz jawnego routingu (router L2b), złącza (JoinNode L2a) lub węzłów, które nie są agentami (zwykła funkcja, bez wywołań LLM) – zwykle to jest powód.
Would a prebuilt SequentialAgent / ParallelAgent / LoopAgent do?
│
├─ YES ──────────────────────────────► use it; stop here
│
└─ NO — I need routing, a join, or non-agent nodes
│
Can you draw the workflow before the input arrives?
│
├─ YES ───────────────────────────► Pillar 1 · Graph workflow (L2a/L2b)
│
└─ NO
├─ Known team, request picks the subset? ─► Pillar 2 · Collaborative (L3a/L3b)
└─ Does the shape depend on the input? ──► Pillar 3 · Dynamic (L4a/L4b)

Uczciwe porównanie wersji 1.x i 2
To nie jest tak, że „wersja 2.0 potrafi to, czego nie potrafiła wersja 1.x” – wersja 1.x też to potrafiła. Zmiana polega na tym, że wersja 2.0 przypisuje każdemu kształtowi bardziej bezpośrednie miejsce docelowe, dzięki czemu znany przepływ sterowania opuszcza prompt i staje się strukturą, którą można zobaczyć i przetestować.
Wzór | Koszt 1.x | Strona główna pakietu ADK 2 |
Wykres | 4 wywołania LLM w przypadku typowej kompilacji; routing ukryty w prompcie | funkcja + węzły agenta jako węzły równorzędne → 1 wywołanie, router instrukcji |
Współpraca | możliwość tworzenia za pomocą | zadeklarowany zespół: |
Dynamiczne | rekurencja powoduje wyjście z platformy. |
|
Cała aplikacja i to, czego nie widać na wykresie
Wszystkie elementy poniżej zostały już utworzone. Workflow udostępnia swoją strukturę pod adresem graph.edges, więc ten obraz jest generowany na podstawie kodu, a nie rysowany ręcznie. Wyniki introspekcji są podsumowaniem tego modułu:
Filar | Co zawiera | Dlaczego |
1. Wykres (L2b) | 10 krawędzi, trasy i wszystko inne | został narysowany przed otrzymaniem jakichkolwiek danych wejściowych; |
2. Współpraca (L3a) | 0 krawędzi – tylko | LLM wybiera podzbiór na podstawie żądania. |
3. Dynamiczny (L4a/L4b) | 3 krawędzie – identyczne w obu przypadkach | rekursja jest napisana w Pythonie, a nie w grafie. |
Ostatni wiersz jest dowodem na odpowiedź na pytanie L4b: L4a i L4b mają ten sam wykres, a tylko jeden z nich jest rekurencyjny.
Co możesz teraz tworzyć
Każdy z wzorów, które właśnie zostały uruchomione, to rzeczywisty kształt produktu:
Udało Ci się przećwiczyć | Na wolności | Początek |
Wykres + router (L2a/L2b) | potoki dokumentów, kroki ETL z LLM, łańcuchy weryfikacji/zatwierdzania, narzędzia do oceny | L2b tego repozytorium |
Koordynator + zespół | kopilot wsparcia z zespołami specjalistów, punktami triage i wielopłaszczyznową weryfikacją. | marathon demo mode 2 |
| formularze wprowadzające, procesy rezerwacji, wprowadzanie nowych klientów, KYC – wszelkie procesy typu „zbierz, a potem działaj”; | |
Dynamiczna szerokość/głębokość (L4a/L4b) | agenci badawczy, generatory raportów, skanowanie kontrolne danych wejściowych o nieznanej wielkości; | tryb maraton demo 3 |
Tworzą
Te 3 wzorce nie wykluczają się wzajemnie. Węzeł wykresu może wywołać koordynatora współpracy, a specjalista może uruchomić dynamiczny przepływ pracy. Wybierz odpowiedni wzorzec dla każdej części problemu – w ten sposób unikniesz przekształcenia każdego systemu agentów w jeden gigantyczny prompt.

💡 Wypróbuj go w swoim przepływie pracy: skrypt, który wygenerował ten wykres, to scripts/graph_dump.py. Skieruj go na dowolny Workflow, a wydrukuje prawdziwe krawędzie – bezpłatny schemat strukturalny dowolnej konstrukcji.
14. Gratulacje

Utworzyliśmy trenera na dzień maratonu, a po drodze wszystkie 3 wzorce aranżacji ADK 2.
Czego się dowiedziałeś(-aś)
- Prolog – mega-prompt, który sam wymyślił pogodę: dlaczego w ogóle istnieje struktura.
- L0–L1 –
Agent,Runner, prawdziwe narzędzie, które model wybiera do wywołania, i pierwszyWorkflow(węzły funkcji + węzły agenta jako węzły równorzędne). - L2a / L2b – przepływy pracy z grafami: równoległe zwielokrotnienie wyjściowe +
JoinNode, a potem deterministyczne przekierowywanie – 1 wywołanie LLM. - L3a – agenci współpracujący: ten sam zespół działa w
chat(izolowany), a potem wsingle_turn(równoległy podzbiór + synteza) – 1 flaga, 2 światy. - L3b –
tasktryb: wstrzymane pytanie doprecyzowujące, skryptowe wznowienie,finish_taskzwracanie zweryfikowanego obiektu. - L4a / L4b – dynamiczne przepływy pracy: szerokość w czasie działania (zwielokrotnienie wyjściowe), a następnie głębokość w czasie działania (rekurencja) z granicami w kodzie.
- L5 – drzewo decyzyjne i sposób tworzenia wzorców.
Wiersze, które warto zachować
Funkcje przygotowują kontekst. Krawędzie definiują przepływ pracy. Router wybiera ścieżkę. Model pisze odpowiedź.
Pozwól LLM kształtować pracę, ale zachowaj granice w kodzie.
Dopasuj wzór do kształtu problemu.
Dalsze kroki
- Uruchom pełną aplikację, z której pochodzą te poziomy – Marathon Race Day Coach, czyli aplikację FastAPI + SSE z interfejsem przeglądarki, która na żywo pokazuje wszystkie 3 tryby: github.com/cuppibla/adk-2-marathon-demo.
- Więcej informacji: adk-workflows-compared – wszystkie 23 oficjalne przykłady przepływów pracy ADK 2, każdy z wersją 1.x i wskazówkami dotyczącymi zastosowania. Zacznij od
docs/three-pillars.md, a potem przejdź do pominiętych w tym ćwiczeniu elementów:07_loop,17_request_input,22_agent_in_workflow. - Przenieś swój własny problem: które części mają znaną strukturę (L2), znany zespół (L3a/L3b), nieznany kształt (L4)?
- Zapoznaj się z kodem: github.com/cuppibla/adk2-tutorial
- Czy przeszedł przez warsztaty? Środki i utworzony dzięki nim projekt nie będą dostępne bezterminowo. Aby nadal bezpłatnie uruchamiać te poziomy, wykonaj krok Konfiguracja do samodzielnego wykonania: bezpłatny klucz AI Studio, bez projektu w chmurze i bez rozliczeń. Zamiana tej jednej komórki to jedyna zmiana.