JavaRush /Курси /ChatGPT Apps /Інструменти агента (Tools): схеми, маршрутизація, помилки...

Інструменти агента (Tools): схеми, маршрутизація, помилки

ChatGPT Apps
Рівень 12 , Лекція 1
Відкрита

1. Інструмент агента: що це таке насправді

У попередніх модулях ви вже бачили інструменти з боку Apps SDK — як «бекенд-функції», до яких ChatGPT звертається через ваш застосунок. Тепер змінимо ракурс: подивімося на інструменти з погляду агента в Agents SDK і розберімося, як він обирає, що викликати, та як поводитися з помилками.

У звичайному бекенді ви звикли мислити категоріями «endpoint», «метод контролера», «функція сервісу». У світі агентів базовою одиницею дії стає інструмент (tool). Водночас tools агента й MCP-tools — різні, хоч і споріднені, речі.

Якщо говорити точно, інструмент у контексті ChatGPT Agents SDK — це опис функції, яку модель може попросити виконати. Сама модель код не запускає: вона генерує структурований запит (зазвичай JSON), а рантайм (ваш код, MCP‑сервер або Agents SDK) уже виконує операцію та повертає результат.

В екосистемі ChatGPT Agents SDK інструмент описують конфігурацією: він має name, description і parameters (JSON Schema аргументів). Агент бачить цей набір інструментів, тримає його у своєму контексті й у процесі міркувань (reasoning) вирішує, який tool викликати та з якими аргументами.

Агент (або ChatGPT як хост) отримує цей список, «запамʼятовує» його у своєму контексті й під час міркувань визначає, який інструмент викликати для конкретного запиту користувача та які аргументи сформувати. Саме тому в специфікаціях постійно повторюють мантру «tools are a contract»: інструменти — це контракт між моделлю й вашим кодом, а не просто «функція в Python/TS».

Можна провести аналогію з класичним API. Маршрут /api/gifts/search — це суто синтаксис: URL, метод, формат тіла. А tool search_gifts — це семантика: «пошук подарунків за профілем і бюджетом». Опис інструмента — це, по суті, такий самий промпт, лише структурований і розрахований на LLM, а не на людину.

2. Типи інструментів: чим саме може займатися LLM‑агент

Щоб не потонути в хаосі «функцій, які вміють усе», корисно дивитися на інструменти як на кілька типових категорій. Це не формальна типізація SDK, а архітектурний підхід, який вам дуже допоможе.

У нашому бекенді LLM‑агенти зазвичай мають три джерела інструментів.

  • Локальні бізнес‑інструменти. Це те, що живе у вашому бекенді: робота з БД, доменна логіка (фільтрація, рекомендації, скоринг). Наприклад, для GiftGenius у нас можуть бути інструменти, які дістають товари зі своєї таблиці PostgreSQL або рахують персональний скоринг «наскільки подарунок зайде цій людині».
  • MCP‑інструменти. Тут MCP‑сервер виступає постачальником інструментів (tools): він реєструє функції, ресурси й промпти та віддає їх клієнту (ChatGPT, LLM‑агенту). Інструменти через MCP можуть викликати зовнішні API, працювати з файлами або надавати шаблони промптів.
  • Інтеграційні інструменти. Це все, що повʼязує вас із рештою світу: ACP/commerce (створення замовлення і checkout), надсилання листів, вебхуки, запис у CRM. Такі інструменти (tools) часто небезпечніші, бо змінюють стан зовнішніх систем. Тож до них потрібно ставитися особливо суворо — з погляду безпеки та ідемпотентності.

Є й інша корисна класифікація — за характером дії. У дослідженнях про LLM‑інструменти зазвичай виокремлюють: інструменти отримання даних (пошук, RAG, get_*), інструменти дій із побічними ефектами (create_order, send_email), суто обчислювальні (calculate_loan) і системні/керувальні (handoff_to_human, finish_task).

Щоб це зафіксувати, зручно подивитися невелику таблицю.

Категорія Приклад у GiftGenius Побічний ефект Ризик
Data Retrieval
search_gifts, get_details
Ні Низький
Action / Mutating
create_order, buy_gift
Так Високий
Computation
estimate_delivery_cost
Ні Середній
System / Control
finish_recommendation
Ні Логічний

З архітектурного погляду найважливіше таке: інструментів лише для читання має бути багато — і вони мають бути «дешевими», а ті, що змінюють стан, — рідкісними, максимально обережними, із журналюванням, ідемпотентністю й часто з підтвердженням від користувача.

Далі ми говоритимемо переважно про інструменти отримання даних та Action‑інструменти, тому що саме на них тримається логіка GiftGenius.

3. JSON Schema як контракт між моделлю і вашим кодом

Тепер давайте заглибимося в те, як описують інструмент. У ChatGPT Agents SDK (як і в Apps SDK) стандартний формат опису параметрів інструмента — JSON Schema: ви описуєте тип object, його properties, типи полів, обовʼязкові поля, обмеження тощо.

Важливо розуміти: JSON Schema тут не лише й не стільки про валідацію. Це частина промпта для моделі. В офіційних настановах OpenAI щодо проєктування інструментів (tools) прямо сказано: якість роботи агента дуже залежить від того, наскільки докладно й однозначно описані поля, їхні назви та коментарі.

Подивімося на приклад для GiftGenius, який уже траплявся в планах курсу.

{
  "name": "search_gifts",
  "description": "Знаходить подарунки за типом отримувача, інтересами та бюджетом.",
  "parameters": {
    "type": "object",
    "properties": {
      "recipient_type": {
        "type": "string",
        "description": "Хто отримувач подарунка (наприклад, 'чоловік', 'жінка', 'дитина')."
      },
      "interests": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Ключові інтереси (спорт, книги, технології тощо)."
      },
      "budget": {
        "type": "number",
        "description": "Максимальний бюджет у валюті користувача."
      }
    },
    "required": ["recipient_type", "budget"]
  }
}

Тут є кілька важливих моментів.

  • По‑перше, name і description. Для моделі це головний сигнал: чи варто взагалі використовувати цей інструмент. Документація про семантичну маршрутизацію підкреслює, що опис інструмента — це фактично API для моделі. Якщо ви назвете його func1 і підпишете «робить щось корисне», модель просто не зрозуміє, коли його викликати. А якщо написати search_gifts і додати зрозумілий опис, вибір стає значно простішим.
  • По‑друге, parameters. Назви полів і їхні описи вкрай важливі. Для LLM recipient_type набагато зрозуміліше, ніж type. Вдалий description на кшталт «Хто отримувач подарунка…» підказує моделі, що сюди потрібно підставити саме тип отримувача, а не, скажімо, формат пакування.
  • По‑третє, required. Це не лише валідація на вашому боці, а й підказка моделі: вона намагатиметься заповнити обовʼязкові поля, а необовʼязкові пропустить, якщо з контексту неясно, що туди ставити. Це зменшує кількість «порожніх» або некоректних tool‑викликів.

Офіційні настанови щодо Apps SDK прямо рекомендують: робіть інструменти вузькими, з однією відповідальністю, з чіткими іменами та описами й уникайте інструментів «зроби все для подарунків», які намагаються обʼєднати різні завдання.

4. Проєктуємо інструменти GiftGenius: від схеми до коду

Візьмімо наш GiftGenius і додамо туди два ключові інструменти LLM‑агента, які знадобляться майже в усіх сценаріях:

  • suggest_gifts(profile, budget) — видає список кандидатів;
  • get_gift_details(gift_id) — показує подробиці про конкретний подарунок.

Наші suggest_gifts і get_gift_details — типовий приклад локальних бізнес‑інструментів із попередньої класифікації, здебільшого з категорії Data Retrieval.

Схема для suggest_gifts

Почнемо з чистого JSON Schema, а потім покажемо, як це може виглядати в TypeScript‑коді бекенду або агентного рантайму.

{
  "name": "suggest_gifts",
  "description": "Підбирає список подарунків на основі профілю отримувача та бюджету.",
  "parameters": {
    "type": "object",
    "properties": {
      "age": {
        "type": "integer",
        "minimum": 0,
        "maximum": 120,
        "description": "Вік отримувача у роках."
      },
      "relationship": {
        "type": "string",
        "enum": ["friend", "coworker", "partner", "family"],
        "description": "Стосунки з отримувачем: друг, колега, партнер, сімʼя."
      },
      "interests": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Інтереси отримувача (спорт, книги, технології тощо)."
      },
      "budget": {
        "type": "number",
        "minimum": 1,
        "description": "Максимальний бюджет у валюті користувача."
      }
    },
    "required": ["budget"]
  }
}

Тут ми використовуємо enum для relationship, щоб модель не вигадувала довільні рядки на кшталт "поганий колега" і не передавала їх далі в код. Такий охайний дизайн схеми допомагає і моделі (вона бачить допустимі варіанти), і розробнику (менше несподіванок у рантаймі).

Тепер уявімо, що в нас є MCP‑сервер на Node.js з якимось умовним McpServer. Реєстрація інструмента може виглядати так:

// Спрощений приклад реєстрації інструмента в MCP‑сервері
server.registerTool(
  {
    name: "suggest_gifts",
    description: "Підбирає подарунки за профілем і бюджетом.",
    inputSchema: suggestGiftsSchema
  },
  async (input, ctx) => {
    const gifts = await findGiftsInDb(input, ctx.userLocale);
    return { items: gifts }; // JSON, який потім побачить агент
  }
);

Код дуже спрощено, але логіка зрозуміла: в одному місці — опис контракту (імʼя, опис, схема), в іншому — реалізація.

Схема для get_gift_details

Другий інструмент, який потрібен майже на будь‑якій вітрині:

{
  "name": "get_gift_details",
  "description": "Отримує повні відомості про подарунок за його ідентифікатором.",
  "parameters": {
    "type": "object",
    "properties": {
      "gift_id": {
        "type": "string",
        "description": "UUID подарунка в базі GiftGenius."
      }
    },
    "required": ["gift_id"]
  }
}

І аналогічна реєстрація:

server.registerTool(
  {
    name: "get_gift_details",
    description: "Повертає детальну інформацію про подарунок.",
    inputSchema: getGiftDetailsSchema
  },
  async ({ gift_id }) => {
    const gift = await db.gifts.findById(gift_id);
    if (!gift) return { notFound: true };
    return { gift };
  }
);

Зверніть увагу: ми тут одразу показуємо, що інструмент може повернути notFound: true. Це перші кроки до семантичних помилок (бізнес‑помилок), про які поговоримо нижче. Агент побачить «подарунок не знайдено» й ухвалить рішення: наприклад, спробує інший ID або запропонує користувачу вибрати інший товар.

5. Як агент обирає, який інструмент викликати

Тепер найцікавіше: маршрутизація. У традиційному веб‑застосунку роутинг жорсткий: URL → конкретний контролер. У світі ChatGPT Apps і агентів вибір інструмента відбувається семантично та ймовірнісно.

Високорівневий цикл можна зобразити так:

flowchart TD
  U[User message] --> M["Модель (агент)"]
  M -->|аналіз запиту| C{Потрібен tool?}
  C -->|ні| T[Текстова відповідь]
  C -->|так| S[Вибір інструмента]
  S --> K[Формування аргументів JSON]
  K --> R[Виконання інструмента]
  R --> M2[Модель бачить результат]
  M2 --> T2[Фінальна відповідь або наступний крок]

На кожному кроці агент бачить кілька речей:

  • По‑перше, system‑інструкції (роль агента, обмеження);
  • По‑друге, історію діалогу;
  • І нарешті, список інструментів (tools) з їхніми name, description, inputSchema.

Коли надходить чергове повідомлення користувача, модель порівнює зміст запиту з описами інструментів (семантичне зіставлення). Якщо запит «підібрати подарунок другу до 50 доларів», опис suggest_gifts звучить значно релевантніше, ніж get_gift_details, і агент із високою ймовірністю обере саме його.

Офіційні настанови підкреслюють дві речі, які сильно впливають на якість маршрутизації.

  • По‑перше, потрібно уникати інструментів, що перетинаються за змістом: якщо у вас є search_gifts і find_gifts, описані приблизно однаково, модель плутатиметься.
  • По‑друге, варто дотримуватися принципу єдиної відповідальності для інструмента: один tool — одне чітке завдання, а не «підібрати подарунки, створити замовлення та надіслати лист».

Усередині різних LLM‑агентів є механізми керування режимом вибору інструментів: наприклад, «auto» (модель сама вирішує, чи потрібен інструмент), «required» (інструмент потрібно викликати обовʼязково), «none» (tools вимкнено). Це допомагає в складних workflow (багатокрокових сценаріях), коли, скажімо, на певному кроці ви хочете примусово викликати suggest_gifts, а не дозволяти моделі просто «розмовляти».

Приклад семантичної маршрутизації в GiftGenius

Нехай у нашого агента є щонайменше два інструменти: suggest_gifts і get_gift_details.

  1. Користувач пише: «Підбери подарунок колезі до 30 доларів, він любить настільні ігри».
  2. Агент бачить, що запит містить мету «підібрати подарунок» і дані про бюджет та інтереси. Опис suggest_gifts підходить ідеально — викликаємо цей інструмент.
  3. Інструмент повертає список із пʼяти подарунків з їхніми ID, назвами та коротким описом.
  4. Користувач далі пише: «Розкажи докладніше про третій варіант». Агент зіставляє «третій варіант» з ID із попереднього результату — і тепер за змістом підходить інструмент get_gift_details. Тож викликаємо його.

Важливо помітити: ніде в коді ви явно не писали «якщо в запиті є слово „підбери“, то виклич suggest_gifts». Цим займається сама модель — на основі ваших описів та історії діалогу. Ваша відповідальність як розробника — зробити так, щоб вибір був очевидним і для моделі, і для людини.

6. Помилки інструментів: не 500, а сигнал для моделі

Памʼятаєте, у get_gift_details ми вже показували notFound: true? Це якраз приклад бізнес‑помилки, яку агент має побачити й осмислено обробити, а не отримувати «голий» 500.

Тепер перейдемо до найболючішого. У звичайному REST‑API щось упало в глибинах бекенду — повернули 500 Internal Server Error, записали стек-трейс у журнал — і далі користувач уже якось упорається. У випадку агента такий підхід працює погано.

Практичні настанови та матеріали про Agents SDK рекомендують ставитися до помилок інструментів як до спостережуваних подій, а не просто до падінь. Це часто називають патерном «Error as Observation».

Грубо кажучи, вам не варто «падати» без пояснення. Натомість краще повертати моделі структуровану відповідь, яка пояснює, що пішло не так, — щоб вона могла адаптувати поведінку: переформулювати запит, перепитати користувача, спробувати інший інструмент тощо.

Типи помилок зазвичай ділять на три групи.

  • Помилки валідації аргументів. Модель може згенерувати некоректні параметри: пропустити обовʼязкове поле, підставити рядок замість числа, вийти за межі допустимих значень. Тут схему й валідацію потрібно використовувати не лише для того, щоб кидати винятки, а й для осмисленої відповіді: наприклад, повернути, яке поле некоректне й чому.
  • Бізнес‑помилки. Це цілком очікувані ситуації на кшталт «товар не знайдено», «регіон недоступний», «бюджет надто малий для цього типу подарунків». З погляду API це теж помилки, але їх потрібно повертати в межах звичайної відповіді — зі зрозумілим кодом і повідомленням, а не як креш.
  • Системні помилки. Тайм-аути зовнішнього сервісу, проблеми мережі, збої бази. Тут агенту зазвичай достатньо акуратного, узагальненого повідомлення на кшталт «служба тимчасово недоступна, спробуйте пізніше». Жодних стек-трейсів, назв таблиць та інших подробиць, які моделі не потрібні й можуть бути небезпечними з погляду безпеки.

Офіційні матеріали про Agents SDK навіть пропонують спеціальний механізм failure_error_function, який дає змогу акуратно сформувати текст помилки, що його побачить модель, замість того щоб просто кидати виняток угору стеком.

Структура «дружньої» помилки

В інструменті агента (у вашому бекенді) ви можете домовитися, що будь‑яка помилка повертається, наприклад, у вигляді обʼєкта:

type ToolError = {
  code: string;      // 'VALIDATION_ERROR', 'OUT_OF_STOCK', ...
  message: string;   // для моделі
  retryable: boolean;
};

А результат роботи інструмента — як обʼєднання:

type SuggestGiftsResult =
  | {
      ok: true;
      items: GiftSummary[];
    }
  | {
      ok: false;
      error: ToolError;
    };

Модель (або агентний рантайм) побачить такий JSON і зможе вирішити: якщо retryable: true, можна спробувати ще раз із невеликими змінами; якщо помилка бізнес‑рівня й вона неповторювана, краще повернутися до користувача та пояснити, що саме не так.

7. Приклади: валідація, бізнес‑помилка і системна помилка

Повернімося до нашого бекенду та інструментів агента й подивімося, як реалізувати ті самі ідеї в коді.

Помилка валідації

Уявімо, що до вас надійшов виклик інструмента suggest_gifts, але модель чомусь вирішила передати відʼємний бюджет.

async function handleSuggestGifts(input: SuggestGiftsInput)
  : Promise<SuggestGiftsResult> {

  if (input.budget <= 0) {
    return {
      ok: false,
      error: {
        code: "VALIDATION_ERROR",
        message: "budget має бути додатним числом.",
        retryable: false
      }
    };
  }

  const items = await findGiftsInDb(input);
  return { ok: true, items };
}

Тут ми свідомо не кидаємо виняток, а повертаємо структуровану помилку. Агент може переосмислити запит: можливо, він вирішить, що переплутав валюту, і перепитає користувача. Або просто визнає, що не може підібрати подарунок із таким бюджетом.

Бізнес‑помилка

Тепер приклад із get_gift_details. Подарунка з указаним ID може просто не бути.

async function handleGetGiftDetails(input: { gift_id: string }) {
  const gift = await db.gifts.findById(input.gift_id);

  if (!gift) {
    return {
      ok: false,
      error: {
        code: "GIFT_NOT_FOUND",
        message: "Подарунок із таким ідентифікатором не знайдено.",
        retryable: false
      }
    };
  }

  return { ok: true, gift };
}

У відповіді моделі можна очікувати щось на кшталт: «Здається, обраний подарунок більше недоступний. Можу запропонувати кілька альтернатив із подібної категорії?». Для цього агенту не потрібно бачити SQL‑помилки та стек-трейси — лише зрозумілі code і message.

Системна помилка

Нарешті, приклад системної помилки. Нехай ваш інструмент звертається до зовнішнього API доставки, який інколи «падає».

async function handleEstimateDelivery(input: EstimateDeliveryInput) {
  try {
    const eta = await callDeliveryApi(input);
    return { ok: true, eta_days: eta };
  } catch (e) {
    return {
      ok: false,
      error: {
        code: "DELIVERY_SERVICE_UNAVAILABLE",
        message: "Служба доставки тимчасово недоступна.",
        retryable: true
      }
    };
  }
}

Агент може вирішити: «Схоже, служба доставки зараз недоступна. Я все одно покажу вам подарунки, але точний час доставки може відрізнятися. Хочете продовжити?».

8. Безпека та ідемпотентність інструментів (швидкий погляд з боку tools)

Повноцінна розмова про безпеку й дозволи буде в окремій темі, але інструменти агента надто тісно з цим повʼязані, щоб зовсім не торкнутися цього питання.

По‑перше, потрібно розділяти інструменти читання та інструменти запису. В описах, схемах і дозволах явно зазначайте, які tools лише читають дані й абсолютно безпечні, а які вміють списувати гроші, змінювати замовлення тощо. Документація і форуми про агентні сценарії прямо говорять про розділення ReadOnly і Mutating‑інструментів (tools).

По‑друге, для мутуючих інструментів потрібно думати про ідемпотентність. Агент або MCP‑клієнт цілком може повторити виклик (наприклад, через мережеву помилку), і ви не хочете, щоб create_order створив два замовлення замість одного. Типові підходи тут такі:

  • idempotency‑key, який передається як аргумент інструмента;
  • перевірка існування операції перед виконанням;
  • розділення кроків на «створи чернетку замовлення» і «підтвердь замовлення».

Усе це дуже тісно повʼязано з тим, як саме ви проєктуєте контракт інструмента: якщо в JSON Schema немає поля для idempotency‑key, додати ідемпотентність потім буде значно болючіше.

9. Невеликий погляд на Agents SDK: як це виглядає в агентному рантаймі

Цей розділ — короткий огляд для тих, хто працюватиме з TypeScript‑орієнтованим Agents SDK. Хоч основна частина курсу в нас про MCP, корисно розуміти, як подібні інструменти бачить Agents SDK і як виглядає типовий tool у рантаймі.

В офіційній документації зазвичай описують сутність на кшталт «функціонального інструмента»: будь‑яка функція, описана через конфігураційний обʼєкт (або helper на кшталт tool(...)) і забезпечена типами, може бути автоматично перетворена на інструмент, для якого SDK згенерує JSON Schema та опис.

На рівні концепції це те саме, що ми вже обговорювали: імʼя функції, її параметри і коментар/description відіграють роль імені, схеми й опису інструмента. Різниця в тому, що більшу частину «механічної» роботи за вас робить SDK та/або допоміжна бібліотека для схем (наприклад, Zod або JSON Schema).

Умовний приклад (псевдо‑TypeScript, спрощено):

type Gift = {
  id: string;
  title: string;
  // ...
};

const suggestGifts = tool({
  name: "suggest_gifts",
  description: "Підбирає список подарунків за типом отримувача і бюджетом.",
  parameters: {
    type: "object",
    properties: {
      recipient_type: {
        type: "string",
        description: "Хто отримувач подарунка (наприклад, 'чоловік', 'жінка', 'дитина')."
      },
      budget: {
        type: "number",
        description: "Максимальний бюджет у валюті користувача."
      }
    },
    required: ["recipient_type", "budget"]
  }
}, async (args: { recipient_type: string; budget: number }): Promise<Gift[]> => {
  // Усередині — ваша доменна логіка
  return findGifts(args.recipient_type, args.budget);
});

SDK (або ваш helper tool) на основі обʼєкта parameters побудує JSON Schema і передасть його агенту, а рантайм подбає про валідацію та маршалінг аргументів туди й назад. Концептуально це рівно те, що ви вручну робили в MCP‑сервері на TypeScript, тільки тепер інструмент «підʼєднано» прямо в агентний рантайм.

Важливо тут не завчити конкретний синтаксис хелпера tool, а вловити думку: якісна типізація + зрозумілий description/коментарі = якісний інструмент.

Якщо все це підсумувати: хороший інструмент агента — це вузька, чітко описана функція з продуманою JSON Schema, зрозумілим описом для моделі й акуратним опрацюванням помилок. Семантична маршрутизація працюватиме лише тоді, коли інструменти не перетинаються за змістом. А мутуючі операції мають бути безпечні та ідемпотентні — інакше агент у продакшн‑середовищі швидко перетвориться на джерело сюрпризів.

10. Типові помилки під час проєктування інструментів агента

Помилка № 1: Занадто широкі інструменти «do_everything».
Інколи дуже хочеться запхнути все в один інструмент manage_gifts, який і шукає подарунки, і показує деталі, і створює замовлення, і надсилає лист. Після цього моделі складно: опис стає розмитим, семантична маршрутизація деградує, і агент починає викликати цей інструмент «про всяк випадок» навіть там, де потрібен простий пошук. Краще розбивати задачі на окремі інструменти з однією, добре зрозумілою відповідальністю.

Помилка № 2: Інструменти, що перекриваються за змістом.
Якщо у вас є search_gifts і find_gifts, і обидва «шукають подарунки за інтересами», модель випадково обиратиме між ними. У результаті поведінка стає нестабільною: однакові запити іноді йдуть в один tool, іноді — в інший. Намагайтеся, щоб кожне імʼя й опис займали унікальну «нішу» у смисловому просторі.

Помилка № 3: Погані або відсутні описи й поля схеми.
Імʼя func1, опис «Does something» і параметр data: string — класичний спосіб зробити агента «нетямущим». Модель не телепат і не може прочитати ваш вихідний код. Вона спирається на description, properties і їхній description у схемі. Якщо ви не поясните, що таке recipient_type, модель гадатиме й помилятиметься.

Помилка № 4: Орієнтація лише на happy‑path та ігнорування помилок.
Багато реалізацій інструментів припускають: «Ну в нас же завжди будуть коректні аргументи й доступний сервіс». У реальному світі модель легко генерує неправильні параметри, зовнішні сервіси падають, а база інколи каже «timeout». Якщо не продумати формат помилок і не повернути агенту осмислене повідомлення, він не зможе скоригувати поведінку й або мовчки падатиме, або галюцинуватиме.

Помилка № 5: Передавати в LLM «сирий» 500 і стек-трейс.
У REST‑API ми звикли зберігати повний стек-трейс у журналі, щоб швидше налагоджуватися. У контексті агента стек-трейс, переданий моделі, — це водночас і марно (модель не знає, що таке SQLException у вашій конкретній бібліотеці), і потенційно небезпечно (зайві деталі реалізації і, можливо, конфіденційна інформація). Куди корисніше перехопити виняток, записати деталі в журнал, а в модель відправити акуратні code і message.

Помилка № 6: Відсутність ідемпотентності в мутуючих інструментах.
Інструмент create_order без idempotency‑key — це пряме запрошення до подвійних замовлень, особливо в умовах мережевих збоїв та автоматичних ретраїв. Якщо ваш агент працює в комерційному сценарії, інструменти, повʼязані з грошима, мають бути спроєктовані так, щоб повторні виклики не призводили до додаткових списань або дублів.

Помилка № 7: Зберігати секрети й технічні деталі в схемі або описі.
Іноді розробник за звичкою пише в description: «Усередині викликає сервіс X на https://internal-api.example.com». Моделі ця інформація не потрібна, користувачу — тим більше. Схеми й описи — частина промпта, вони живуть у контексті моделі. Тож туди не варто класти URL‑адреси внутрішніх сервісів, назви приватних таблиць і тим паче секрети.

Помилка № 8: Передавати в інструменти все підряд замість продуманого набору полів.
Легко піддатися ідеї «просто передамо всередину весь промпт користувача рядком, а там розберемося». Так ви втрачаєте користь структурування через JSON Schema: модель уже не розуміє, які саме частини запиту важливі для логіки, ви позбуваєтеся валідації та передбачуваності. Краще витягти із запиту явні поля (budget, interests, user_location) і описати їх як частину контракту інструмента.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ