Claude Agent SDK проти OpenAI Agents SDK проти Google ADK: один агент, три версії
Claude Agent SDK проти OpenAI Agents SDK проти Google ADK: один агент для етикеток харчових продуктів створений тричі, з описом того, що робить кожен набір, та того, що доводиться писати самостійно.
Кожен великий постачальник ШІ тепер постачає SDK для агентів, і пропозиції майже ідентичні. Дайте нам ваші інструменти та запит, і ми запустимо цей цикл: виклики інструментів, структурований вихід, сеанси та відстеження включено. Якщо маркетинг настільки схожий, що ж насправді відрізняє ці набори, і на якому з них варто будувати свої рішення?
Щоб дізнатися це, ми створили одного й того самого агента тричі: за допомогою Claude Agent SDK від Anthropic, SDK для агентів від OpenAI та Agent Development Kit (ADK) від Google. Цей агент — це не іграшка. Це інструмент для аналізу етикеток харчових продуктів, який читає фото, використовує кілька інструментів для аналізу, надає висновок та вдосконалюється з кожною новою інформацією. З одним агентом та трьома інструментами будь-які відмінності у результатах походять від SDK, а не від самої проблеми.
Коротко кажучи: усі три підходи майже повністю збігаються щодо складної частини — циклу міркувань, — але різняться у всьому, що пов’язано з нею. Вони відрізняються тим, як оголошується інструмент, як додається зображення та чи отримується взагалі текстовий результат. Найбільш показовим є те, що вони різняться у тому, що жоден з них не робить за вас. До кінця ви дізнаєтесь, який набір підходить для якої роботи та скільки роботи залишиться у вас після його вибору.
Ще один елемент пронизує всі три версії. Агент був створений для навчання на основі досвіду. Він пам’ятає продукти, які вже оглядав, та назви добавок, які зміг ідентифікувати, і зберігає цю інформацію на диску, тож кожен наступний запуск все менше покладається на модель, виконується швидше та поводиться більш детерміновано. Ваги моделі ніколи не змінюються. Саме агент накопичує навички. Жоден з SDK не надає цього вже готовим, що робить його корисним інструментом для визначення межі роботи цих інструментів та початку вашої власної роботи над проектом.
По-перше, що вважається агентом
Модель простої мови — це не агент. Уявіть її як функцію, яка приймає текст та зображення та повертає текст. Жодна інформація не зберігається між викликами; вона не може виконувати код чи завантажувати сторінку, а навіть не може знову себе викликати. Якщо дати їй етикетку з інформацією про харчування, вона розповість, як би провела дослідження, проте дослідження так і не відбувається.
Агент — це модель, яка працює у циклі з використанням інструментів. Схема її роботи ніколи не змінюється. Ви даєте моделі мету та список інструментів, які вона може використовувати. Вона відповідає або кінцевим результатом, або запитом на використання інструменту, наприклад «знайди інформацію про E211». Якщо вона просить про інструмент, щось його виконує та повертає результат, після чого модель продовжує роботу. Цикл повторюється, поки не з’явиться кінцева відповідь.
Цей цикл і є суттю всього: модель приймає рішення, запускається інструмент, надходить результат, модель знову приймає рішення. Наш дослідник проходить цей процес багато разів — один раз для пошуку продукту, по одному разу для кожного додаткового компонента, потім для перевірки варіанту «Здоровіший вибір», визначення класу та остаточного синтезу. На кожному кроці модель обирає наступний крок на основі того, що щойно дізналася. Саме це робить її агентною, і саме тому один виклик API, обгорнутий у цикл for, не підходить.
Зверніть увагу на те, що насправді генерує модель: лише „Я хотів би викликати check_sfa_additive з цими аргументами“. Щось інше має перетворити це бажання на справжній виклик функції та забезпечити продовження роботи. Цим „щось“ є harness, який містить більше складних внутрішніх механізмів, ніж очікують більшість людей. Він поділяється на три шари. Шар Розробки — це місце, де створюється агент. Шар Експлуатації — це місце, де агент використовується у продакшені. План керування — це місце, де керується ціла флотилія агентів. Саме шар Розробки забезпечує запуск усього процесу, і саме там знаходяться ці SDK.
Почніть з рівня Розробки, де створюється окремий агент. Він складається з самого циклу (виклик моделі, виявлення запитів на використання інструментів, повторення дій до завершення, безпечне завершення роботи при досягненні ліміту кроків або бюджету) та персони — тобто системного запиту, який пояснює моделі, хто вона та як поводитися. Навколо цих елементів знаходяться схеми інструментів, які описують кожен інструмент для моделі у форматі, який вона очікує, та процес виконання інструментів, який фактично запускає вашу функцію, сервер MCP або вбудований механізм, наприклад для читання файлів, та фіксує результат. Клієнт MCP дозволяє агенту підключатися до серверів сторонніх постачальників. Менеджмент контексту зберігає поточний текст розмови, обробляє зображення та скорочує його обсяг, коли він стає занадто великим. Налаштування постачальника включають автентифікацію, кінцеві точки та формати запитів для конкретного постачальника. Крім того, існує структурований вихід, який примушує та перевіряє кінцеву відповідь згідно з фіксованою формою, а також робочі процеси з кількома агентами, які поєднують агентів у послідовності, паралельно чи у циклах.
SDK допомагають полегшити все це. Переходячи від виконання скриптів до керування сервісом, з’являється шар Runtime та ще більший список вимог. Агенту потрібне розміщення для виконання, тобто кінцева точка з ізоляцією сеансів, до якої можуть звертатися інші системи. Йому потрібен шлюз інструментів, механізми повторних спроб, таймаутів та обробки облікових даних, які забезпечують надійність викликів інструментів у разі несправності верхнього рівня API, а також керована пам’ять, щоб сеанси та довгостроковий стан зберігалися у сховищі, яке виживає після завершення процесу та може бути використане між різними інстанціями. Також потрібна ідентичність робочого навантаження для виклику інструментів, щоб ці виклики не здійснювалися за допомогою особистого ключа когось, а також можливість спостереження з відстеженням та записами про те, які інструменти були використані, з чим та чому. Додайте пісочницю для власного коду агента чи інструментів браузера, стійкі цикли, які продовжують роботу з останнього завершеного кроку після збою, та можливість масштабування за рахунок конкурентності та автомасштабування за заднім фоном ендпоїнта.
Під ним знаходиться рівень керування, який одночасно керує багатьма агентами. Реєстр дозволяє публікувати та знаходити агенти під час виконання, замість того щоб їх прямо пов’язувати в коді. Кожен агент потребує ідентичності як окремої, ідентифікованої одиниці в каталозі, а також чіткого визначення прав, які мають бути обов’язково дотримувані, а не лише припускатися. Пізніше необхідні журнали аудиту та відповідності, які показують, що робила ця група агентів, механізми керування даними щодо того, що може зберігатися та розкриватися у спільній пам’яті, а також контроль витрат та квот із бюджетами та обмеженнями швидкості. Агенти можуть взаємодіяти один з одним через відкритий протокол, такий як A2A. Оскільки результати роботи інструментів надходять безпосередньо назад у модель, важливі механізми захисту та контролю, а оцінка дозволяє з’ясувати, чи є відповіді правильними, а не просто чи завершилося виконання. Реєстр інструментів та серверів MCP забезпечує каталогізацію, версіонування, пошук, об’єднання ресурсів та автентифікацію для кожного сервера, а швидке версіонування дозволяє фіксувати, порівнювати та скасовувати запити, щоб результати виконання залишалися відтворюваними. Коротко кажучи, кожен із цих наборів є готовою системою. Claude, OpenAI та Google забезпечують всю інфраструктуру — логіку виконання, інструменти, обробку контексту та підключення постачальників, залишаючи вам можливість писати ключові елементи: ваші інструменти, ваші запити та формат вихідних даних. ADK є винятком у назві, хоча виконує ту саму функцію, тому під «SDK» нижче розуміються всі три набори.
Вони розходяться у думках щодо того, які елементи кріплення вони надають, наскільки кожен елемент є автономним, та де саме кріплення закінчується, а ваш код мусить взяти на себе контроль. Найчистіший спосіб уточнити це — створити по одному агенту в кожному з них. Як тільки всі три будуть створені, можна буде сформувати повне кріплення та позначити, що саме надає кожен набір та що залишає для вас.
Агент, який тестується: дослідник етикеток з інформацією про харчування
Чесний тест має змусити ці набори виконувати ту роботу, для якої вони створені: це ланцюг міркувань між кількома інструментами, де кожен наступний крок залежить від результатів попереднього. Одина лише виклик моделі в межах певної фреймворк-структури не буде ефективною. Справжню роботу виконує дослідник. Якщо показати йому фото етикетки з інформацією про харчування, він виконає п’ять завдань.
- Він читає етикетку за допомогою власного зорового розпізнавання, витягуючи назву продукту, повний перелік інгредієнтів та добавок, кількість цукру та насичених жирів на 100 мл, а також інформацію про те, чи є продукт напоєм. Фото є єдиним джерелом інформації, оскільки немає бази даних продуктів, на яку можна було б покластися.
- Для кожної знайденої добавки, незалежно від того, чи вказано на етикетці
E471чи „Соєва лецитин“, він звертається до списку дозволених добавок SFA від Сінгапуру та повідомляє про їх статус та будь-які попередження для споживачів. - Він запитує базу даних HPB на сайті data.gov.sg, щоб дізнатися, чи має продукт символ Healthier Choice.
- Для напоїв він визначає очікуваний рівень харчової цінності A/B/C/D на основі кількості цукру та насичених жирів.
- Він об’єднує всю отриману інформацію в класифікацію — ЗЕЛЕНЕ, ЯНТАРНЕ чи ЧЕРВОНЕ — згідно з кожним висновком, вказуючи інструмент чи етикетку, які його дали, а також обґрунтування моделі на початку.
Він також не починає з нуля щоразу. Він пам’ятає те, що бачив, і навчається протягом роботи, тож як продукт, який перевіряли вчора, так і назва добавки, з якою раніше були проблеми, будуть у розпорядженні наступного разу. Більше про це пізніше.
Отже, тестове середовище пропонує інструмент із змінною довжиною, справжнє джерело даних з Сінгапуру, можливість введення зображень, вердикт, який можна перевірити у відділі супермаркету, та агента, який трохи покращується з кожною спробою.
Забезпечення справедливого порівняння
Усе, що не є частиною SDK, мусило залишатися ідентичним. Усі три демонстрації використовують один проксі LiteLLM — шлюз, сумісний з OpenAI, який також обслуговує кінцеву точку /v1/messages від Anthropic для SDK Claude. Один кореневий файл .env містить ключ, базову URL та назву моделі для кожного з них; моделі — це Claude Sonnet 4.6, GPT-5.4 та Gemini 3.5 Flash. Спосіб, яким кожен SDK підключається до цього проксі, дозволяє багато чого з’ясувати.
Кожна демонстрація знаходиться у власному проекті uv, тож ви можете запустити одну, не встановлюючи залежності інших. Таблиця додаткових інгредієнтів SFA була створена один раз на основі PDF „Permitted-Additives“, яке публікує уряд Сінгапуру з питань харчування, що дало результат у вигляді файлу sfa_additives.json (приблизно 540 записів, з яких близько 270 містять номери E), а потім без змін скопійована до кожного проекту. Зображення для тестування також були ідентичними: два справжніх продукти з Сінгапуру — пакетик Milo 3in1 та коробка з молоком Marigold HL.
Це залишає лише те, що справді є рішенням SDK: як визначається інструмент, як додається зображення, як підключається модель, чи існує текстовий результат та як можна побачити, що сталося.
Попередження перед кодом. Наведені нижче фрагменти містять інструмент recall_product та аргумент e_number_hint. Вони забезпечують функції пам’яті та самовдосконалення, про які йтиметься далі, тож поки що можна їх проігнорувати.
SDK Claude Agent від Anthropic
SDK Claude Agent базується безпосередньо на Claude Code — агенті, який багато хто вже використовує в терміналі, і саме це рішення впливає на все інше. Ви не створюєте цикли з примітивних елементів; ви керуєте повністю перевіреним агентом та надаєте йому свої інструменти та запити. Вбудовані інструменти (Read, Write, Edit, Bash, WebFetch) вже є, модель дозволів та керування контекстом вже реалізовані, а ваші власні інструменти підключаються через сервер MCP, який працює всередині вашого власного процесу. Усе виконується асинхронно за допомогою anyio.
Те, що ви купуєте, — це справжній агент для роботи з комп’ютером, готовий до використання. Будь-який інструмент, який потребує читання файлів, виконання команд оболонки, редагування коду чи перегляду інформації, надходить у вигляді продакшн-готового рішення вже з першого дня, адже це та сама технологія, яка працює в Claude Code. MCP є першокласним інструментом, тому користувацький інструмент, який ви напишете, буде працювати без змін у Claude Code, Claude Desktop та у вашому власному додатку. Серед цих трьох варіантів цей варіант використовує найбільш розвинену среду виконання агентів.
Вартість визначається інструментами, для яких ви вручну вказуєте назву, опис та схему:
@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))
Цей словник {arg: type} вимагає більше часу на введення, ніж два інші набори, проте не залишає жодних можливостей для неоднозначності. Інструменти потім доступні через внутрішній сервер MCP, а модель посилається на них за допомогою префікса mcp__<server>__<tool>; це потрібно пам’ятати під час заповнення поля 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,
},
)
Зображення додаються таким самим способом «зроби це сам». Аргументу image= не існує. Функція query() приймає асинхронний ітерабель з словників повідомлень, тож ви самостійно створюєте первинні блоки контенту, сумісні з Claude — блок тексту поруч із блоком зображення:
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
Гострий край — це модельне підключення. SDK керує вбудованою CLI Claude Code, яка використовує формат повідомлень Anthropic, тому ви можете перенаправити її до проксі за допомогою змінних середовища (ANTHROPIC_BASE_URL та ANTHROPIC_AUTH_TOKEN). Передавати об’єкт клієнта не потрібно. Перевагою є повністю прозорий цикл: ви друкуєте кожен ToolUseBlock у момент його отримання та можете спостерігати за розвитком кожного циклу додавання в реальному часі. Ось приклад роботи з пакетом 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.
Де виникають проблеми. Не існує вбудованого структурованого формату вихідних даних, тому ви отримуєте текст, який потрібно або обробляти, або ж докладно вказувати його форму, що є найбільшою щоденною різницею порівняно з SDK OpenAI. Схеми створюються вручну, тому потрібно більше писати та підтримувати синхронізацію з кожною функцією. Підключення моделей відбувається через середовище, і проксі, до якого ви звертаєтесь, мусить надавати кінцеву точку формату Anthropic /v1/messages, оскільки сама по собі кінцева точка, сумісна з OpenAI, недостатня. Розглядайте список allowed_tools як попередню затвердження, а не як санкчуарій: це означає „пропустити запит на підтвердження для цих інструментів“, а не „агент може бачити лише ці інструменти“, і ті, хто сприймає його як список дозволених інструментів, будуть здивовані. Якщо ігнорувати префікс mcp__sg__, інструмент просто залишиться незатвердженим без жодної помилки. Вплив на систему також є більшим, оскільки запускається фоновий процес Claude Code, а не здійснюється простий виклик API.
Обирайте цей варіант тоді, коли агенту потрібно керувати пристроєм. Це означає читання та запис файлів, виконання команд шелу, редагування кодової бази чи перегляд вмісту — будь-яку задачу, де вбудовані інструменти Claude Code допомагають уникнути необхідності створення сандбоксу. Це також природний вибір, якщо ви вже працюєте з MCP або створюєте щось, що має нагадувати Claude Code. Цикл стрімінгу легко спостерігати, що є перевагою для агентів, які працюють протягом тривалого часу.
Використовуйте його тоді, коли вам потрібен компактний цикл виклику функцій з введенням даних, який повертає структурований об’єкт, адже саме для цього створений SDK OpenAI. Використовуйте інший варіант, якщо ви не можете надати кінцеву точку у форматі Anthropic або якщо важлива мінімальна кількість залежностей. Звичайне завдання на кшталт „викликати три інструменти та повернути об’єкт Pydantic“ потребує значно менше ресурсів.
SDK OpenAI Agents
SDK OpenAI — це легкий, навмисно створений у стилі Python обгорток навколо цього механізму, який повністю присвятований самій мові. Підказки типів перетворюються на схеми інструментів, описи функцій — на їхні описи, а моделі Pydantic — на контракт вихідних даних. Ніщо не вимагає певної структури проекту, немає окремого середовища виконання та жодних зайвих етапів у форматі MCP. Ви пишете функції та моделі, створюєте Agent та передаєте його функції Runner.run. Мета — зменшити відстань між Python-функцією та функціональним агентом до мінімуму.
Його найкраща функція — це обробка даних у двох напрямках. Вкажіть output_type=YourModel, і у відповідь отримаєте перевірений об’єкт Python, а не бітовий фрагмент, який ви сподіваєтесь отримати у форматі JSON; SDK формулює запит, аналізує відповідь, перевіряє її та повертається до моделі, якщо формат даних не відповідає вимогам. Схеми, які автоматично створюються з типових підказок, разом із безкоштовною панеллю контролю для відстеження на власному сервері OpenAI, роблять цей підхід найшвидшим способом створення структурованого, прозорого агента. Коли завдання полягає у „прийняти ці дані та надати результат у форматі, який можна обробити“, жоден інший інструмент не є настільки прямим.
Інструменти зовсім не потребують створення схем:
@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. """
...
Декоратор читає підказки щодо типів та розділ Args у документації та створює схему JSON, тож немає потреби вручну щось підтримувати.
Справжня користь проявляється у результаті. Висновок оголошується як модель 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
За допомогою output_type=NutritionVerdict модель повертає перевірений об’єкт без необхідності обробки даних та без ризиків. Цікавим трюком є розміщення reasoning на початку — структурований вихід водночас слугує місцем для нотаток, тож модель обмірковує результати вголос перед тим, як остаточно їх задокументувати, а ви залишаєте охайний об’єкт та обґрунтування разом.
Підключення моделі та введення зображень є найбільш охайними з цих трьох варіантів:
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
Це клієнт AsyncOpenAI, призначений для проксі, загорнутий у OpenAIChatCompletionsModel, з елементом input_image, який передає фото. Без жодних складнощів.
Важливі моменти. За замовчуванням виклики інструментів відбуваються паралельно, тому модель може одночасно запустити кілька викликів check_sfa_additive. Наші виклики є асинхронними та не мають побічних ефектів, що є перевагою. Інструменти, які змінюють спільний стан, підтримують нереентрнтні з’єднання або залежать від певної послідовності, будуть працювати некоректно, а помилки з’являтимуться періодично та залежатимуть від часу — це найгірший варіант. Треба або зробити інструменти безпечними для паралельної роботи, або обмежити дії моделі.
Використання трекінгу має свої недоліки. Панель керування чудова, але дані трекінгу надсилаються на власний ендпоїнт прийому даних OpenAI, і через проксі сторонньої організації ключ, виданий проксі, не може автентифікуватися там. Тож однією рядкою коду set_tracing_disabled(True) можна вимкнути цю функцію, і ваш найкращий інструмент для моніторингу зникне. Поза адресою api.openai.com доводиться покладатися на OpenTelemetry або власні механізми логування. Існують ще менші проблеми: за проксі потрібен модель OpenAIChatCompletionsModel, оскільки стандартний шлях API Responses спрямований на ендпоїнти OpenAI, а неправильний вибір призводить до заплутаних помилок. Схема output_type має відповідати правилам строгого режиму, тому моделі з глибокою ієрархією або багатьма об’єднаннями можуть спричинити повторні спроби валідації; через це типи Finding та NutritionVerdict залишаються простими. І в коробці немає інструментів для роботи з комп’ютером, тому немає файлової системи, оболонки чи можливості перегляду, якщо тільки ви їх не додасте.
Ось результат для пакетика 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.
Оберіть його тоді, коли завдання має структурований вхід та вихід, наприклад класифікація, вилучення даних, оцінювання чи формування вердиктів, де текстові дані кращі за прозу, і ви хочете використовувати мінімум коду на Python. Команди, які люблять типові підказки, оцінять це, а завдяки бекенду OpenAI безкоштовне відстеження робить відлагоджування багатокрокових агентів приємним.
Пропустіть його тоді, коли ваші інструменти не можна зробити безпечними для паралельної роботи, і ви не хочете мати справу з паралельним режимом за замовчуванням, коли вам потрібна можливість спостереження, але ви працюєте через не-OpenAI шлюз (відстеження зникає), або коли агент мусить використовувати інструменти файлової системи та командного рядка без додаткових налаштувань, що є сферою діяльності Claude. Для кількох співпрацюючих агентів з чітким потоком керування краще підходить ADK, і це третій інструментарій.
Google's Agent Development Kit (ADK)
Серед цих трьох ADK — це справжня фреймворк-система з чіткими правилами, на відміну від інших, які залишаються більш простими. Він включає агентів, сеанси, Runner, SessionService та чітко визначені багатоагентні робочі процеси за допомогою SequentialAgent, ParallelAgent та агентів-циклів. Запропонована структура проекту дозволяє інструментам знаходити ваші агенти, а adk web відкриває локальний інтерфейс чату з інспектором подій. Інструменти є звичайними функціями Python із документацією у стилі Google docstrings, без декораторів чи словників схем, а обгортка LiteLlm робить його найбільш незалежним від конкретних постачальників варіантом.
ADK — це архітектура для систем, а не для скриптів. Коли під „агентом“ насправді мається на увазі кілька агентів, наприклад планувальник, який передає завдання працівникам, послідовна чи паралельна структура обробки, ADK пропонує їх як компоненти першого класу, що дозволяє уникнути ручного створення логіки керування. У ньому вбудовані сесії, інтерфейс для налагодження є найкращим у своїй групі, а модель, незалежна від постачальника, не змушує вас прив’язуватися до одного виробника. Він розроблений для розвитку у складний, зі станом, багатоагентний додаток.
Тут визначення інструментів є найпростішими:
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.
"""
...
Схема створюється на основі документації у стилі Google з елементами Args та Returns, тож її якість має велике значення. Нечітка документація безпосередньо впливає на вибір інструментів моделлю, тому саме документація є фактичним контрактом.
Щоб adk web зміг знайти ваш root_agent, проект має певну структуру пакетів:
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),
])
Модель передається через обгортку LiteLlm від ADK, де префікс openai/ змушує LiteLlm використовувати протокол, сумісний з OpenAI, для зв’язку з проксі. Найкращим із трьох способів є передача зображень за допомогою types.Part.from_bytes, а adk web пропонує найкращий вбудований досвід розробки у цьому порівнянні.
Проблемні моменти. Найбільше проблем створює вага. Поза adk web необхідно підключити Runner, SessionService та вказати ID додатку, користувача та сеансу ще до надсилання першого повідомлення — це багато формальностей порівняно з кількома рядками, які потрібні іншим рішенням. Крім того, сама структура також має велике значення. Рядок from . import agent у файлі __init__.py є способом, яким adk web знаходить об’єкт root_agent, і будь-яке відхилення від цієї структури ускладнює його виявлення. litellm генерує попередження щодо невикористовуваних бекендів (нешкідливі повідомлення про bedrock та sagemaker та попередження „no module named botocore“), а ADK додає попередження про схему [EXPERIMENTAL], через що доводиться вимикати обидва механізми під час імпорту. Структурований вихід також є складнішим у керуванні, оскільки response_schema Gemini через проксі є більш чутливим до змін, ніж output_type OpenAI, тому в цьому демо використовується оцінка тексту на основі запиту. Чесно кажучи, це настільки ж залежить від проксі, як і від ADK. Останній момент: у варіанті LiteLlm разом із Gemini-flash агент описував свої дії менше, ніж інші при однаковому запиті, що свідчить про те, що поведінка залежить від моделі та її налаштувань, а не лише від SDK.
Результат для пакета Milo:
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.
Обирайте ADK тоді, коли створюєте систему з кількома взаємодіючими агентами, чітко визначеними послідовними, паралельними або циклічними процесами, справжнім станом сеансу та можливістю заміни моделей між постачальниками. Інструмент adk web окуповує себе вже під час розробки, а архітектура повертає початкові витрати у міру розширення проекту.
Обійдіться без нього тоді, коли є лише один простий агент. Код для запуску та сеансу, а також передбачений формат — це додаткові витрати, які ви ніколи не повернете. Для найшвидшого результату використовуйте SDK OpenAI, а для агента на комп’ютері з вбудованими інструментами — Claude. ADK має сенс лише у великих масштабах, а в інших випадках це більше фреймворк, ніж вам потрібно.
Запуск демонстрацій
Після створення всіх трьох агентів ось як їх запустити. Кожен з них є проектом uv, і кожен з них читає кореневий файл .env, у якому містяться ключ проксі, базова URL та назви трьох моделей:
cd openai-demo # or claude-demo, or adk-demo
uv run python main.py ../milo.jpeg
uv run python main.py ../hl.jpeg
Щоб відновити таблицю SFA з PDF, виконайте uv run --with pdfplumber python build_additives.py. Передайте шлях до власної фотографії етикетки. Дві поставлені етикетки є справжніми продуктами з Сінгапуру, і їхні оцінки відповідають очікуванням: молоко отримує клас Nutri-Grade B, а Milo у вигляді порошку після приготування отримує оцінку C.
Більше, ніж один спробування
Демонстрація, яка виконує один чистий проходження, приховує цікаві аспекти. Три доповнення, ідентичні за формою у всіх SDK, роблять агентів більш реалістичними, і кожне з них щось говорить про SDK, який лежить в основі.
Реальні дані. Перевірка додаткових речовин — це не якийсь іграшковий словник із сімома записами. Файл build_additives.py аналізує офіційний PDF SFA, у якому три таблиці мають різну структуру стовпців (що саме по собі є складною задачею), та виділяє приблизно 540 додаткових речовин. Під час завантаження кожна демонстрація створює нормалізований індекс назв, щоб позначення „мононатрійглутамат“ відповідало офіційному позначенню у PDF „Monosodium L-glutamate“. Індекс номерів E/INS, заснований на базовому номері, дозволяє „500“ все одно знаходити „500(ii)“. Короткий покажчик враховує справжні сленгові терміни, відсутні у PDF, такі як „MSG“ та „вітамін C“. Усе, що справді не входить до списку, відображається як просте „не в списку“, а ніколи не як хибне „дозволено“.
Пам’ять та навчання. Ці два аспекти найкраще розглядати разом:
- Пояснення. Кожен агент відображає свої міркування: у випадку OpenAI це поле
reasoningу вигляді тексту, а у Claude та ADK — розділ## Reasoningна початку. - Згадування. Спочатку запускається інструмент
recall_product, який виводить будь-які попередні вердикти щодо того ж продукту, причому кожен запуск зберігає свій власний результат. Якщо одну мітку перевіряють двічі, під час другої перевірки результат порівнюється з першим висновком. - Навчання. Якщо мітка виводить назву, яку таблиця не розпізнає, а модель надає правильне число через
e_number_hint, пару „назва–число“ зберігається у файліagent_memory.json. Під час наступного запуску ця назва ідентифікується без необхідності запитувати модель.
Це і є навчання на рівні системи. Ваги ніколи не змінюються, проте агент вдосконалює власні дані та інструменти завдяки досвіду. Це практичний, досяжний вид навчання, на відміну від тонкої налаштуваності, яку жоден з цих інструментів не здійснює під час роботи. Кожен з них містить вбудований шар сеансів, який можна використовувати для роботи з пам’яттю у продакшені (OpenAI’s SQLiteSession, сховище сеансів Claude, SessionService ADK), а файл JSON просто робить демонстрацію портативною та зручною для перевірки.
Чим більше міток воно читає, тим краще стає. Фото, у якому назви інгредієнтів модель перетворює на числа, навчає систему пошуку нового псевдоніма, і кожен досліджений продукт стає чимось, що наступна обробка може згадати. Коли вперше з’являється «дисодій фосфат», процес опирається на модель для його перетворення на E339; після цього детерміністична таблиця просто знає це, тож все відбувається швидше, дешевше та може бути повторено без виклику моделі. На всій полиці з продуктами agent_memory.json перетворюється на словник псевдонімів та історію висновків, яку сам агент скомпілював. Якщо спрямувати групу агентів до одного спільного файлу пам’яті, назва, навчена одним агентом, стає відомою всім. Модель залишається незмінною, а агент — ні.
Останній деталь з реальних тестів: коли просили ввести номер E разом із назвою, усі три моделі надійно виконали завдання, самостійно перетворивши „Дифосфат натрію“ на E339. Це результат роботи циклу — загальні знання моделей компенсують те, що не може надати детерміністичний пошук, а система запам’ятовує результат.
Хто що надає
Після створення, запуску та розширення усіх трьох агентів можна сформувати повну структуру та позначити, що саме надало кожне SDK, а що довелося створювати вручну. Уявіть собі сітку, де зелений колір означає, що це надає SDK, жовтий — частково, а червоний — що це створюється власноруч. Компоненти поділяються на ті самі три рівні: рівень розробки для створення агентів, рівень роботи для їх керування та рівень керування для управління флотом. SDK знаходяться на першому рівні.
Якщо подивитися на рівень розробки, майже все має зелений колір; інструменти майже повністю згодні щодо створення одного агента. Якщо ж подивитися на два нижчі рівні, ситуація змінюється: кілька зелених чи помаранчевих елементів по краях (робочі процеси та оцінка ADK, відстеження дій OpenAI) знаходяться серед моря червоного кольору, яке є спільним для всіх трьох. Саме цей контраст є справжнім висновком. У створенні агента вони згодні, а його запуск та керування залишаються на вашій совісті.
Прогалини в SDK
Рівень розробки — це те, що SDK роблять простим. Рівні виконання та керування переважно відсутні в них, і, чесно кажучи, саме це SDK не призначені забезпечувати.
Почніть з проблем, які виникли лише під час демонстраційної збірки. Однією з них є інструментальний шлюз, який шар виконання відрізняє від звичайного виклику інструментів. Механізм керування викликає ваш інструмент коректно, але не робить нічого для забезпечення його надійності. Наприклад, API HCS від data.gov.sg іноді повертає код 503 разом із HTML-тілом, і простий виклик response.json() призводив до зупинки всього процесу (що стало болісним уроком). Допоміжна функція _safe_json, таймаути у десять секунд та альтернативні рішення типу „не в списку“ вирішили цю проблему, тож нестабільність вихідних інструментів перетворилася на просто помічену проблему, яка більше не зупиняє агента. Повторні спроби, стратегії відкладення та формування помилок всередині інструментів — усе це на вашій відповідальності, хоча саме це й призначений для виконання шлюз.
Другою прогалиною є управління пам’яттю. Усі три підходи включають шар сеансу, який зберігає стан розмови на одному вузлі, але це не те саме, що додаток, який зберігає дані у пам’яті, до якої може отримати доступ весь комплекс систем. Файл agent_memory.json, створений тут (запам’ятовані псевдоніми, історія recall_product, записи, які вдосконалюють агента з кожною міткою) — це логіка домену, розташована зверху, і фраза „чим більше ви його запускаєте, тим краще“ — це не те, що може надати спеціальний інструментарій. Підхід, заснований на реальних даних, є схожим. Парсинг PDF формату SFA на понад 540 структурованих елементів, створення нормалізованого індексу та пошук за базовими номерами — усе це не входить до функцій SDK, а надання агенту реальних даних — це шаблон, який потрібно налаштувати вручну, а не перемикач, який можна просто ввімкнути.
Безпека конкурентної роботи інструментів гірша, ніж просто їх некерована робота, оскільки сам механізм виконання створює небезпеку. За замовчуванням SDK OpenAI виконує незалежні виклики інструментів паралельно, і забезпечення їх безпеки у цих умовах залежить від вас. Ще один звичайний аспект: формування результату та його зберігання — це звичайний код програми, яким SDK не керує.
Якщо дивитися на шар виконання, агент спочатку потребує хостованого виконання — способу запуску з чогось іншого, ніж з сеансу терміналу, з можливістю одночасного виконання багатьох операцій та автоматичного масштабування. Йому потрібна ідентичність завдання — облікові дані, які надаються інструментам, щоб виклики відбувалися як від певного завдання, а не через API-ключ, прихований у змінній середовища. Крім того, потрібні надійні, можливі до продовження цикли, щоб у разі збою процес продовжувався з того місця, де зупинився, а не починався заново. Жоден з цих елементів відсутній у скриптах на ноутбуці, і жоден з них не є тим, що SDK стверджує надавати. Шар виконання також має масштабуватися у міру зростання навантаження.
У рівні керування всі три інструменти фактично нічого не роблять. Оцінка — це перший випадок: фраза „все пройшло без помилок“ не означає, що „результат був правильним“, а належна оцінка якості агента залежить переважно від вас. ADK є частковим винятком завдяки своїй системі оцінки, тоді як два інші залишають це питання відкритим.
Далі йдуть механізми контролю та захист від вставки команд. Кожен результат роботи інструменту є ненадійним вхідним даним, яке повертається до моделі, а фото з міткою чи відповідь API можуть містити інструкцію на кшталт „ігноруйте свої правила“. Рівень покриття є нерівномірним, і ніщо не відбувається автоматично, тому модель загроз належить вам.
Далі йде ідентичність агента із визначенням обсягу дозволів. Ці набори дозволяють встановити персонажа, проте не вказують, яким є статус агента як основного об’єкта каталогу та що йому дозволено доступувати, тож прив’язка його до реального власника та обмеження його доступу залишаються на вашій відповідальності.
Підключення до одного сервера MCP — це вже інша справа, адже всі три надають для цього відповідний клієнт. Однак реєстр інструментів та MCP, який каталогізує та версіонує інструменти та керує низкою серверів MCP з можливостями пошуку, об’єднання, використання облікових даних для кожного сервера та перевірки їхньої працездатності, знову ж таки залишається на ваш розсуд.
Аналогічна проблема з’являється на один рівень вище у реєстрі агентів, де агенти публікуються, щоб інші могли їх знаходити та викликати під час виконання, а не через жорстко закодовані зв’язки. ADK є частковим винятком, підтримуючи A2A та картки агентів, тоді як два інші залишають це на ваш розсуд.
Нарешті є керування витратами та квотами — журнал аудиту, який підтверджує дії флоту, керування спільним сховищем даних та швидке версіонування. Системний запит — це просто рядок, який належить вам, а модель є стохастичною, тому фіксація, порівняння та скасування запитів — це процедури, які ви повинні самостійно впровадити.
Це не є критикою. Розумно закінчувати на циклі агента та пов’язаних з ним механізмах. Однак це означає, що вибір SDK вирішує, можливо, половину вимог, які ставить перед собою продакшн-агент.
То який SDK вам слід використовувати?
Щодо самих наборів, ось короткий опис кожного в одному реченні. Оберіть Claude Agent SDK, якщо агент має працювати з комп’ютером, обробляти файли, виконувати команди в терміналі, працювати з кодом та переглядати інтернет; це найбільш розвинена система виконання, яка потребує ручного визначення схем, не передбачає типованого виводу та підключення через змінні середовища. Оберіть OpenAI Agents SDK для структурованого введення та виведення з мінімальним використанням Python; він забезпечує найшвидший процес обробки даних у типованому форматі, за умови прийняття стандартних паралельних інструментів та відсутності можливості відстеження дій через проксі. Оберіть Google ADK, коли кілька агентів мають співпрацювати через чітко визначені робочі процеси з використанням справжніх сеансів; його інтерфейс для розробників є найкращим, а вибір моделей — найширшим, хоча простий одиночний агент може вважати його занадто складним.
Насправді це різні інструменти, а не три варіанти на одній шкалі. Один і той самий агент може бути створений у всіх них, оскільки основна частина — логічний цикл обробки інструментів — є спільною для всіх. Відмінності полягають у додаткових елементах, які оточують цю основу, і саме вони мають визначати ваш вибір.
Що показало створення трьох версій
Створення агента тричі дало змогу чітко побачити один висновок: механізм роботи агента є вже вирішеною та стандартизованою проблемою, і всі три набори ефективно її вирішують. Справжні відмінності полягають у додаткових елементах — у ручно написаних чи автоматично сформованих схемах, у вихідних даних у вигляді вільного тексту чи введеного тексту, а також у використанні повного фреймворку, легкого клієнта чи окремого виконуваного модуля. Це питання підбору під конкретну задачу, а не якості. Підберіть SDK під вашу задачу — чи то Claude для керування комп’ютером, OpenAI для отримання результатів у введеному форматі чи ADK для багатоагентних систем — і будь-який з цих варіантів добре вам послужить.
Ключовий урок — це межа, а три шари показують, де вона проходить. Комплекти належать до шару розробки та надаються вам протягом одного дня. Шари часу виконання та керування, тобто реальне керування агентом та управління флотом, належать вам, і саме тут зосереджується більшість інженерних зусиль. Инструмент для досліджень став корисним лише після додавання того, що не надається жодним SDK: обробленої таблиці SFA для орієнтації, інструменту обробки несправностей, який зазвичай належить до інтерфейсу, та пам’яті, яка покращує його функціонал з кожною новою міткою. Тож оберіть SDK залежно від його підходу до шару розробки, а потім передбачіть кошти на два нижчі шари.
За цією історією прихована ще більша історія, яка знаходиться у нижчих шарах. Оскільки створення агентів окремими користувачами тепер стало звичайною практикою, конкуренція перемістилася на рівень того, хто керує цими агентами та хто їх регулює. Там формуються нові продукти: середовища виконання на кшталт AWS Bedrock AgentCore та Google’s Gemini Enterprise Agent Runtime, які можуть підтримувати будь-що, що створено за допомогою будь-якого з трьох наборів, а також системи керування на кшталт Microsoft’s Agent 365 та Google Enterprise, які реєструють, ідентифікують та контролюють цілі флоти агентів. Вони продають, майже слово в слово, елементи цієї структури. Проблема полягає у тому, що кожен хмарний провайдер хоче мати всі три шари, тож SDK, який ви оберете сьогодні, схилить вас до використання середовища виконання та системи керування певного постачальника завтра.
Пов’язані матеріали
- Створення самокоригуючих агентів за допомогою LangGraph: п’ять практичних порад — Створіть пошукового агента LangGraph, який буде повторювати спроби у разі невдачі, з підтримкою стану, умовних країв, функцією зберігання стану, людським схваленням, а також поясненням принципів роботи малих вузлів із прикладами коду.
- 10 фреймворків для агентів ШІ, які варто знати у 2026 році: LangGraph, CrewAI та інші — Десять фреймворків для агентів, відсортованих за способом їхньої координації, із описом переваг, найкращих сценаріїв використання та посібником з вибору підходящого фреймворку для вашої команди.