Przejdź do treści
Blog

A2A: agent przestaje być biblioteką, staje się usługą

Protokół agent-to-agent zamienia agenta w mikrousługę wywoływalną po HTTP, niezależnie od języka i frameworka. Pokazuję, jak to wygląda w kodzie i kiedy naprawdę warto rozdzielać agentów na osobne procesy.

Przemysław Zagórski6 min czytania

Do tej pory w tej serii agenci mieszkali w jednym procesie. Pipeline z trzech agentów to trzy obiekty w tym samym pliku, wywoływane przez ten sam silnik, dzielące ten sam stan sesji.

A2A zmienia w tym jedną rzecz, a ona pociąga za sobą wszystko inne: agent staje się adresem HTTP. Inny agent, napisany w innym języku, w innym frameworku, uruchomiony u kogoś innego, może go wywołać, nie wiedząc, co jest w środku.

Wygląda to na szczegół wdrożeniowy, ale to ta sama zmiana, którą przeszły aplikacje monolityczne przy przejściu na usługi, z tymi samymi zyskami i kosztami.

Jak to wygląda w kodzie

Wystawienie istniejącego agenta wymaga jednej linii. Agent nie musi być do tego napisany w żaden szczególny sposób.

from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.agents import LlmAgent

root_agent = LlmAgent(
    name="code_analyst_agent",
    model=MODEL,
    instruction="Analizujesz kod pod kątem podatności.",
    tools=[scan_for_hardcoded_secrets, scan_for_sql_injection],
)

a2a_app = to_a2a(root_agent, port=8001)

Uruchamiasz to jak każdą aplikację ASGI, na przykład przez uvicorn. Od tego momentu agent jest usługą.

Po drugiej stronie konsument podłącza go jako narzędzie obok swoich lokalnych:

KONSUMENT (port 8000)
  code_security_orchestrator
  ├── read_file_snippet      ← funkcja lokalna
  └── code_analyst_remote    ← agent zdalny przez A2A
                                  │
                                  ▼
                            PRODUCENT (port 8001)
                              code_analyst_agent

Dla orkiestratora zdalny agent wygląda jak kolejne narzędzie na liście. Nie wie, że po drugiej stronie jest model, ani jaki. Może tam być agent w Go, w Javie albo coś, co w ogóle nie jest agentem, tylko usługą udającą jego interfejs.

Wizytówka agenta

Element, który odróżnia A2A od zwykłego wywołania REST, to agent card: metadane opisujące, co agent potrafi, jakie ma umiejętności i jak z nim rozmawiać.

Przy to_a2a() wizytówka generuje się automatycznie z tego, co już jest w definicji agenta. To jest moment, w którym pole description, wyglądające wcześniej na dokumentację dla człowieka, staje się kontraktem publicznym. Konsument czyta je, żeby zdecydować, czy w ogóle wywołać tę usługę.

Jest też drugi tryb, przez adk api_server --a2a, który serwuje wielu agentów z jednego katalogu. Ma przewagę w integracji z narzędziami do podglądu, ale wymaga napisania wizytówek ręcznie. Do pierwszego wystawienia prostsza jest ta jednolinijkowa.

Kiedy to ma sens

Rozdzielenie agentów na osobne procesy nie jest ulepszeniem samo w sobie. Ma cztery uzasadnienia i sprawdź, czy któreś Cię dotyczy.

Inny właściciel. Zespół bezpieczeństwa utrzymuje agenta do analizy podatności i nie chce, żeby pięć innych zespołów wklejało sobie jego kod. Wystawia go raz, reszta konsumuje.

Inny cykl życia. Agent, którego reguły zmieniają się co tydzień, i agent stabilny od pół roku nie muszą być wdrażane razem.

Inne wymagania zasobowe. Coś, co potrzebuje dużo pamięci albo dostępu do specyficznej infrastruktury, nie powinno wymuszać takiej maszyny na całej reszcie.

Inny język. To jest przewaga nieosiągalna w jednym procesie. Zespół pracujący w Go wystawia agenta, konsument w Pythonie go używa, nikt niczego nie przepisuje.

Jeśli żadne z tych czterech nie zachodzi, zostań w jednym procesie. Wywołanie funkcji jest szybsze, tańsze i łatwiejsze do zdiagnozowania niż wywołanie po sieci.

Co się psuje, gdy agent staje się usługą

Tu część, której nie ma w materiałach o A2A, a która decyduje o tym, czy wdrożenie się utrzyma.

Ślad wykonania się rozrywa. W jednym procesie widzisz cały przebieg w jednym miejscu. Po rozdzieleniu masz dwa niezależne systemy i pytanie „dlaczego agent tak odpowiedział” wymaga skorelowania logów po obu stronach. Identyfikator korelacji trzeba przewidzieć przed pierwszym wdrożeniem, a nie po pierwszym incydencie.

Opóźnienia się sumują. Agent zdalny sam wywołuje model, więc do zwykłego opóźnienia sieciowego dochodzi pełen czas generowania odpowiedzi. Łańcuch trzech agentów przez A2A to trzy takie czasy jeden po drugim. Przy interfejsie, w którym ktoś czeka, bywa to różnica między sekundami a minutami.

Awaria zdalna wygląda jak zła odpowiedź. Jeśli usługa po drugiej stronie zwróci błąd, a Twój agent potraktuje to jako zwykły wynik narzędzia, model wygeneruje odpowiedź na podstawie komunikatu o błędzie. Użytkownik dostanie coś, co brzmi sensownie i nie ma pokrycia. Traktowanie błędów zdalnych jak błędów, a nie jak treści, jest tu obowiązkowe.

Kontrakt jest tekstem, nie schematem. Wizytówka opisuje możliwości w języku naturalnym, a nie jako typowane API. Zmiana zachowania agenta po stronie producenta nie wywoła błędu kompilacji u konsumenta. Wywoła gorsze odpowiedzi, których nikt nie powiąże z tamtą zmianą. To najpoważniejsza różnica względem klasycznych mikrousług i argument za tym, żeby po stronie konsumenta mieć własny zestaw testów sprawdzający, czy zdalny agent nadal robi to, co robił.

Jedno zdanie do zapamiętania

A2A przenosi agenta z warstwy biblioteki do warstwy integracji. Wszystko, co wiesz o wersjonowaniu, kontraktach i awariach częściowych w systemach rozproszonych, zaczyna obowiązywać. Nowe jest tylko to, że po drugiej stronie kontrakt jest opisany zdaniem, a nie schematem.

Kto może wywołać Twojego agenta

Pytanie, które przy to_a2a() zadaje się za późno, bo uruchomienie działa od razu i nic nie przypomina, że czegoś brakuje.

Agent wystawiony jako usługa jest zwykłym punktem końcowym HTTP. to_a2a() zwraca aplikację Starlette i nie dokłada do niej żadnego uwierzytelniania, a przewodnik po wystawianiu agenta w ogóle o nim nie wspomina. Jeśli podniesiesz to na maszynie dostępnej z sieci i nie postawisz przed tym niczego, każdy, kto zna adres, może wywołać Twojego agenta i zapłacisz za każde takie wywołanie tokenami.

Trzy rzeczy do rozstrzygnięcia przed pierwszym wdrożeniem poza laptopem.

Uwierzytelnianie stoi przed agentem, nie w nim. To warstwa infrastruktury: bramka, reverse proxy, uwierzytelnianie po stronie platformy. Wpisywanie sprawdzania tożsamości do instrukcji agenta jest tym samym błędem, co opisane w tekście o człowieku w pętli: decyzja o dostępie nie może zależeć od modelu.

Wizytówka jest publiczna z założenia. Opisuje, co agent potrafi, bo po to istnieje. Traktuj jej treść jak dokumentację wystawioną na zewnątrz i nie wpisuj tam nazw wewnętrznych systemów ani szczegółów, których nie chcesz ujawniać. To jest pierwsza rzecz, którą przeczyta ktoś, kto znajdzie Twój adres.

Uprawnienia po drugiej stronie są uprawnieniami wywołującego. Jeśli zdalny agent ma dostęp do bazy, to każdy, kto może go wywołać, ma pośrednio ten dostęp. Rozdzielenie agentów na usługi rozszerza powierzchnię ataku dokładnie tak, jak każde inne rozdzielenie systemu, tylko trudniej to zauważyć, bo wygląda na dodanie narzędzia do listy.

Jak zacząć bez wdrażania czegokolwiek

Można to zobaczyć w całości na jednym laptopie, w dwóch terminalach.

  1. Weź agenta, którego już masz, i dopisz jedną linię z to_a2a(). Uruchom na porcie 8001.
  2. Zbuduj drugiego agenta, który podłączy tamtego jako zdalne narzędzie, i uruchom go na porcie 8000.
  3. Zadaj pytanie wymagające obu. Zobacz, jak konsument decyduje o wywołaniu zdalnego i co dostaje z powrotem.
  4. Wyłącz producenta w trakcie rozmowy. To najważniejszy krok z całej czwórki, bo pokaże, jak Twój konsument zachowuje się przy awarii. Jeśli udaje, że wszystko w porządku, wiesz, co poprawić przed wdrożeniem.

Czwarty punkt robi się rzadko, a to on rozstrzyga o tym, czy system nadaje się do produkcji.

Podsumowanie

A2A jest technicznie proste i to jest zarówno jego zaletą, jak i pułapką. Jedna linia zamienia agenta w usługę, więc próg wejścia praktycznie nie istnieje. Konsekwencje architektoniczne są przy tym takie same jak przy każdym innym rozdzieleniu systemu na usługi.

Reguła, którą stosuję: rozdzielaj wtedy, gdy rozdzielenie rozwiązuje problem organizacyjny, a nie techniczny. Inny właściciel, inny cykl wydawniczy, inny język. Jeśli powodem jest „będzie czyściej”, zostań w jednym procesie i wróć do tematu, gdy pojawi się drugi zespół.

Pozostałe części serii: droga od czatu do systemu agentowego, migracja na graf, testowanie agentów i człowiek w pętli.

Źródła

  1. [1]A2A: wystawianie agenta (quickstart)Google / adk.dev
  2. [2]A2A: konsumowanie zdalnego agenta (quickstart)Google / adk.dev
  3. [3]Agent Development Kit: dokumentacjaGoogle
Przemysław Zagórski

Przemysław Zagórski

Programista i architekt, 14+ lat w telco i enterprise IT. Prowadzi warsztaty z inżynierii kontekstu, GitHub Copilota, Google ADK oraz ekosystemu Gemini dla zespołów, które muszą dowozić produkcyjnie.

Jeśli widzisz te problemy u siebie, zwykle da się je rozbroić w kilka dni roboczych. Nie kolejnym narzędziem, tylko zmianą sposobu pracy zespołu. Chętnie omówię Wasz przypadek.