Claude Agent SDK kontra OpenAI Agents SDK kontra Google ADK: jeden agent, trzy wersje
Claude Agent SDK kontra OpenAI Agents SDK kontra Google ADK: jeden agent do tworzenia etykiet żywności zbudowany trzy razy – co obejmuje każdy zestaw oraz co nadal musisz napisać samodzielnie.
Każdy duży dostawca technologii AI dostarcza obecnie SDK dla agentów, a ich propozycje są niemal identyczne. Daj nam swoje narzędzia i instrukcje, a my uruchomimy cały proces: wywołania narzędzi, strukturyzowany wynik, sesje oraz śledzenie działań. Skoro marketing jest tak podobny, co naprawdę odróżnia te zestawy i na którym powinno się oprzeć rozwoju?
Sposobem na ustalenie tego było stworzenie tego samego agenta trzy razy: za pomocą SDK Claude Agent od Anthropic, SDK OpenAI Agents oraz Agent Development Kit od Google. Agent to nie zabawka – to narzędzie do analizy etykiet żywnościowe, które odczytuje zdjęcie, wykorzystuje kilka narzędzi do analizy, podaje werdykt i doskonali się w miarę oglądania coraz większej liczby etykiet. Przy jednym agencie i trzech różnych interfejsach wszelkie różnice w wynikach wynikają z SDK, a nie z samego problemu.
Wersja krótka: wszystkie trzy rozwiązania niemal w pełni pokrywają się w kwestii trudnej części, czyli pętli rozumowania, a różnią się we wszystkim, co jest z nią powiązane. Różnią się sposobem deklarowania narzędzia, sposobem dodawania obrazu oraz tym, czy otrzymuje się w ogóle tekstowy wynik. Najbardziej wymowne jest to, że różnią się tym, czego żadne z nich dla Ciebie nie robi. Pod koniec będziesz wiedział, które zestawienie nadaje się do danego zadań oraz ile pracy pozostanie Ci do wykonania po jego wyborze.
Kolejny element łączy wszystkie trzy wersje. Agent został zaprojektowany tak, by uczyć się na podstawie doświadczeń. Pamięta produkty, które już przeanalizował, oraz nazwy dodatków, których rozwiązanie już zna, a te informacje są zapisywane na dysku, dzięki czemu każdy kolejny uruchomienie mniej polega na modelu, kończy się szybciej i zachowuje się w sposób bardziej deterministyczny. Wagi modelu nigdy się nie zmieniają. To agent gromadzi umiejętności. Żaden z SDK nie oferuje tego od razu, co czyni to przydatnym narzędziem do zrozumienia, gdzie kończy się gotowe rozwiązanie, a zaczyna własna praca inżynierska.
Najpierw: co stanowi agenta
Model w prostym języku nie jest agentem. Można go traktować jako funkcję, która przyjmuje tekst i obrazy oraz zwraca tekst. Nic nie jest przenoszone pomiędzy kolejnymi wywołaniami – nie może wykonywać kodu ani ładować strony, a nawet nie może ponownie się sam wywołać. Podaj mu etykietę żywieniową, a on powie ci, w jaki sposób zamierza to zbadać, jednak to badanie nigdy nie następuje.
Agent to model działający w pętli z użyciem narzędzi. Ten schemat nigdy się nie zmienia. Podajesz modelowi cel oraz listę narzędzi, których może używać. Odpowiada on albo końcowym wynikiem, albo prośbą o wywołanie danego narzędzia, na przykład „sprawdź E211”. Jeśli poprosi o użycie narzędzia, coś je wykona i zwróci wynik, a model kontynuuje działanie. Cykl powtarza się, aż pojawi się ostateczna odpowiedź.
To cykl stanowi całą ideę: model podejmuje decyzję, uruchamiana jest narzędzie, pojawia się wynik, model ponownie podejmuje decyzję. Nasz badacz przechodzi przez wiele etapów – raz w celu wyszukania produktu, raz dla każdego składnika, następnie w celu sprawdzenia opcji zdrowszych, określenia jakości oraz ostatecznej syntezy. Za każdym razem model wybiera kolejny krok na podstawie tego, czego właśnie się nauczył. To właśnie sprawia, że system ma zdolność do działania samodzielnie, i dlatego jeden wywołanie API w ramach pętli for nie spełnia wymagań.
Zwróć uwagę na to, co faktycznie wytwarza model: tylko „Chciałbym wywołać check_sfa_additive z tymi argumentami”. Coś innego musi przekształcić to życzenie w rzeczywiste wywołanie funkcji i zapewnić ciągłość działania. Tym czymś jest harness, który zawiera więcej mniej atrakcyjnych elementów technicznych, niż większość ludzi się spodziewa. Dzieli się on na trzy warstwy. Warstwa rozwijania to miejsce, gdzie buduje się agenta. Warstwa czasu wykonywania to miejsce, gdzie agent jest używany w produkcji. Plan sterowania to miejsce, gdzie zarządza się całym zespołem agentów. To właśnie warstwa rozwoju sprawia, że pętla w ogóle działa, i to tam znajdują się te SDK.
Zaczynamy od warstwy Rozwoju, w której budowany jest pojedynczy agent. Składa się ona z samego pętli (wywołanie modelu, wykrywanie żądań użycia narzędzi, powtarzanie aż do zakończenia, bezpieczne wyjście przy osiągnięciu limitu rund lub budżetu) oraz z persony, czyli instrukcji systemowych, które mówią modelowi, kim jest i jak ma działać. Wokół nich znajdują się schematy narzędzi, które opisują każde narzędzie dla modelu w formacie, którego oczekuje, oraz mechanizm wykonywania narzędzi, który faktycznie uruchamia Twoją funkcję, serwer MCP lub wbudowane rozwiązania, takie jak odczyt plików, i przechowuje wynik. Klient MCP umożliwia agentowi dostęp do serwerów third-party. Zarządzanie kontekstem przechowuje bieżącą transkrypcję, obsługuje obrazy i usuwa niepotrzebne dane, gdy staje się zbyt długa. Konfiguracja dostawcy obejmuje autoryzację, punkty końcowe oraz formaty żądań dla danego dostawcy. Dodatkowo istnieją strukturyzowane wyniki, które wymuszają i sprawdzają ostateczną odpowiedź pod kątem określonej formy, oraz procesy robocze z wieloma agentami, które łączą agenty sekwencyjnie, równolegle lub w cyklach.
SDK-y upraszczają to wszystko. Przechodząc od uruchamiania skryptów do obsługi usług, pojawia się warstwa Runtime wraz z dłuższym wykazem wymagań. Agent potrzebuje hostowanej eksploatacji, czyli punktu końcowego z izolacją sesji, do którego mogą się łączyć inne systemy. Potrzebuje również bramy narzędziowej, mechanizmów ponawiania prób, limitów czasowych oraz obsługi danych uwierzytelniających, które zapewniają wiarygodność wywołań narzędzi w przypadku awarii API. Konieczna jest także zarządzana pamięć, aby sesje i długoterminowe dane przechowywały się w miejscu dostępnym po zakończeniu procesu i mogły być udostępniane pomiędzy instancjami. Agent wymaga identyfikatora obciążenia do przedstawiania przy wywoływaniu narzędzi, aby takie wywołania nie odbywały się przy użyciu osobistego klucza kogoś innego, a także możliwości obserwacji, w postaci śladów i okresów, które pokazują, które narzędzia zostały uruchomione, z jakimi danymi i dlaczego. Dodaj pustynię testową dla własnego kodu agenta lub narzędzi przeglądarki, odpornych pętli, które kontynuują pracę od ostatniego zakończonego kroku po awarii, oraz możliwość skalowania poprzez równoczesne wykonywanie zadań i automatyczne skalowanie za pośrednictwem punktu końcowego.
Poniżej znajduje się Control Plane, który zarządza wieloma agentami jednocześnie. Rejestr umożliwia publikację i wykrywanie agentów w trakcie działania, zamiast łączenia ich bezpośrednio w kodzie. Każdy agent potrzebuje tożsamości jako własnej, identyfikowalnej jednostki w katalogu, a także określonych uprawnień, które są egzekwowane, a nie tylko zakładane. Następnie potrzebny jest rejestr audytu i zgodności pokazujący, co zrobiła cała grupa agentów, mechanizmy zarządzania danymi dotyczące tego, co może być przechowywane i udostępniane w pamięci wspólnej, oraz kontrole kosztów i limitów wraz z budżetami i ograniczeniami szybkości. Agenci mogą komunikować się ze sobą za pomocą otwartego protokołu, takiego jak A2A. Ponieważ wyniki działania narzędzi trafiają bezpośrednio z powrotem do modelu, ważne są zasady bezpieczeństwa i mechanizmy obrony przed atakami, a ocena pozwala stwierdzić, czy odpowiedzi są poprawne, a nie tylko czy proces został zakończony. Rejestr narzędzi i serwerów MCP zajmuje się katalogowaniem, wersjonowaniem, wyszukiwaniem, gromadzeniem zasobów oraz autoryzacją na poziomie poszczególnych serwerów. Szybkie wersjonowanie umożliwia fiksację, porównywanie i cofanie promptów, dzięki czemu ich wykonywanie pozostaje powtarzalne. Krótko mówiąc, każdy z tych zestawów to gotowe rozwiązanie. Rozwiązania Claude’a, OpenAI i Google obejmują cały mechanizm działania, infrastrukturę narzędziową, obsługę kontekstu oraz połączenia z dostawcami, pozostawiając Ci możliwość napisania najważniejszych elementów: własnych narzędzi, promptów oraz formatu wyjściowego. ADK to nieco odmienna nazwa, choć pełni tę samą funkcję, więc „SDK-y” opisane poniżej obejmują w przybliżeniu wszystkie trzy rozwiązania.
Różnią się tym, jakie elementy uprzęży dostarczają, jak bardzo każdy z tych elementów jest specyficzny, oraz w którym momencie uprząż po prostu się kończy, a kod musi przejąć kontrolę. Najlepszym sposobem na uściślenie tego jest stworzenie po jednym agencie w każdym z tych elementów. Gdy wszystkie trzy istnieją, można zaprojektować pełną uprząż i określić, co każdy zestaw dostarcza, a co pozostawia do załatwienia użytkownikowi.
Agent pod testem: badacz etykiet żywnościowych
Sprawiedliwy test musi sprawdzić, do czego służą te zestawy – czyli proces rozumowania wykonywany za pomocą kilku narzędzi, przy którym każdy kolejny krok zależy od wyników poprzedniego. Jedna tylko wywołanie modelu w ramach określonego frameworka nie wystarczy. To badacz wykonuje rzeczywistą pracę – pokazano mu zdjęcie etykiety żywnościowej, a on przeprowadza pięć różnych operacji.
- Czyta etykietę za pomocą własnego systemu widzenia modelu, wyodrębniając nazwę produktu, pełny wykaz składników i dodatków, ilość cukru oraz tłuszczów nasyconych na 100 ml oraz informację, czy produkt jest napojem. Foto jest jedynym źródłem prawdy – nie ma żadnej bazy danych produktów, na którą można by się powołać.
- Dla każdego znalezionego dodatku, niezależnie od tego, czy na etykiecie widnieje
E471czy „Lecytyna sojowa”, sprawdza listę dodatków dozwolonych przez SFA w Singapurze i podaje status oraz wszelkie ostrzeżenia skierowane do konsumentów. - Pyta bazę danych HPB dostępną na data.gov.sg, aby sprawdzić, czy produkt posiada symbol Healthier Choice.
- Dla napojów oblicza przewidywany poziom Nutri-Grade A/B/C/D na podstawie ilości cukru i tłuszczów nasyconych.
- Łączy wszystkie te informacje w stopniowaną ocenę: ZIELONY, BŁĄKITNY lub CZERWONY, z podaniem źródła – narzędzia lub etykiety – które ją dostarczyły, przy czym na początku przedstawia uzasadnienie modelu.
On też nie zaczyna od zera za każdym razem. Pamięta to, co już widział, i uczy się w trakcie pracy, więc zarówno produkt zbadany wczoraj, jak i nazwa dodatku, którą kiedyś miał trudności z rozszyfrowaniem, są dostępne przy następnej okazji. Więcej na ten temat później.
Zatem środowisko testowe oferuje pętlę narzędzi o zmiennej długości, prawdziwy źródło danych z Singapuru, możliwość wprowadzania obrazów, werdykt, który można sprawdzić w alejce supermarketu, oraz agenta, który z każdym uruchomieniem poprawia się nieco.
Zapewnienie uczciwej porównywalności
Wszystko, co nie stanowiło SDK, musiało pozostać identyczne. Wszystkie trzy demo korzystają z jednego proxy LiteLLM – bramy kompatybilnej z OpenAI, która jednocześnie obsługuje endpoint Anthropic /v1/messages dla SDK Claude. Jeden plik .env zawiera klucz, podstawową adresację URL oraz nazwę modelu dla każdego z nich, przy czym modelami są Claude Sonnet 4.6, GPT-5.4 oraz Gemini 3.5 Flash. Sposób, w jaki każde SDK jest skierowane do tego proxy, ujawnia wiele informacji.
Każda demonstracja znajduje się w swoim własnym projekcie uv, więc można ją uruchomić bez instalowania zależności innych projektów. Tabela dodatków SFA została utworzona tylko raz na podstawie pliku PDF „Permitted-Additives”, który publikuje singapurska agencja żywnościowa, co dało plik sfa_additives.json (około 540 wpisów, z których około 270 zawiera numery E), a następnie skopiowano go bez zmian do każdego projektu. Obrazy testowe były również identyczne: dwa rzeczywiste produkty z Singapuru – torebka Milo 3in1 oraz puszka mleka Marigold HL.
Pozostaje więc tylko to, co faktycznie jest decyzją SDK: jak zdefiniowany jest narzędzie, jak dodawane są obrazy, jak skonfigurowany jest model, czy istnieje tekstowy wynik oraz jak można zobaczyć, co się wydarzyło.
Uwaga przed pokazaniem kodu. Poniższe fragmenty zawierają narzędzie recall_product oraz argument e_number_hint. Są one podstawą funkcji pamięci i samodoskonalenia opisanych dalej, więc na razie możesz je zignorować.
SDK Claude Agent od Anthropic
SDK Claude Agent jest bezpośrednio zintegrowane z Claude Code – narzędziem, które wiele osób już używa w terminalu, a ta decyzja wpływa na wszystko. Nie budujesz pętli z prostych elementów; korzystasz z gotowego, sprawdzonego narzędzia do zarządzania agentem, dostarczając mu swoje narzędzia i instrukcje. Wbudowane narzędzia (Read, Write, Edit, Bash, WebFetch) są już dostępne, model uprawnień oraz zarządzanie kontekstem są już rozwiązane, a twoje własne narzędzia są dodawane za pośrednictwem serwera MCP działającego wewnątrz twojego procesu. Wszystko działa asynchronicznie za pomocą anyio.
To, co kupujesz, to prawdziwy agent do pracy z komputerem, gotowy do użycia. Wszystko, co wymaga czytania plików, wykonywania poleceń w shellu, edycji kodu źródłowego lub przeglądania treści, dostępne jest od pierwszego dnia w wersji przeznaczonej do produkcji, ponieważ wykorzystuje tę samą infrastrukturę co Claude Code. MCP ma status elementu pierwszej klasy, dzięki czemu narzędzie stworzone przez Ciebie będzie działać bez zmian w Claude Code, Claude Desktop oraz w Twoim własnym aplikacji. Spośród tych trzech rozwiązań to właśnie ono opiera się na najbardziej rozwiniętym środowisku uruchamiania agentów.
Koszt pojawia się w narzędziach, gdzie ręcznie wpisujesz nazwę, opis oraz schemat:
@tool(
"check_sfa_additive",
"Check whether a food additive is permitted by the Singapore Food Agency, "
"using the full SFA permitted-additives list parsed from the official PDF. "
"Accepts an E-number ('E211') OR a name ('Sodium Benzoate', 'Soy Lecithin'). "
"If you pass a name and also know its E/INS number, set e_number_hint — an "
"unrecognised name that the hint resolves is REMEMBERED for next time.",
{"additive": str, "e_number_hint": str},
)
async def check_sfa_additive(args: dict) -> dict:
raw = args["additive"].strip()
hint = args.get("e_number_hint", "").strip()
entry = _resolve_additive(raw)
if not entry and hint:
entry = _resolve_additive(hint)
if entry: # learn: this label name -> this number, persisted to disk
num = entry["e_number"] or entry.get("ins") or ""
_MEMORY["learned_aliases"][_norm(raw)] = re.sub(r"\(.*\)", "", num).lower()
_save_memory(_MEMORY)
return _ok(_format_entry(entry, raw))
Ten słownik {arg: type} wymaga więcej wpisywania niż dwa pozostałe zestawy, ale nie pozostawia żadnych możliwości niejednoznaczności. Narzędzia są następnie dostępne przez serwer MCP wewnątrz procesu, a model odnosi się do nich za pomocą przedrostka mcp__<server>__<tool>, który musisz pamiętać podczas uzupełniania pola allowed_tools:
server = create_sdk_mcp_server(
name="sg-nutrition-tools",
version="1.0.0",
tools=[recall_product, check_sfa_additive, check_hcs, calculate_nutri_grade],
)
options = ClaudeAgentOptions(
system_prompt=SYSTEM_PROMPT,
mcp_servers={"sg": server},
allowed_tools=[
"mcp__sg__recall_product",
"mcp__sg__check_sfa_additive",
"mcp__sg__check_hcs",
"mcp__sg__calculate_nutri_grade",
],
model=CLAUDE_MODEL,
permission_mode="bypassPermissions",
max_turns=20,
# Point the bundled CLI at the LiteLLM proxy's Anthropic endpoint.
env={
**os.environ,
"ANTHROPIC_BASE_URL": BASE_URL,
"ANTHROPIC_AUTH_TOKEN": API_KEY,
},
)
Zdjęcia wkleja się w ten sam sposób „zrób to sam”. Nie istnieje argument image=. Funkcja query() przyjmuje asynchroniczny zbiór słowników z wiadomościami, więc samodzielnie tworzysz surowe bloki treści typu Claude – blok tekstowy obok bloku z obrazem:
async def message_stream():
yield {
"type": "user",
"message": {"role": "user", "content": [
{"type": "text", "text": "Investigate this nutrition label."},
{"type": "image", "source": {"type": "base64", "media_type": mime, "data": b64}},
]},
}
async with ClaudeSDKClient(options=options) as client:
await client.query(message_stream())
async for message in client.receive_response():
... # stream ToolUseBlock / TextBlock as they arrive
Ostry krawędź to model wiring. SDK uruchamia dołączony Claude Code CLI, który używa formatu wiadomości Anthropic, więc kierujesz go do proxy za pomocą zmiennych środowiskowych (ANTHROPIC_BASE_URL i ANTHROPIC_AUTH_TOKEN). Nie ma obiektu klienta do przekazania. Zaletą jest całkowicie widoczny cykl: wyświetlasz każdy ToolUseBlock w momencie jego przybycia i możesz na żywo obserwować rozwój cyklu dodawczego. Oto przykład działania na paczce Milo:
sausheong claude-demo % uv run python main.py ../milo.jpeg
Investigating image: ../milo.jpeg
────────────────────────────────────────────────────────────
I'll start by reading the label carefully, then run all checks in parallel.
**Reading from the label:**
- **Product:** Nestlé MILO 3in1
- **Net weight:** 27g powder sachet (add hot water to prepare — this is a **powder, not a ready-to-drink beverage**)
- **Ingredients:** Sugar, PROTOMAL® Malt Extract (Contains Barley), Skimmed Milk (Cow's Milk), Cocoa, Palm Oil, Minerals (Dicalcium Phosphate, Disodium Phosphate, Ferric Pyrophosphate), Resistant Dextrin, Flavourings, Vitamins (C, B3, D, B6, B2, B12)
- **Identifiable additives:** Dicalcium Phosphate (E341), Disodium Phosphate (E339), Ferric Pyrophosphate; Flavourings (generic — cannot identify specific ones)
Kicking off recall + HCS check + all additive checks simultaneously:
→ tool: recall_product({'product_name': 'Nestlé MILO 3in1'})
→ tool: check_hcs({'product_name': 'MILO 3in1'})
→ tool: check_sfa_additive({'additive': 'Dicalcium Phosphate', 'e_number_hint': 'E341'})
→ tool: check_sfa_additive({'additive': 'Disodium Phosphate', 'e_number_hint': 'E339'})
→ tool: check_sfa_additive({'additive': 'Ferric Pyrophosphate', 'e_number_hint': 'E450'})
All checks returned. Note: this is a **powder**, not a ready-to-drink beverage, so Nutri-Grade (which requires per-100ml liquid values) does **not apply** — I will skip `calculate_nutri_grade`.
---
## Reasoning
**Step 1 — Product recall.** This product has been seen before. The prior verdict is consistent with what I read now — I'll treat this fresh investigation as the authoritative one and use the prior as a cross-check.
**Step 2 — Label reading.**
- MILO 3in1 is a **27g powder sachet** — you add hot water to make a drink. It is classified as a "Tonic Food Drink" on the label. Because it is sold as a dry powder (not a pre-packaged ready-to-drink liquid), Nutri-Grade per-100ml calculation does not apply.
- Nutritional values per serving (27g): Energy 110 kcal, Total Fat ~2.4g, Saturated Fat ~1.2g, Total Sugars ~13.8g (of which Added Sugars ~10g), Sodium ~38mg.
- **Sugar is the #1 ingredient** — it appears first in the ingredient list, before the malt extract.
**Step 3 — Additives.**
- **Dicalcium Phosphate (E341):** SFA-permitted ✅ — used as a mineral/calcium source.
- **Disodium Phosphate (E339):** SFA-permitted ✅ — used as an acidity regulator/mineral.
- **Ferric Pyrophosphate:** SFA-permitted ✅ — used as an iron supplement/mineral source.
- **Resistant Dextrin:** A dietary fibre ingredient (prebiotic fibre), not a regulated additive — no E number, no SFA check needed.
- **Flavourings:** Generic label — cannot identify specific flavouring compounds; SFA check not possible.
- **Vitamins (C, B3, D, B6, B2, B12):** Added as nutritional fortification, not food additives in the regulatory sense. Riboflavin (B2) carries E101 when used as a colourant, but here it's explicitly declared as a vitamin supplement — standard and expected.
**Step 4 — Healthier Choice Symbol.** HCS certified ✅ (MILO 3in1 Activ-Go appears multiple times in the HPB dataset — `check_hcs`).
**Step 5 — Sugar content reality check.** Each 27g sachet contains ~13.8g total sugars (~10g added sugars). That's more than **half the sachet's weight is sugar**, and exceeds the WHO daily added-sugar guideline of 25g in less than one cup. This is label-read, not a tool finding.
---
## Verdict
### 🟢 GREEN — No Concern
- **All three declared additives are SFA-permitted** (Dicalcium Phosphate E341, Disodium Phosphate E339, Ferric Pyrophosphate) — `check_sfa_additive` ×3.
- **Carries the Healthier Choice Symbol** — HPB has certified MILO 3in1 Activ-Go — `check_hcs`.
- **Vitamins and minerals fortified** — B2, B3, B6, B12, C, D, plus calcium and iron — label.
- **Contains barley malt extract** — a whole-grain source of energy — label.
- **Resistant Dextrin** (prebiotic dietary fibre) is a functional ingredient, not a concern — label.
### 🟡 AMBER — Worth Knowing
- **Palm Oil present** — a saturated fat source. Saturated fat is 1.2g per sachet (~4.4g per 100g of powder). Not alarming at one serving, but worth knowing if you have multiple cups a day — label.
- **"Flavourings" are not specified** — cannot determine whether natural or artificial. No SFA check was possible — label.
- **Nutri-Grade does not apply here** — this is sold as a powder. If you reconstitute it and compare the drink to ready-to-drink alternatives, it would likely land in Grade C or D territory based on sugar content, but no regulatory grade is required on the packet.
### 🔴 RED — Genuinely Concerning
- **Sugar is the #1 ingredient** — it appears first in the list, meaning it is the dominant ingredient by weight. Each sachet delivers **~13.8g total sugars / ~10g added sugars** — label. That's 40% of the WHO's recommended 25g/day added-sugar limit in a single cup. If you're drinking 2–3 sachets a day (as Nestlé's own label suggests for daily energy), you are consuming **20–30g of added sugar from MILO alone**, likely exceeding the daily limit.
- **Marketing framing vs. nutritional reality:** The packet prominently says "Nourishing Energy" and shows vitamins, but the sugar load is the dominant nutritional feature. The fortification (vitamins, minerals) does not offset this — label.
**Bottom line for a Singapore shopper:** MILO 3in1 is safe from an additives and regulatory standpoint — everything checks out with SFA and HPB. But it is a **sugar-heavy product** dressed up in health language. Treat it as an occasional treat rather than a daily nutritious breakfast drink, especially for children.
Gdzie to sprawia problemy. Nie ma wbudowanego, strukturalnego formatu wyjściowego, więc otrzymujesz tekst, który musisz albo przetworzyć, albo wymusić określoną strukturę, co stanowi największą różnicę w codziennej pracy w porównaniu z SDK OpenAI. Schematy są ręcznie definiowane, więc trzeba napisać więcej kodu i utrzymywać synchronizację z każdą funkcją. Połączenie modeli odbywa się przez środowisko, a proxy, do którego się odwołujesz, musi oferować endpoint w formacie Anthropic /v1/messages, ponieważ sam endpoint kompatybilny z OpenAI nie wystarcza. Traktuj listę allowed_tools jako z góry zatwierdzone narzędzia, a nie jako środowisko testowe: oznacza ona „pomijaj prośby o potwierdzenie dla tych narzędzi”, a nie „agent może widzieć tylko te narzędzia”; osoby, które interpretują ją jako listę dozwolonych elementów, będą zaskoczone. Zapomnij o prefiksie mcp__sg__ – w takim przypadku narzędzie po prostu pozostanie niezatwierdzone, bez żadnego błędu. Ślad wydajnościowy jest również większy, ponieważ uruchamiasz w tle środowisko Claude Code zamiast dokonywać prostego wywołania API.
Wybierz to wtedy, gdy agent musi obsługiwać maszynę – to oznacza czytanie i zapisywanie plików, wykonywanie poleceń w shellu, edycję bazy kodu lub przeglądanie, czyli każde zadanie, w którym wbudowane narzędzia Claude Code oszczędzają czas na tworzenie środowiska sandbox. Jest to również naturalny wybór, jeśli już korzystasz z MCP lub tworzysz coś, co ma przypominać Claude Code. Pętla strumieniowa jest łatwa do obserwacji, co jest przydatne dla agentów działających przez długi czas.
Wybierz to, gdy potrzebujesz lekkiego pętla wywołań funkcji, która zwraca zstrukturyzowany obiekt – to właśnie tam doskonale sprawdza się SDK OpenAI. Wybierz inne rozwiązanie, jeśli nie możesz dostarczyć punktu końcowego w formacie Anthropic lub jeśli małe wymagania co do zależności jest istotne. Taka prosta operacja typu „wywołaj trzy narzędzia, zwróć obiekt Pydantic” wymaga znacznie mniej zasobów.
SDK OpenAI Agents
SDK OpenAI to lekka, celowo napisana w stylu Pythona otoczka wokół tego mechanizmu, która w pełni opiera się na samym języku. Wskazówki typów przekształcają się w schematy narzędzi, opisy dokumentacji w ich opisy, a modele Pydantic w umowę wyjściową. Nic nie narzuca określonego układu projektu – nie ma oddzielnego środowiska wykonawczego ani konieczności korzystania z MCP. Piszesz funkcje i modele, tworzysz Agenta i przekazujesz go do Runner.run. Celem jest jak najkrótsza odległość pomiędzy funkcją w Pythonie a działającym agentem.
Jego najlepszą cechą jest możliwość wysyłania i odbierania danych w formacie tekstowym. Wystarczy指定了 output_type=YourModel, a w odpowiedzi otrzymuje się zweryfikowany obiekt w języku Python, a nie zbiór danych, który można by błędnie uznać za JSON; SDK tworzy zapytanie, analizuje odpowiedź, weryfikuje ją i ponownie wysyła dane do modelu, jeśli ich struktura jest nieprawidłowa. Schematy uzyskiwane bezpłatnie z wskazówek typów, w połączeniu z bezpłatną panelą analityczną na własnym backendzie OpenAI, sprawiają, że to najszybszy sposób na stworzenie zorganizowanego, łatwego do monitorowania agenta. Gdy zadaniem jest „weź te dane wejściowe i daj mi tekstową odpowiedź”, żaden inny zestaw narzędzi nie jest tak bezpośredni.
Narzędzia te w ogóle nie wymagają tworzenia schematów:
@function_tool
async def check_sfa_additive(additive: str, e_number_hint: str = "") -> str:
"""Check whether a food additive is permitted by the Singapore Food Agency.
Looks the additive up in the full SFA permitted-additives list (parsed from
the official SFA PDF). Accepts either an E-number or a plain-English name as
printed on a Singapore label.
Args:
additive: An E-number ('E211', 'e211', 'en:e211') OR an additive name
('Sodium Benzoate', 'Soy Lecithin', 'MSG').
e_number_hint: Optional. If you pass a name and also know its E/INS
number, supply it here. If the name isn't recognised but the number
is, the mapping is REMEMBERED so the name resolves directly next time. """
...
Dekorator czyta wskazówki typowe oraz sekcję Args w dokumentacji, a następnie tworzy schemat JSON, dzięki czemu nie ma potrzeby ręcznego utrzymywania żadnych informacji.
Największe korzyści daje to w wyniku generowanym. Werdykt jest reprezentowany jako model Pydantic:
class NutritionVerdict(BaseModel):
reasoning: str # declared first: the model works out loud before committing
product_name: str
summary: str
green: list[Finding]
amber: list[Finding]
red: list[Finding]
recommendation: str
Przy użyciu output_type=NutritionVerdict funkcja zwraca zweryfikowany obiekt, bez konieczności analizy tekstu ani ryzyka błędów. Ciekawym sposobem jest umieszczenie reasoning na początku – strukturyzowany wynik służy jednocześnie jako notatnik, dzięki czemu model może przemyśleć rozwiązanie przed podjęciem ostatecznej decyzji, a Ty zachowujesz uporządkowany obiekt wraz z uzasadnieniem.
Łączenie modelu z danymi wejściowymi w postaci obrazów jest najprostsze ze wszystkich trzech przypadków:
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
model = OpenAIChatCompletionsModel(model=OPENAI_MODEL, openai_client=client)
agent = Agent(name="SG Nutrition Investigator", model=model,
instructions=INSTRUCTIONS, output_type=NutritionVerdict,
tools=[recall_product, check_sfa_additive, check_hcs, calculate_nutri_grade])
user_input = [{"role": "user", "content": [
{"type": "input_text", "text": "Investigate this nutrition label."},
{"type": "input_image", "image_url": _data_url(image_path)}, # base64 data URL
]}]
result = await Runner.run(agent, input=user_input)
verdict: NutritionVerdict = result.final_output
To jest klient AsyncOpenAI przeznaczony do pracy z proxyem, otoczony warstwą OpenAIChatCompletionsModel, z elementem input_image zawierającym zdjęcie. Bez żadnych komplikacji.
Uwagi. Wywołania narzędzi są domyślnie realizowane równolegle, więc model bez problemu uruchamia kilka wywołań check_sfa_additive jednocześnie. Nasze narzędzia są asynchroniczne i nie powodują żadnych efektów ubocznych, co stanowi zaletę. Narzędzia, które modyfikują wspólny stan, utrzymują połączenie niereentrantne lub zależą od określonej kolejności, będą zachowywać się niewłaściwie, a błędy pojawiają się sporadycznie i zależą od czasu – to najgorszy scenariusz. Należy albo sprawić, by narzędzia były bezpieczne w warunkach równoległej pracy, albo ograniczyć działanie modelu.
Śledzenie ma swoje wady. Panel sterowania jest doskonały, ale dane śledzenia trafiają do własnego punktu przyjmowania danych OpenAI, a za proxyem third-party klucz wydany przez proxy nie może tam się autoryzować. Dlatego po użyciu set_tracing_disabled(True) najlepszy narzędzie do obserwowalności znika w jednej linii kodu. Z dala od api.openai.com trzeba polegać na OpenTelemetry lub własnych rozwiązaniach do logowania. Istnieją jeszcze inne problemy – za proxyem potrzebny jest OpenAIChatCompletionsModel, ponieważ domyślna ścieżka API Responses skierowana jest do punktów końcowych OpenAI, a niewłaściwy wybór powoduje kłopotliwe błędy. Schemat output_type musi spełniać zasady trybu ścisłego, więc modele z głębokim wnestowaniem lub wieloma połączeniami mogą wywołać ponowne próby walidacji; z tego powodu Finding i NutritionVerdict pozostają prostsze. W pudełku nie znajdują się żadne narzędzia do pracy z komputerem, więc nie ma systemu plików, wiersza poleceń ani przeglądarki, chyba że je dodasz.
Oto wynik dla saszetki Milo:
sausheong openai-demo % uv run python main.py ../milo.jpeg
Investigating image: ../milo.jpeg
────────────────────────────────────────────────────────────
Product: Nestlé MILO 3 in 1 Activ-Go
Reasoning: I read the sachet as **Nestlé MILO 3 in 1 Activ-Go**. The front says “goodness of malt, milk & cocoa” and the back says “MILO Ionic Food Drink,” so this is a **powdered drink mix**, not a ready-to-drink beverage. Because it is not sold as a beverage with per-100ml nutrition for the prepared drink as consumed, I did **not** calculate Nutri-Grade; that tool is only for beverages.
I first checked whether this product had been investigated before. A prior record existed, and it broadly matched what I can read here: a sweetened powdered malt-cocoa-milk drink sachet with permitted phosphate additives, relatively high in sugar for a single sachet, and not found in the HCS database. I used that only as background and then re-read this label fresh.
From the nutrition panel, I can read:
- Serving size: **1 sachet (27g)**
- Servings per package: **1**
- Per 100g / per serving shown side by side
- **Total sugars: 50.1g per 100g; 13.8g per serving**
- **Saturated fat: 0.5g per 100g; 1.2g per serving**
This is a powder, so the relevant direct reading is per 100g, not per 100ml.
I can read the ingredient list as:
**Sugar, Protomalt™ Malt Extract (contains barley), skimmed milk/cow’s milk, cocoa, palm oil, minerals (dicalcium phosphate, disodium phosphate), fibre (pyrophosphate), resistant dextrin, flavourings, vitamins (C, B3, D, B6, B2, B12).**
For additives, I checked each identifiable additive individually where possible:
- **Dicalcium phosphate**: checked and found **permitted by SFA**. That lands in GREEN.
- **Disodium phosphate**: checked and found **permitted by SFA**. That also lands in GREEN.
- The label also contains the broader terms **“phosphates”** and **“pyrophosphate”/“fibre (pyrophosphate)”** in wording around ingredients, but the image does not clearly identify a specific additive code for the pyrophosphate entry, and the generic umbrella term “phosphates” is not reliable enough on its own. I therefore do not treat the generic term as confirmed permitted just from the broad word alone. I only rely on the specifically named phosphates I could check.
- **Flavourings** is too generic to identify a specific additive, so I could not check it individually.
- The vitamins and minerals are nutrients rather than red-flag food additives in the SFA additive sense.
I also checked for the **Healthier Choice Symbol** using the product name. It was **not found** in the HCS database.
Main nutritional takeaways from the label:
- Sugar is the **first ingredient**, which usually means it is the largest ingredient by weight.
- The product contains **50.1g sugar per 100g** powder, and **13.8g sugar per 27g sachet**. That is quite a lot for one small sachet drink.
- Saturated fat is **1.2g per sachet**, which is not extreme, but the bigger concern here is sugar.
So the overall picture is: the identifiable phosphate additives appear permitted, but nutritionally this is still a **sweetened convenience drink mix** rather than a lower-sugar everyday option.
Summary: This is a powdered MILO drink sachet, not a ready-to-drink beverage. The clearly identifiable phosphate additives on the label are permitted by SFA, but sugar is the first ingredient and the product contains 50.1g sugar per 100g, or 13.8g per 27g sachet. It was not found in the Healthier Choice Symbol database.
🟢 Dicalcium phosphate is permitted by SFA. [check_sfa_additive]
🟢 Disodium phosphate is permitted by SFA. [check_sfa_additive]
🟢 This is a powdered drink mix rather than a ready-to-drink beverage, so Nutri-Grade was not applicable here. [label]
🟡 Generic terms such as “flavourings” and the unclear “fibre (pyrophosphate)” wording are not specific enough to confirm exact additive identities from the image alone. [label]
🟡 The product was not found in the Healthier Choice Symbol database. [check_hcs]
🟡 Saturated fat is 1.2g per 27g sachet (0.5g per 100g listed on the label panel image). [label]
🔴 Sugar is the first ingredient on the label. [label]
🔴 Total sugars are 50.1g per 100g and 13.8g per 27g sachet, which is high for a small single-serve drink mix. [label]
Recommendation: Fine as an occasional sachet drink if convenience matters, but not the best everyday choice if you are trying to reduce sugar. If you drink MILO often, consider using plain MILO powder with your own milk and less sugar, or choose a lower-sugar version.
Wybierz to wtedy, gdy zadanie jest zorganizowane w formie strukturyzowanych elementów, takich jak klasyfikacja, wydobywanie informacji, ocenianie lub wydawanie werdyktów, gdzie tekst zapisany w formie typów danych jest lepszy od zwykłego tekstu, a chcesz użyć jak najmniej kodu w Pythonie. Zespół, który lubi wskazówki typowe, będzie z tego zadowolony, a dzięki backendowi OpenAI darmowe śledzenie działań ułatwia debugowanie agenta wykonującego wiele kroków.
Pomijaj to wtedy, gdy twoje narzędzia nie mogą być bezpieczne pod względem równoczesności i wolisz uniknąć problemów z domyślnym trybem równoległym, gdy potrzebujesz możliwości obserwacji, ale pracujesz za bramką niebędącą OpenAI (wtedy śledzenie znika), lub gdy agent musi od razu korzystać z narzędzi systemu plików i wiersza poleceń – co jest domeną Claude’a. W przypadku kilku współpracujących agentów pod ścisłą kontrolą przepływu danych, lepszym rozwiązaniem jest ADK, i to jest trzeci zestaw narzędzi.
Google’s Agent Development Kit (ADK)
Ze wszystkich trzech ADK jest tym, który naprawdę stanowi ramy, mając określone zasady działania, podczas gdy pozostałe pozostają bardziej elastyczne. Zawiera agenty, sesje, Runnera, SessionService oraz wyraźne schematy pracy wielu agentów za pomocą SequentialAgent, ParallelAgent i agentów pętlowych. Przeddefiniowana struktura projektu umożliwia narzędziom znalezienie odpowiedniego agenta, a adk web otwiera lokalną interfejs czatową z inspektorem zdarzeń. Narzędzia to zwykłe funkcje w Pythonie, udokumentowane w stylu Google docstrings, bez dekoratorów ani słowników schematów, a wrapper LiteLlm czyni z niego najbardziej niezależny od konkretnego dostawcy wybór.
ADK to architektura dla systemów, a nie skryptów. Gdy „agent” oznacza w rzeczywistości kilka agentów – takich jak planer przekazujący zadania pracownikom, sekwencyjny łańcuch przetwarzania lub równoległe rozproszenie zadań – ADK oferuje je jako elementy pierwszej klasy, które można łączyć, oszczędzając w ten sposób konieczności ręcznego projektowania struktury sterowania. Sesje są wbudowane, interfejs debugowania należy do najlepszych w tej kategorii, a model niezależny od dostawcy zapobiega przywiązaniu się do jednego producenta. System ten jest zaprojektowany tak, by rozwijać się w złożoną, stanową aplikację wieloagentową.
Definicje narzędzi są tutaj najprostsze:
async def check_sfa_additive(additive: str, e_number_hint: str = "") -> dict:
"""Check whether a food additive is permitted under Singapore Food Agency rules.
Looks the additive up in the full SFA permitted-additives list (parsed from
the official SFA PDF). Accepts either an E-number or a plain-English name as
printed on a Singapore label.
Args:
additive: An E-number ('E211', 'e211', 'en:e211') OR an additive name
('Sodium Benzoate', 'Soy Lecithin', 'MSG').
e_number_hint: Optional E/INS number for when you pass a name. If the
name isn't recognised but the number is, the mapping is REMEMBERED
so the name resolves directly next time.
Returns:
dict with the input, resolved e_number/name, permitted status, schedule
and any consumer note. found=False if it is not in the SFA list.
"""
...
Schemat jest tworzony na podstawie tego dokumentu typu Google Args i Returns, co oznacza, że jego jakość ma rzeczywiste znaczenie. Niejasny dokument bezpośrednio utrudnia modelowi wybór narzędzi, dlatego właśnie ten dokument stanowi rzeczywisty kontrakt.
Aby adk web mógł znaleźć Twój root_agent, projekt musi mieć określoną strukturę pakietów:
adk-demo/
sg_nutrition_investigator/
__init__.py # from . import agent
agent.py # tools + root_agent
main.py # standalone Runner + InMemorySessionService
root_agent = LlmAgent(
name="sg_nutrition_investigator",
model=LiteLlm(model="openai/" + GEMINI_MODEL, api_base=BASE_URL, api_key=API_KEY),
instruction=INSTRUCTION,
tools=[FunctionTool(recall_product), FunctionTool(check_sfa_additive),
FunctionTool(check_hcs), FunctionTool(calculate_nutri_grade)],
)
# image input — the cleanest of the three:
message = types.Content(role="user", parts=[
types.Part(text="Investigate this nutrition label."),
types.Part.from_bytes(data=Path(image_path).read_bytes(), mime_type=mime),
])
Model jest przekazywany przez narzędzie ADK wykorzystujące obudowę LiteLlm, przy czym przedrostek openai/ sprawia, że LiteLlm używa protokołu kompatybilnego z OpenAI w komunikacji z proxy. Przekazywanie obrazów za pomocą types.Part.from_bytes jest najbardziej wygodne z tych trzech metod, a adk web oferuje najlepsze wbudowane środowisko do rozwoju w ramach tego porównania.
Uwagi ważne. Największy problem dotyczy masy. Poza adk web trzeba podłączyć Runner, SessionService oraz jasno określone ID aplikacji, użytkownika i sesji przed wysłaniem pierwszej wiadomości – to mnóstwo formalności w porównaniu z zaledwie kilkoma linijkami potrzebnymi w innych rozwiązaniach. Układ kodu również ma znaczenie. Linijka from . import agent w pliku __init__.py jest sposobem, w jaki adk web odkrywa root_agent, a każde odstępstwo od tej struktury zakłóca to proces odkrywania. litellm generuje komunikaty dotyczące nieużywanych backendów (bezpieczne ostrzeżenia typu bedrock i sagemaker oraz komunikaty „no module named botocore”), natomiast ADK dodaje ostrzeżenie o schemacie [EXPERIMENTAL], w rezultacie czego oba te elementy są wyłączane już przy imporcie. Strukturyzowany wynik jest również bardziej skomplikowany, ponieważ response_schema Gemini jest bardziej wrażliwy za proxyem niż output_type OpenAI, dlatego w tym przykładzie użyto oceny tekstowej uzyskanej na podstawie promptu. Szczerze mówiąc, to tak samo zależy od proxya, jak i od ADK. Ostatnia uwaga: w wersji LiteLlm w połączeniu z Gemini-flash agent opisywał swoje wyniki słabiej niż pozostali przy tym samym promptie, co pokazuje, że zachowanie zależy od modelu i sposobu połączenia, a nie tylko od SDK.
Wynik dla Milo sachet:
sausheong adk-demo % uv run python main.py ../milo.jpeg
Investigating image: ../milo.jpeg
────────────────────────────────────────────────────────────
→ tool: recall_product({'product_name': 'Nestle MILO 3 in 1'})
→ tool: check_sfa_additive({'e_number_hint': 'E341', 'additive': 'Dicalcium Phosphate'})
→ tool: check_sfa_additive({'additive': 'Disodium Phosphate', 'e_number_hint': 'E339'})
→ tool: check_sfa_additive({'additive': 'Ferric Pyrophosphate'})
→ tool: check_hcs({'product_name': 'Nestle MILO 3 in 1'})
→ tool: calculate_nutri_grade({'saturated_fat_per_100ml': 0.5, 'sugar_per_100ml': 6.1})
## Reasoning
We investigated the label of **Nestle MILO 3 in 1 (with Activ-Go)**. Here is our step-by-step analysis:
1. **Product Categorisation & Reconstitution**:
* This is a dry beverage powder sold in single-serving 27g sachets.
* The nutritional information panel provides two columns: "Per Serving 27g" (the dry sachet) and "Per 100ml*" (as reconstituted by adding 200ml of hot water).
* For the **Singapore Nutri-Grade** system, the grading is calculated based on the beverage *as reconstituted* according to the directions.
2. **Sugar & Saturated Fat Analysis (Per 100ml prepared)**:
* **Total Sugars**: **6.1g per 100ml** (of which 4.8g is Added Sugar).
* **Saturated Fat**: **0.5g per 100ml**.
* Feeding these values into the Nutri-Grade calculator yields **Nutri-Grade C** (due to the sugar content being > 5g/100ml). Grade C beverages are classified as "less healthy" and must display the Nutri-Grade label at retail.
3. **Ingredients & Additives Analysis**:
* **Sugar is the #1 Ingredient**: Refined sugar is listed first on the ingredients list, meaning it is the largest ingredient by weight in this packet—even ahead of malt extract and milk powder.
* **Additives**:
* **Dicalcium Phosphate** (E341(ii)) and **Disodium Phosphate** (E339(ii)) are SFA-approved food additives used as stabilizers and emulsifiers.
* **Ferric Pyrophosphate** is an SFA-approved mineral nutrient used to fortify the drink with Iron.
* **Healthier Choice Symbol (HCS)**: The packet displays the red HCS logo. This is because it is formulated to be "25% lower in sugar" *compared to regular malted beverages*. However, in absolute terms, it still carries enough sugar to land in Nutri-Grade C.
---
## Verdict
### 🟢 Green Findings
* **Fortified with Vitamins & Minerals** `[label]`: Contains B-vitamins (B2, B3, B6, B12), Vitamin C, Vitamin D, Calcium, and Iron (via *Ferric Pyrophosphate* `[check_sfa_additive]`).
* **Contains Soluble Fibre** `[label]`: Features *Resistant Dextrin*, a prebiotic soluble dietary fibre (1.1g per serving) that supports gut health.
* **SFA-Approved Additives** `[check_sfa_additive]`: Phosphates used for stabilizing and emulsifying (*Dicalcium Phosphate* and *Disodium Phosphate*) are fully permitted.
* **Healthier Choice Certified** `[check_hcs]`: Carries Singapore's HCS logo for having at least 25% less sugar than standard malted chocolate drinks.
### 🟡 Amber Findings
* **Nutri-Grade C** `[calculate_nutri_grade]`: When prepared as instructed, it gets a **Grade C** because of its **6.1g of sugar per 100ml**. Grade C drinks are in the "less healthy" bracket.
* **Contains Palm Oil** `[label]`: Palm oil is added to give a rich mouthfeel, contributing **1.2g of saturated fat per serving** (0.5g/100ml).
### 🔴 Red Findings
* **Sugar is the Main Ingredient** `[label]`: Sugar is listed as the very first ingredient on the label, which means there is more plain sugar by weight than malt extract (*PROTOMALT*) or milk powder.
* **High Sugar Load per Cup** `[label]`: A single small 27g sachet contains **13.8g of total sugar** (equivalent to about **3 teaspoons of sugar**), of which **10.8g** (approx. 2.5 teaspoons) is added refined sugar. Drinking multiple cups a day can quickly max out your recommended daily limit for added sugars.
Wybierz ADK wtedy, gdy budujesz system: z wieloma współpracującymi agentami, wyraźnymi sekwencyjnymi, równoległymi lub pętlowymi procesami pracy, rzeczywistym stanem sesji oraz możliwością wymiany modeli między różnymi dostawcami. Narzędzie adk web zwraca się już podczas rozwoju, a architektura rekompensuje początkowy koszt w miarę rozszerzania projektu.
Pomijaj go wtedy, gdy istnieje tylko jeden prosty agent. Kod bazowy do uruchamiania i zarządzania sesją, wraz z określonym układem, stanowią dodatkowe obciążenie, którego nigdy nie uda ci się zrekompensować. Aby uzyskać najszybszy wynik, użyj SDK OpenAI, a dla agenta korzystającego z komputera z wbudowanymi narzędziami – rozwiązania od Claude’a. ADK uzasadnia swoją złożoność przy dużych skali, natomiast w mniejszych projektach jest to więcej niż potrzebny framework.
Uruchamianie demonstracji
Gdy wszystkie trzy agenty zostały stworzone, oto jak je uruchomić. Każdy z nich to projekt uv, a każdy z nich czyta plik .env znajdujący się w katalogu głównym, który zawiera klucz proxy, podstawową adresację URL oraz nazwy trzech modeli:
cd openai-demo # or claude-demo, or adk-demo
uv run python main.py ../milo.jpeg
uv run python main.py ../hl.jpeg
Aby zregenerować tabelę SFA z pliku PDF, uruchom uv run --with pdfplumber python build_additives.py. Podaj ścieżkę do własnego zdjęcia etykiety. Dwie dołączone etykiety to prawdziwe produkty z Singapuru, które uzyskują oceny zgodne z oczekiwaniami: mleko otrzymuje ocenę Nutri-Grade B, a Milo w postaci proszku po przygotowaniu otrzymuje ocenę C.
Przekraczanie granic pojedynczego testu
Demo pokazujące jeden czysty proces ukrywa najciekawsze aspekty. Trzy dodatki, identyczne pod względem kształtu we wszystkich SDK, sprawiają, że agenci są bardziej realistyczni, a każdy z nich mówi coś o SDK, na którym są oparte.
Prawdziwe dane. Sprawdzanie dodatków to nie jakiś zabawny słownik z siedmioma hasłami. Skrypt build_additives.py analizuje oficjalny plik PDF SFA, w którym trzy tabele wykorzystują trzy różne układy kolumn (co samo w sobie stanowi wyzwanie), i przekształca je w około 540 dodatków. Podczas ładowania każda demonstracja tworzy znormalizowany indeks nazw, dzięki czemu oznaczenie „monosodowy glutaminian” odpowiada oficjalnemu określeniu z PDF, czyli „Monosodium L-glutamate”. Indeks numerów E/INS, oparty na numerze bazowym, umożliwia znalezienie pozycji „500” również w wersji „500(ii)”. Krótka tabela obsługuje autentyczne slanga nieobecne w PDF, takie jak „MSG” i „witamina C”. Wszystko, co rzeczywiście nie znajduje się na liście, jest oznaczane jako zwykłe „nie ma na liście”, a nigdy jako fałszywe „dozwolone”.
Pamięć i uczenie się. Te dwa aspekty najlepiej rozumieć razem:
- Wyjaśnij. Każdy agent pokazuje swój tok rozumowania – w przypadku OpenAI jako polе
reasoningz wpisanym tekstem, a w przypadku Claude i ADK jako sekcję## Reasoningna początku. - Przypomnij. Najpierw uruchamiana jest funkcja
recall_product, która przywołuje wszelkie wcześniejsze werdykty dotyczące tego samego produktu, a każde uruchomienie zapisuje swój własny wynik. Jeśli jeden etykiet jest sprawdzany dwukrotnie, druga próba porównuje się z pierwszym wnioskiem. - Naucz się. Jeśli etykieta wyświetli nazwę, której tabela nie rozpoznaje, a model dostarczy poprawną liczbę za pomocą
e_number_hint, powiązanie nazwy z liczbą jest zapisywane w plikuagent_memory.json. Podczas następnego uruchomienia ta nazwa zostanie rozpoznana bez konieczności pytania modelu.
To jest uczenie się na poziomie systemu. Wagi nigdy się nie zmieniają, a mimo to agent doskonali swoje dane i narzędzia na podstawie doświadczeń. Jest to praktyczny i osiągalny rodzaj uczenia się, w odróżnieniu od drobnej kalibracji, której żaden z tych zestawów nie realizuje w czasie działania. Każdy z nich zawiera wbudowaną warstwę sesji, którą można wykorzystać do przechowywania danych produkcyjnych (np. SQLiteSession od OpenAI, magazyn sesji w Claude, SessionService w ADK), a plik JSON po prostu sprawia, że demonstracja jest przenośna i łatwa do sprawdzenia.
Im więcej etykiet odczytuje, tym lepiej radzi sobie. Zdjęcie, którego nazwy składników model przekształca na liczby, uczy system nowego aliasu, a każdy zbadany produkt staje się czymś, co kolejna sesja może przywołać. Gdy po raz pierwszy pojawia się „fosforan dwuzasadowy”, sesja polega na tym, że model przekształca go na E339; później tablica deterministyczna po prostu wie to, więc proces jest szybszy, tańszy i powtarzalny bez konieczności wywoływania modelu. W miarę rozszerzania się listy produktów plik agent_memory.json przekształca się w słownik aliasów oraz historię decyzji, które sam agent zebrał. Gdy cała flota korzysta z jednego wspólnego pliku pamięci, nazwa poznaną przez jednego agenta staje się znana wszystkim. Model pozostaje nieruchomy, natomiast agent – nie.
Ostatni szczegół z rzeczywistych testów: gdy poproszono o podanie numeru E wraz z nazwą, wszystkie trzy modele poprawnie to zrobiły, przekształcając „Fosforan dwuzasadowy” na E339 bez żadnej pomocy. To właśnie ten mechanizm pełni swoją funkcję – ogólna wiedza modeli uzupełnia to, czego nie obejmuje deterministyczne wyszukiwanie, a system zapamiętuje wynik.
Kto dostarcza co
Gdy wszystkie trzy agenty zostaną stworzone, uruchomione i rozbudowane, można przedstawić całą strukturę i oznaczyć, co dokładnie dostarczyło każde SDK w porównaniu z tym, co trzeba było stworzyć ręcznie. Wyobraźmy sobie siatkę, w której zielony kolor oznacza, że SDK to dostarcza, żółty – że dostarcza to częściowo, a czerwony – że trzeba to stworzyć samodzielnie. Komponenty dzielą się na te same trzy warstwy: warstwa rozwoju służąca do tworzenia agentów, warstwa czasu rzeczywistego do ich obsługi oraz warstwa sterowania do zarządzania flotą. SDK znajdują się w pierwszej warstwie.
Jeśli spojrzysz na warstwę rozwoju, prawie wszystko ma kolor zielony; zestawy narzędzi są niemal w pełni zgodne co do budowy jednego agenta. Jeśli jednak przyjrzysz się dwóm warstwom poniżej, obraz się odwraca: kilka zielonych lub pomarańczowych komórek na brzegach (procesy pracy i ocena ADK oraz śledzenie akcji OpenAI) unosi się na morzu czerwieni, które jest wspólne dla wszystkich trzech. To kontrast stanowi prawdziwy wniosek. Co do budowy agenta są zgodni, natomiast jego uruchamianie i zarządzanie pozostawiają to tobie.
Luki w SDK
Warstwa rozwoju to to, co SDK upraszczają. Warstwy czasu wykonywania i sterowania w nich w większości brakuje, a realistycznie rzecz biorąc, nie to właśnie SDK mają zapewnić.
Zacznij od problemów, które pojawiły się już podczas budowy demonstracyjnej. Jeden z nich to tool gateway – warstwa runtime odróżnia go od zwykłego wywołania narzędzia. Narzędzie jest wiernie wywoływane przez system, ale nic nie jest robione, aby zapewnić jego niezawodność. Na przykład API HCS z data.gov.sg czasami zwraca kod 503 wraz z treścią w formacie HTML, a proste wywołanie response.json() powodowało przerwanie całego procesu (lekcja nauczona boleśnie). Rozwiązaniem okazały się pomocnik _safe_json, czas oczekiwania wynoszący dziesięć sekund oraz rozwiązania awaryjne typu „nie ma w liście”, dzięki czemu niestabilny dostawca usług staje się jedynie informacją, a nie przyczyną zatrzymania agenta. Powtórne próby, strategie opóźniania oraz kształtowanie błędów wewnątrz narzędzi to zadania, które powinien przejąć właśnie gateway.
Drugą lukią jest pamięć zarządzana. Wszystkie trzy rozwiązania zawierają warstwę sesji, która reprezentuje stan rozmowy na jednym węźle, ale nie jest to to samo co aplikacja przechowująca dane w pamięci, do której może uzyskać dostęp cała grupa agentów. Plik agent_memory.json tworzony w tym procesie (uczone aliasy, historia recall_product, zapisy ulepszające agenta za każdym razem po nadaniu etykiety) stanowi logikę specyficzną dla danego domeny, a stwierdzenie „im więcej uruchamiasz, tym lepiej” nie jest cechą charakterystyczną żadnego gotowego narzędzia. Podobnie jest z wykorzystaniem rzeczywistych danych – analiza pliku PDF SFA na ponad 540 strukturalnych elementów, tworzenie znormalizowanego indeksu oraz wyszukiwanie według numerów bazowych: nic z tego nie należy do zakresu funkcji SDK, a dostarczanie agentowi rzeczywistych danych to wzorzec, który musisz sam skonfigurować, a nie przełącznik, który można po prostu włączyć.
Bезpieczeństwo równoczesnego wykonywania narzędzi jest gorsze niż zwykłe brak obsługi, ponieważ sam framework generuje to zagrożenie. Domyślnie SDK OpenAI uruchamia niezależne wywołania narzędzi równolegle, a to od Ciebie zależy, jak sprawić, by Twoje narzędzia były w tym kontekście bezpieczne. Jeszcze jedna bieżąca kwestia: wyświetlanie wyniku i jego zapisywanie w dowolnym miejscu to zwykły kod aplikacji, którego SDK w ogóle nie dotyka.
Patrząc na warstwę czasu wykonywania, agent potrzebuje przede wszystkim wykonywania w chmurze – sposobu na uruchomienie go z czegoś innego niż sesja terminalowa, z możliwością wielu równoczesnych procesów i skalowalnością w tle. Potrzebuje również identyfikatora obciążenia – danych uwierzytelniających przekazywanych narzędziom, aby połączenia były realizowane jako określone obciążenie, a nie poprzez klucz API ukryty w zmiennych środowiskowych. Co więcej, wymagane są trwałe, możliwe do wznowienia pętle, dzięki którym awaria w połowie procesu może być kontynuowana zamiast restartować całe wykonywanie. Żadna z tych funkcji nie istnieje w skrypcie na laptopie, a żadna z nich nie jest obiecywana przez SDK. Warstwa czasu wykonywania musi również umożliwiać skalowanie agentów wraz ze wzrostem obciążenia.
W płaszczyźnie sterowania wszystkie trzy narzędzia praktycznie nic nie robią. Ewaluacja to pierwszy przypadek: stwierdzenie „działało bez błędów” nie oznacza, że „było poprawne”, a właściwe mierzenie jakości agenta w dużej mierze zależy od ciebie. ADK stanowi częściową wyjątkową sytuację dzięki swojemu frameworkowi do ewaluacji, podczas gdy pozostałe dwa pozostawiają tę kwestię otwartą.
Następnie mamy zasady bezpieczeństwa oraz ochronę przed wstrzykiwaniem poleceń. Każdy wynik narzędzia to niezaufany dane wracające do modelu, a zdjęcie z etykietą lub odpowiedź API mogą zawierać instrukcję typu „zignoruj swoje zasady”. Zakres ochrony jest nierównomierny i nic nie jest automatyczne, więc model zagrożeń należy do ciebie.
Następnie pojawia się tożsamość agenta wraz z definiowaniem zakresu uprawnień. Te narzędzia umożliwiają ustawienie postaci agenta, ale nie informują o jego statusie jako głównego elementu katalogu ani o tym, do czego ma dostęp, więc to na Ciebie spada obowiązek powiązania go z rzeczywistym właścicielem i ograniczenia jego dostępu.
Połączenie z jednym serwerem MCP to inna sprawa, ponieważ wszystkie trzy oferują odpowiedni klient. Natomiast rejestr narzędzi i MCP, który kataloguje i wersjonuje narzędzia oraz zarządza zespołem serwerów MCP poprzez funkcje wykrywania, agregacji, zarządzania uprawnieniami dla poszczególnych serwerów oraz sprawdzania ich stanu, ponownie pozostawia się Tobie do realizacji.
Ta sama luka występuje na wyższym poziomie w rejestrze agentów, gdzie agenci są publikowani, aby inni mogli ich wykryć i używać w czasie wykonywania aplikacji, a nie poprzez sztywno zdefiniowane połączenia. ADK stanowi częściową wyjątkowość, obsługując funkcje A2A oraz karty agentów, podczas gdy pozostałe dwa rozwiązania pozostawiają to do Twojej decyzji.
Na koniec mamy zarządzanie kosztami i kwotami, rejestr audytowy potwierdzający działania floty, zarządzanie wspólnym magazynem danych oraz szybkie wersjonowanie. Prompt systemu to po prostu ciąg znaków, który należy do ciebie, a model jest stochastyczny, więc ustalanie stałych wartości promptów, porównywanie ich wersji oraz cofanie zmian to zasady, które musisz samodzielnie egzekwować.
To nie jest krytyka. Rozsądne jest zatrzymanie się na pętli agenta i powiązanych z nią elementach. Oznacza to jednak, że wybór SDK rozwiązuje być może połowę problemów związanych z agentem produkcyjnym.
Które SDK powinieneś więc użyć?
Aby wrócić do samych zestawów, oto krótka charakterystyka każdego z nich w jednym zdaniu. Wybierz Claude Agent SDK, gdy agent ma obsługiwać komputer, zarządzać plikami, shelliem, kodem oraz przeglądać internet – to najbardziej rozwinięty interfejs działania, wymagający ręcznych schematów, bez wyjść typowanych oraz połączeń z zmiennymi środowiskowymi. Wybierz OpenAI Agents SDK dla strukturyzowanych danych wejściowych i wyjściowych przy minimalnym użyciu Pythona – zapewnia najszybszą transmisję danych typowanych, pod warunkiem akceptacji domyślnego użycia narzędzi równoległych oraz utraty możliwości śledzenia działań za pośrednictwem proxy. Wybierz Google ADK, gdy kilka agentów musi współpracować poprzez wyraźne procesy robocze oparte na rzeczywistych sesjach – jego interfejs deweloperski jest najpotężniejszy, a oferta modeli najszersza, chociaż prosty agent samodzielny może uznać go za zbyt obciążający.
Poniżej mowa jest o różnych narzędziach, a nie o trzech elementach na jednej skali. Ten sam agent może zostać zaimplementowany we wszystkich z nich, ponieważ rdzeń, czyli pętla rozumowania nad narzędziami, jest wspólny. Różnice występują w elementach dodatkowych wokół tego rdzenia, i to one powinny decydować o Twoim wyborze.
Co ujawniło budowanie go trzy razy
Budowanie agenta trzy razy doprowadziło do jednoznacznego wniosku: pętla agenta to już rozwiązany, standardowy problem, a wszystkie trzy zestawy realizują go skutecznie. Prawdziwe różnice leżą w elementach dodatkowych – w schematach napisanych ręcznie w porównaniu z tymi wyprowadzonymi automatycznie, w tekście wolnym w porównaniu z wynikami wpisywanymi, a także w zintegrowanym środowisku wykonawczym w porównaniu z lżejszym klientem lub pełnym frameworkiem. To kwestie dopasowania, a nie jakości. Dopasuj SDK do zadania – czy to Claude do obsługi komputera, OpenAI do uzyskiwania wyników wpisywanych, czy ADK do systemów wieloagentowych – a każdy z tych trzech rozwiązań będzie dla Ciebie przydatny.
Trwałą lekcją jest granica, a trzy warstwy pokazują, gdzie ona się znajduje. Pakiety obejmują warstwę rozwoju i przekazują ją użytkownikowi w ciągu popołudnia. Warstwa czasu wykonywania i płaszczyzna sterowania, czyli obsługa rzeczywistego agenta oraz zarządzanie flotą, należą do użytkownika i to tam skupia się większość wysiłków inżynieryjnych. Narzędzie badawcze stało się przydatne dopiero po dodaniu elementów, których nie dostarcza żadne SDK: zanalizowanej tabeli SFA służącej jako punkt odniesienia, mechanizmu obsługi awarii, który zwykle znajduje się w bramce narzędziowej, oraz pamięci, która ulepsza jego funkcjonowanie z każdą dodaną etykietą. Dlatego wybierz SDK ze względu na jego dopasowanie do warstwy rozwoju, a następnie przygotuj budżet na dwie pozostałe warstwy.
Za tym tekstem kryje się dłuższa historia, znajdująca się w niższych warstwach. Ponieważ tworzenie agentów pojedynczych stało się powszechne, konkurencja przeniosła się na to, kto będzie zarządzał tymi agentami. Powstają tam nowe produkty: środowiska działania takie jak AWS Bedrock AgentCore i Google’s Gemini Enterprise Agent Runtime, które mogą hostować cokolwiek, co wygenerują te trzy zestawy, a także systemy zarządzania takie jak Microsoft’s Agent 365 i Google Enterprise, które rejestrują, identyfikują i kontrolują całe floty agentów. Sprzedają one praktycznie element po elemencie te komponenty. Problem polega na tym, że każda chmura chce mieć wszystkie trzy warstwy, więc SDK, które wybierzesz dzisiaj, skłoni cię jutro do wyboru środowiska działania i systemu zarządzania konkretnego dostawcy.
Literatura pokrewna
- Budowanie samokorygujących się agentów za pomocą LangGraph: pięć praktycznych wskazówek — Stwórz agenta wyszukiwawczego LangGraph, który próbuje ponownie w przypadku błędu, z obsługą stanu, krawędziami warunkowymi, funkcją zapisywania stanu, zatwierdzeniem przez człowieka oraz małymi węzłami, opisanymi przy użyciu działającego kodu.
- 10 frameworki agentów AI, które należy znać w 2026 roku: LangGraph, CrewAI i inne — Te frameworki agentów uszeregowane według sposobu koordynacji agentów, wraz z zaletami i wadami, najlepszymi zastosowaniami oraz przewodnikiem decyzyjnym pomagającym wybrać odpowiedni dla twojego zespołu.