Practical notes: Stworzyłem tego samego agenta na trzy sposoby: Interactions API, ADK oraz
Szczegółowy opis Practical notes: Stworzyłem tego samego agenta na trzy sposoby: Interactions API, ADK oraz sloty na kontrakty, sprawdzenia i kod do wklejenia dla zespołów stosujących ten wzorzec.
To przewodnictwo pokazuje, jak odbudować ścieżkę od surowców do działającego systemu w następujący sposób: stworzyłem ten sam agent na trzy różne sposoby – za pomocą Interactions API, ADK oraz Antigravity SDK. Główny nacisk kładziony jest na konkretne kroki operacyjne, wyraźne sprawdzenia oraz kod, który można bez problemu umieścić w repozytorium, nie musząc zgadywać intencji twórcy. Na etapie przeglądu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed jakimikolwiek zmianami w kodzie. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Obok wyników funkcjonalnych należy zapisywać czas wykonywania operacji oraz koszt tokenów lub zapytań. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.
Ustawienia i kroki realizacji
Gdy przechodzisz przez etap konfiguracji i realizacji, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustaw punkty kontrolne po kosztownych krokach. Narzędzie do kontynuacji pracy nie powinno ponownie naliczać opłat za tę samą wywołanie LLM, gdy operator próbuje ponownie uruchomić późniejszy węzeł.
export GOOGLE_API_KEY="..." # get this at aistudio.google.com
gcloud auth application-default login
Metoda 1: Interactions API – sam piszesz narzędzie i pętlę
Gdy przechodzisz przez etap API Interactions metodą 1, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dopinane później. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdej wywołania. Bez takich informacji debugowanie agenta trwa godzinami.
def execute_sql(query: str) -> list[dict]:
client = bigquery.Client()
config = bigquery.QueryJobConfig(maximum_bytes_billed=20 * 10**9)
rows = client.query_and_wait(query, job_config=config, max_results=50)
return [{k: str(v) for k, v in dict(row).items()} for row in rows]
execute_sql_tool = {
"type": "function",
"name": "execute_sql",
"description": (
"Run a BigQuery Standard SQL SELECT query against "
"`bigquery-public-data.hacker_news.full`, the public Hacker News "
"dataset (stories and comments since 2006). Columns: id INT, "
"type STRING (story/comment/job/poll), title STRING (stories only), "
"text STRING (body, HTML-escaped), `by` STRING (username), score INT, "
"parent INT, descendants INT, timestamp TIMESTAMP, url STRING, "
"dead BOOL, deleted BOOL. Returns at most 50 rows."
),
"parameters": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
}
while True:
calls = [s for s in interaction.steps if s.type == "function_call"]
if not calls:
break
results = [{
"type": "function_result",
"name": step.name,
"call_id": step.id,
"result": [{"type": "text", "text": json.dumps(execute_sql(**step.arguments))}],
} for step in calls]
interaction = client.interactions.create(
model=MODEL,
input=results,
system_instruction=INSTRUCTION,
tools=[execute_sql_tool],
previous_interaction_id=interaction.id,
)
Metoda 2: ADK – framework dostarcza narzędzia
Gdy pracujesz nad etapem Method 2 ADK, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdego wywołania. Debugowanie bez takich informacji marnuje godziny. Gdy pracujesz nad etapem Method 2 ADK, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do wspólnych środowisk.
import google.auth
from google.adk import Agent
from google.adk.integrations.bigquery import BigQueryCredentialsConfig, BigQueryToolset
from google.adk.integrations.bigquery.config import BigQueryToolConfig, WriteMode
credentials, _ = google.auth.default()
toolset = BigQueryToolset(
credentials_config=BigQueryCredentialsConfig(credentials=credentials),
bigquery_tool_config=BigQueryToolConfig(write_mode=WriteMode.BLOCKED),
)
root_agent = Agent(name="hn_opinion_agent", model=..., instruction=..., tools=[toolset])
Metoda 3: Antigravity SDK, pas bezpieczeństwa plus MCP
Etap Metody 3 Antigravity SDK działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden przykład udanego działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian przed rozszerzeniem zakresu. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, składysek z danymi poufnymi oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Udostępniaj narzędzia z wąskimi schematami oraz wyraźnymi oznaczeniami efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan, zanim automatycznie je zatwierdzą.
from google.antigravity import Agent, LocalAgentConfig
from google.antigravity.types import McpStreamableHttpServer
bigquery_mcp = McpStreamableHttpServer(
name="bigquery",
type="http",
url="https://bigquery.googleapis.com/mcp",
headers={"Authorization": f"Bearer {token}",
"x-goog-user-project": project},
enabled_tools=["execute_sql_readonly", "get_table_info", ...],
)
config = LocalAgentConfig(system_instructions=..., mcp_servers=[bigquery_mcp])
async with Agent(config) as agent:
response = await agent.chat(question)
Porównanie
Etap porównywania działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden idealny przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres badania. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę przywracania do normalnego stanu. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości nieodebranych stanowią część produktu, a nie elementy dodawane później. Utrzymuj stan grafu w prostej formie i z określonym typem danych. Wplecione struktury ukrywają informację o tym, który węzeł zapisał dane w danym polu, i powodują przerwanie kontynuacji działania po zakłóceniach.
Servowanie
Faza Serving it funkcjonuje najlepiej, gdy traktowana jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Utrzymuj stan grafu w prostej formie i z określonym typem danych. Wkładki nawarstwione utrudniają zidentyfikowanie, który węzeł zapisał dane do którego pola, i powodują przerwę w kontynuacji działania po zakłóceniach. Faza Serving it funkcjonuje najlepiej, gdy traktowana jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych.
Uwaga dotycząca konta usługowego
Aby zapewnić przejrzystość na etapie realizacji, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanej punktacji kontrolnej, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać oddzielnie od kodu aplikacji. Pliki środowiskowe, magazyny poufnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Zastosuj zatwierdzenie przez człowieka do operacji, które wiążą się z wydatkami lub zmianami w danych produkcyjnych. Połączenia realizowane w czasie kompilacji nie gwarantują pełnej kompletności procesu biznesowego.
Który wybrać
W fazie decydowania, który wariant wykorzystać, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa nieudanych transakcji stanowią część produktu, a nie elementy dodawane później. Konieczne jest uzyskanie zatwierdzenia przez człowieka w przypadkach, gdy dochodzi do wydawania pieniędzy lub zmiany danych produkcyjnych. Połączenia realizowane w czasie kompilacji nie równają się pełnej kompletności funkcjonalności produktu.
Lista kontrolna operacyjna
Faza listy kontrolnej operacyjnej działa najlepiej, gdy jest traktowana jako mierzalna powierzchnia do analizy. Należy zebrać jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą odwrócenia działań, zanim rozszerzy się zakres pracy.
Należy traktować tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Należy nadać nazwy poszczególnym elementom, zdefiniować kryteria sukcesu oraz odrzucić przypadki cichego, częściowego ukończenia zadania.
Zachowuj prostą i typowaną strukturę stanu grafu. Wkładane błony ukrywają informację o tym, który węzeł zapisał dane do którego pola, i powodują przerwanie kontynuacji działania po przerwach.
Gdy budżet na to pozwala, dodaj test sprawdzający kluczową ścieżkę w procesie CI przy użyciu fixitów, a nie rzeczywistych, płatnych API.
Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych.
Zachowuj prostą i typowaną strukturę stanu grafu. Wkładane błony ukrywają informację o tym, który węzeł zapisał dane do którego pola, i powodują przerwanie kontynuacji działania po przerwach.
Zanim przejdziesz na nowszą wersję stacku, zamroź wersje obecne, utwórz dokładny zapis działania dla kluczowej ścieżki i potwierdź kroki odwracające zmiany. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji uprawnień oraz jasno określonego właściciela odpowiedzialnego za rotację haseł. Wolisz nudną niezawodność od pomysłowych, jednorazowych demonstracji.
Uwaga dotycząca partii 016bc4c24234: unikaj przechowywania kluczy dostawcy w repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj transkrypcje obok narzędzi do oceny, aby późniejsze zmiany modeli pozostały porównywalne.
Pracując nad etapem 0 notatki dotyczącej wzmocnienia bezpieczeństwa, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy plikom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadań.
Szczegół wzmocnienia bezpieczeństwa 0/754: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie osobistych obserwacji.
Notatka dotycząca wzmocnienia bezpieczeństwa na etapie 0 działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian przed rozszerzeniem zakresu prac. Dokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę przywracania do normalnego stanu. Próby ponowne, kontrole ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później.
Szczegóły wzmocnienia bezpieczeństwa 0/773: zmierz czas wykonywania operacji, klasę błędu oraz zużycie zasobów dla tej notatki, a następnie zdecyduj, czy zachować zmianę, opierając się na ustalonej serii pytań, a nie na indywidualnych obserwacjach.
Dla etapu 1 notatki dotyczącej wzmocnienia bezpieczeństwa zdefiniuj dane wejściowe, osobę odpowiedzialną za daną czynność oraz kryteria zakończenia przed wprowadzaniem zmian w kodzie. Operatorzy powinni móc ponownie wykonać tę czynność na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.
Szczegóły wzmocnienia bezpieczeństwa 1/773: zmierz czas działania ściany, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.