Środowiska frontendu z ADK i A2UI

1. Przegląd

Większość aplikacji agentów zwraca zwykły tekst. A2UI to zmienia. Jest to protokół z 18 deklaratywnymi elementami interfejsu, który umożliwia agentowi tworzenie rozbudowanych, interaktywnych interfejsów. Klient renderuje je natywnie. Nie wymaga nowego kodu interfejsu dla każdego układu.

To ćwiczenie wykorzystuje pakiet Agent Development Kit (ADK) do tworzenia agenta i A2UI do generowania interfejsu.

Co utworzysz

Panel infrastruktury w chmurze w 3 etapach:

  1. Standardowy agent, który zwraca dane zasobu w postaci zwykłego tekstu.
  2. Agent A2UI, który zwraca te same dane co uporządkowany plik JSON A2UI.
  3. Wyrenderowany agent, który wyświetla kod JSON A2UI jako interaktywne komponenty interfejsu w interfejsie programisty ADK.

Agent ADK A2UI

Czego się nauczysz

  • Jak działa A2UI: 18 elementów podstawowych, 3 typy wiadomości, płaski model komponentów
  • Jak używać pakietu A2UI SDK, aby poprosić agenta ADK o wygenerowanie kodu JSON A2UI
  • Jak renderować komponenty A2UI w adk web

Czego potrzebujesz

  • projekt Google Cloud z włączonymi płatnościami;
  • przeglądarka, np. Chrome;
  • Python 3.12 lub nowszy

To ćwiczenie jest przeznaczone dla średnio zaawansowanych programistów, którzy znają już Pythona i Google Cloud.

Wykonanie tego laboratorium zajmie około 15–20 minut.

Zasoby utworzone w tym laboratorium powinny kosztować mniej niż 5 USD.

2. Konfigurowanie środowiska

Tworzenie projektu Google Cloud

  1. W konsoli Google Cloud na stronie selektora projektu wybierz lub utwórz projekt w chmurze Google.
  2. Sprawdź, czy w projekcie Cloud włączone są płatności. Dowiedz się, jak sprawdzić, czy w projekcie są włączone płatności.

Uruchamianie edytora Cloud Shell

Aby uruchomić sesję Cloud Shell w konsoli Google Cloud, kliknij Aktywuj Cloud Shell.

Spowoduje to uruchomienie sesji w dolnym panelu konsoli Google Cloud.

Aby uruchomić edytor, na pasku narzędzi w oknie Cloud Shell kliknij Otwórz edytor.

Ustawianie zmiennych środowiskowych

Na pasku narzędzi edytora Cloud Shell kliknij Terminal i Nowy terminal, a następnie uruchom te polecenia, aby ustawić projekt i lokalizację oraz skonfigurować ADK do korzystania z Gemini w Vertex AI.

export GOOGLE_CLOUD_PROJECT=<INSERT_YOUR_GCP_PROJECT_HERE>
export GOOGLE_CLOUD_LOCATION=global
export GOOGLE_GENAI_USE_VERTEXAI=True

Włącz interfejsy API

W terminalu uruchom to polecenie, aby włączyć wymagane interfejsy API:

gcloud services enable aiplatform.googleapis.com

Instalowanie zależności

Aby zainstalować najnowszą wersję pakietu Agent Development Kit (ADK), uruchom w terminalu to polecenie:

pip install -U google-adk a2ui-agent-sdk
export PATH="$HOME/.local/bin:$PATH"

3. Tworzenie agenta

Zacznij od standardowego agenta ADK, który zwraca zwykły tekst. Tak obecnie wygląda większość aplikacji agentów.

Tworzenie folderu agenta

Utwórz folder o nazwie a2ui_agent, który będzie zawierać kod źródłowy agenta i narzędzi.

Zdefiniuj narzędzie i dane testowe

Utwórz plik a2ui_agent/resources.py z tą treścią. To narzędzie zwraca listę zasobów w chmurze wraz z ich stanem.

RESOURCES = [
    {
        "name": "auth-service",
        "type": "Cloud Run",
        "region": "us-west1",
        "status": "healthy",
        "cpu": "2 vCPU",
        "memory": "1 GiB",
        "instances": 3,
        "url": "https://auth-service-abc123.run.app",
        "last_deployed": "2026-04-18T14:22:00Z",
    },
    {
        "name": "events-db",
        "type": "Cloud SQL",
        "region": "us-east1",
        "status": "warning",
        "tier": "db-custom-8-32768",
        "storage": "500 GB SSD",
        "connections": 195,
        "version": "PostgreSQL 16",
        "issue": "Storage usage at 92%",
    },
    {
        "name": "analytics-pipeline",
        "type": "Cloud Run",
        "region": "us-west1",
        "status": "error",
        "cpu": "2 vCPU",
        "memory": "4 GiB",
        "instances": 0,
        "url": "https://analytics-pipeline-ghi789.run.app",
        "last_deployed": "2026-04-10T16:45:00Z",
        "issue": "CrashLoopBackOff: OOM killed",
    },
]

def get_resources() -> list[dict]:
    """Get all cloud resources in the current project.
    Returns a list of cloud infrastructure resources including their
    name, type, region, status, and type-specific details.
    Status is one of: healthy, warning, error. Resources with
    warning or error status include an 'issue' field describing
    the problem.
    """
    return RESOURCES

Określanie agenta

Utwórz plik a2ui_agent/agent.py z tą zawartością:

from google.adk.agents import Agent
from .resources import get_resources

root_agent = Agent(
    model="gemini-3-flash-preview",
    name="cloud_dashboard",
    description="A cloud infrastructure assistant that reports on project resources.",
    instruction=(
        "You are a cloud infrastructure assistant. When users ask about their "
        "cloud resources, use the get_resources tool to fetch the current state. "
        "Summarize the results clearly in plain text."
    ),
    tools=[get_resources],
)

4. Testowanie agenta

ADK zawiera interfejs programisty, którego możesz używać do interakcji z agentem i wysyłania do niego promptów w przeglądarce na potrzeby testowania.

Uruchamianie interfejsu programistycznego pakietu ADK

W terminalu edytora Cloud Shell uruchom to polecenie, aby otworzyć interfejs programisty ADK:

adk web --port 8080 --allow_origins "*" --reload_agents

Wyświetli się komunikat podobny do tego:

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

Otwieranie interfejsu deweloperskiego pakietu ADK

Interfejs programisty ADK możesz otworzyć w przeglądarce, klikając adres URL testowania lokalnego z naciśniętym klawiszem Ctrl lub Cmd albo klikając przycisk Podgląd w przeglądarce i wybierając Podejrzyj na porcie 8080.

Gdy wyświetli się interfejs programisty ADK, w menu kliknij a2ui_agent.

Wysyłanie przykładowych promptów

Wyślij przykładowy prompt do agenta:

What's running in my project?

Teraz wypróbuj inny przykładowy prompt, aby uzyskać więcej tekstu:

Does anything need my attention?

Twoja rozmowa powinna wyglądać podobnie do tej poniżej:

Agent tekstowy ADK

Zobaczysz ścianę tekstu. Dokładne, ale nie zapewnia dobrych wrażeń użytkownika.

5. Generowanie pliku JSON A2UI

Co by było, gdyby agent mógł opisywać interfejs zamiast po prostu wyświetlać tekst? A2UI to protokół, który umożliwia agentom tworzenie interaktywnych interfejsów z katalogu 18 elementów podstawowych. Klient renderuje je natywnie.

Pakiet SDK A2UI dla Pythona zawiera menedżera schematów, który generuje dla Ciebie prompty systemowe. Uczy ona LLM pełnego katalogu komponentów A2UI, prawidłowych nazw i typów właściwości oraz struktury JSON.

Aktualizowanie agenta

Zamień zawartość pliku a2ui_agent/agent.py na taką:

from google.adk.agents import Agent
from a2ui.schema.manager import A2uiSchemaManager
from a2ui.basic_catalog.provider import BasicCatalog
from .resources import get_resources

schema_manager = A2uiSchemaManager(
    version="0.8",
    catalogs=[BasicCatalog.get_config("0.8")],
)

instruction = schema_manager.generate_system_prompt(
    role_description=(
        "You are a cloud infrastructure assistant. When users ask about "
        "their cloud resources, use the get_resources tool to fetch the "
        "current state."
    ),
    workflow_description=(
        "Analyze the user's request and return structured UI when appropriate."
    ),
    ui_description=(
        "Use cards for resource summaries, rows and columns for comparisons, "
        "icons for status indicators, and buttons for drill-down actions. "
        "Do NOT use markdown formatting in text values. Use the usageHint "
        "property for heading levels instead. "
        "Respond ONLY with the A2UI JSON array. Do NOT include any text "
        "outside the JSON. Put all explanations into Text components."
    ),
    include_schema=True,
    include_examples=True,
)

root_agent = Agent(
    model="gemini-3-flash-preview",
    name="cloud_dashboard",
    description="A cloud infrastructure assistant that renders rich A2UI interfaces.",
    instruction=instruction,
    tools=[get_resources],
)

Metoda generate_system_prompt() łączy opis roli z pełnym schematem JSON interfejsu A2UI i przykładami z kilkoma próbami, dzięki czemu LLM dokładnie wie, jak sformatować dane wyjściowe. Nie musisz ręcznie tworzyć katalogu komponentów.

6. Testowanie danych wyjściowych JSON

Jeśli interfejs programisty ADK jest nadal uruchomiony, powinien automatycznie ponownie wczytać zmiany wprowadzone w agencie.

Kliknij a2ui_agent, rozpocznij nową sesję, klikając + Nowa sesja w prawym górnym rogu interfejsu programisty ADK, a następnie wyślij ten sam prompt co wcześniej:

What's running in my project?

Tym razem agent odpowiada w formacie JSON A2UI zamiast w formacie zwykłego tekstu. W danych wyjściowych czatu zobaczysz wiadomości strukturalne zawierające beginRendering, surfaceUpdatedataModelUpdate.

ADK A2UI JSON

Kod JSON opisuje rozbudowany interfejs z kartami, ikonami i przyciskami, ale adk web wyświetla go jako zwykły tekst. W następnym kroku sprawisz, że będą renderowane jako rzeczywiste komponenty interfejsu.

7. Informacje o A2UI

Sprawdź wygenerowany przez agenta kod JSON. Zawiera ona 3 rodzaje wiadomości. Każda odpowiedź A2UI ma taką samą strukturę:

1. beginRendering

Tworzy powierzchnię renderowania i nadaje nazwę komponentowi głównemu:

{"beginRendering": {"surfaceId": "default", "root": "main-column"}}

2. surfaceUpdate

Wysyła drzewo komponentów jako płaską listę z odwołaniami do identyfikatorów (nie zagnieżdżoną):

{"surfaceUpdate": {"surfaceId": "default", "components": [
  {"id": "main-column", "component": {"Column": {"children": {"explicitList": ["title", "card1"]}}}},
  {"id": "title", "component": {"Text": {"text": {"literalString": "My Resources"}, "usageHint": "h1"}}},
  {"id": "card1", "component": {"Card": {"child": "card1-content"}}},
  {"id": "card1-content", "component": {"Text": {"text": {"path": "service_name"}}}}
]}}

3. dataModelUpdate

Wysyła dane oddzielnie od struktury:

{"dataModelUpdate": {"surfaceId": "default", "contents": [
  {"key": "service_name", "valueString": "auth-service"},
  {"key": "status", "valueString": "healthy"}
]}}

Komponenty są powiązane z danymi za pomocą {"path": "key"}. Możesz aktualizować dane bez ponownego wysyłania drzewa komponentów.

18 elementów podstawowych

Kategoria

Komponenty

Układ

Karta, Kolumna, Wiersz, Lista, Karty, Separator, Okno modalne

Wyświetlacz

Tekst, obraz, ikona, film, odtwarzacz audio

Wejście

TextField, DateTimeInput, MultipleChoice, CheckBox, Slider

Działanie

Przycisk

Agent tworzy różne układy z tego samego katalogu. Szczegółowe informacje o każdym elemencie znajdziesz w dokumentacji komponentów. Widok przeglądania, panel priorytetowy i formularz konfiguracji korzystają z tych samych 18 elementów podstawowych. Nie są potrzebne żadne nowe komponenty interfejsu.

8. Renderowanie komponentów A2UI

Agent generuje prawidłowy kod JSON A2UI, ale adk web wyświetla go jako zwykły tekst. Aby wyrenderować go jako rzeczywiste komponenty interfejsu, potrzebujesz małego narzędzia, które przekształci dane wyjściowe JSON A2UI agenta w format oczekiwany przez wbudowany renderer adk web.

Utwórz narzędzie do renderowania A2UI

Utwórz plik a2ui_agent/a2ui_utils.py z tą zawartością:

import json
import re
from google.genai import types
from google.adk.agents.callback_context import CallbackContext
from google.adk.models.llm_response import LlmResponse

def _wrap_a2ui_part(a2ui_message: dict) -> types.Part:
    """Wrap a single A2UI message for rendering in adk web."""
    datapart_json = json.dumps({
        "kind": "data",
        "metadata": {"mimeType": "application/json+a2ui"},
        "data": a2ui_message,
    })
    blob_data = (
        b"<a2a_datapart_json>"
        + datapart_json.encode("utf-8")
        + b"</a2a_datapart_json>"
    )
    return types.Part(
        inline_data=types.Blob(
            data=blob_data,
            mime_type="text/plain",
        )
    )

def a2ui_callback(
    callback_context: CallbackContext,
    llm_response: LlmResponse,
) -> LlmResponse | None:
    """Convert A2UI JSON in text output to rendered components."""
    if not llm_response.content or not llm_response.content.parts:
        return None
    for part in llm_response.content.parts:
        if not part.text:
            continue
        text = part.text.strip()
        if not text:
            continue
        if not any(k in text for k in ("beginRendering", "surfaceUpdate", "dataModelUpdate")):
            continue
        # Strip markdown fences
        if text.startswith("```"):
            text = text.split("\n", 1)[-1]
            if text.endswith("```"):
                text = text[:-3].strip()
        # Find where JSON starts (skip conversational prefix)
        json_start = None
        for i, ch in enumerate(text):
            if ch in ("[", "{"):
                json_start = i
                break
        if json_start is None:
            continue
        json_text = text[json_start:]
        # raw_decode parses JSON and ignores trailing text
        try:
            parsed, _ = json.JSONDecoder().raw_decode(json_text)
        except json.JSONDecodeError:
            # Handle concatenated JSON objects: {"a":1} {"b":2}
            try:
                fixed = "[" + re.sub(r'\}\s*\{', '},{', json_text) + "]"
                parsed, _ = json.JSONDecoder().raw_decode(fixed)
            except json.JSONDecodeError:
                continue
        if not isinstance(parsed, list):
            parsed = [parsed]
        a2ui_keys = {"beginRendering", "surfaceUpdate", "dataModelUpdate", "deleteSurface"}
        a2ui_messages = [msg for msg in parsed if isinstance(msg, dict) and any(k in msg for k in a2ui_keys)]
        if not a2ui_messages:
            continue
        new_parts = [_wrap_a2ui_part(msg) for msg in a2ui_messages]
        return LlmResponse(
            content=types.Content(role="model", parts=new_parts),
            custom_metadata={"a2a:response": "true"},
        )
    return None

To narzędzie wykonuje 2 czynności:

  1. Wyodrębnia JSON A2UI z tekstowych danych wyjściowych agenta.
  2. Zawiera każdą wiadomość A2UI w formacie oczekiwanym przez wbudowany w adk web moduł renderowania A2UI.

Aktualizowanie agenta

Zastąp zawartość pliku a2ui_agent/agent.py tym kodem: Jedyną zmianą w porównaniu z poprzednim krokiem jest importowanie a2ui_callback i parametr after_model_callback w agencie:

from google.adk.agents import Agent
from a2ui.schema.manager import A2uiSchemaManager
from a2ui.basic_catalog.provider import BasicCatalog
from .resources import get_resources
from .a2ui_utils import a2ui_callback

schema_manager = A2uiSchemaManager(
    version="0.8",
    catalogs=[BasicCatalog.get_config("0.8")],
)

instruction = schema_manager.generate_system_prompt(
    role_description=(
        "You are a cloud infrastructure assistant. When users ask about "
        "their cloud resources, use the get_resources tool to fetch the "
        "current state."
    ),
    workflow_description=(
        "Analyze the user's request and return structured UI when appropriate."
    ),
    ui_description=(
        "Use cards for resource summaries, rows and columns for comparisons, "
        "icons for status indicators, and buttons for drill-down actions. "
        "Do NOT use markdown formatting in text values. Use the usageHint "
        "property for heading levels instead. "
        "Respond ONLY with the A2UI JSON array. Do NOT include any text "
        "outside the JSON. Put all explanations into Text components."
    ),
    include_schema=True,
    include_examples=True,
)

root_agent = Agent(
    model="gemini-3-flash-preview",
    name="cloud_dashboard",
    description="A cloud infrastructure assistant that renders rich A2UI interfaces.",
    instruction=instruction,
    tools=[get_resources],
    after_model_callback=a2ui_callback,
)

9. Testowanie renderowanego interfejsu

Jeśli interfejs programisty ADK jest nadal uruchomiony, powinien automatycznie ponownie wczytać zmiany wprowadzone w agencie.

Odśwież kartę przeglądarki, kliknij a2ui_agent, a potem rozpocznij nową sesję, klikając + Nowa sesja w prawym górnym rogu interfejsu programisty ADK. Wyślij ten sam prompt co wcześniej:

What's running in my project?

Tym razem adk web renderuje komponenty A2UI jako rzeczywisty interfejs: karty ze wskaźnikami stanu, szczegółami zasobów i przyciskami działań.

Agent ADK A2UI

Wypróbuj inny prompt, aby zobaczyć, jak agent tworzy inny interfejs z tego samego zestawu elementów podstawowych:

Does anything need my attention?

Na koniec spróbuj użyć innego prompta, aby wygenerować inny interfejs do wdrożenia nowej usługi:

I need to deploy a new service

Każdy prompt jest kierowany do tego samego agenta, tego samego narzędzia i tych samych 18 obiektów podstawowych. Każdy prompt powoduje jednak wyświetlenie innego interfejsu z innym zamiarem.

10. Czyszczenie

Aby uniknąć pozostawienia uruchomionych serwerów lokalnych, zwolnij miejsce na zasoby:

  • W terminalu, w którym działa adk web, naciśnij Ctrl+C, aby zatrzymać serwer agenta.

Jeśli Twój projekt został utworzony specjalnie na potrzeby tego ćwiczenia, możesz go usunąć w całości:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}

11. Gratulacje

Masz agenta ADK, który generuje bogaty, interaktywny interfejs użytkownika za pomocą A2UI.

Czego się dowiedziałeś

  • A2UI to protokół z 18 deklaratywnymi elementami3 typami wiadomości.
  • Pakiet A2UI SDK generuje prompty systemowe, które uczą LLM katalogu komponentów.
  • Ten sam agent, narzędzie i elementy pierwotne tworzą różne interfejsy użytkownika dla różnych zamiarów.
  • Komponenty A2UI można renderować bezpośrednio w adk web podczas tworzenia.

Tworzenie frontendu produkcyjnego

W tym ćwiczeniu wyrenderowano A2UI w adk web na potrzeby programowania i testowania.

W przypadku środowiska produkcyjnego możesz utworzyć interfejs za pomocą jednego z oficjalnych modułów renderujących A2UI:

Platforma

Mechanizm renderowania

Zainstaluj

Internet (React)

@a2ui/react

npm install @a2ui/react

Internet (Lit)

@a2ui/lit

npm install @a2ui/lit

Internet (Angular)

@a2ui/angular

npm install @a2ui/angular

Urządzenia mobilne/komputery

Flutter GenUI SDK

Pierwsze kroki

Dokumentacja