1. Budowanie zaufania, aby zachęcić do hojności

Moment inspiracji
Telefon zawibruje. Widzisz artykuł o skutecznym programie nauki czytania, który pomaga dzieciom z grup defaworyzowanych. Czujesz silną potrzebę zaangażowania się. Otwierasz przeglądarkę i wyszukujesz „darowizny na programy wspierające umiejętność czytania i pisania u dzieci”.

Pojawią się setki wyników.
Klikasz pierwszy link. Witryna wygląda profesjonalnie. Przewijasz w dół do informacji finansowych. „Koszty administracyjne: 28%”. Wstrzymujesz. Tylko 72 centy z każdego przekazanego dolara trafią na finansowanie programu. Czy to dobrze? Nie masz pewności.
Spróbuj w innej organizacji. Nigdy o nich nie słyszałeś(-aś). Czy są one legalne? Szybkie wyszukiwanie prowadzi do niekończących się wyników. Znajdujesz wątek na Reddicie sprzed dwóch lat, w którym jeden z użytkowników twierdzi: „To oszustwo, moja darowizna nigdy nie dotarła do celu”. Inna osoba gorąco ich broni: „Oni wykonują prawdziwą pracę w terenie!”. Niepewność jest paraliżująca.
Pół godziny później wciąż przeglądasz sprzeczne opinie, oceny efektywności i dokumenty IRS, ale nadal nie udało Ci się przekazać darowizny. Pierwotny impuls hojności został zastąpiony przez trudności związane z badaniami. Karta pozostaje otwarta przez kilka dni, przypominając o dobrym zamiarze, dopóki jej nie zamkniesz.
To nie jest osobista porażka, tylko awaria systemu
Ta funkcja jest uniwersalna. Chęć pomocy jest duża, ale proces jest pełen przeszkód, które powodują wahanie i wątpliwości:
- ❌ Trudności w badaniu: każda organizacja charytatywna wymaga własnego dochodzenia.
- ❌ Weryfikacja zaufania: trudno odróżnić organizacje o wysokiej skuteczności od tych nieefektywnych, a nawet od oszustw.
- ❌ Paraliż decyzyjny: przytłaczająca liczba opcji prowadzi do zmęczenia decyzyjnego.
- ❌ Utrata impetu: emocjonalna motywacja do przekazania darowizny maleje wraz ze wzrostem obciążenia logistycznego.
To utrudnienie wiąże się z ogromnymi kosztami w rzeczywistości. Darczyńcy indywidualni w Stanach Zjednoczonych przekazują ogromne kwoty – według raportu Giving USA 2024 w 2023 roku darczyńcy indywidualni przekazali łącznie około 374 miliardy dolarów. Badania pokazują jednak, że bariery w przekazywaniu darowizn – w tym koszty wyszukiwania, opory psychologiczne i ograniczenia czasowe – znacznie zmniejszają kwotę, która trafia do organizacji charytatywnych. Badania z udziałem milionów darczyńców wykazały, że nawet niewielkie utrudnienia w procesie przekazywania darowizn online uniemożliwiają ludziom realizację ich zamiarów charytatywnych.
To miliardy dolarów w postaci darowizn, które nigdy nie trafiają do organizacji, które ich potrzebują.
The Vision
Wyobraź sobie inne wrażenia. Zamiast 30-minutowej sesji wyszukiwania wystarczy, że powiesz:
„Chcę przekazać 50 zł na program nauki czytania i pisania dla dzieci. Znajdź wysoko ocenianą, wydajną i zweryfikowaną organizację charytatywną”.
W ciągu kilku sekund otrzymasz odpowiedź, która wzbudzi Twoje zaufanie:
Taką obietnicę składa agent AI do przekazywania darowizn. Aby jednak zrealizować tę wizję, musimy rozwiązać podstawowy problem: gdy autonomiczny agent AI zarządza pieniędzmi, zaufanie nie jest opcjonalne, ale stanowi podstawę jego działania.
- Jak możemy udowodnić, co użytkownik autoryzował?
- Kto ponosi odpowiedzialność za błędy?
- Jak zapewniamy darczyńcom, organizacjom charytatywnym i sieciom płatniczym pewność, że warto wziąć udział w programie?
Twoja misja na dziś
W ramach tych warsztatów stworzysz takiego godnego zaufania agenta, łącząc 2 zaawansowane technologie:
Google Agent Development Kit (ADK) | Agent Payments Protocol (AP2) | |
Role | Fabryka do tworzenia agentów AI klasy produkcyjnej | Architektoniczny plan budowania zaufania w transakcjach AI |
Co zapewnia | • Platforma do orkiestracji wielu agentów | • Granice zabezpieczeń oparte na rolach |
Więcej informacji |
Co utworzysz
Po zakończeniu tych warsztatów będziesz mieć:
✅ System wielu agentów z wyspecjalizowanymi rolami:
- Asystent zakupów, który znajduje zweryfikowane organizacje charytatywne
- Agent sprzedawcy, który tworzy wiążące oferty darowizn
- Dostawca danych logowania, który bezpiecznie przetwarza płatności
- Orchestrator, który koordynuje cały przepływ.
✅ 3 rodzaje weryfikowalnych danych logowania:
- IntentMandate: „Znajdź organizację charytatywną zajmującą się edukacją”
- CartMandate: „50 PLN na rzecz Room to Read, podpisane przez sprzedawcę”
- PaymentMandate: „Process via simulated payment” (Przetwórz za pomocą symulowanej płatności)
✅ Bezpieczeństwo w każdej warstwie:
- Granice zaufania oparte na rolach
- Wyraźna zgoda użytkownika
✅ Pełny rejestr kontrolny:
- Każda decyzja jest śledzona
- Każda zarejestrowana zgoda
- Każde przekazanie jest widoczne
🔒 Ważne: to bezpieczne środowisko edukacyjne
Chcesz budować zaufanie?
W następnym module skonfigurujemy środowisko programistyczne i utworzymy pierwszego agenta AI. Szybko dowiesz się, dlaczego proste agenty nie są godne zaufania, a potem spędzisz resztę warsztatów na nauce, jak to naprawić.
Zacznijmy od zrozumienia problemu z pierwszej ręki.
2. Przygotowywanie obszaru roboczego
Podstawa zaufanych agentów
Zanim stworzymy naszego agenta AI Giving Agent, musimy przygotować czyste, spójne i prawidłowo skonfigurowane środowisko deweloperskie. Ten moduł to skoncentrowany krok, który ma na celu zapewnienie, że wszystkie niezbędne narzędzia i usługi są dostępne.
Po pomyślnym zakończeniu tej konfiguracji możesz w pełni skupić się na ekscytującej pracy nad tworzeniem logiki agenta w kolejnych modułach, nie martwiąc się o problemy z konfiguracją.
Dostęp do Cloud Shell
Najpierw otworzymy Cloud Shell, czyli terminal w przeglądarce z zainstalowanym pakietem Google Cloud SDK i innymi niezbędnymi narzędziami.
Potrzebujesz środków w Google Cloud?
Kliknij Aktywuj Cloud Shell u góry konsoli Google Cloud (jest to ikona terminala na pasku nawigacyjnym w prawym górnym rogu).

Znajdź identyfikator projektu Google Cloud:
- Otwórz konsolę Google Cloud: https://console.cloud.google.com
- Wybierz projekt, którego chcesz użyć w tych warsztatach, z menu u góry strony.
- Identyfikator projektu jest wyświetlany na karcie Informacje o projekcie w panelu
.
Po otwarciu Cloud Shell sprawdź, czy masz uwierzytelnienie:
# Check that you are logged in
gcloud auth list
Twoje konto powinno być widoczne jako (ACTIVE).
Konfigurowanie projektu
Teraz skonfiguruj projekt Google Cloud i włącz niezbędne interfejsy API.
Ustawianie identyfikatora projektu
# Set your project using the auto-detected environment variable in Cloud Shell
gcloud config set project $GOOGLE_CLOUD_PROJECT
# Verify the project has been set
echo "Your active Google Cloud project is: $(gcloud config get-value project)"
Włącz wymagane interfejsy API
Twoi agenci potrzebują dostępu do kilku usług Google Cloud:
gcloud services enable \
aiplatform.googleapis.com \
secretmanager.googleapis.com \
cloudtrace.googleapis.com
Może to potrwać 1–2 minuty. Zobaczysz:
Operation "operations/..." finished successfully.
Co zapewniają te interfejsy API:
- aiplatform.googleapis.com: dostęp do modeli Gemini na potrzeby rozumowania agenta.
- secretmanager.googleapis.com: bezpieczne przechowywanie kluczy interfejsu API (sprawdzona metoda w środowisku produkcyjnym).
- cloudtrace.googleapis.com: widoczność ścieżki odpowiedzialności
Klonowanie kodu startowego
Pobierz repozytorium warsztatowe ze wszystkimi kodami szablonów i zasobami:
git clone https://github.com/ayoisio/adk-ap2-charity-agents
cd adk-ap2-charity-agents
git checkout codelab
Sprawdźmy, co mamy:
ls -la
Zobaczysz, że:
charity_advisor/– miejsce, w którym będziemy tworzyć agentów i narzędzia.scripts/– skrypty pomocnicze do testowania i weryfikacjideploy.sh– skrypt pomocniczy do wdrożeniasetup.py– skrypt pomocniczy do instalacji modułu.env.template– plik zmiennych środowiskowych
Konfigurowanie środowiska Pythona
Teraz utworzymy izolowane środowisko Pythona dla naszego projektu.
Tworzenie i aktywowanie środowiska wirtualnego
# Create the virtual environment
python3 -m venv venv
# Activate it
source venv/bin/activate
✅ Weryfikacja: w prompcie powinien się teraz wyświetlać prefiks (venv).
Instalowanie zależności
pip install -r charity_advisor/requirements.txt
pip install -e .
Spowoduje to zainstalowanie:
- google-adk: framework Agent Development Kit
- google-cloud-aiplatform: integracja z Vertex AI i Gemini
- ap2: Agent Payments Protocol SDK (z GitHub)
- python-dotenv: zarządzanie zmiennymi środowiskowymi
Flaga -e umożliwia importowanie modułów adk_ap2_charity_agents z dowolnego miejsca.
Konfigurowanie pliku środowiska
Utwórz konfigurację na podstawie szablonu:
# Copy the template
cp .env.template .env
# Get your current Project ID
PROJECT_ID=$(gcloud config get-value project)
# Replace the placeholder with your actual project ID
sed -i "s/your-project-id/$PROJECT_ID/g" .env
# Verify the replacement worked
grep GOOGLE_CLOUD_PROJECT .env
Zobaczysz, że:
GOOGLE_CLOUD_PROJECT=your-actual-project-id
Weryfikacja
Uruchom skrypt weryfikacyjny, aby sprawdzić, czy wszystko jest poprawnie skonfigurowane:
python scripts/verify_setup.py
Powinny pojawić się same zielone znaczniki wyboru:
======================================================================
SETUP VERIFICATION
======================================================================
✓ Python version: 3.11.x
✓ google-adk: 1.17.0
✓ google-cloud-aiplatform: 1.111.0+
✓ ap2: 0.1.0
✓ python-dotenv: 1.0.0+
✓ .env file found and contains project ID
✓ Google Cloud project configured: your-project-id
✓ Mock charity database found
✓ Agent templates ready
✓ All directories present
======================================================================
✓ Setup complete! You are ready to build trustworthy agents.
======================================================================
Rozwiązywanie problemów
Co dalej?
Środowisko jest już w pełni przygotowane. Wiesz już, jak:
- ✅ Skonfigurowano projekt Google Cloud
- ✅ Wymagane interfejsy API włączone
- ✅ Zainstalowano biblioteki ADK i AP2
- ✅ Kod szablonu gotowy do modyfikacji
W następnym module utworzysz pierwszego agenta AI za pomocą kilku wierszy kodu i dowiesz się, dlaczego prości agenci nie są godni zaufania w przypadku transakcji finansowych.
3. Twój pierwszy agent i odkrywanie luki w zaufaniu

Od pomysłu do interakcji
W poprzednim module przygotowaliśmy środowisko programistyczne. Teraz zaczyna się ciekawa praca. Stworzymy i uruchomimy pierwszego agenta, nadamy mu pierwszą funkcję i przy okazji odkryjemy podstawowe wyzwania, które musimy rozwiązać, aby był naprawdę godny zaufania.
Ten moduł to zdjęcie „przed” – moment, który pokazuje, dlaczego budowanie godnych zaufania agentów wymaga czegoś więcej niż tylko zapewnienia LLM dostępu do narzędzi.
Krok 1. Sprawdź agenta startowego
Najpierw przyjrzyjmy się szablonowi pierwszego agenta. Zawiera on podstawową strukturę z symbolami zastępczymi, które uzupełnimy w następnych krokach.
👉 Otwórz plik
charity_advisor/simple_agent/agent.py
w edytorze.
Zobaczysz:
"""
A simple agent that can research charities using Google Search.
"""
# MODULE_3_STEP_2_IMPORT_COMPONENTS
simple_agent = Agent(
name="SimpleAgent",
model="gemini-2.5-flash",
# MODULE_3_STEP_3_WRITE_INSTRUCTION
instruction="""""",
# MODULE_3_STEP_4_ADD_TOOLS
tools=[]
)
Zwróć uwagę, że komentarze zastępcze są zgodne z wzorcem: MODULE_3_STEP_X_DESCRIPTION. Zastąpimy te znaczniki, aby stopniowo tworzyć agenta.
Krok 2. Zaimportuj wymagane komponenty
Zanim utworzymy instancję klasy Agent lub użyjemy narzędzia google_search, musimy zaimportować je do pliku.
👉 Znajdź:
# MODULE_3_STEP_2_IMPORT_COMPONENTS
👉 Zastąp ten wiersz tym tekstem:
from google.adk.agents import Agent
from google.adk.tools import google_search
Teraz w naszym pliku są dostępne klasa Agent i narzędzie google_search.
Krok 3. Napisz instrukcję dla agenta
Instrukcja to „opis stanowiska” agenta – informuje model LLM, kiedy i jak używać narzędzi. Napiszmy taki, który poprowadzi agenta w wyszukiwaniu informacji o organizacjach charytatywnych.
👉 Znajdź:
# MODULE_3_STEP_3_WRITE_INSTRUCTION
instruction="""""",
👉 Zastąp te 2 wiersze tymi:
instruction="""You are a helpful research assistant. When a user asks you to find information about charities,
use the google_search tool to find the most relevant and up-to-date results from the web.
Synthesize the search results into a helpful summary.""",
Krok 4. Dodaj narzędzie wyszukiwania
Agent bez narzędzi to tylko rozmówca. Nadajmy agentowi pierwszą funkcję: możliwość wyszukiwania w internecie.
👉 Znajdź:
# MODULE_3_STEP_4_ADD_TOOLS
tools=[]
👉 Zastąp te 2 wiersze tymi:
tools=[google_search]
Krok 5. Weryfikacja kompletnego agenta
Zanim zaczniemy testować, sprawdźmy, czy wszystkie elementy są na swoim miejscu.
👉 Twój pełny
charity_advisor/simple_agent/agent.py
plik powinien wyglądać dokładnie tak:
"""
A simple agent that can research charities using Google Search.
"""
from google.adk.agents import Agent
from google.adk.tools import google_search
simple_agent = Agent(
name="SimpleAgent",
model="gemini-2.5-flash",
instruction="""You are a helpful research assistant. When a user asks you to find information about charities,
use the google_search tool to find the most relevant and up-to-date results from the web.
Synthesize the search results into a helpful summary.""",
tools=[google_search]
)
Krok 6. Testowanie agenta – ujawnianie luk w zaufaniu
Agent jest już w pełni skonfigurowany, więc przetestujmy go i przeanalizujmy jego działanie. W tym miejscu odkrywamy, dlaczego proste modele nie są wiarygodne w przypadku podejmowania decyzji finansowych.
Test 1. Problem z wykrywaniem
👉 W terminalu Cloud Shell uruchom to polecenie:
adk run charity_advisor/simple_agent
Powinny się wyświetlić dane wyjściowe podobne do tych:
INFO:google.adk.agents:Loading agent from charity_advisor/simple_agent
INFO:google.adk.agents:Agent 'SimpleAgent' ready
[user]:
Prompt [user]: czeka teraz na Twoje dane.
👉 W wierszu [user] wpisz:
Can you find me a verified, highly-rated charity for children's literacy?
👉 Naciśnij Enter i sprawdź odpowiedź.
Po chwili agent zsyntetyzuje wyniki wyszukiwania i wygeneruje odpowiedź podobną do tej:
Z wyszukiwania w internecie wynika, że do cenionych organizacji charytatywnych zajmujących się umiejętnością czytania i pisania u dzieci należą Reading Is Fundamental i Room to Read. Do weryfikacji statusu i ocen organizacji często polecane są źródła takie jak Charity Navigator i GuideStar. Znalazłem też kilka dyskusji online, m.in. na forach takich jak Reddit, gdzie użytkownicy dzielą się osobistymi doświadczeniami związanymi z różnymi mniejszymi, lokalnymi programami nauki czytania i pisania.
Przeanalizujmy to. Czy pracownik rozwiązał nasz problem?
❌ Nie. Doskonale odzwierciedla ludzkie doświadczenie, które opisaliśmy w module 1. Udało mu się zautomatyzować proces „googlowania” i przekazać nam z powrotem problem „paraliżu analitycznego”.
W ten sposób ujawnia się pierwsza luka w zaufaniu: brak wiarygodnych danych.
Agent przeszukuje otwarty internet, co oznacza, że:
- ✅ Szybko znalazł wyniki (lepsze wrażenia użytkowników).
- ❌ Łączy wysoko oceniane organizacje z dyskusjami na Reddicie (niewiarygodne źródła).
- ❌ Nie odróżnia zweryfikowanych organizacji charytatywnych od potencjalnych oszustw (brak weryfikacji).
- ❌ Prosi nas o zweryfikowanie informacji, które właśnie podał (przerzucając na nas ten obowiązek).
Test 2. Problem z wykonaniem
Teraz przejdźmy do drugiego, kluczowego testu. W odpowiedzi na prompt [user]: spróbuj przekazać darowiznę:
Okay, please donate $50 to Room to Read for me.
Odpowie on przeprosinami, przyznając się do swoich ograniczeń:
Rozumiemy, że chcesz przekazać darowiznę. To wspaniale! Jestem jednak asystentem ds. badań i nie mam możliwości obsługi transakcji finansowych ani przetwarzania płatności. Aby przekazać darowiznę, musisz bezpośrednio wejść na oficjalną stronę organizacji Room to Read.
To drugi, równie ważny moment „Aha!”.
Nie tylko nie można ufać agentowi w kwestii znalezienia odpowiedniej organizacji charytatywnej, ale też nie można mu jeszcze powierzyć zadania przekazania darowizny.
👉 Naciśnij
Ctrl+C
, aby wyjść po zakończeniu testowania.
Wizualizacja dwóch luk
Czego się właśnie dowiedziałeś(-aś)
W tym module udało Ci się utworzyć i wyposażyć pierwszego agenta AI. W ten sposób odkryliśmy 2 podstawowe wyzwania związane z budowaniem wiarygodnego systemu.
Opanowane kluczowe pojęcia
✅ Klasa agenta:
- Podstawowy element składowy ADK
- Łączy rozumowanie LLM (mózg) z narzędziami (rękami)
- Skonfigurowany z modelem, instrukcjami i narzędziami
✅ Struktura oparta na folderach:
- Każdy agent znajduje się w osobnym folderze.
- Pakiet ADK szuka
agent_folder/agent.py - Bieganie z
adk run agent_folder
✅ Lista narzędzi:
- Definiuje możliwości agenta
- Model LLM decyduje, kiedy i jak używać narzędzi
- Może zawierać wiele narzędzi do różnych działań.
✅ Prompt z instrukcjami:
- Określa zachowanie agenta, podobnie jak opis stanowiska.
- Określa rolę, aktywatory, działania i format wyjściowy
- Kluczowe dla niezawodnego korzystania z narzędzia
✅ Problem z zaufaniem:
- Przerwa w odkrywaniu: niezweryfikowane źródła o różnej jakości.
- Brak możliwości wykonania: brak funkcji zabezpieczeń, brak zgody użytkownika, brak ścieżki audytu.
Co dalej
W następnym module zaczniemy tworzyć rozwiązanie, wdrażając architekturę AP2 opartą na rolach.
Utwórzmy pierwszego agenta i zobaczmy, jak działa podział ról.
4. Tworzenie agenta zakupów – wykrywanie na podstawie ról

Podstawa zaufania: rozdział ról
W ostatnim module dowiedzieliśmy się, że prosty agent ogólnego przeznaczenia zawodzi na 2 frontach: nie zapewnia wiarygodnego wyszukiwania i nie może przeprowadzać bezpiecznych transakcji. Zacznijmy rozwiązywać te problemy, wdrażając pierwszą zasadę protokołu płatności dla agentów: architekturę opartą na rolach.
Zanim napiszemy kod, dowiedzmy się, dlaczego ta zasada jest ważna.
Zasada AP2: rozdzielenie ról
Problem z agentami, którzy „robią wszystko”
Wyobraź sobie, że zatrudniasz jedną osobę, która będzie Twoim doradcą finansowym, księgowym i brokerem inwestycyjnym. Wygodne? Tak. Bezpieczne? Zdecydowanie nie. Mogą one:
- Twoje cele inwestycyjne (rola doradcy)
- Dostęp do Twoich kont (rola księgowego)
- Uprawnienia do przenoszenia środków (rola brokera)
Jeśli ta osoba zostanie przejęta lub popełni błąd, wszystko będzie zagrożone.
Rozwiązanie AP2: jeden agent, jedno zadanie
AP2 stosuje zasadę rozdzielenia odpowiedzialności, aby tworzyć granice zaufania:
Dlaczego to jest ważne:
- ✅ Ograniczony zasięg: jeśli agent zakupowy zostanie przejęty, atakujący nie będzie mieć dostępu do danych uwierzytelniających płatności.
- ✅ Prywatność: dostawca danych logowania nigdy nie widzi Twojej rozmowy o zakupach.
- ✅ Zgodność: łatwiej spełnić wymagania PCI-DSS, gdy dane dotyczące płatności są odseparowane.
- ✅ Odpowiedzialność: jasne określenie odpowiedzialności za każdy etap.
Sposób komunikacji agentów: stan jako wspólny notatnik
Agenty nie mają bezpośredniego dostępu do danych innych agentów, więc komunikują się za pomocą stanu udostępnionego. Można ją traktować jako tablicę, na której wszyscy agenci mogą pisać i z której mogą odczytywać informacje:
# Shopping Agent writes:
state["intent_mandate"] = {
"natural_language_description": "Donate $50 to Room to Read",
"merchants": ["Room to Read"],
"intent_expiry": "2024-11-07T15:32:16Z",
"amount": 50.0
}
# Merchant Agent reads:
intent = state["intent_mandate"]
charity_name = intent["merchants"][0]
amount = intent["amount"]
# Creates CartMandate based on IntentMandate...
# Credentials Provider reads:
cart_mandate = state["cart_mandate"]
# Processes payment...
W ten sposób zachowujemy granice zaufania, a jednocześnie umożliwiamy współpracę.
Nasz pierwszy agent: agent zakupowy
Odpowiedzialność Agenta zakupów jest prosta i skupiona na:
- Użyj narzędzia
find_charities, aby wysłać zapytanie do naszej zaufanej bazy danych. - Prezentowanie opcji użytkownikowi
- Użyj narzędzia
save_user_choice, aby utworzyć element IntentMandate i zapisać go w stanie. - Przekazanie sprawy następnemu agentowi (sprzedawcy)
To wszystko. Brak obsługi płatności i tworzenia koszyka – tylko wykrywanie i przekazywanie.
Zbudujmy go krok po kroku.
Krok 1. Dodaj narzędzie Input Validation Helper
Podczas tworzenia narzędzi produkcyjnych kluczowe znaczenie ma weryfikacja danych wejściowych. Utwórzmy funkcję pomocniczą, która sprawdza dane organizacji charytatywnej przed zapisaniem ich w stanie.
👉 Otwórz
charity_advisor/tools/charity_tools.py
U góry zobaczysz funkcję find_charities (już ukończoną). Przewiń w dół, aby znaleźć:
# MODULE_4_STEP_1_ADD_VALIDATION_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _validate_charity_data(charity_name: str, charity_ein: str, amount: float) -> tuple[bool, str]:
"""
Validates charity selection data before saving to state.
This helper function performs basic validation to ensure data quality
before it gets passed to other agents in the pipeline.
Args:
charity_name: Name of the selected charity
charity_ein: Employer Identification Number (should be format: XX-XXXXXXX)
amount: Donation amount in USD
Returns:
(is_valid, error_message): Tuple where is_valid is True if all checks pass,
and error_message contains details if validation fails
"""
# Validate charity name
if not charity_name or not charity_name.strip():
return False, "Charity name cannot be empty"
# Validate EIN format (should be XX-XXXXXXX)
if not charity_ein or len(charity_ein) != 10 or charity_ein[2] != '-':
return False, f"Invalid EIN format: {charity_ein}. Expected format: XX-XXXXXXX"
# Validate amount
if amount <= 0:
return False, f"Donation amount must be positive, got: ${amount}"
if amount > 1_000_000:
return False, f"Donation amount exceeds maximum of $1,000,000: ${amount}"
# All checks passed
return True, ""
Krok 2. Dodaj narzędzie IntentMandate Creation Helper
Teraz utwórzmy funkcję pomocniczą, która tworzy strukturę AP2 IntentMandate. Jest to jeden z 3 rodzajów weryfikowalnych danych logowania w AP2.
👉 W tym samym pliku znajdź:
# MODULE_4_STEP_2_ADD_INTENTMANDATE_CREATION_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _create_intent_mandate(charity_name: str, charity_ein: str, amount: float) -> dict:
"""
Creates an IntentMandate - AP2's verifiable credential for user intent.
This function uses the official Pydantic model from the `ap2` package
to create a validated IntentMandate object before converting it to a dictionary.
Args:
charity_name: Name of the selected charity
charity_ein: Employer Identification Number
amount: Donation amount in USD
Returns:
Dictionary containing the IntentMandate structure per AP2 specification
"""
from datetime import datetime, timedelta, timezone
from ap2.types.mandate import IntentMandate
# Set the expiry for the intent
expiry = datetime.now(timezone.utc) + timedelta(hours=1)
# Step 1: Instantiate the Pydantic model with official AP2 fields
intent_mandate_model = IntentMandate(
user_cart_confirmation_required=True,
natural_language_description=f"Donate ${amount:.2f} to {charity_name}",
merchants=[charity_name],
skus=None,
requires_refundability=False,
intent_expiry=expiry.isoformat()
)
# Step 2: Convert the validated model to a dictionary for state storage
intent_mandate_dict = intent_mandate_model.model_dump()
# Step 3: Add the codelab's custom fields to the dictionary
timestamp = datetime.now(timezone.utc)
intent_mandate_dict.update({
"timestamp": timestamp.isoformat(),
"intent_id": f"intent_{charity_ein.replace('-', '')}_{int(timestamp.timestamp())}",
"charity_ein": charity_ein,
"amount": amount,
"currency": "USD"
})
return intent_mandate_dict
Krok 3. Utwórz narzędzie do przekazywania stanu za pomocą IntentMandate
Teraz utwórzmy narzędzie, które tworzy obiekt IntentMandate i zapisuje go w stanie.
👉 W tym samym pliku przewiń w dół do sekcji
save_user_choice
funkcja . Znajdź:
# MODULE_4_STEP_3_COMPLETE_SAVE_TOOL
👉 Zastąp ten wiersz tym tekstem:
# Validate inputs before creating IntentMandate
is_valid, error_message = _validate_charity_data(charity_name, charity_ein, amount)
if not is_valid:
logger.error(f"Validation failed: {error_message}")
return {"status": "error", "message": error_message}
# Create AP2 IntentMandate using our updated helper function
intent_mandate = _create_intent_mandate(charity_name, charity_ein, amount)
# Write the IntentMandate to shared state for the next agent
tool_context.state["intent_mandate"] = intent_mandate
logger.info(f"Successfully created IntentMandate and saved to state")
logger.info(f"Intent ID: {intent_mandate['intent_id']}")
logger.info(f"Intent expires: {intent_mandate['intent_expiry']}")
# Return success confirmation
return {
"status": "success",
"message": f"Created IntentMandate: ${amount:.2f} donation to {charity_name} (EIN: {charity_ein})",
"intent_id": intent_mandate["intent_id"],
"expiry": intent_mandate["intent_expiry"]
}
Krok 4. Dodaj narzędzie Display Formatting Helper
Zanim utworzymy agenta, dodajmy jeszcze jeden element pomocniczy, który będzie formatować dane organizacji charytatywnych w sposób przyjazny dla użytkownika.
👉 Przewiń, aby znaleźć:
# MODULE_4_STEP_4_ADD_FORMATTING_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _format_charity_display(charity: dict) -> str:
"""
Formats a charity dictionary into a user-friendly display string.
This helper function demonstrates how to transform structured data
into readable text for the user.
Args:
charity: Dictionary containing charity data (name, ein, mission, rating, efficiency)
Returns:
Formatted string suitable for display to the user
"""
name = charity.get('name', 'Unknown')
ein = charity.get('ein', 'N/A')
mission = charity.get('mission', 'No mission statement available')
rating = charity.get('rating', 0.0)
efficiency = charity.get('efficiency', 0.0)
# Format efficiency as percentage
efficiency_pct = int(efficiency * 100)
# Build formatted string
display = f"""
**{name}** (EIN: {ein})
⭐ Rating: {rating}/5.0
💰 Efficiency: {efficiency_pct}% of funds go to programs
📋 Mission: {mission}
""".strip()
return display
Krok 5. Tworzenie agenta zakupowego – importowanie komponentów
Gdy nasze narzędzia są już gotowe i działają bez zarzutu, możemy utworzyć agenta, który będzie z nich korzystać.
👉 Otwórz
charity_advisor/shopping_agent/agent.py
Zobaczysz szablon z komentarzami zastępczymi. Zbudujmy go krok po kroku.
👉 Znajdź:
# MODULE_4_STEP_5_IMPORT_COMPONENTS
👉 Zastąp ten wiersz tym tekstem:
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.charity_tools import find_charities, save_user_choice
Krok 6. Napisz instrukcję dla agenta
Instrukcja to miejsce, w którym definiujemy opis stanowiska i przepływ pracy agenta. Jest to bardzo ważne, ponieważ źle napisana instrukcja prowadzi do nieprzewidywalnych działań.
👉 Znajdź:
# MODULE_4_STEP_6_WRITE_INSTRUCTION
instruction="""""",
👉 Zastąp te 2 wiersze tymi:
instruction="""You are a research specialist helping users find verified charities.
Your workflow:
1. When the user describes what cause they want to support (e.g., "education", "health", "environment"),
use the find_charities tool to search our vetted database.
2. Present the results clearly. The tool returns formatted charity information that you should
show to the user.
3. When the user selects a charity and specifies an amount, use the save_user_choice tool
to create an IntentMandate and record their decision. You MUST call save_user_choice with:
- charity_name: The exact name of the chosen charity
- charity_ein: The EIN of the chosen charity
- amount: The donation amount in dollars (as a number, not a string)
4. After successfully saving, inform the user:
- That you've created an IntentMandate (mention the intent ID if provided)
- When the intent expires
- That you're passing their request to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is discovery and creating the IntentMandate
- You do NOT process payments
- You do NOT see the user's payment methods
- You do NOT create cart offers (that's the Merchant Agent's job)
- After calling save_user_choice, your work is done
WHAT IS AN INTENTMANDATE:
An IntentMandate is a structured record of what the user wants to do. It includes:
- Natural language description ("Donate $50 to Room to Read")
- Which merchants can fulfill it
- When the intent expires
- Whether user confirmation is required
This is the first of three verifiable credentials in our secure payment system.
If the user asks you to do anything related to payment processing, politely explain that
you don't have that capability and that their request will be handled by the appropriate
specialist agent.""",
Krok 7. Dodaj narzędzia do agenta
Teraz przyznajmy agentowi dostęp do obu narzędzi.
👉 Znajdź:
# MODULE_4_STEP_7_ADD_TOOLS
👉 Zastąp te 2 wiersze tymi:
tools=[
FunctionTool(func=find_charities),
FunctionTool(func=save_user_choice)
]
Krok 8. Weryfikacja ukończonego agenta
Sprawdźmy, czy wszystko jest prawidłowo podłączone.
👉 Twój pełny
charity_advisor/shopping_agent/agent.py
powinien teraz wyglądać tak:
"""
Shopping Agent - Finds charities from a trusted database and saves the user's choice.
This agent acts as our specialized "Research Analyst."
"""
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.charity_tools import find_charities, save_user_choice
shopping_agent = Agent(
name="ShoppingAgent",
model="gemini-2.5-pro",
description="Finds and recommends vetted charities from a trusted database, then creates an IntentMandate capturing the user's donation intent.",
instruction="""You are a research specialist helping users find verified charities.
Your workflow:
1. When the user describes what cause they want to support (e.g., "education", "health", "environment"),
use the find_charities tool to search our vetted database.
2. Present the results clearly. The tool returns formatted charity information that you should
show to the user.
3. When the user selects a charity and specifies an amount, use the save_user_choice tool
to create an IntentMandate and record their decision. You MUST call save_user_choice with:
- charity_name: The exact name of the chosen charity
- charity_ein: The EIN of the chosen charity
- amount: The donation amount in dollars (as a number, not a string)
4. After successfully saving, inform the user:
- That you've created an IntentMandate (mention the intent ID if provided)
- When the intent expires
- That you're passing their request to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is discovery and creating the IntentMandate
- You do NOT process payments
- You do NOT see the user's payment methods
- You do NOT create cart offers (that's the Merchant Agent's job)
- After calling save_user_choice, your work is done
WHAT IS AN INTENTMANDATE:
An IntentMandate is a structured record of what the user wants to do. It includes:
- Natural language description ("Donate $50 to Room to Read")
- Which merchants can fulfill it
- When the intent expires
- Whether user confirmation is required
This is the first of three verifiable credentials in our secure payment system.
If the user asks you to do anything related to payment processing, politely explain that
you don't have that capability and that their request will be handled by the appropriate
specialist agent.""",
tools=[
FunctionTool(func=find_charities),
FunctionTool(func=save_user_choice)
]
)
✅ Świetnie! Utworzono agenta zgodnego z AP2, który jest gotowy do wdrożenia w środowisku produkcyjnym i ma:
- Weryfikacja danych wejściowych
- Prawidłowe tworzenie obiektu IntentMandate za pomocą modeli Pydantic AP2
- Sformatowane dane wyjściowe
- Jasne granice ról
- Szczegółowe instrukcje
- Obsługa błędów
Krok 9. Przetestuj agenta zakupowego
Sprawdźmy, czy nasz agent działa prawidłowo, tworzy odpowiednie obietnice dotyczące intencji i przestrzega swoich ograniczeń.
👉 W terminalu Cloud Shell uruchom:
adk run charity_advisor/shopping_agent
Pojawi się wiersz poleceń [user]:.
Test 1. Odkrywanie za pomocą zaufanej bazy danych
👉 Typ:
I want to donate to an education charity. What are my options?
Po chwili agent udzieli odpowiedzi. Dzięki _format_charity_display pomocnikowi wyniki są pięknie sformatowane:
W naszej bazie danych znaleźliśmy 3 zweryfikowane organizacje charytatywne zajmujące się edukacją:
Room to Read (EIN: 77-0479905)
⭐ Ocena: 4,9/5,0
💰 Skuteczność: 88% środków jest przeznaczanych na programy
📋 Misja: zmienia życie milionów dzieci w społecznościach o niskich dochodach, koncentrując się na umiejętności czytania i pisania oraz równości płci w edukacji.
Teach For America (EIN: 13-3541913)
⭐ Ocena: 4,7/5,0
💰 Skuteczność: 81% środków jest przeznaczanych na programy
📋 Misja: zwiększanie możliwości edukacyjnych dzieci z trudnych środowisk.
Tech Education Alliance (EIN: 45-2345678)
⭐ Ocena: 4,8/5,0
💰 Skuteczność: 92% środków jest przeznaczanych na programy
📋 Misja: zapewnia edukację informatyczną w szkołach o ograniczonych możliwościach.
Którą organizację charytatywną chcesz wesprzeć i jaką kwotę chcesz przekazać?
Porównaj to z prostym agentem z modułu 3, który wyświetlał niezweryfikowane wyniki Google. To jest różnica między wykrywaniem niezaufanym a zaufanym.
Test 2. Zapisywanie wyboru użytkownika i tworzenie obiektu IntentMandate
👉 Typ:
I'll donate $50 to Room to Read.
Powinien on wywołać narzędzie save_user_choice z prawidłowymi parametrami. Dzięki tworzeniu IntentMandate za pomocą modeli AP2 zobaczysz bardziej ustrukturyzowaną odpowiedź:
Super! Utworzyliśmy dla Ciebie dokument IntentMandate dotyczący darowizny:
Szczegóły intencji:
- Identyfikator intencji: intent_774795905_1730927536
- Kwota: 50,00 USD na rzecz organizacji Room to Read (EIN: 77-0479905)
- Wygasa: 2024-11-07T15:32:16Z (za godzinę)
Ten dokument IntentMandate odzwierciedla Twoją intencję przekazania darowizny i zawiera ograniczenia, które zapewniają bezpieczne przetwarzanie transakcji. Przekazuję teraz tę informację do naszego bezpiecznego procesora płatności, aby utworzyć formalną ofertę i dokończyć przekazywanie darowizny.
W tle wydarzyło się kilka rzeczy:
_validate_charity_data()zweryfikowano dane wejściowe._create_intent_mandate()użył modelu AP2 Pydantic do utworzenia struktury:
# Created and validated via Pydantic
intent_mandate_model = IntentMandate(
user_cart_confirmation_required=True,
natural_language_description="Donate $50.00 to Room to Read",
merchants=["Room to Read"],
skus=None,
requires_refundability=False,
intent_expiry="2024-11-07T15:32:16Z"
)
# Converted to dict and extended with custom fields
intent_mandate_dict = intent_mandate_model.model_dump()
intent_mandate_dict.update({
"charity_ein": "77-0479905",
"amount": 50.0,
"currency": "USD"
})
- Narzędzie zapisało w stanie udostępnionym TYLKO element IntentMandate:
state["intent_mandate"] = intent_mandate_dict
- Do LLM została zwrócona wiadomość o sukcesie zawierająca szczegóły intencji.
- Model LLM utworzył końcową wiadomość dla użytkownika.
Ten dokument IntentMandate jest gotowy do odebrania przez przedstawiciela sprzedawcy (moduł 5). Sprzedawca wyodrębni z dokumentu IntentMandate nazwę organizacji charytatywnej i kwotę oraz sprawdzi, czy dokument nie wygasł.
Test 3. Weryfikacja w praktyce
Sprawdźmy, czy nasz pomocnik weryfikacji wykrywa nieprawidłowe dane wejściowe.
👉 Typ:
I'll donate -$25 to Room to Read.
Agent powinien wychwycić nieprawidłową kwotę:
Wystąpił problem: kwota darowizny musi być dodatnia, otrzymano: $-25.0
Podaj kwotę darowizny (musi być dodatnia), a ja utworzę dla Ciebie IntentMandate.
To jest przykład programowania defensywnego w praktyce. Nasz _validate_charity_datapomocnik zapobiegł wprowadzeniu do systemu nieprawidłowych danych i utworzeniu nieprawidłowego obiektu IntentMandate.
Test 4. Weryfikacja granicy zaufania
👉 Poproś agenta o przetworzenie płatności:
Now process my credit card payment.
Agent powinien odmówić, przestrzegając zakresu swojej roli:
Nie mam możliwości przetwarzania płatności – nie należy to do moich obowiązków. Moim zadaniem jest pomóc Ci znaleźć zweryfikowane organizacje charytatywne i utworzyć dokument IntentMandate, który odzwierciedla Twoje intencje dotyczące darowizny.
Twój dokument IntentMandate został już utworzony i przekazany do naszego bezpiecznego procesora płatności. Agent sprzedawcy utworzy formalną ofertę (CartMandate), a dostawca danych logowania zajmie się płatnością za Twoją wyraźną zgodą.
To jest granica zaufania w działaniu. Agent wie, że nie ma uprawnień do obsługi danych dotyczących płatności, a jego instrukcja wyraźnie nakazuje mu wyjaśnienie tego użytkownikom, a także zapoznanie ich z koncepcją IntentMandate.
👉 Naciśnij
Ctrl+C
, aby wyjść po zakończeniu testowania.
Co właśnie zostało utworzone
Udało Ci się wdrożyć pierwszy element architektury AP2 z prawidłowym tworzeniem obiektu IntentMandate za pomocą modeli Pydantic AP2.
Opanowane kluczowe pojęcia
✅ Architektura oparta na rolach:
- Każdy agent ma jedno jasno określone zadanie.
- Agenci komunikują się za pomocą stanu udostępnionego, a nie bezpośredniego dostępu.
- Granice zaufania ograniczają wpływ naruszenia bezpieczeństwa
✅ IntentMandate (AP2 Credential #1):
- Utworzone przy użyciu oficjalnych modeli Pydantic AP2 na potrzeby weryfikacji
- Ustrukturyzowane rejestrowanie intencji użytkownika
- Obejmuje wygaśnięcie zabezpieczeń (zapobiega atakom typu replay)
- Określa ograniczenia (sprzedawcy, możliwość zwrotu środków, potwierdzenie)
- Opis w języku naturalnym dla ludzi
- Czytelne dla agentów
- Model weryfikowany przed przekształceniem w słownik
✅ Stan jako wspomnienie udostępnione:
tool_context.stateto „notatnik”, do którego mają dostęp wszyscy agenci.- Zapisywanie w stanie = udostępnianie weryfikowalnych danych logowania
- Odczyt ze stanu = wykorzystywanie i weryfikowanie danych logowania
- Agenty podrzędne wyodrębniają z danych logowania potrzebne informacje.
✅ FunctionTool:
- Konwertuje funkcje Pythona na narzędzia wywoływane przez LLM
- Opiera się na docstringach i wskazówkach dotyczących typów, aby model LLM mógł je zrozumieć.
- Automatycznie obsługuje wywołanie
- Komponowanie narzędzi: małe, wyspecjalizowane narzędzia > narzędzia monolityczne
✅ Instrukcje dla pracowników obsługi klienta:
- Wskazówki dotyczące przepływu pracy krok po kroku
- Wyraźne granice („NIE...”)
- Specyfikacje parametrów zapobiegające błędom
- Definicje techniczne (co to jest IntentMandate)
- Obsługa przypadków skrajnych (co powiedzieć, gdy…)
Co dalej
W następnym module utworzymy agenta sprzedawcy, który będzie odbierać IntentMandate i tworzyć drugie poświadczenie weryfikowalne: CartMandate.
Agent zakupowy utworzył obiekt IntentMandate, który rejestruje zamiar użytkownika z datą ważności. Teraz potrzebujemy agenta, który odczyta te dane logowania, sprawdzi, czy nie wygasły, i utworzy formalną, podpisaną ofertę o treści: „Ja, sprzedawca, zobowiązuję się do utrzymania tej ceny i dostarczenia tych towarów”.
Utwórzmy agenta sprzedawcy i zobaczmy, jak działa drugi rodzaj danych logowania AP2.
5. Tworzenie agenta sprzedawcy – oferty wiążące i CartMandate

Od odkrywania do zaangażowania
W poprzednim module utworzyliśmy agenta zakupów – specjalistę, który wyszukuje zweryfikowane organizacje charytatywne i tworzy obiekt IntentMandate, który rejestruje zamiary użytkownika. Teraz potrzebujemy agenta, który otrzyma ten dokument i utworzy formalną, wiążącą ofertę.
W tym miejscu pojawia się druga kluczowa zasada AP2: weryfikowalne dane logowania za pomocą CartMandate.
Zasada AP2: CartMandate i oferty wiążące
Dlaczego potrzebujemy roli sprzedawcy
W module 4 agent zakupowy utworzył obiekt IntentMandate i zapisał go w stanie:
state["intent_mandate"] = {
"natural_language_description": "Donate $50 to Room to Read",
"merchants": ["Room to Read"],
"amount": 50.0,
"intent_expiry": "2024-11-07T15:32:16Z"
}
To jednak tylko zamiar użytkownika. Zanim będziemy mogli przetworzyć płatność, musimy mieć:
- formalną strukturę oferty, którą rozumieją systemy płatności;
- dowód na to, że sprzedawca zaakceptuje tę cenę.
- Zobowiązanie wiążące, którego nie można zmienić w trakcie transakcji.
- Sprawdzenie, czy intencja nie wygasła.
To zadanie agenta sprzedawcy.
Co to jest CartMandate?
CartMandate to termin używany przez AP2 na określenie „cyfrowego koszyka”, który służy jako wiążąca oferta. Jest ona zgodna ze standardem W3C PaymentRequest, co oznacza, że:
- Format jest rozpoznawany przez firmy obsługujące płatności na całym świecie.
- Zawiera wszystkie szczegóły transakcji w standardowy sposób.
- Może być podpisany kryptograficznie, aby potwierdzić autentyczność.
Można to porównać do pisemnej wyceny od wykonawcy:
- ❌ Słownie: „Tak, mogę wykonać to zadanie za około 50 złotych”.
- ✅ Pisemna wycena: wyszczególnione koszty, suma, podpis, data.
Pisemna wycena jest wiążąca. Dokument CartMandate jest cyfrowym odpowiednikiem tego dokumentu.
Struktura CartMandate
Obiekt CartMandate w AP2 ma określoną strukturę zagnieżdżoną:
cart_mandate = {
"contents": { # ← AP2 wrapper
"id": "cart_xyz123",
"cart_expiry": "2024-11-07T15:47:16Z",
"merchant_name": "Room to Read",
"user_cart_confirmation_required": False,
"payment_request": { # ← W3C PaymentRequest nested inside
"method_data": [...],
"details": {...},
"options": {...}
}
},
"merchant_authorization": "SIG_a3f7b2c8" # ← Merchant signature
}
3 główne elementy:
1. contents – kontener koszyka zawierający:
- Identyfikator koszyka i data ważności
- Nazwa sprzedawcy
- W3C PaymentRequest
2. payment_request (w treści) – co jest kupowane:
- method_data: akceptowane formy płatności
- szczegóły: produkty i suma,
- opcje: wymagania dotyczące dostawy i informacji o płatniku;
3. merchant_authorization – podpis kryptograficzny
Podpisy sprzedawców: dowód zobowiązania
Podpis sprzedawcy jest niezbędny. Potwierdza to:
- Ta oferta pochodzi od autoryzowanego sprzedawcy
- Sprzedawca zobowiązuje się do honorowania tej dokładnej ceny.
- od momentu utworzenia oferta nie została zmieniona;
W środowisku produkcyjnym byłby to podpis kryptograficzny z użyciem infrastruktury klucza publicznego (PKI) lub tokenów sieciowych JSON (JWT). Na potrzeby warsztatów edukacyjnych zasymulujemy to za pomocą haszu SHA-256.
# Production (real signature):
signature = sign_with_private_key(cart_data, merchant_private_key)
# Workshop (simulated signature):
cart_hash = hashlib.sha256(cart_json.encode()).hexdigest()
signature = f"SIG_{cart_hash[:16]}"
Nasza misja: stworzenie agenta sprzedawcy
Przedstawiciel handlowy:
- Odczytanie IntentMandate ze stanu (tego, co napisał agent Zakupów)
- Sprawdź, czy intencja nie wygasła.
- Wyodrębnij nazwę organizacji charytatywnej, kwotę i inne szczegóły.
- Tworzenie struktury PaymentRequest zgodnej ze standardem W3C za pomocą modeli Pydantic AP2
- Zapakuj go w CartMandate interfejsu AP2 z datą ważności.
- Dodawanie symulowanego podpisu sprzedawcy
- Napisz dokument CartMandate, aby określić stan dostawcy danych uwierzytelniających (następny moduł)
Zbudujmy go krok po kroku.
Krok 1. Dodaj narzędzie Expiry Validation Helper
Najpierw skonfigurujmy plik narzędzi związanych z merchantem i dodajmy pomocnika do sprawdzania ważności IntentMandate.
👉 Otwórz
charity_advisor/tools/merchant_tools.py
Dodajmy weryfikację daty ważności:
👉 Znajdź:
# MODULE_5_STEP_1_ADD_EXPIRY_VALIDATION_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _validate_intent_expiry(intent_expiry_str: str) -> tuple[bool, str]:
"""
Validates that the IntentMandate hasn't expired.
This is a critical security check - expired intents should not be processed.
Args:
intent_expiry_str: The ISO 8601 timestamp string from the IntentMandate.
Returns:
(is_valid, error_message): Tuple indicating if intent is still valid.
"""
try:
# The .replace('Z', '+00:00') is for compatibility with older Python versions
expiry_time = datetime.fromisoformat(intent_expiry_str.replace('Z', '+00:00'))
now = datetime.now(timezone.utc)
if expiry_time < now:
return False, f"IntentMandate expired at {intent_expiry_str}"
time_remaining = expiry_time - now
logger.info(f"IntentMandate valid. Expires in {time_remaining.total_seconds():.0f} seconds")
return True, ""
except (ValueError, TypeError) as e:
return False, f"Invalid intent_expiry format: {e}"
Krok 2. Dodaj narzędzie Signature Generation Helper
Teraz utwórzmy funkcję pomocniczą, która będzie generować symulowany podpis sprzedawcy.
👉 Znajdź:
# MODULE_5_STEP_2_ADD_SIGNATURE_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _generate_merchant_signature(cart_contents: CartContents) -> str:
"""
Generates a simulated merchant signature for the CartMandate contents.
In production, this would use PKI or JWT with the merchant's private key.
For this codelab, we use a SHA-256 hash of the sorted JSON representation.
Args:
cart_contents: The Pydantic model of the cart contents to sign.
Returns:
Simulated signature string (format: "SIG_" + first 16 chars of hash).
"""
# Step 1: Dump the Pydantic model to a dictionary. The `mode='json'` argument
# ensures that complex types like datetimes are serialized correctly.
cart_contents_dict = cart_contents.model_dump(mode='json')
# Step 2: Use the standard json library to create a stable, sorted JSON string.
# separators=(',', ':') removes whitespace for a compact and canonical representation.
cart_json = json.dumps(cart_contents_dict, sort_keys=True, separators=(',', ':'))
# Step 3: Generate SHA-256 hash.
cart_hash = hashlib.sha256(cart_json.encode('utf-8')).hexdigest()
# Step 4: Create signature in a recognizable format.
signature = f"SIG_{cart_hash[:16]}"
logger.info(f"Generated merchant signature: {signature}")
return signature
Krok 3A. Utwórz podpis narzędzia i skonfiguruj je
Teraz zacznijmy tworzyć główne narzędzie. Utworzymy go stopniowo w 4 podkrokach. Najpierw podpis funkcji i konfiguracja początkowa.
👉 Znajdź:
# MODULE_5_STEP_3A_CREATE_TOOL_SIGNATURE
👉 Zastąp ten wiersz tym tekstem:
async def create_cart_mandate(tool_context: Any) -> Dict[str, Any]:
"""
Creates a W3C PaymentRequest-compliant CartMandate from the IntentMandate.
This tool reads the IntentMandate from shared state, validates it, and
creates a formal, signed offer using the official AP2 Pydantic models.
Returns:
Dictionary containing status and the created CartMandate.
"""
logger.info("Tool called: Creating CartMandate from IntentMandate")
# MODULE_5_STEP_3B_ADD_VALIDATION_LOGIC
Krok 3B. Dodaj logikę weryfikacji
Teraz dodajmy logikę odczytywania i weryfikowania dokumentu IntentMandate za pomocą modeli Pydantic AP2 oraz wyodrębniania potrzebnych danych.
👉 Znajdź:
# MODULE_5_STEP_3B_ADD_VALIDATION_LOGIC
👉 Zastąp ten wiersz tym tekstem:
# 1. Read IntentMandate dictionary from state
intent_mandate_dict = tool_context.state.get("intent_mandate")
if not intent_mandate_dict:
logger.error("No IntentMandate found in state")
return {
"status": "error",
"message": "No IntentMandate found. Shopping Agent must create intent first."
}
# 2. Parse dictionary into a validated Pydantic model
try:
intent_mandate_model = IntentMandate.model_validate(intent_mandate_dict)
except Exception as e:
logger.error(f"Could not validate IntentMandate structure: {e}")
return {"status": "error", "message": f"Invalid IntentMandate structure: {e}"}
# 3. Validate that the intent hasn't expired (CRITICAL security check)
is_valid, error_message = _validate_intent_expiry(intent_mandate_model.intent_expiry)
if not is_valid:
logger.error(f"IntentMandate validation failed: {error_message}")
return {"status": "error", "message": error_message}
# 4. Extract data. Safely access standard fields from the model, and
# custom fields (like 'amount') from the original dictionary.
charity_name = intent_mandate_model.merchants[0] if intent_mandate_model.merchants else "Unknown Charity"
amount = intent_mandate_dict.get("amount", 0.0)
# MODULE_5_STEP_3C_CREATE_CARTMANDATE_STRUCTURE
Krok 3C. Tworzenie struktury CartMandate
Teraz zbudujmy strukturę PaymentRequest zgodną ze standardem W3C i umieśćmy ją w AP2 CartMandate za pomocą modeli Pydantic.
👉 Znajdź:
# MODULE_5_STEP_3C_CREATE_CARTMANDATE_STRUCTURE
👉 Zastąp ten wiersz tym tekstem:
# 5. Build the nested Pydantic models for the CartMandate
timestamp = datetime.now(timezone.utc)
cart_id = f"cart_{hashlib.sha256(f'{charity_name}{timestamp.isoformat()}'.encode()).hexdigest()[:12]}"
cart_expiry = timestamp + timedelta(minutes=15)
payment_request_model = PaymentRequest(
method_data=[PaymentMethodData(
supported_methods="CARD",
data={"supported_networks": ["visa", "mastercard", "amex"], "supported_types": ["debit", "credit"]}
)],
details=PaymentDetailsInit(
id=f"order_{cart_id}",
display_items=[PaymentItem(
label=f"Donation to {charity_name}",
amount=PaymentCurrencyAmount(currency="USD", value=amount) # Pydantic v2 handles float -> str conversion
)],
total=PaymentItem(
label="Total Donation",
amount=PaymentCurrencyAmount(currency="USD", value=amount)
)
),
options=PaymentOptions(request_shipping=False)
)
cart_contents_model = CartContents(
id=cart_id,
cart_expiry=cart_expiry.isoformat(),
merchant_name=charity_name,
user_cart_confirmation_required=False,
payment_request=payment_request_model
)
# MODULE_5_STEP_3D_ADD_SIGNATURE_AND_SAVE
Krok 3D. Dodaj podpis i zapisz w stanie
Na koniec podpiszmy CartMandate za pomocą naszego modelu Pydantic i zapiszmy go w stanie dla następnego agenta.
👉 Znajdź:
# MODULE_5_STEP_3D_ADD_SIGNATURE_AND_SAVE
👉 Zastąp ten wiersz tym tekstem:
# 6. Generate signature from the validated Pydantic model
signature = _generate_merchant_signature(cart_contents_model)
# 7. Create the final CartMandate model, now including the signature
cart_mandate_model = CartMandate(
contents=cart_contents_model,
merchant_authorization=signature
)
# 8. Convert the final model to a dictionary for state storage and add the custom timestamp
cart_mandate_dict = cart_mandate_model.model_dump(mode='json')
cart_mandate_dict["timestamp"] = timestamp.isoformat()
# 9. Write the final dictionary to state
tool_context.state["cart_mandate"] = cart_mandate_dict
logger.info(f"CartMandate created successfully: {cart_id}")
return {
"status": "success",
"message": f"Created signed CartMandate {cart_id} for ${amount:.2f} donation to {charity_name}",
"cart_id": cart_id,
"cart_expiry": cart_expiry.isoformat(),
"signature": signature
}
Krok 4. Tworzenie agenta sprzedawcy – importowanie komponentów
Teraz utwórzmy agenta, który będzie korzystać z tego narzędzia.
👉 Otwórz
charity_advisor/merchant_agent/agent.py
Zobaczysz szablon ze znacznikami zastępczymi. Zacznijmy od zaimportowania tego, czego potrzebujemy.
👉 Znajdź:
# MODULE_5_STEP_4_IMPORT_COMPONENTS
👉 Zastąp ten wiersz tym tekstem:
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.merchant_tools import create_cart_mandate
Krok 5. Napisz instrukcję dla agenta sprzedawcy
Teraz napiszemy instrukcję, która powie agentowi, kiedy i jak ma używać narzędzia.
👉 Znajdź:
# MODULE_5_STEP_5_WRITE_INSTRUCTION
instruction="""""",
👉 Zastąp te 2 wiersze tymi:
instruction="""You are a merchant specialist responsible for creating formal, signed offers (CartMandates).
Your workflow:
1. Read the IntentMandate from shared state.
The IntentMandate was created by the Shopping Agent and contains:
- merchants: List of merchant names
- amount: Donation amount
- charity_ein: Tax ID
- intent_expiry: When the intent expires
2. Use the create_cart_mandate tool to create a W3C PaymentRequest-compliant CartMandate.
This tool will:
- Validate the IntentMandate hasn't expired (CRITICAL security check)
- Extract the charity name and amount from the IntentMandate
- Create a structured offer with payment methods, transaction details, and merchant info
- Generate a merchant signature to prove authenticity
- Save the CartMandate to state for the payment processor
3. After creating the CartMandate, inform the user:
- That you've created a formal, signed offer
- The cart ID
- When the cart expires (15 minutes)
- That you're passing it to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is creating signed CartMandates from valid IntentMandates
- You do NOT process payments
- You do NOT see the user's payment methods or credentials
- You do NOT interact with payment networks
- You MUST validate that the IntentMandate hasn't expired before creating a cart
- After calling create_cart_mandate, your work is done
WHAT IS A CARTMANDATE:
A CartMandate is a binding commitment that says:
"I, the merchant, commit to accepting $X for this charity donation, and I prove it with my signature."
This commitment is structured using the W3C PaymentRequest standard and includes:
- Payment methods accepted (card, bank transfer)
- Transaction details (amount, charity name)
- Cart expiry (15 minutes from creation)
- Merchant signature (proof of commitment)
This is the second of three verifiable credentials in our secure payment system.""",
Krok 6. Dodaj narzędzia do Merchant Agent
👉 Znajdź:
# MODULE_5_STEP_6_ADD_TOOLS
tools=[],
👉 Zastąp te 2 wiersze tymi:
tools=[
FunctionTool(func=create_cart_mandate)
],
Krok 7. Sprawdź agenta Complete Merchant Agent
Sprawdźmy, czy wszystko jest prawidłowo podłączone.
👉 Twój pełny
charity_advisor/merchant_agent/agent.py
powinien teraz wyglądać tak:
"""
Merchant Agent - Creates W3C-compliant CartMandates with merchant signatures.
This agent acts as our "Contract Creator."
"""
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.merchant_tools import create_cart_mandate
merchant_agent = Agent(
name="MerchantAgent",
model="gemini-2.5-flash",
description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
tools=[
FunctionTool(func=create_cart_mandate)
],
instruction="""You are a merchant specialist responsible for creating formal, signed offers (CartMandates).
Your workflow:
1. Read the IntentMandate from shared state.
The IntentMandate was created by the Shopping Agent and contains:
- merchants: List of merchant names
- amount: Donation amount
- charity_ein: Tax ID
- intent_expiry: When the intent expires
2. Use the create_cart_mandate tool to create a W3C PaymentRequest-compliant CartMandate.
This tool will:
- Validate the IntentMandate hasn't expired (CRITICAL security check)
- Extract the charity name and amount from the IntentMandate
- Create a structured offer with payment methods, transaction details, and merchant info
- Generate a merchant signature to prove authenticity
- Save the CartMandate to state for the payment processor
3. After creating the CartMandate, inform the user:
- That you've created a formal, signed offer
- The cart ID
- When the cart expires (15 minutes)
- That you're passing it to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is creating signed CartMandates from valid IntentMandates
- You do NOT process payments
- You do NOT see the user's payment methods or credentials
- You do NOT interact with payment networks
- You MUST validate that the IntentMandate hasn't expired before creating a cart
- After calling create_cart_mandate, your work is done
WHAT IS A CARTMANDATE:
A CartMandate is a binding commitment that says:
"I, the merchant, commit to accepting $X for this charity donation, and I prove it with my signature."
This commitment is structured using the W3C PaymentRequest standard and includes:
- Payment methods accepted (card, bank transfer)
- Transaction details (amount, charity name)
- Cart expiry (15 minutes from creation)
- Merchant signature (proof of commitment)
This is the second of three verifiable credentials in our secure payment system."""
)
✅ Punkt kontrolny: masz teraz kompletnego agenta sprzedawcy z prawidłowym tworzeniem AP2 CartMandate za pomocą modeli Pydantic.
Krok 8. Przetestuj agenta sprzedawcy
Teraz sprawdźmy, czy nasz agent prawidłowo tworzy obciążenia koszyka z podpisami i weryfikuje datę ważności.
Konfiguracja testu: uruchamianie skryptu testowego
👉 W terminalu Cloud Shell uruchom:
python scripts/test_merchant.py
Oczekiwane dane wyjściowe:
======================================================================
MERCHANT AGENT TEST
======================================================================
Simulated IntentMandate from Shopping Agent:
charity: Room to Read
amount: $50.00
expiry: 2024-11-07T16:32:16Z
----------------------------------------------------------------------
Merchant Agent Response:
----------------------------------------------------------------------
Perfect! I've received your IntentMandate and created a formal, signed offer (CartMandate) for your donation.
**CartMandate Details:**
- **Cart ID**: cart_3b4c5d6e7f8a
- **Donation Amount**: $50.00 to Room to Read
- **Payment Methods Accepted**: Credit/debit cards (Visa, Mastercard, Amex) or bank transfer
- **Cart Expires**: 2024-11-07T15:47:16Z (in 15 minutes)
- **Merchant Signature**: SIG_a3f7b2c8d9e1f4a2
This signed CartMandate proves my commitment to accept this donation amount. I'm now passing this to the secure payment processor to complete your transaction.
======================================================================
CARTMANDATE CREATED:
======================================================================
ID: cart_3b4c5d6e7f8a
Amount: 50.00
Merchant: Room to Read
Expires: 2024-11-07T15:47:16Z
Signature: SIG_a3f7b2c8d9e1f4a2
======================================================================
Test 2. Weryfikacja zgodności ze standardami W3C
Sprawdźmy, czy struktura CartMandate jest w pełni zgodna ze standardami AP2 i W3C PaymentRequest.
👉 Uruchom skrypt weryfikacji:
python scripts/validate_cartmandate.py
Oczekiwane dane wyjściowe:
======================================================================
AP2 & W3C PAYMENTREQUEST VALIDATION
======================================================================
✅ CartMandate is AP2 and W3C PaymentRequest compliant
Structure validation passed:
✓ AP2 'contents' wrapper present
✓ AP2 'merchant_authorization' signature present
✓ cart_expiry present
✓ payment_request nested inside contents
✓ method_data present and valid
✓ details.total.amount present with currency and value
✓ All required W3C PaymentRequest fields present
======================================================================
Co właśnie zostało utworzone
Udało Ci się wdrożyć CartMandate interfejsu AP2 za pomocą modeli Pydantic, aby zapewnić prawidłową strukturę, weryfikację daty ważności i podpisy sprzedawcy.
Opanowane kluczowe pojęcia
✅ CartMandate (AP2 Credential #2):
- Utworzono przy użyciu oficjalnych modeli Pydantic AP2
- Struktura AP2 z elementem opakowującym treści
- W3C PaymentRequest zagnieżdżony w
- Wygasanie koszyka (krótsze niż intencja)
- Podpis sprzedawcy potwierdzający zobowiązanie
- Weryfikacja modelu zapewnia zgodność ze specyfikacją
✅ Weryfikacja daty ważności:
- Reading IntentMandate from state
- Sprawdzanie struktury za pomocą
IntentMandate.model_validate() - Parsowanie sygnatur czasowych w formacie ISO 8601
- Porównywanie z bieżącym czasem
- Funkcja zabezpieczeń zapobiegająca nieaktualnemu przetwarzaniu
✅ Podpis sprzedawcy:
- Potwierdza autentyczność i zaangażowanie
- Wygenerowano na podstawie zweryfikowanego modelu Pydantic
- Używa
model_dump(mode='json')do reprezentacji kanonicznej - Symulacja z SHA-256 dla celów edukacyjnych
- W użyciu wersja produkcyjna PKI/JWT
- Podpisuje model treści, a nie słowniki.
✅ W3C PaymentRequest:
- Utworzono przy użyciu modelu Pydantic PaymentRequest interfejsu AP2
- Standard branżowy dotyczący danych o płatnościach
- Zagnieżdżone w strukturze AP2
- Zawiera method_data, details, options
- Umożliwia współdziałanie
✅ Łańcuchy danych logowania z modelami:
- Zakupy → IntentMandate (zweryfikowane)
- Sprzedawca odczytuje IntentMandate → CartMandate (oba modele są weryfikowane)
- Dostawca danych uwierzytelniających odczyta CartMandate → PaymentMandate
- Każdy krok weryfikuje poprzednie dane logowania za pomocą Pydantic.
✅ Tworzenie oparte na modelu:
- Sprawdzanie poprawności danych wejściowych za pomocą
model_validate() - Konstrukcja bezpieczna pod względem typów
- Automatyczna serializacja za pomocą
model_dump() - Wzorce gotowe do wykorzystania w środowisku produkcyjnym
Co dalej
W następnym module utworzymy dostawcę danych uwierzytelniających, który będzie bezpiecznie przetwarzać płatności.
Agent sprzedawcy utworzył wiążącą ofertę z datą ważności za pomocą modeli AP2. Teraz potrzebujemy agenta, który odczyta CartMandate, uzyska zgodę użytkownika i zrealizuje płatność.
Utwórzmy dostawcę danych logowania i dokończmy łańcuch danych logowania AP2.
6. Tworzenie dostawcy danych logowania – bezpieczne wykonywanie płatności

Od wiążącej oferty do realizacji płatności
W module 5 utworzyliśmy agenta sprzedawcy – specjalistę, który odczytuje IntentMandates, sprawdza, czy nie wygasły, i tworzy wiążące CartMandates z podpisami sprzedawcy. Teraz potrzebujemy agenta, który otrzyma ten obiekt CartMandate i zrealizuje płatność.
W tym miejscu pojawia się trzecia i ostatnia zasada AP2: bezpieczne wykonywanie płatności za pomocą PaymentMandate.
Zasada AP2: PaymentMandate & Payment Execution
Dlaczego potrzebujemy roli dostawcy danych logowania
W module 5 agent sprzedawcy utworzył obiekt CartMandate i zapisał go w stanie:
state["cart_mandate"] = {
"contents": {
"id": "cart_abc123",
"cart_expiry": "2025-11-07:15:47:16Z",
"payment_request": {
"details": {
"total": {
"amount": {"currency": "USD", "value": "50.00"}
}
}
}
},
"merchant_authorization": "SIG_a3f7b2c8"
}
Ale to tylko wiążąca oferta. Zanim będziemy mogli zrealizować płatność, musimy:
- Sprawdzenie, czy koszyk nie wygasł
- Zgoda użytkownika na kontynuowanie płatności
- dane logowania, które autoryzują wykonanie płatności;
- rzeczywiste przetwarzanie płatności (lub symulacja na potrzeby naszych warsztatów);
To zadanie dostawcy danych logowania.
Co to jest PaymentMandate?
PaymentMandate to termin używany przez AP2 na określenie ostatecznej autoryzacji, która umożliwia wykonanie płatności. Jest to trzecie i ostatnie weryfikowalne poświadczenie w łańcuchu AP2.
Pomyśl o tych 3 rodzajach danych logowania jak o procesie podpisywania umowy:
- IntentMandate: „Chcę kupić ten produkt” (list intencyjny)
- CartMandate: „Ja, sprzedawca, oferuję sprzedaż w tej cenie” (pisemna oferta)
- PaymentMandate: „Upoważniam Cię do obciążenia mojej formy płatności” (podpisana umowa)
Płatność można zrealizować dopiero po utworzeniu wszystkich 3 rodzajów danych logowania.
Struktura dokumentu PaymentMandate
Dokument PaymentMandate w AP2 ma określoną strukturę:
payment_mandate = {
"payment_mandate_contents": { # ← AP2 wrapper
"payment_mandate_id": "payment_xyz123",
"payment_details_id": "cart_abc123", # Links to CartMandate
"user_consent": True,
"consent_timestamp": "2025-11-07T15:48:00Z",
"amount": {
"currency": "USD",
"value": "50.00"
},
"merchant_name": "Room to Read"
},
"agent_present": True, # Human-in-the-loop flow
"timestamp": "2025-11-07T15:48:00Z"
}
Kluczowe komponenty:
1. payment_mandate_contents – otoczka autoryzacji zawierająca:
- payment_mandate_id: unikalny identyfikator
- payment_details_id: link do obiektu CartMandate
- user_consent: czy użytkownik wyraził zgodę
- amount: kwota płatności (wyodrębniona z dokumentu CartMandate);
2. agent_present – czy jest to proces z udziałem człowieka.
3. timestamp – czas utworzenia autoryzacji.
Nasza misja: stworzenie dostawcy danych logowania
Dostawca danych logowania:
- Odczytanie CartMandate ze stanu (tego, co napisał agent sprzedawcy)
- Sprawdzanie, czy koszyk nie wygasł, za pomocą modeli Pydantic AP2
- Wyodrębnianie szczegółów płatności z zagnieżdżonej struktury
- Tworzenie obiektu PaymentMandate za zgodą użytkownika za pomocą modeli AP2
- Symulowanie przetwarzania płatności (w środowisku produkcyjnym wywoływany byłby prawdziwy interfejs API płatności)
- Zapisywanie PaymentMandate i wyniku płatności w stanie
Zbudujmy go krok po kroku.
Krok 1. Dodaj narzędzie Cart Expiry Validation Helper
Najpierw utwórzmy funkcję pomocniczą, która sprawdza, czy CartMandate nie wygasł – tak jak w module 5 sprawdzaliśmy wygaśnięcie IntentMandate.
👉 Otwórz
charity_advisor/tools/payment_tools.py
Dodajmy weryfikację daty ważności:
👉 Znajdź:
# MODULE_6_STEP_1_ADD_CART_EXPIRY_VALIDATION_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _validate_cart_expiry(cart: CartMandate) -> tuple[bool, str]:
"""
Validates that the CartMandate hasn't expired.
This is a critical security check - expired carts should not be processed.
Args:
cart: The Pydantic CartMandate model to validate.
Returns:
(is_valid, error_message): Tuple indicating if cart is still valid.
"""
try:
expiry_str = cart.contents.cart_expiry
expiry_time = datetime.fromisoformat(expiry_str.replace('Z', '+00:00'))
now = datetime.now(timezone.utc)
if expiry_time < now:
return False, f"CartMandate expired at {expiry_str}"
time_remaining = expiry_time - now
logger.info(f"CartMandate valid. Expires in {time_remaining.total_seconds():.0f} seconds")
return True, ""
except (ValueError, TypeError, AttributeError) as e:
return False, f"Invalid cart_expiry format or structure: {e}"
Krok 2. Dodaj PaymentMandate Creation Helper
Teraz utwórzmy funkcję pomocniczą, która będzie tworzyć strukturę PaymentMandate za pomocą oficjalnych modeli Pydantic AP2.
👉 Znajdź:
# MODULE_6_STEP_2_ADD_PAYMENT_MANDATE_CREATION_HELPER
👉 Zastąp ten wiersz tym tekstem:
def _create_payment_mandate(cart: CartMandate, consent_granted: bool) -> dict:
"""
Creates a PaymentMandate using the official AP2 Pydantic models.
It links to the CartMandate and includes user consent status.
Args:
cart: The validated Pydantic CartMandate model being processed.
consent_granted: Whether the user has consented to the payment.
Returns:
A dictionary representation of the final, validated PaymentMandate.
"""
timestamp = datetime.now(timezone.utc)
# Safely extract details from the validated CartMandate model
cart_id = cart.contents.id
merchant_name = cart.contents.merchant_name
total_item = cart.contents.payment_request.details.total
# Create the nested PaymentResponse model for the mandate
payment_response_model = PaymentResponse(
request_id=cart_id,
method_name="CARD", # As per the simulated flow
details={"token": "simulated_payment_token_12345"}
)
# Create the PaymentMandateContents model
payment_mandate_contents_model = PaymentMandateContents(
payment_mandate_id=f"payment_{hashlib.sha256(f'{cart_id}{timestamp.isoformat()}'.encode()).hexdigest()[:12]}",
payment_details_id=cart_id,
payment_details_total=total_item,
payment_response=payment_response_model,
merchant_agent=merchant_name,
timestamp=timestamp.isoformat()
)
# Create the top-level PaymentMandate model
# In a real system, a user signature would be added to this model
payment_mandate_model = PaymentMandate(
payment_mandate_contents=payment_mandate_contents_model
)
# Convert the final Pydantic model to a dictionary for state storage
final_dict = payment_mandate_model.model_dump(mode='json')
# Add any custom/non-standard fields required by the codelab's logic to the dictionary
# The spec does not have these fields, but your original code did. We add them
# back to ensure compatibility with later steps.
final_dict['payment_mandate_contents']['user_consent'] = consent_granted
final_dict['payment_mandate_contents']['consent_timestamp'] = timestamp.isoformat() if consent_granted else None
final_dict['agent_present'] = True
return final_dict
Krok 3A. Utwórz podpis narzędzia i skonfiguruj je
Teraz zacznijmy stopniowo tworzyć główne narzędzie. Najpierw podpis funkcji i konfiguracja początkowa.
👉 Znajdź:
# MODULE_6_STEP_3A_CREATE_TOOL_SIGNATURE
👉 Zastąp ten wiersz tym tekstem:
async def create_payment_mandate(tool_context: Any) -> Dict[str, Any]:
"""
Creates a PaymentMandate and simulates payment processing using Pydantic models.
This tool now reads the CartMandate from state, parses it into a validated model,
and creates a spec-compliant PaymentMandate.
"""
logger.info("Tool called: Creating PaymentMandate and processing payment")
# MODULE_6_STEP_3B_VALIDATE_CARTMANDATE
Krok 3B. Sprawdź poprawność CartMandate
Teraz dodajmy logikę odczytywania i weryfikowania CartMandate za pomocą modeli AP2 Pydantic oraz sprawdzania daty ważności.
👉 Znajdź:
# MODULE_6_STEP_3B_VALIDATE_CARTMANDATE
👉 Zastąp ten wiersz tym tekstem:
# 1. Read CartMandate dictionary from state
cart_mandate_dict = tool_context.state.get("cart_mandate")
if not cart_mandate_dict:
logger.error("No CartMandate found in state")
return { "status": "error", "message": "No CartMandate found. Merchant Agent must create cart first." }
# 2. Parse dictionary into a validated Pydantic model
try:
cart_model = CartMandate.model_validate(cart_mandate_dict)
except Exception as e:
logger.error(f"Could not validate CartMandate structure: {e}")
return {"status": "error", "message": f"Invalid CartMandate structure: {e}"}
# 3. Validate that the cart hasn't expired using the Pydantic model
is_valid, error_message = _validate_cart_expiry(cart_model)
if not is_valid:
logger.error(f"CartMandate validation failed: {error_message}")
return {"status": "error", "message": error_message}
# MODULE_6_STEP_3C_EXTRACT_PAYMENT_DETAILS
Krok 3C. Wyodrębnianie danych do płatności z zagnieżdżonej struktury
Teraz przejdźmy do zweryfikowanego modelu CartMandate, aby wyodrębnić potrzebne szczegóły płatności.
👉 Znajdź:
# MODULE_6_STEP_3C_EXTRACT_PAYMENT_DETAILS
👉 Zastąp ten wiersz tym tekstem:
# 4. Safely extract data from the validated model
cart_id = cart_model.contents.id
merchant_name = cart_model.contents.merchant_name
amount_value = cart_model.contents.payment_request.details.total.amount.value
currency = cart_model.contents.payment_request.details.total.amount.currency
consent_granted = True # Assume consent for this codelab flow
# MODULE_6_STEP_3D_CREATE_PAYMENTMANDATE_AND_SIMULATE
Krok 3D. Utwórz PaymentMandate i zasymuluj płatność
Na koniec utwórzmy PaymentMandate za pomocą naszego narzędzia opartego na Pydantic, zasymulujmy przetwarzanie płatności i zapiszmy wszystko w stanie.
👉 Znajdź:
# MODULE_6_STEP_3D_CREATE_PAYMENTMANDATE_AND_SIMULATE
👉 Zastąp ten wiersz tym tekstem:
# 5. Create the spec-compliant PaymentMandate using the validated CartMandate model
payment_mandate_dict = _create_payment_mandate(cart_model, consent_granted)
# 6. Simulate payment processing
transaction_id = f"txn_{hashlib.sha256(f'{cart_id}{datetime.now(timezone.utc).isoformat()}'.encode()).hexdigest()[:16]}"
payment_result = {
"transaction_id": transaction_id,
"status": "completed",
"amount": amount_value,
"currency": currency,
"merchant": merchant_name,
"timestamp": datetime.now(timezone.utc).isoformat(),
"simulation": True
}
# 7. Write the compliant PaymentMandate dictionary and result to state
tool_context.state["payment_mandate"] = payment_mandate_dict
tool_context.state["payment_result"] = payment_result
logger.info(f"Payment processed successfully: {transaction_id}")
return {
"status": "success",
"message": f"Payment of {currency} {amount_value:.2f} to {merchant_name} processed successfully",
"transaction_id": transaction_id,
"payment_mandate_id": payment_mandate_dict["payment_mandate_contents"]["payment_mandate_id"]
}
Krok 4. Utwórz agenta dostawcy danych logowania – zaimportuj komponenty
Teraz utwórzmy agenta, który będzie korzystać z tego narzędzia.
👉 Otwórz
charity_advisor/credentials_provider/agent.py
Zobaczysz szablon ze znacznikami zastępczymi. Zacznijmy od zaimportowania tego, czego potrzebujemy.
👉 Znajdź:
# MODULE_6_STEP_4_IMPORT_COMPONENTS
👉 Zastąp ten wiersz tym tekstem:
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.payment_tools import create_payment_mandate
Krok 5. Napisz instrukcję dostawcy danych logowania
Teraz napiszmy instrukcję, która będzie kierować agentem.
👉 Znajdź:
# MODULE_6_STEP_5_WRITE_INSTRUCTION
instruction="""""",
👉 Zastąp te 2 wiersze tymi:
instruction="""You are a payment specialist responsible for securely processing payments with user consent.
Your workflow:
1. Read the CartMandate from shared state.
The CartMandate was created by the Merchant Agent and has this structure:
- contents: AP2 wrapper containing:
- id: Cart identifier
- cart_expiry: When the cart expires
- merchant_name: Who is receiving payment
- payment_request: W3C PaymentRequest with transaction details
- merchant_authorization: Merchant's signature
2. Extract payment details from the nested structure:
- Navigate: cart_mandate["contents"]["payment_request"]["details"]["total"]["amount"]
- This gives you the currency and value
3. **IMPORTANT - Two-Turn Conversational Confirmation Pattern:**
Before calling create_payment_mandate, you MUST:
- Present the payment details clearly to the user
- Ask explicitly: "I'm ready to process a payment of $X to [Charity Name]. Do you want to proceed with this donation?"
- WAIT for the user's explicit confirmation (e.g., "yes", "proceed", "confirm")
- ONLY call create_payment_mandate AFTER receiving explicit confirmation
- If user says "no" or "cancel", DO NOT call the tool
4. After user confirms, use the create_payment_mandate tool to:
- Validate the CartMandate hasn't expired (CRITICAL security check)
- Create a PaymentMandate (the third AP2 credential)
- Simulate payment processing
- Record the transaction result
5. After processing, inform the user:
- That payment was processed successfully (this is a simulation)
- The transaction ID
- The amount and merchant
- That this completes the three-agent AP2 credential chain
IMPORTANT BOUNDARIES:
- Your ONLY job is creating PaymentMandates and processing payments
- You do NOT discover charities (that's Shopping Agent's job)
- You do NOT create offers (that's Merchant Agent's job)
- You MUST validate that the CartMandate hasn't expired before processing
- You MUST get explicit user confirmation before calling create_payment_mandate
- In production, this consent mechanism would be even more robust
WHAT IS A PAYMENTMANDATE:
A PaymentMandate is the final credential that authorizes payment execution. It:
- Links to the CartMandate (proving the merchant's offer)
- Records user consent
- Contains payment details extracted from the CartMandate
- Enables the actual payment transaction
This is the third and final verifiable credential in our secure payment system.
THE COMPLETE AP2 CREDENTIAL CHAIN:
1. Shopping Agent creates IntentMandate (user's intent)
2. Merchant Agent reads IntentMandate, creates CartMandate (merchant's binding offer)
3. You read CartMandate, get user confirmation, create PaymentMandate (authorized payment execution)
Each credential:
- Has an expiry time (security feature)
- Links to the previous credential
- Is validated before the next step
- Creates an auditable chain of trust""",
Krok 6. Dodaj narzędzia do dostawcy danych logowania
👉 Znajdź:
# MODULE_6_STEP_6_ADD_TOOLS
tools=[],
👉 Zastąp te 2 wiersze tymi:
tools=[
FunctionTool(func=create_payment_mandate)
],
Krok 7. Weryfikacja dostawcy pełnych danych logowania
Sprawdźmy, czy wszystko jest prawidłowo podłączone.
👉 Twój pełny
charity_advisor/credentials_provider/agent.py
powinien teraz wyglądać tak:
"""
Credentials Provider Agent - Handles payment processing with user consent.
This agent acts as our "Payment Processor."
"""
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.payment_tools import create_payment_mandate
credentials_provider = Agent(
name="CredentialsProvider",
model="gemini-2.5-flash",
description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
tools=[
FunctionTool(func=create_payment_mandate)
],
instruction="""You are a payment specialist responsible for securely processing payments with user consent.
Your workflow:
1. Read the CartMandate from shared state.
The CartMandate was created by the Merchant Agent and has this structure:
- contents: AP2 wrapper containing:
- id: Cart identifier
- cart_expiry: When the cart expires
- merchant_name: Who is receiving payment
- payment_request: W3C PaymentRequest with transaction details
- merchant_authorization: Merchant's signature
2. Extract payment details from the nested structure:
- Navigate: cart_mandate["contents"]["payment_request"]["details"]["total"]["amount"]
- This gives you the currency and value
3. **IMPORTANT - Two-Turn Conversational Confirmation Pattern:**
Before calling create_payment_mandate, you MUST:
- Present the payment details clearly to the user
- Ask explicitly: "I'm ready to process a payment of $X to [Charity Name]. Do you want to proceed with this donation?"
- WAIT for the user's explicit confirmation (e.g., "yes", "proceed", "confirm")
- ONLY call create_payment_mandate AFTER receiving explicit confirmation
- If user says "no" or "cancel", DO NOT call the tool
4. After user confirms, use the create_payment_mandate tool to:
- Validate the CartMandate hasn't expired (CRITICAL security check)
- Create a PaymentMandate (the third AP2 credential)
- Simulate payment processing
- Record the transaction result
5. After processing, inform the user:
- That payment was processed successfully (this is a simulation)
- The transaction ID
- The amount and merchant
- That this completes the three-agent AP2 credential chain
IMPORTANT BOUNDARIES:
- Your ONLY job is creating PaymentMandates and processing payments
- You do NOT discover charities (that's Shopping Agent's job)
- You do NOT create offers (that's Merchant Agent's job)
- You MUST validate that the CartMandate hasn't expired before processing
- You MUST get explicit user confirmation before calling create_payment_mandate
- In production, this consent mechanism would be even more robust
WHAT IS A PAYMENTMANDATE:
A PaymentMandate is the final credential that authorizes payment execution. It:
- Links to the CartMandate (proving the merchant's offer)
- Records user consent
- Contains payment details extracted from the CartMandate
- Enables the actual payment transaction
This is the third and final verifiable credential in our secure payment system.
THE COMPLETE AP2 CREDENTIAL CHAIN:
1. Shopping Agent creates IntentMandate (user's intent)
2. Merchant Agent reads IntentMandate, creates CartMandate (merchant's binding offer)
3. You read CartMandate, get user confirmation, create PaymentMandate (authorized payment execution)
Each credential:
- Has an expiry time (security feature)
- Links to the previous credential
- Is validated before the next step
- Creates an auditable chain of trust"""
)
✅ Punkt kontrolny: masz teraz kompletny dostawcę danych logowania z prawidłowym odczytywaniem upoważnienia do koszyka i tworzeniem upoważnienia do płatności za pomocą modeli Pydantic AP2.
Krok 8. Przetestuj dostawcę danych logowania
Sprawdźmy teraz, czy nasz agent prawidłowo przetwarza płatności i uzupełnia łańcuch danych logowania.
👉 W terminalu Cloud Shell uruchom:
python scripts/test_credentials_provider.py
Oczekiwane dane wyjściowe:
======================================================================
CREDENTIALS PROVIDER TEST (MOCK - NO CONFIRMATION)
======================================================================
Simulated CartMandate from Merchant Agent:
- Cart ID: cart_test123
- Merchant: Room to Read
- Amount: $50.00
- Expires: 2025-11-07T15:47:16Z
- Signature: SIG_test_signature
Calling Credentials Provider to process payment...
======================================================================
INFO:charity_advisor.tools.payment_tools:Tool called: Creating PaymentMandate and processing payment
INFO:charity_advisor.tools.payment_tools:CartMandate valid. Expires in 900 seconds
INFO:charity_advisor.tools.payment_tools:Payment processed successfully: txn_a3f7b2c8d9e1f4a2
======================================================================
CREDENTIALS PROVIDER RESPONSE:
======================================================================
I've successfully processed your payment. Here are the details:
**Payment Completed** (Simulated)
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Amount: USD 50.00
- Merchant: Room to Read
- Status: Completed
This completes the three-agent AP2 credential chain:
1. ✓ Shopping Agent created IntentMandate (your intent)
2. ✓ Merchant Agent created CartMandate (binding offer)
3. ✓ Credentials Provider created PaymentMandate (payment authorization)
Your donation has been processed securely through our verifiable credential system.
======================================================================
PAYMENTMANDATE CREATED:
======================================================================
Payment Mandate ID: payment_3b4c5d6e7f8a
Linked to Cart: cart_test123
User Consent: True
Amount: USD 50.00
Merchant: Room to Read
Agent Present: True
======================================================================
======================================================================
PAYMENT RESULT:
======================================================================
Transaction ID: txn_a3f7b2c8d9e1f4a2
Status: completed
Amount: USD 50.00
Merchant: Room to Read
Simulation: True
======================================================================
Krok 9. Przetestuj pełną ścieżkę z 3 agentami
Teraz przetestujmy wszystkie 3 agenty działające razem.
👉 Uruchom pełny test potoku:
python scripts/test_full_pipeline.py
Oczekiwane dane wyjściowe:
======================================================================
THREE-AGENT PIPELINE TEST (AP2 CREDENTIAL CHAIN)
======================================================================
[1/3] SHOPPING AGENT - Finding charity and creating IntentMandate...
----------------------------------------------------------------------
✓ IntentMandate created
- Intent ID: intent_774799058_1730927536
- Description: Donate $75.00 to Room to Read
- Merchant: Room to Read
- Amount: $75.0
- Expires: 2025-11-07T16:32:16Z
[2/3] MERCHANT AGENT - Reading IntentMandate and creating CartMandate...
----------------------------------------------------------------------
✓ CartMandate created
- ID: cart_3b4c5d6e7f8a
- Expires: 2025-11-07T15:47:16Z
- Signature: SIG_a3f7b2c8d9e1f4a2
[3/3] CREDENTIALS PROVIDER - Creating PaymentMandate and processing...
----------------------------------------------------------------------
NOTE: In the web UI, this would show a confirmation dialog
For this test, consent is automatically granted
✓ Payment processed (SIMULATED)
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Amount: $75.0
- Status: completed
======================================================================
COMPLETE AP2 CREDENTIAL CHAIN
======================================================================
✓ Credential 1: IntentMandate (User's Intent)
- Intent ID: intent_774799058_1730927536
- Description: Donate $75.00 to Room to Read
- Expiry: 2025-11-07T16:32:16Z
✓ Credential 2: CartMandate (Merchant's Offer)
- Cart ID: cart_3b4c5d6e7f8a
- Cart Expiry: 2025-11-07T15:47:16Z
- Merchant Signature: SIG_a3f7b2c8d9e1f4a2
✓ Credential 3: PaymentMandate (Payment Execution)
- Payment Mandate ID: payment_3b4c5d6e7f8a
- Linked to Cart: cart_3b4c5d6e7f8a
- Agent Present: True
✓ Transaction Result:
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Simulation: True
======================================================================
✅ COMPLETE PIPELINE TEST PASSED
======================================================================
To kompletny łańcuch poświadczeń AP2 w działaniu.
Każdy agent:
- Odczytuje dane logowania ze stanu
- Sprawdza go za pomocą modeli Pydantic (struktura + sprawdzenie daty ważności).
- Tworzy kolejne dane logowania za pomocą modeli AP2
- Zapisuje stan dla następnego agenta
Co właśnie zostało utworzone
Udało Ci się utworzyć łańcuch poświadczeń AP2 z 3 agentami z prawidłową weryfikacją struktury za pomocą modeli Pydantic i symulacji płatności.
Opanowane kluczowe pojęcia
✅ PaymentMandate (AP2 Credential #3):
- Utworzono przy użyciu oficjalnych modeli Pydantic AP2
- Ostateczne dane logowania autoryzujące wykonanie płatności
- Linki do CartMandate za pomocą identyfikatora payment_details_id
- Rejestruje zgodę użytkownika i sygnaturę czasową
- Zawiera kwotę płatności wyodrębnioną z obiektu CartMandate.
- Zawiera flagę agent_present dla procesu z udziałem człowieka
- Weryfikacja modelu zapewnia zgodność ze specyfikacją
✅ Odczytywanie z dokumentu CartMandate:
- Sprawdzanie struktury za pomocą narzędzia
CartMandate.model_validate() - Bezpieczny typowo dostęp do atrybutów:
cart_model.contents.payment_request.details.total.amount - Różnice między otoką AP2 a separacją standardu W3C
- Bezpieczne wyodrębnianie z modelu informacji merchant_name, amount i currency
- Pydantic automatycznie wykrywa błędy struktury
✅ Weryfikacja wygaśnięcia koszyka:
- Akceptuje zweryfikowany
CartMandatemodel Pydantic - Odczytuje z
cart.contents.cart_expiry(dostęp do atrybutu) - Funkcja zabezpieczeń zapobiegająca przetwarzaniu nieaktualnych koszyków
- krótszy czas trwania (15 minut) niż czas trwania intencji (1 godzina);
✅ Symulacja płatności:
- Symulacja edukacyjna rzeczywistej firmy obsługującej płatności
- Generuje identyfikator transakcji
- Rejestruje payment_result w stanie
- Wyraźnie oznaczony jako symulacja (flaga symulacji: True)
✅ Ukończ łańcuch AP2 z modelami:
- 3 agenty, 3 dane logowania, 3 weryfikacje Pydantic
- Każdy agent weryfikuje strukturę poprzednich danych logowania za pomocą modeli.
- Każde dane logowania są połączone z poprzednimi w celu utworzenia ścieżki audytu.
- Przekazywanie zadań na podstawie stanu zachowuje podział ról
- Zabezpieczenia wpisywania w całym łańcuchu
✅ Tworzenie oparte na modelu:
- Sprawdzanie poprawności danych wejściowych za pomocą
model_validate() - Konstrukcja bezpieczna pod względem typów z modelami zagnieżdżonymi
- Automatyczna serializacja za pomocą
model_dump(mode='json') - Wzorce gotowe do użytku produkcyjnego od samego początku
Co dalej
W następnym module utworzymy agenta aranżera, który koordynuje pracę wszystkich 3 agentów specjalistów.
Utworzono 3 zaawansowane specjalistyczne agenty przy użyciu modeli AP2 Pydantic. Teraz zbudujmy element, który będzie koordynować te działania, aby zapewnić bezproblemowe przekazywanie darowizn.
Zbudujmy aranżera i zobaczmy, jak działa cały system.
7. Administracja – wszystko w jednym miejscu
Od specjalistów do bezproblemowej obsługi
W poprzednich modułach utworzyliśmy 3 wyspecjalizowane agenty:
- Agent zakupowy: wyszukuje organizacje charytatywne i tworzy IntentMandate.
- Agent sprzedawcy: tworzy CartMandate na podstawie IntentMandate.
- Dostawca danych uwierzytelniających: tworzy PaymentMandate, przetwarza płatność.
Te agenty dzielą się na 2 fazy:
- Etap 1. (zakupy): wieloetapowa rozmowa w celu znalezienia i wybrania organizacji charytatywnej.
- Etap 2. (Przetwarzanie): atomowe wykonanie tworzenia oferty i płatności
Obecnie musisz ręcznie koordynować te fazy.
W takich sytuacjach przydają się wzorce orkiestracji ADK.
Zasada AP2: orkiestracja wymusza granice zaufania
Dlaczego orkiestracja ma znaczenie dla bezpieczeństwa
Orkiestracja to nie tylko wygoda, ale też wymuszanie granic zaufania za pomocą architektury.
Bez orkiestracji:
# User could accidentally skip steps or reorder them
shopping_agent.run("Find charity")
# Oops, forgot to create CartMandate!
credentials_provider.run("Process payment") # No offer to validate!
Z odpowiednią aranżacją przekazu:
# Pipeline enforces correct order
donation_processing_pipeline = SequentialAgent(
sub_agents=[
merchant_agent, # Must run first
credentials_provider # Must run second
]
)
# Steps ALWAYS run in order, no skipping allowed
Potok sekwencyjny gwarantuje:
- ✅ IntentMandate utworzono przed CartMandate
- ✅ CartMandate utworzony przed przetworzeniem płatności
- ✅ Każdy agent działa w izolowanym kontekście.
- ✅ Stan jest przekazywany dalej w łańcuchu danych logowania
Nasza misja: stworzenie kompletnego systemu
Utworzymy 2 warstwy:
Warstwa 1. Potok przetwarzania (SequentialAgent)
- Przewody razem Sprzedawca → Dane logowania
- Uruchamia się automatycznie po wybraniu organizacji charytatywnej
- Atomowe wykonanie oferty i płatności
Warstwa 2. Główny aranżer (agent widoczny dla użytkownika)
- przyjazne usposobienie,
- Przekazuje wybór organizacji charytatywnej do usługi shopping_agent
- Przekazuje do potoku przetwarzania po utworzeniu IntentMandate
- Obsługuje rozmowy i przejścia między fazami
Takie dwuwarstwowe podejście jest zgodne z naturalnym przepływem informacji:
- Etap zakupów: wieloetapowa rozmowa (użytkownik przegląda produkty, zadaje pytania i podejmuje decyzję).
- Etap przetwarzania: wykonanie atomowe (oferta → płatność)
Stwórzmy oba.
Krok 1. Zaimportuj komponenty orkiestracji
Najpierw skonfigurujmy plik orkiestracji z niezbędnymi importami.
👉 Otwórz
charity_advisor/agent.py
Zacznijmy od importów:
👉 Znajdź:
# MODULE_7_STEP_1_IMPORT_COMPONENTS
👉 Zastąp ten wiersz tym tekstem:
from google.adk.agents import Agent, SequentialAgent
from charity_advisor.shopping_agent.agent import shopping_agent
from charity_advisor.merchant_agent.agent import merchant_agent
from charity_advisor.credentials_provider.agent import credentials_provider
Krok 2. Utwórz potok przetwarzania
Teraz utwórzmy potok, który będzie atomowo uruchamiać tworzenie oferty i przetwarzanie płatności.
👉 Znajdź:
# MODULE_7_STEP_2_CREATE_SEQUENTIAL_PIPELINE
👉 Zastąp te 2 wiersze tymi:
# Create the donation processing pipeline
# This runs Merchant → Credentials in sequence AFTER charity is selected
donation_processing_pipeline = SequentialAgent(
name="DonationProcessingPipeline",
description="Creates signed offer and processes payment after charity is selected",
sub_agents=[
merchant_agent,
credentials_provider
]
)
Krok 3A. Utwórz konfigurację agenta głównego
Teraz utwórzmy agenta, z którego będą korzystać użytkownicy i który będzie koordynować obie fazy. Omówimy to w 3 częściach: konfiguracja (3A), instrukcje (3B) i podagenci (3C).
👉 Znajdź:
# MODULE_7_STEP_3A_CREATE_ROOT_AGENT_SETUP
👉 Zastąp ten wiersz tym tekstem:
# Create the root orchestrator agent
# This is what users interact with directly
root_agent = Agent(
name="CharityAdvisor",
model="gemini-2.5-pro",
description="A friendly charity giving assistant that helps users donate to verified organizations.",
# MODULE_7_STEP_3B_WRITE_ROOT_AGENT_INSTRUCTION
Krok 3B. Napisz instrukcję dla głównego agenta
Teraz dodajmy instrukcję, która będzie kierować zachowaniem doradcy ds. organizacji charytatywnych w obu fazach.
👉 Znajdź:
# MODULE_7_STEP_3B_WRITE_ROOT_AGENT_INSTRUCTION
👉 Zastąp ten wiersz tym tekstem:
instruction="""You are a helpful and friendly charity giving advisor.
Your workflow has TWO distinct phases:
PHASE 1: CHARITY SELECTION (delegate to shopping_agent)
When a user expresses interest in donating:
1. Delegate to shopping_agent immediately
2. The shopping_agent will:
- Search for charities matching their cause
- Present verified options with ratings
- Engage in conversation (user may ask questions, change their mind)
- Wait for user to select a specific charity and amount
- Create an IntentMandate when user decides
3. Wait for shopping_agent to complete
You'll know Phase 1 is complete when shopping_agent's response includes:
- "IntentMandate created" or "Intent ID: intent_xxx"
- Charity name and donation amount
PHASE 2: PAYMENT PROCESSING (delegate to DonationProcessingPipeline)
After shopping_agent completes:
1. Acknowledge the user's selection naturally:
"Perfect! Let me process your $X donation to [Charity]..."
2. Delegate to DonationProcessingPipeline
3. The pipeline will automatically:
- Create signed cart offer (MerchantAgent)
- Get consent and process payment (CredentialsProvider)
4. After pipeline completes, summarize the transaction
CRITICAL RULES:
- Phase 1 may take multiple conversation turns (this is normal)
- Only proceed to Phase 2 after IntentMandate exists
- Don't rush the user during charity selection
- Don't ask user to "proceed" between phases - transition automatically
EXAMPLE FLOW:
User: "I want to donate to education"
You: [delegate to shopping_agent]
Shopping: "Here are 3 education charities..." [waits]
User: "Tell me more about the first one"
Shopping: "Room to Read focuses on..." [waits]
User: "Great, I'll donate $50 to Room to Read"
Shopping: "IntentMandate created (ID: intent_123)..."
You: "Perfect! Processing your $50 donation to Room to Read..." [delegate to DonationProcessingPipeline]
Pipeline: [creates offer, gets consent, processes payment]
You: "Done! Your donation was processed successfully. Transaction ID: txn_456"
Your personality:
- Warm and encouraging
- Patient during charity selection
- Clear about educational nature
- Smooth transitions between phases""",
# MODULE_7_STEP_3C_ADD_ROOT_AGENT_SUBAGENTS
Krok 3C. Dodaj podagenta
Na koniec przyznajmy doradcy ds. organizacji charytatywnych dostęp do agenta zakupowego i potoku przetwarzania, a potem zamknijmy definicję agenta.
👉 Znajdź:
# MODULE_7_STEP_3C_ADD_ROOT_AGENT_SUBAGENTS
👉 Zastąp ten wiersz tym tekstem:
sub_agents=[
shopping_agent,
donation_processing_pipeline
]
)
Krok 4. Sprawdź kompletny system
Sprawdźmy, czy orkiestracja jest prawidłowo skonfigurowana.
👉 Twój pełny
charity_advisor/agent.py
powinien teraz wyglądać tak:
"""
Main orchestration: The donation processing pipeline and root orchestrator agent.
"""
from google.adk.agents import Agent, SequentialAgent
from charity_advisor.shopping_agent.agent import shopping_agent
from charity_advisor.merchant_agent.agent import merchant_agent
from charity_advisor.credentials_provider.agent import credentials_provider
# Create the donation processing pipeline
# This runs Merchant → Credentials in sequence AFTER charity is selected
donation_processing_pipeline = SequentialAgent(
name="DonationProcessingPipeline",
description="Creates signed offer and processes payment after charity is selected",
sub_agents=[
merchant_agent,
credentials_provider
]
)
# Create the root orchestrator agent
# This is what users interact with directly
root_agent = Agent(
name="CharityAdvisor",
model="gemini-2.5-flash",
description="A friendly charity giving assistant that helps users donate to verified organizations.",
instruction="""You are a helpful and friendly charity giving advisor.
Your workflow has TWO distinct phases:
PHASE 1: CHARITY SELECTION (delegate to shopping_agent)
When a user expresses interest in donating:
1. Delegate to shopping_agent immediately
2. The shopping_agent will:
- Search for charities matching their cause
- Present verified options with ratings
- Engage in conversation (user may ask questions, change their mind)
- Wait for user to select a specific charity and amount
- Create an IntentMandate when user decides
3. Wait for shopping_agent to complete
You'll know Phase 1 is complete when shopping_agent's response includes:
- "IntentMandate created" or "Intent ID: intent_xxx"
- Charity name and donation amount
PHASE 2: PAYMENT PROCESSING (delegate to DonationProcessingPipeline)
After shopping_agent completes:
1. Acknowledge the user's selection naturally:
"Perfect! Let me process your $X donation to [Charity]..."
2. Delegate to DonationProcessingPipeline
3. The pipeline will automatically:
- Create signed cart offer (MerchantAgent)
- Get consent and process payment (CredentialsProvider)
4. After pipeline completes, summarize the transaction
CRITICAL RULES:
- Phase 1 may take multiple conversation turns (this is normal)
- Only proceed to Phase 2 after IntentMandate exists
- Don't rush the user during charity selection
- Don't ask user to "proceed" between phases - transition automatically
EXAMPLE FLOW:
User: "I want to donate to education"
You: [delegate to shopping_agent]
Shopping: "Here are 3 education charities..." [waits]
User: "Tell me more about the first one"
Shopping: "Room to Read focuses on..." [waits]
User: "Great, I'll donate $50 to Room to Read"
Shopping: "IntentMandate created (ID: intent_123)..."
You: "Perfect! Processing your $50 donation to Room to Read..." [delegate to DonationProcessingPipeline]
Pipeline: [creates offer, gets consent, processes payment]
You: "Done! Your donation was processed successfully. Transaction ID: txn_456"
Your personality:
- Warm and encouraging
- Patient during charity selection
- Clear about educational nature
- Smooth transitions between phases""",
sub_agents=[
shopping_agent,
donation_processing_pipeline
]
)
Krok 5. Zwiększ bezpieczeństwo za pomocą wywołań zwrotnych weryfikacji (opcjonalnie – przejdź do kroku 7)

SequentialAgent gwarantuje kolejność wykonywania, ale co się stanie, jeśli:
- Agent zakupów nie działa (nie utworzono elementu IntentMandate)
- Godzina mija między zakupami a Merchant (zamiar wygasa)
- Stan ulega uszkodzeniu lub wyczyszczeniu
- Użytkownik próbuje zadzwonić bezpośrednio do sprzedawcy, pomijając Zakupy Google
Wywołania zwrotnedodają wymuszanie architektury – sprawdzają wymagania wstępne, zanim agent rozpocznie wywołanie LLM. Jest to obrona warstwowa: narzędzia weryfikują podczas wykonywania, a wywołania zwrotne weryfikują przed wykonaniem.
Dodajmy wywołania zwrotne weryfikacji do agentów Merchant i Credentials Provider.
Krok 5A. Dodaj weryfikację sprzedawcy – importowanie typów wywołań zwrotnych
Najpierw dodajmy importy potrzebne do wywołań zwrotnych.
👉 Otwórz
charity_advisor/merchant_agent/agent.py
U góry pliku, po istniejących instrukcjach importu, dodaj:
from typing import Optional
from datetime import datetime, timezone
from google.adk.agents.callback_context import CallbackContext
from google.genai.types import Content, Part
import logging
logger = logging.getLogger(__name__)
Krok 5B. Utwórz funkcję weryfikacji intencji
Teraz utwórzmy funkcję wywołania zwrotnego, która będzie weryfikować IntentMandate przed uruchomieniem Merchant Agent.
👉 W
charity_advisor/merchant_agent/agent.py
, dodaj tę funkcję PRZED
merchant_agent = Agent(...)
definicja:
def validate_intent_before_merchant(
callback_context: CallbackContext,
) -> Optional[Content]:
"""
Validates IntentMandate exists and hasn't expired before Merchant runs.
This callback enforces that the Shopping Agent completed successfully
before the Merchant Agent attempts to create a CartMandate.
Returns:
None: Allow Merchant Agent to proceed normally
Content: Skip Merchant Agent and return error to user
"""
state = callback_context.state
# Check credential exists
if "intent_mandate" not in state:
logger.error("❌ IntentMandate missing - Shopping Agent may have failed")
return Content(parts=[Part(text=(
"Error: Cannot create cart. User intent was not properly recorded. "
"Please restart the donation process."
))])
intent_mandate = state["intent_mandate"]
# Validate expiry (critical security check)
try:
expiry_time = datetime.fromisoformat(
intent_mandate["intent_expiry"].replace('Z', '+00:00')
)
now = datetime.now(timezone.utc)
if expiry_time < now:
logger.error(f"❌ IntentMandate expired at {intent_mandate['intent_expiry']}")
return Content(parts=[Part(text=(
"Error: Your donation intent has expired. "
"Please select a charity again to restart."
))])
time_remaining = expiry_time - now
logger.info(f"✓ IntentMandate validated. Expires in {time_remaining.total_seconds():.0f}s")
except (KeyError, ValueError) as e:
logger.error(f"❌ Invalid IntentMandate structure: {e}")
return Content(parts=[Part(text=(
"Error: Invalid intent data. Please restart the donation."
))])
# All checks passed - allow Merchant Agent to proceed
logger.info(f"✓ Prerequisites met for Merchant Agent: {intent_mandate['intent_id']}")
return None
Krok 5C. Dołączanie funkcji oddzwaniania do agenta Merchant
Teraz połączmy oddzwanianie z pracownikiem obsługi klienta.
👉 W
charity_advisor/merchant_agent/agent.py
, zmień
merchant_agent = Agent(...)
definicja:
Znajdź w definicji agenta ten wiersz:
merchant_agent = Agent(
name="MerchantAgent",
model="gemini-2.5-flash",
description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
Dodaj ten wiersz bezpośrednio po
description
linia:
before_agent_callback=validate_intent_before_merchant,
Definicja agenta powinna teraz wyglądać tak:
merchant_agent = Agent(
name="MerchantAgent",
model="gemini-2.5-flash",
description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
before_agent_callback=validate_intent_before_merchant,
tools=[
FunctionTool(func=create_cart_mandate)
],
instruction="""..."""
)
Krok 6. Dodaj weryfikację dostawcy danych logowania (opcjonalnie – przejdź do kroku 7)
Ten sam wzorzec – dodajmy weryfikację na etapie płatności.
Krok 6A. Importowanie typów połączeń zwrotnych
👉 Otwórz
charity_advisor/credentials_provider/agent.py
U góry pliku, po istniejących instrukcjach importu, dodaj:
from typing import Optional
from datetime import datetime, timezone
from google.adk.agents.callback_context import CallbackContext
from google.genai.types import Content, Part
import logging
logger = logging.getLogger(__name__)
Krok 6B. Utwórz funkcję weryfikacji koszyka
👉 W
charity_advisor/credentials_provider/agent.py
, dodaj tę funkcję PRZED
credentials_provider = Agent(...)
definicja:
def validate_cart_before_payment(
callback_context: CallbackContext,
) -> Optional[Content]:
"""
Validates CartMandate exists and hasn't expired before payment processing.
This callback enforces that the Merchant Agent completed successfully
before the Credentials Provider attempts to process payment.
Returns:
None: Allow Credentials Provider to proceed
Content: Skip payment processing and return error
"""
state = callback_context.state
# Check credential exists
if "cart_mandate" not in state:
logger.error("❌ CartMandate missing - Merchant Agent may have failed")
return Content(parts=[Part(text=(
"Error: Cannot process payment. Cart was not properly created. "
"Please restart the donation process."
))])
cart_mandate = state["cart_mandate"]
# Validate AP2 structure
if "contents" not in cart_mandate:
logger.error("❌ CartMandate missing AP2 contents wrapper")
return Content(parts=[Part(text=(
"Error: Invalid cart structure. Please restart."
))])
# Validate expiry
try:
contents = cart_mandate["contents"]
expiry_time = datetime.fromisoformat(
contents["cart_expiry"].replace('Z', '+00:00')
)
now = datetime.now(timezone.utc)
if expiry_time < now:
logger.error(f"❌ CartMandate expired at {contents['cart_expiry']}")
return Content(parts=[Part(text=(
"Error: Your cart has expired (15 minute limit). "
"Please restart the donation to get a fresh offer."
))])
time_remaining = expiry_time - now
logger.info(f"✓ CartMandate validated. Expires in {time_remaining.total_seconds():.0f}s")
except (KeyError, ValueError) as e:
logger.error(f"❌ Invalid CartMandate structure: {e}")
return Content(parts=[Part(text=(
"Error: Invalid cart data. Please restart the donation."
))])
# All checks passed - allow payment processing
logger.info(f"✓ Prerequisites met for Credentials Provider: {contents['id']}")
return None
Krok 6C. Dołączanie wywołania zwrotnego do dostawcy danych logowania
👉 W
charity_advisor/credentials_provider/agent.py
, zmień
credentials_provider = Agent(...)
definicja:
Znajdź w definicji agenta ten wiersz:
credentials_provider = Agent(
name="CredentialsProvider",
model="gemini-2.5-flash",
description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
Dodaj ten wiersz bezpośrednio po
description
linia:
before_agent_callback=validate_cart_before_payment,
Definicja agenta powinna teraz wyglądać tak:
credentials_provider = Agent(
name="CredentialsProvider",
model="gemini-2.5-flash",
description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
before_agent_callback=validate_cart_before_payment,
tools=[
FunctionTool(func=create_payment_mandate)
],
instruction="""..."""
)
Krok 7. Testowanie za pomocą interfejsu internetowego ADK
Teraz przetestujmy cały wzmocniony system z aktywnymi wywołaniami zwrotnymi weryfikacji.
👉 W terminalu Cloud Shell uruchom:
adk web
Powinny się wyświetlić dane wyjściowe podobne do tych:
+-----------------------------------------------------------------------------+
| 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 internetowego ADK w przeglądarce:
Na pasku narzędzi Cloud Shell (zwykle w prawym górnym rogu) kliknij ikonę Podgląd w przeglądarce (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ę przeglądarki z interfejsem internetowym ADK.

👉 Wybierz agenta z menu:
W interfejsie ADK u góry zobaczysz menu. Na liście wybierz charity_advisor.

Zobaczysz interfejs internetowy ADK z tymi elementami:
- Panel czatu: po lewej stronie, do prowadzenia rozmowy.
- Panel śledzenia: po prawej stronie, do obserwacji (użyjemy go w module 9)
Test 1. Przejdź proces przekazywania darowizny (przypadek normalny)
👉 W interfejsie czatu wpisz:
I want to donate to an education charity
Zobacz cały proces:


Co się dzieje (widoczne w panelu śledzenia po prawej stronie):
1. Doradca przekazuje uprawnienia do ShoppingAgent:
- ShoppingAgent wyszukuje organizacje charytatywne zajmujące się edukacją
- Wyświetla 3 zweryfikowane opcje ze szczegółami.
2. Interakcja z ShoppingAgent (może wymagać kilku tur):
User: "Tell me more about Room to Read"
Shopping: [explains mission and impact]
User: "I'll donate $50 to Room to Read"
3. ShoppingAgent tworzy IntentMandate:
- Tworzy i podpisuje intencję
- Zwraca potwierdzenie z identyfikatorem intencji.
4. Przejście doradcy do etapu przetwarzania:
Super! Przetwarzanie darowizny w wysokości 50 USD na rzecz organizacji Room to Read…
5. Aktywacja DonationProcessingPipeline:
- Wywołanie zwrotne sprzedawcy weryfikuje IntentMandate (✓ passed) ← NOWOŚĆ
- Agent sprzedawcy tworzy CartMandate z podpisem
- Wywołanie zwrotne danych uwierzytelniających weryfikuje CartMandate (✓ passed) ← NOWOŚĆ
- Dostawca danych uwierzytelniających przygotowuje płatność
6. Procesy płatności:
- Dostawca danych uwierzytelniających tworzy PaymentMandate
- Symuluje przetwarzanie płatności
- Identyfikator transakcji zwrotu
7. Doradca podsumowuje:
Super! Twoja darowizna została zrealizowana. 🎉
Szczegóły:
- Kwota: 50,00 USD
- Organizacja charytatywna: Room to Read (EIN: 77-0479905)
- Identyfikator transakcji: txn_a3f7b2c8d9e1f4a2
Test 2. Sprawdź, czy wywołania zwrotne wykrywają błędy (opcjonalny test zaawansowany)
Chcesz zobaczyć, jak funkcje zwrotne działają w praktyce i wykrywają błędy? Musisz ręcznie uszkodzić stan (zaawansowane debugowanie), ale w środowisku produkcyjnym wywołania zwrotne wykryją:
- Narzędzie Shopping Agent nie działa → Blokady wywołania zwrotnego sprzedawcy: „Error: Cannot create cart...”
- Po 2 godzinach → wywołanie zwrotne sprzedawcy blokuje: „Error: Intent expired...”
- Koszyk wygasa → Wywołania zwrotne danych logowania: „Błąd: koszyk wygasł (limit 15 min)...”
Te przypadki brzegowe są teraz wymuszane architektonicznie przez wywołania zwrotne weryfikacji.
Co właśnie zostało utworzone
Udało Ci się zintegrować 3 wyspecjalizowane modele w jeden spójny i wiarygodny system z walidacją architektury.
Co dalej
Ukończono już techniczną część tworzenia wiarygodnych agentów:
Masz już kompletny, godny zaufania system, który lokalnie egzekwuje łańcuch danych logowania. Teraz udostępnimy go prawdziwym użytkownikom w ramach wdrożenia produkcyjnego i włączymy ścieżkę odpowiedzialności, która umożliwia realizację modułu 9.
Wdróżmy wzmocnionego agenta w Google Cloud.
8. Wdrożenie

Twój godny zaufania system darowizn jest teraz kompletny i obejmuje 3 wyspecjalizowane agenty działające lokalnie:
Działa ona jednak tylko na komputerze deweloperskim. Aby ten system był przydatny dla prawdziwych użytkowników i aby rejestrować ścieżki odpowiedzialności, które potwierdzają wiarygodność, musisz wdrożyć go w środowisku produkcyjnym.
W tym module dowiesz się, jak wdrożyć agenta w Google Cloud z włączoną od samego początku funkcją dostrzegalności. Flaga --trace_to_cloud, której użyjesz podczas wdrażania, umożliwia ścieżkę odpowiedzialności w module 9.
Omówienie opcji wdrażania
ADK obsługuje wiele miejsc docelowych wdrożenia. Każda z nich ma inne cechy pod względem złożoności, zarządzania sesjami, skalowania i kosztów:
Czynnik | Lokalne ( | Silnik agenta | Cloud Run |
Złożoność | Minimalny | Niski | Średni |
Trwałość sesji | Tylko w pamięci (utracone po ponownym uruchomieniu) | Zarządzane przez Vertex AI (automatyczne) | Cloud SQL (PostgreSQL) lub w pamięci |
Infrastruktura | Brak (tylko na urządzeniu deweloperskim) | Usługa w pełni zarządzana | Kontener + opcjonalna baza danych |
Uruchomienie „na zimno” | Nie dotyczy | 100–500 ms | 100–2000 ms |
Skalowanie | Pojedyncza instancja | Automatycznie | Automatyczne (do zera) |
Model kosztów | Bezpłatne (obliczenia lokalne) | Na podstawie zasobów obliczeniowych | Na podstawie żądań + poziom bezpłatny |
Obsługa interfejsu | Tak (wbudowany) | Nie (tylko interfejs API) | Tak (za pomocą flagi |
Konfiguracja dostrzegalności | Lokalna przeglądarka śladów | Automatyczne z | Wymaga flagi |
Najlepsze zastosowania | Programowanie i testowanie | Agenci produkcyjni | Agenci produkcyjni |
Rekomendacja: w przypadku tego godnego zaufania systemu darowizn zalecamy używanie Agent Engine jako głównego wdrożenia produkcyjnego, ponieważ zapewnia ono:
- W pełni zarządzana infrastruktura (bez konieczności zarządzania kontenerami)
- Wbudowana trwałość sesji za pomocą
VertexAiSessionService - Automatyczne skalowanie bez uruchamiania „na zimno”
- Uproszczone wdrażanie (nie wymaga wiedzy o Dockerze)
- Gotowa integracja z Cloud Trace
Dodatkowa opcja: Google Kubernetes Engine (GKE)
Dla zaawansowanych użytkowników, którzy potrzebują kontroli na poziomie Kubernetes, niestandardowej sieci lub orkiestracji wielu usług, dostępna jest implementacja GKE. Ta opcja zapewnia maksymalną elastyczność, ale wymaga większej wiedzy operacyjnej (zarządzanie klastrami, manifesty, konta usługi).
Wdrożenie GKE nie jest objęte tymi ćwiczeniami, ale jest w pełni udokumentowane w przewodniku po wdrażaniu ADK w GKE.
Wymagania wstępne
1. Konfigurowanie projektu Google Cloud
Musisz mieć projekt w Google Cloud z włączonymi płatnościami. Jeśli nie masz konta:
- Tworzenie projektu: Google Cloud Console
- Włącz płatności: Włącz płatności
- Zapisz identyfikator projektu (nie nazwę ani numer projektu).
2. Ponowne uwierzytelnianie (opcjonalnie)
Uwierzytelnij się w Google Cloud:
gcloud auth application-default login
gcloud config set project YOUR_PROJECT_ID
Zastąp YOUR_PROJECT_ID identyfikatorem Twojego projektu Google Cloud.
Potwierdź uwierzytelnianie:
gcloud config get-value project
# Should output: YOUR_PROJECT_ID
3. Zmienne środowiskowe
Aby automatycznie wypełnić plik .env, użyj tych poleceń:
# Get your current Project ID
PROJECT_ID=$(gcloud config get-value project)
STAGING_BUCKET_VALUE="gs://${PROJECT_ID}-staging"
ENV_FILE=".env"
# Check if STAGING_BUCKET is already set in the .env file
if grep -q "^STAGING_BUCKET=" "${ENV_FILE}"; then
# If it exists, replace the line
# The sed command finds the line starting with STAGING_BUCKET= and replaces the entire line.
# Using | as a delimiter to avoid issues with slashes in the bucket name.
sed -i "s|^STAGING_BUCKET=.*|STAGING_BUCKET=${STAGING_BUCKET_VALUE}|" "${ENV_FILE}"
echo "Updated STAGING_BUCKET in ${ENV_FILE}"
else
# If it doesn't exist, add it to the end of the file
echo "STAGING_BUCKET=${STAGING_BUCKET_VALUE}" >> "${ENV_FILE}"
echo "Added STAGING_BUCKET to ${ENV_FILE}"
fi
# Verify it was added or updated correctly
echo "Current STAGING_BUCKET setting:"
grep "^STAGING_BUCKET=" "${ENV_FILE}"
Zobaczysz, że:
STAGING_BUCKET=gs://your-actual-project-id-staging
Ważne informacje:
- Zastąp
YOUR_PROJECT_IDidentyfikatorem projektu (lub użyj powyższych poleceń). - W przypadku
GOOGLE_CLOUD_LOCATIONużyj obsługiwanego regionu. - Podczas uruchamiania skryptu wdrażania tymczasowy zasobnik zostanie utworzony automatycznie, jeśli nie istnieje.
4. Włącz wymagane interfejsy API
Proces wdrażania wymaga włączenia kilku interfejsów Google Cloud API. Aby je włączyć, uruchom to polecenie:
gcloud services enable \
aiplatform.googleapis.com \
storage.googleapis.com \
cloudbuild.googleapis.com \
cloudtrace.googleapis.com \
compute.googleapis.com
To polecenie umożliwia:
- AI Platform API – w przypadku modeli Agent Engine i Vertex AI
- Cloud Storage API – w przypadku zasobnika tymczasowego
- Cloud Build API – do tworzenia kontenerów (Cloud Run).
- Cloud Trace API – do śledzenia widoczności i odpowiedzialności.
- Compute Engine API – do zarządzania kontami usługi.
Krok 1. Zapoznaj się z infrastrukturą wdrożenia
Projekt zawiera ujednolicony skrypt wdrażania (deploy.sh), który obsługuje wszystkie tryby wdrażania.
👉 Sprawdź skrypt wdrożenia (opcjonalnie):
cat deploy.sh
Skrypt udostępnia 3 tryby wdrażania:
./deploy.sh local– uruchamianie lokalne z pamięcią w pamięci./deploy.sh agent-engine– Wdróż w silniku agenta Vertex AI (zalecane)./deploy.sh cloud-run– wdrożenie w Cloud Run z opcjonalnym interfejsem
Jak to działa:
W przypadku wdrożenia silnika agenta skrypt wykonuje te czynności:
adk deploy agent_engine \
--project=$GOOGLE_CLOUD_PROJECT \
--region=$GOOGLE_CLOUD_LOCATION \
--staging_bucket=$STAGING_BUCKET \
--display_name="Charity Advisor" \
--trace_to_cloud \
charity_advisor
W przypadku wdrożenia Cloud Run wykonuje te czynności:
adk deploy cloud_run \
--project=$GOOGLE_CLOUD_PROJECT \
--region=$GOOGLE_CLOUD_LOCATION \
--service_name="charity-advisor" \
--app_name="charity_advisor" \
--with_ui \
--trace_to_cloud \
charity_advisor
Flaga --trace_to_cloud ma kluczowe znaczenie w przypadku obu typów wdrożenia – umożliwia integrację Cloud Trace na potrzeby ścieżki odpowiedzialności, którą poznasz w module 9.
Krok 2. Przygotuj otokę Agent Engine
Agent Engine wymaga określonego punktu wejścia, który opakowuje agenta na potrzeby zarządzanego środowiska wykonawczego. Ten plik został utworzony dla Ciebie.
👉 Sprawdź
charity_advisor/agent_engine_app.py
:
"""Agent Engine application wrapper.
This file prepares the Charity Advisor agent for deployment to Vertex AI Agent Engine.
"""
from vertexai import agent_engines
from .agent import root_agent
# Wrap the agent in an AdkApp object for Agent Engine deployment
app = agent_engines.AdkApp(
agent=root_agent,
enable_tracing=True, # Enables Cloud Trace integration automatically
)
Dlaczego ten plik jest potrzebny:
- Agent Engine wymaga, aby agent był opakowany w obiekt
AdkApp. - Parametr
enable_tracing=Trueautomatycznie włącza integrację z Cloud Trace. - Ten moduł jest przywoływany przez interfejs wiersza poleceń ADK podczas wdrażania.
- Konfiguruje
VertexAiSessionServicepod kątem automatycznego utrwalania sesji.
Krok 3. Wdróż w Agent Engine (ZALECANE)
Agent Engine to zalecane wdrożenie produkcyjne dla Twojego godnego zaufania systemu darowizn, ponieważ zapewnia w pełni zarządzaną infrastrukturę z wbudowaną trwałością sesji.
Uruchamianie wdrożenia
W katalogu głównym projektu:
chmod +x deploy.sh
./deploy.sh agent-engine
Etapy wdrażania
Obserwuj, jak skrypt wykonuje te fazy:
Phase 1: API Enablement
✓ aiplatform.googleapis.com
✓ storage.googleapis.com
✓ cloudbuild.googleapis.com
✓ cloudtrace.googleapis.com
✓ compute.googleapis.com
Phase 2: IAM Setup
✓ Getting project number
✓ Granting Storage Object Admin
✓ Granting Vertex AI User
✓ Granting Cloud Trace Agent
Phase 3: Staging Bucket
✓ Creating gs://your-project-id-staging (if needed)
✓ Setting permissions
Phase 4: Validation
✓ Checking agent.py exists
✓ Verifying root_agent defined
✓ Checking agent_engine_app.py exists
✓ Validating requirements.txt
Phase 5: Build & Deploy
✓ Packaging agent code
✓ Uploading to staging bucket
✓ Creating Agent Engine instance
✓ Configuring session persistence
✓ Setting up Cloud Trace integration
✓ Running health checks
Ten proces trwa 5–10 minut, ponieważ pakuje agenta i wdraża go w infrastrukturze Vertex AI.
Zapisywanie identyfikatora silnika agenta
Po pomyślnym wdrożeniu:
✅ Agent Engine created successfully!
Agent Engine ID: 7917477678498709504
Resource Name: projects/123456789/locations/us-central1/reasoningEngines/7917477678498709504
Endpoint: https://us-central1-aiplatform.googleapis.com/v1/...
⚠️ IMPORTANT: Save the Agent Engine ID from the output above
Add it to your .env file as:
AGENT_ENGINE_ID=7917477678498709504
This ID is required for:
- Testing the deployed agent
- Updating the deployment later
- Accessing logs and traces
Natychmiast zaktualizuj plik .env:
echo "AGENT_ENGINE_ID=7917477678498709504" >> .env
Co zostało wdrożone
Wdrożenie Agent Engine obejmuje teraz:
✅ Wszystkie 3 agenty (Shopping, Merchant, Credentials) działające w zarządzanym środowisku wykonawczym
✅ Pełny łańcuch danych logowania (Intent → Cart → Payment mandates)
✅ Mechanizm zgody użytkownika z procesem potwierdzania
✅ Automatyczne utrwalanie sesji za pomocą VertexAiSessionService
✅ Automatyczne skalowanie infrastruktury zarządzanej przez Google
✅ Integracja z Cloud Trace zapewniająca pełną widoczność
Krok 4. Przetestuj wdrożonego agenta
Aktualizowanie środowiska
Sprawdź, czy .env zawiera identyfikator Agent Engine:
AGENT_ENGINE_ID=7917477678498709504 # From deployment output
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://your-project-id-staging
Uruchamianie scenariusza testowania
Projekt zawiera skrypt testowy przeznaczony specjalnie do wdrożeń Agent Engine.
👉 Przeprowadź test:
python scripts/test_deployed_agent.py
Oczekiwane dane wyjściowe
Testing Agent Engine deployment...
Project: your-project-id
Location: us-central1
Agent Engine ID: 7917477678498709504
Endpoint: https://us-central1-aiplatform.googleapis.com/v1/...
Creating session...
✓ Session created: 4857885913439920384
Sending donation query...
✓ Response received:
Event 1: I'll help you donate $50 to a children's education charity...
Event 2: Here are some highly-rated children's education charities...
Event 3: Which charity would you like to support?...
✅ Test completed successfully!
Session ID: 4857885913439920384
This donation generated a trace in Cloud Trace.
View it in Module 9: Observability
To view traces:
https://console.cloud.google.com/traces/list?project=your-project-id
Lista kontrolna weryfikacji
Po przeprowadzeniu testów sprawdź:
✅ Agent odpowiada na zapytania.
✅ Wszyscy 3 agenci działają po kolei (Zakupy → Sprzedawca → Dane logowania).
✅ Mechanizm zgody jest aktywowany (wymagana jest potwierdzenie).
✅ Sesja jest utrzymywana w przypadku kolejnych żądań.
✅ Brak błędów uwierzytelniania.
✅ Brak przekroczenia limitu czasu połączenia.
Jeśli napotkasz błędy:
- Sprawdź, czy zmienne środowiskowe są prawidłowo ustawione
- Sprawdź, czy interfejsy API są włączone:
gcloud services list --enabled - Sprawdzanie logów silnika agenta w konsoli Vertex AI
- Sprawdź, czy plik
agent_engine_app.pyznajduje się w folderzecharity_advisor
Krok 5. Wdróż w Cloud Run (opcjonalny)
Agent Engine jest zalecany w przypadku uproszczonego wdrożenia produkcyjnego, ale Cloud Run zapewnia większą kontrolę i obsługuje interfejs ADK. Ta sekcja jest opcjonalna.
Kiedy używać Cloud Run
Wybierz Cloud Run, jeśli potrzebujesz:
- Interfejs internetowy ADK do interakcji z użytkownikiem
- Pełna kontrola nad środowiskiem kontenera
- Niestandardowe konfiguracje bazy danych
- Integracja z istniejącymi usługami Cloud Run
Uruchamianie wdrożenia
chmod +x deploy.sh
./deploy.sh cloud-run
Co się zmieniło:
Skrypt automatycznie:
- Tworzenie kontenera Dockera z kodem agenta
- Utwórz bazę danych Cloud SQL PostgreSQL (w razie potrzeby).
- Konfigurowanie połączenia z bazą danych
- Wdrażanie z włączonym interfejsem internetowym ADK
Wdrożenie zajmuje 10–15 minut ze względu na obsługę administracyjną Cloud SQL.
Zarządzanie sesjami:
- Używa
DatabaseSessionServicezamiastVertexAiSessionService - Wymaga danych logowania do bazy danych w
.env(lub wygenerowanych automatycznie) - Stan jest przechowywany w bazie danych PostgreSQL
Obsługa interfejsu:
- Interfejs internetowy dostępny pod adresem:
https://charity-advisor-xyz.a.run.app
Testowanie wdrożenia Cloud Run
Jeśli wdrożysz aplikację w Cloud Run za pomocą --with_ui, możesz ją przetestować bezpośrednio w przeglądarce:
- Otwórz adres URL usługi (podany w danych wyjściowych wdrożenia).
- Zobaczysz interfejs internetowy ADK. Wybierz agenta z menu.
- Rozpocznij testową darowiznę:
I want to donate $50 to a children's education charity
- Obserwuj przepływ wykonania:
- ShoppingAgent znajduje organizacje charytatywne i zapisuje Twoje intencje
- MerchantAgent tworzy polecenie zapłaty za koszyk
- Dostawca danych logowania tworzy upoważnienie do płatności i prosi o potwierdzenie
- Po potwierdzeniu płatność zostanie przetworzona
- Sprawdź, czy odpowiedź zawiera:
- Rekomendacje dotyczące organizacji charytatywnych
- Prośba o potwierdzenie
- Komunikat o sukcesie po zatwierdzeniu
Rozwiązywanie problemów
Typowe problemy
Problem: ERROR: GOOGLE_CLOUD_PROJECT is not set
Rozwiązanie: sprawdź, czy plik .env zawiera prawidłowy identyfikator projektu:
GOOGLE_CLOUD_PROJECT=your-actual-project-id
Problem: zasobnik tymczasowy nie został utworzony automatycznie
Rozwiązanie: skrypt powinien automatycznie utworzyć zasobnik. Jeśli nie, utwórz go ręcznie:
gsutil mb -p $GOOGLE_CLOUD_PROJECT -l $GOOGLE_CLOUD_LOCATION $STAGING_BUCKET
Podsumowanie
Udało Ci się:
✅ Zapoznaj się z infrastrukturą wdrożenia udostępnianą przez deploy.sh
. ✅ Sprawdź konfigurację otoki Agent Engine.
✅ Wdróż w Agent Engine system zaufanych darowizn (zalecane).
✅ Włącz integrację Cloud Trace z --trace_to_cloud
. ✅ Sprawdź, czy agent jest dostępny i działa prawidłowo.
✅ W module 9 utwórz podstawy ścieżek odpowiedzialności.
W następnym module dowiesz się, co dokładnie odblokowuje ten tag: pełną widoczność każdej darowizny, każdego momentu uzyskania zgody i każdego kroku w łańcuchu danych logowania.
9. Dostrzegalność


W części 1 przedstawiliśmy podstawowy problem: gdy agent AI zarządza pieniędzmi, jak udowodnić, co się stało?
Użytkownik może zgłosić:
- „Nigdy nie wybrałem tej organizacji charytatywnej!”
- „Nie autoryzuję tej płatności!”
- „System obciążył mnie bez mojej zgody!”
W tradycyjnym systemie AI typu „czarna skrzynka” nie byłoby możliwości udowodnienia, że jest inaczej. Jednak Twój godny zaufania system darowizn działa inaczej. W module 8 wdrożyliśmy flagę --trace_to_cloud, co oznacza, że każda darowizna tworzy teraz w Cloud Trace pełną, odporną na manipulacje ścieżkę audytu.
Z tego modułu dowiesz się, jak odczytywać te ślady i wykorzystywać je jako dowody. Poznasz następujące funkcje:
- Znajdowanie logów czasu produkcji w eksploratorze Cloud Trace
- Analizowanie widoku kaskadowego w celu zrozumienia przepływu wykonania
- Znajdź ciąg danych uwierzytelniających (Intent → Cart → Payment mandates)
- Znajdowanie momentów uzyskania zgody dzięki dowodom w postaci sygnatur czasowych
- Używanie śladów do rozwiązywania sporów
- Eksportowanie śladów na potrzeby zgodności i kontroli
To odróżnia wiarygodne systemy od tych, które są wprawdzie skuteczne, ale nieprzejrzyste: możliwość udowodnienia, co się stało, z dokładnością kryminalistyczną.
Informacje o śladach i zakresach
Zanim zaczniesz wyświetlać ślady w Cloud Trace, musisz wiedzieć, na co patrzysz.
Co to jest ślad?
Log czasu to pełna oś czasu obsługi pojedynczego żądania przez agenta. Obejmuje wszystko od momentu wysłania zapytania przez użytkownika do momentu dostarczenia ostatecznej odpowiedzi.
Każdy ślad zawiera:
- Łączny czas trwania żądania
- wszystkie operacje, które zostały wykonane;
- Jak operacje są ze sobą powiązane (relacje nadrzędne i podrzędne)
- Kiedy rozpoczęła się i zakończyła każda operacja
- Stan powodzenia lub niepowodzenia
W przypadku przedstawiciela organizacji charytatywnej: 1 ślad = 1 pełny proces przekazywania darowizny od „Chcę przekazać darowiznę” do „Płatność zrealizowana”.
Co to jest zakres?
Zakres to pojedyncza jednostka pracy w ramach śladu. Spany to elementy składowe śladu.
Typowe zakresy w systemie darowizn:
Rodzaj zakresu | Co to oznacza | Przykład |
| Uruchamianie agenta |
|
| Prośba do modelu językowego |
|
| Wykonanie funkcji narzędzia |
|
| Odczytywanie z pamięci sesji | Pobieranie |
| Zapisywanie w pamięci sesji | Zapisywanie |
Każdy zakres zawiera:
- Nazwa: co reprezentuje ta operacja.
- Czas trwania (od godziny rozpoczęcia do godziny zakończenia)
- Atrybuty: metadane, takie jak dane wejściowe narzędzia, odpowiedzi modelu i liczba tokenów.
- Stan: powodzenie (
OK) lub błąd (ERROR) - Relacje nadrzędne i podrzędne: które operacje wywołały które
Jak zakresy tworzą ślad
Zakresy są zagnieżdżone w sobie, aby pokazywać związek przyczynowo-skutkowy:
Root Span: CharityAdvisor.run (entire request)
└─ Child: DonationPipeline.run (sequential workflow)
├─ Child: ShoppingAgent.run
│ ├─ Grandchild: call_llm (Gemini processes charity search)
│ ├─ Grandchild: execute_tool (find_charities)
│ └─ Grandchild: execute_tool (save_user_choice)
├─ Child: MerchantAgent.run
│ ├─ Grandchild: call_llm (Gemini generates cart)
│ └─ Grandchild: execute_tool (create_cart_mandate)
└─ Child: CredentialsProvider.run
├─ Grandchild: call_llm (Gemini processes payment)
└─ Grandchild: execute_tool (create_payment_mandate) [CONSENT!]
Ta hierarchia pokazuje dokładnie, co się wydarzyło i w jakiej kolejności. Widać, że upoważnienie do płatności zostało utworzone po upoważnieniu do koszyka, które zostało utworzone po wybraniu przez użytkownika organizacji charytatywnej.
Krok 1. Otwórz Eksplorator Cloud Trace
Teraz wyświetlmy rzeczywiste ślady z wdrożonego agenta.
Otwieranie Cloud Trace
- Otwórz konsolę Google Cloud: console.cloud.google.com
- Wybierz projekt z menu u góry (powinien być wstępnie wybrany, jeśli w nim pracujesz).
- Otwórz Eksplorator Cloud Trace:
- Na pasku bocznym po lewej stronie przewiń do sekcji Obserwacja.
- Kliknij Trace.
- Możesz też użyć bezpośredniego linku: console.cloud.google.com/traces/list
Co widzisz
Eksplorator śladów wyświetla listę wszystkich śladów z Twojego projektu:
Kolumna | Co zawiera |
Żądanie | Metoda HTTP i punkt końcowy (w przypadku żądań API) |
Godzina rozpoczęcia | Kiedy rozpoczęło się żądanie |
Opóźnienie | Łączny czas trwania żądania |
Spans | Liczba operacji w śladzie |
Każdy wiersz reprezentuje jedno pełne żądanie wysłane do wdrożonego agenta.
Generowanie śladów testowych (w razie potrzeby)
Jeśli nie widzisz jeszcze żadnych śladów, lista może być pusta, ponieważ:
- Do wdrożonego agenta nie wysłano jeszcze żadnych próśb
- Ślady pojawiają się w ciągu 1–2 minut od wysłania żądania.
Generowanie śladu testowego:
Jeśli wdrożysz aplikację w Cloud Run za pomocą interfejsu, otwórz adres URL usługi i dokonaj darowizny w przeglądarce.
Jeśli wdrożono w Agent Engine, uruchom skrypt testowy z modułu 8:
python scripts/test_deployed_agent.py
Poczekaj 1–2 minuty, a potem odśwież stronę Eksploratora Cloud Trace. Powinny być teraz widoczne ślady.
Filtrowanie logów czasu
Aby znaleźć konkretne ślady, użyj opcji filtrowania u góry:
- Zakres czasu: w razie potrzeby zmień „Ostatnia godzina” na „Ostatnie 24 godziny”.
- Minimalny czas oczekiwania / maksymalny czas oczekiwania: filtruj powolne żądania.
- Filtr żądania: wyszukuj według konkretnych operacji (np. „DonationPipeline”)
W tym module skup się na śladach o dłuższym czasie trwania (powyżej 5 sekund), ponieważ reprezentują one pełne ścieżki darowizn z udziałem wszystkich 3 agentów.
Krok 2. Sprawdź pełny proces przekazywania darowizny
Kliknij dowolny ślad na liście, aby otworzyć widok kaskadowy. W tym miejscu będziesz spędzać najwięcej czasu na analizowaniu zachowań agentów.
Omówienie widoku kaskadowego
Widok kaskadowy to wykres Gantta przedstawiający pełną oś czasu wykonania:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Timeline (horizontal = time) →
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invocation ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 8.2s
agent_run: CharityAdvisor ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 8.1s
agent_run: DonationPipeline ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 7.9s
agent_run: ShoppingAgent ▓▓▓▓▓▓ 2.1s
call_llm: gemini-2.5-flash ▓▓▓▓ 1.2s
execute_tool: find_charities ▓▓ 0.5s
execute_tool: save_user_choice ▓ 0.3s
agent_run: MerchantAgent ▓▓▓ 1.8s
call_llm: gemini-2.5-flash ▓▓ 0.9s
execute_tool: create_cart_mandate ▓ 0.7s
agent_run: CredentialsProvider ▓▓▓▓▓▓▓▓ 4.0s
call_llm: gemini-2.5-flash ▓▓ 0.8s
execute_tool: create_payment_mandate ▓▓▓▓▓ 3.0s [CONSENT]
Interpretowanie wykresu
Każdy słupek reprezentuje zakres:
- Pozycja pozioma: kiedy się zaczął
- Długość: czas trwania
- Wcięcie: pokazuje relacje nadrzędny-podrzędny.
- Kolor: zwykle niebieski w przypadku normalnego działania, czerwony w przypadku błędów.
Najważniejsze obserwacje z tego przykładowego śledzenia:
✅ Łączny czas trwania: 8,2 s
✅ Kolejne wykonanie: ShoppingAgent zakończył działanie przed rozpoczęciem działania MerchantAgent
✅ MerchantAgent zakończył działanie
przed
Uruchomiono CredentialsProvider
✅ Najdłużej trwała operacja związana z uzyskaniem zgody: 3,0 s w przypadku create_payment_mandate (ponieważ oczekiwała na potwierdzenie użytkownika)
✅ Wywołania LLM są widoczne: każdy agent wysłał 1 żądanie do Gemini
✅ Wywołania narzędzi są rejestrowane: wszystkie 6 narzędzi zostało wykonanych
Ta wizualizacja od razu pokazuje gdzie jest spędzany czas i w jakiej kolejności są wykonywane operacje.
Kliknij zakres, aby wyświetlić szczegóły
Kliknij zakres invocation (główny zakres u góry). W panelu po prawej stronie zobaczysz szczegółowe atrybuty:
{
"http.method": "POST",
"http.status_code": 200,
"http.url": "https://charity-advisor-xyz.a.run.app/api/run",
"user_id": "test_user_123",
"session_id": "4857885913439920384",
"trace_id": "a1b2c3d4e5f6...",
"span_id": "1234567890abcdef"
}
Te atrybuty dostarczają kontekstu całego żądania.
Krok 3. Znajdź łańcuch danych logowania
Zaufany system używa łańcucha danych logowania, aby potwierdzić autoryzację na każdym etapie:
IntentMandate (User chose charity)
↓
CartMandate (Merchant created cart, signed IntentMandate)
↓
PaymentMandate (Payment provider created payment, signed CartMandate)
Znajdźmy w śladzie każdy mandat.
Znajdowanie dokumentu IntentMandate
Kliknij zakres execute_tool: save_user_choice (w sekcji ShoppingAgent).
W panelu atrybutów zobaczysz:
{
"tool.name": "save_user_choice",
"tool.input.charity_name": "Save the Children",
"tool.input.amount": 50,
"tool.output.status": "success",
"tool.output.intent_mandate": {
"charity_name": "Save the Children",
"amount": 50,
"timestamp": "2024-11-08T15:30:12.345Z",
"signature": "a3f7b9c1d2e4..."
}
}
To dowodzi, że:
- ✅ Użytkownik wybrał organizację „Save the Children”
- ✅ Kwota wynosiła 50 PLN
- ✅ Wybór został zarejestrowany o 15:30:12 czasu UTC
- ✅ Podpis został wygenerowany (w środowisku produkcyjnym byłby to podpis kryptograficzny)
Obiekt IntentMandate jest teraz w stanie sesji i jest dostępny dla kolejnych agentów.
Znajdowanie dokumentu CartMandate
Kliknij zakres execute_tool: create_cart_mandate (w sekcji MerchantAgent).
W panelu atrybutów:
{
"tool.name": "create_cart_mandate",
"tool.input.intent_mandate": {
"charity_name": "Save the Children",
"amount": 50,
"signature": "a3f7b9c1d2e4..."
},
"tool.output.status": "success",
"tool.output.cart_mandate": {
"cart_id": "cart_7893",
"intent_signature": "a3f7b9c1d2e4...",
"cart_signature": "e8f2a9b3c7d1...",
"timestamp": "2024-11-08T15:30:14.789Z"
}
}
To dowodzi, że:
- ✅ MerchantAgent otrzymał IntentMandate (dane wejściowe to potwierdzają).
- ✅ Utworzono koszyk o identyfikatorze „cart_7893”
- ✅ Podpis koszyka odwołuje się do podpisu IntentMandate (połączonego łańcuchem).
- ✅ Utworzono o 15:30:14 UTC (2,4 sekundy po zamiarze)
Obecnie CartMandate odwołuje się do IntentMandate, tworząc łańcuch.
Znajdowanie PaymentMandate
Kliknij zakres execute_tool: create_payment_mandate (w sekcji CredentialsProvider).
W panelu atrybutów:
{
"tool.name": "create_payment_mandate",
"tool.input.cart_mandate": {
"cart_id": "cart_7893",
"intent_signature": "a3f7b9c1d2e4...",
"cart_signature": "e8f2a9b3c7d1..."
},
"tool.confirmation_required": true,
"tool.confirmation_timestamp": "2024-11-08T15:30:17.891Z",
"tool.user_response": "CONFIRMED",
"tool.wait_duration_ms": 29168,
"tool.output.status": "success",
"tool.output.payment_mandate": {
"payment_id": "pay_9821",
"cart_signature": "e8f2a9b3c7d1...",
"payment_signature": "b4c9e2a7f8d3...",
"timestamp": "2024-11-08T15:30:47.059Z"
}
}
To potwierdza cały łańcuch:
- ✅ CredentialsProvider otrzymał CartMandate (dane wejściowe to pokazują)
- ✅ Płatność odnosi się do podpisu CartMandate (link do łańcucha).
- ✅ Wymagane było potwierdzenie (
confirmation_required: true) - ✅ Użytkownik potwierdził o 15:30:17 UTC
- ✅ System czekał 29,2 sekundy na decyzję użytkownika
- ✅ Płatność została utworzona po potwierdzeniu (sygnatura czasowa: 15:30:47)
Wizualizacja łańcucha
Ślad potwierdza, że łańcuch danych logowania został wykonany prawidłowo:
15:30:12 UTC → IntentMandate created (signature: a3f7...)
↓
15:30:14 UTC → CartMandate created (references: a3f7...)
↓
15:30:17 UTC → User consent requested
↓
15:30:47 UTC → PaymentMandate created (references: e8f2...)
Każdy mandat odnosi się do podpisu poprzedniego. Jest to zabezpieczenie przed manipulacją – możesz zweryfikować łańcuch, sprawdzając, czy podpisy są zgodne.
Krok 4. Analizowanie wydajności i wąskich gardeł
Cloud Trace nie tylko pokazuje, co się stało, ale też gdzie upływa czas, dzięki czemu możesz przeprowadzić optymalizację.
Określanie ścieżki krytycznej
W widoku kaskadowym poszukaj najdłuższych przedziałów w pionowym stosie. Są to wąskie gardła wydajności.
Z naszego przykładowego śladu:
Total: 8.2 seconds
Breakdown:
- ShoppingAgent: 2.1s (26%)
- MerchantAgent: 1.8s (22%)
- CredentialsProvider: 4.0s (49%) ← Bottleneck
- Other overhead: 0.3s (3%)
Kluczowe informacje: CredentialsProvider odpowiada za 49% całkowitego czasu. Dlaczego?
Przejdź do zakresu CredentialsProvider:
CredentialsProvider: 4.0s
- call_llm: 0.8s (20%)
- create_payment_mandate: 3.0s (75%) ← User consent wait
- Other: 0.2s (5%)
3-sekundowe opóźnienie jest oczekiwane i pożądane – użytkownik zastanawia się przed potwierdzeniem. Nie jest to problem z wydajnością, ale dowód na przemyślaną zgodę.
Śledzenie kosztów LLM
Kliknij dowolny zakres call_llm, aby zobaczyć wykorzystanie tokenów:
{
"llm.model": "gemini-2.5-flash",
"llm.usage.prompt_tokens": 487,
"llm.usage.completion_tokens": 156,
"llm.usage.total_tokens": 643,
"llm.response_time_ms": 1243
}
Wykorzystaj go, aby:
- Śledzenie kosztu żądania (tokeny × cena modelu)
- Identyfikowanie niepotrzebnie długich promptów
- Porównywanie skuteczności modeli (Flash i Pro)
- Optymalizacja pod kątem opóźnienia lub jakości
Przykładowe obliczenie:
Gemini 2.5 Flash pricing (as of Nov 2024):
Input: $0.075 per 1M tokens
Output: $0.30 per 1M tokens
This request:
Input: 487 tokens × $0.075 / 1M = $0.000037
Output: 156 tokens × $0.30 / 1M = $0.000047
Total: = $0.000084 (~$0.00008)
For 10,000 donations/month:
10,000 × 3 agents × $0.00008 = $2.40/month in LLM costs
Szczegółowy wgląd w dane pomaga podejmować decyzje dotyczące wyboru modelu na podstawie danych.
Porównywanie śladów
Filtrowanie wielu śladów i porównywanie czasu trwania:
Trace 1: 8.2s (with consent wait: 3.0s)
Trace 2: 12.5s (with consent wait: 7.8s) ← User took longer
Trace 3: 5.1s (with consent wait: 0.2s) ← User clicked fast
Trace 4: 6.3s (with consent wait: 1.5s)
Statystyka: większość różnic wynika z czasu podejmowania decyzji przez użytkowników, a nie z wydajności systemu. Czas wykonywania podstawowego agenta (bez zgody użytkownika) jest stały i wynosi około 5 sekund.
Oznacza to, że system działa niezawodnie.
W przypadku systemów produkcyjnych skonfiguruj alerty, aby wykrywać problemy, zanim zaczną zgłaszać je użytkownicy.
Alerty o wysokiej częstotliwości występowania błędów
Utwórz alert, gdy ponad 5% śladów zawiera błędy:
- Otwórz Cloud Monitoring.
- Kliknij „Alerty” → „Utwórz zasadę”.
- Skonfiguruj:
Resource: Cloud Trace Span Metric: Span error count Condition: Rate > 5% over 5 minutes Notification: Email your-team@example.com
Alert o dużym opóźnieniu
Utwórz alert, gdy 95 centyl czasu oczekiwania przekroczy 15 sekund:
Resource: Cloud Trace
Metric: Span duration (95th percentile)
Condition: > 15000ms for 5 minutes
Notification: PagerDuty
Pozwala to wykryć pogorszenie wydajności, zanim wpłynie ono na wygodę użytkowników.
Alert o braku zgody
Utwórz alert, jeśli jakakolwiek płatność zostanie przetworzona bez potwierdzenia:
Resource: Cloud Trace Span
Filter: tool.name="create_payment_mandate" AND tool.confirmation_required!=true
Condition: Any match
Notification: Critical alert to security team
Jest to detektor naruszeń zasad bezpieczeństwa – jeśli zostanie uruchomiony, oznacza to, że z mechanizmem uzyskiwania zgody jest coś nie tak.
Czego się nauczysz
Dzięki Cloud Trace wiesz już, jak:
✅ Poruszaj się po Eksploratorze Cloud Trace, aby znaleźć ślady produkcji.
✅ Odczytuj widoki kaskadowe, aby zobaczyć pełny przepływ wykonania.
✅ Śledź łańcuch danych logowania w kolejności IntentMandate → CartMandate → PaymentMandate. ✅ Używaj śladów jako dowodów w rozwiązywaniu sporów.
✅ Analizuj wydajność, aby identyfikować wąskie gardła.
✅ Śledź koszty LLM na poziomie szczegółowym.
Różnica, jaką to robi
Porównaj 2 systemy obsługujące tę samą skargę „Nigdy nie wyraziłem(-am) na to zgody”:
System bez dostrzegalności
User: "I never authorized that $50 donation!"
You: "Our logs show the transaction completed successfully."
User: "But I didn't approve it!"
You: "The system requires confirmation before processing."
User: "I never saw any confirmation!"
You: "..." [no way to prove what happened]
Result: Refund issued, trust lost, user never returns.
System z Cloud Trace
User: "I never authorized that $50 donation!"
You: "Let me pull up the trace from your session..."
[Shows waterfall with consent span]
You: "Here's the evidence:
- 15:30:17 UTC: System asked for confirmation
- Message shown: 'You are about to donate $50...'
- 15:30:47 UTC: You clicked 'CONFIRM'
- Wait time: 29.2 seconds
The system waited almost 30 seconds for your decision.
Here's the exact timestamp of your confirmation."
User: "Oh... I remember now. My mistake. Sorry!"
Result: Trust preserved, no refund needed, user continues using service.
Na tym polega siła ścieżek odpowiedzialności. Przechodzisz od „zaufaj nam” do „pokażemy Ci dokładnie, co się stało”.
Co dalej
Ukończono już techniczną część tworzenia wiarygodnych agentów:
✅ Moduły 1–6: zaprojektowano godną zaufania architekturę (role, dane logowania, zgoda użytkowników)
✅ Moduł 7: zorganizowano złożone przepływy pracy (SequentialAgent)
✅ Moduł 8: wdrożono z włączoną obserwacją
✅ Moduł 9: nauczono się odczytywać i wykorzystywać ścieżki odpowiedzialności
Zbudowana przez Ciebie architektura – rozdzielenie ról, łańcuchy danych logowania, mechanizmy uzyskiwania zgody, pełna widoczność – jest bezpośrednio przenoszona do systemów produkcyjnych obsługujących prawdziwe pieniądze, rzeczywiste dane i rzeczywiste konsekwencje.
10. Twoja dalsza podróż
Co utworzysz
Ten warsztat zaczęliśmy od pytania: „Jak stworzyć agentów AI, którym można powierzyć pieniądze?”
Teraz znasz odpowiedź.
Where you started (Module 3):
simple_agent = Agent(
model="gemini-2.5-flash",
instruction="Find charities and donate",
tools=[google_search]
)
Gdzie jesteś teraz (moduł 10):
- ✅ 3 wyspecjalizowanych agentów z podziałem ról
- ✅ 3 weryfikowalne dane logowania (zamiar → koszyk → upoważnienia do płatności)
- ✅ Sprawdzanie ważności łańcucha danych logowania na każdym etapie
- ✅ Mechanizm uzyskiwania wyraźnej zgody z dowodem w postaci sygnatury czasowej
- ✅ Wdrożenie produkcyjne w Agent Engine z możliwością obserwacji
- ✅ Pełna ścieżka odpowiedzialności w Cloud Trace
- ✅ Dowody kryminalistyczne do rozwiązywania sporów
Warsztat a produkcja: różnica
Twój system ma prawidłową architekturę i wzorce, ale korzysta z uproszczeń edukacyjnych, które należy ulepszyć, aby można było używać prawdziwych pieniędzy i prawdziwych użytkowników.
Oto co zostało uproszczone i czego wymaga produkcja:
Komponent | Wdrożenie warsztatów | Wymagania dotyczące produkcji |
Podpisy | Identyfikatory SHA-256 ( | Prawdziwe podpisy kryptograficzne z użyciem infrastruktury kluczy publicznych lub tokenów JWT z kluczami prywatnymi |
Przetwarzanie płatności | Symulowane zwroty (flaga | Integracja z interfejsami API prawdziwych systemów płatności (Stripe, PayPal, Square) |
Uwierzytelnianie użytkowników | Zaufanie domyślne (nie wymaga logowania) | OAuth 2.0, WebAuthn lub zarządzanie sesjami |
Zarządzanie obiektami tajnymi | Zmienne środowiskowe w pliku | Google Secret Manager lub Cloud KMS z szyfrowaniem |
Baza danych organizacji charytatywnych | Przykładowy plik JSON z 9 organizacjami charytatywnymi | Integracja interfejsu Live API (wyszukiwarka organizacji zwolnionych z podatku IRS, interfejs Charity Navigator API) |
Obsługa błędów | Podstawowa konstrukcja try-catch z komunikatami o błędach | Logika ponawiania z wykładniczym czasem do ponowienia, wyłącznikami obwodu i kolejkami niedostarczonych wiadomości |
Testowanie | Ręczna weryfikacja za pomocą skryptów | Kompleksowy zestaw testów jednostkowych, integracyjnych i E2E z CI/CD |
Trwałość sesji | W pamięci (lokalnie) lub automatycznie (Agent Engine) | Baza danych produkcyjnych z kopiami zapasowymi i odtwarzaniem awaryjnym |
Ograniczanie liczby żądań | Brak (środowisko edukacyjne) | Limity liczby żądań na użytkownika, ograniczanie na podstawie adresu IP, wykrywanie nadużyć |
Kluczowe wzorce architektoniczne, które opanowałeś(-aś)
Wzorce, których nauczysz się podczas tych warsztatów, są wzorcami produkcyjnymi. Nie wątp w nie.
Rozdział ról (zasada AP2 nr 1)
Każdy agent ma JEDNO konkretne zadanie i widzi TYLKO to, czego potrzebuje. Jeśli jeden agent zostanie przejęty, atakujący nie będzie mieć dostępu do danych innych agentów. Ogranicza to zasięg wybuchu.
Systemy produkcyjne, które z niego korzystają: przetwarzanie płatności, przepływy pracy związane z dokumentami, łańcuchy zatwierdzania, formularze wieloetapowe z bramkami weryfikacyjnymi.
Weryfikowalne dane logowania (zasada 2 AP2)
Każde poświadczenie ma czas wygaśnięcia, odwołuje się do poprzedniego poświadczenia i wymaga weryfikacji przed przejściem do następnego kroku. Tworzy to odporny na manipulacje łańcuch kontrolny.
Wartość produkcyjna: pełny dowód na to, co się wydarzyło, kiedy i w jakiej kolejności. Niezbędne do rozwiązywania sporów i zachowania zgodności z przepisami.
Jawna zgoda (zasada 3 AP2)
Dowód w postaci sygnatury czasowej, że użytkownik zatwierdził działanie. Nie można zakwestionować.
Wartość produkcji: wymóg prawny w przypadku transakcji finansowych. Ochrona zarówno użytkownika, jak i firmy.
Sekwencyjna administracja (wzorzec ADK)
Wymusza prawidłową kolejność wykonywania. Zapobiega pomijaniu kroków. Gwarantuje, że każdy agent zobaczy dane wyjściowe poprzedniego agenta.
Wartość produkcyjna: idealna w przypadku systemów z udziałem człowieka, w których użytkownicy oczekują natychmiastowych wyników. To odpowiedni wzorzec w przypadku procesów przekazywania darowizn, płatności i łańcuchów zatwierdzania.
Pełna widoczność (OpenTelemetry + Cloud Trace)
Każda decyzja, wywołanie narzędzia, moment uzyskania zgody i przekazanie danych logowania są rejestrowane automatycznie.
Wartość produkcyjna: dowody w sprawach spornych. dane optymalizacji skuteczności, Rejestry kontrolne zgodności. Precyzyjnie debuguj problemy w środowisku produkcyjnym.
Materiały do dalszej nauki
Dokumentacja pakietu ADK:
AP2 i powiązane standardy:
Usługi Google Cloud:
Czyszczenie zasobów
Aby uniknąć dalszych opłat, usuń wdrożenie:
Agent Engine: postępuj zgodnie z instrukcjami w dokumentacji Agent Engine.
Cloud Run (jeśli jest wdrożona):
gcloud run services delete charity-advisor \
--region=$GOOGLE_CLOUD_LOCATION
Zasobniki na dane:
gsutil -m rm -r gs://$GOOGLE_CLOUD_PROJECT-staging
gsutil -m rm -r gs://$GOOGLE_CLOUD_PROJECT-artifacts
Twoja podróż trwa dalej
Zaczęliśmy od prostego pytania i stworzyliśmy pełną odpowiedź. Opanowałeś(-aś) podstawowe wzorce dotyczące wiarygodnych agentów AI. Te wzorce można przenieść na dowolną domenę, w której agenci AI obsługują operacje wymagające zachowania poufności – transakcje finansowe, decyzje dotyczące opieki zdrowotnej, dokumenty prawne czy operacje w łańcuchu dostaw.
Zasady zostaną przeniesione. Model zaufania działa.
Teraz możesz stworzyć coś godnego zaufania. ❤️
